Skip to Content

Google Wallet

Drive geofenced notifications and custom messages on your users’ Google Wallet passes. Zeotap writes the merchantLocations geofence field on individual pass objects, clears it when a campaign ends, and can send custom pass messages — all keyed to the user’s own pass. The Android OS handles location detection; Zeotap only makes the API call at the right time.

Zeotap never creates passes or manages enrollment. It only modifies the merchantLocations field (and, optionally, adds a message) on passes your users have already saved to Google Wallet.

Prerequisites

  • A Google Wallet issuer account (Google Pay & Wallet Console) with the Google Wallet API enabled.
  • A GCP service account invited as a Developer on your issuer (see Authentication).
  • Pass objects already issued to users, and each user’s Wallet object ID flowing into Zeotap as a profile attribute.

Authentication

Google Wallet uses Service Account (JWT) authentication. Zeotap signs a short-lived JSON Web Token with your service account key and exchanges it for an OAuth 2.0 access token scoped to wallet_object.issuer.

  1. In the Google Cloud Console, enable the Google Wallet API for your project.
  2. Create a service account (IAM & Admin → Service Accounts). It needs no GCP IAM roles — the Wallet API uses its own permission model.
  3. Create a JSON key for the service account and download it.
  4. In the Google Pay & Wallet Console (Users & Permissions), invite the service account’s email and grant it the Developer role on your issuer account.
  5. Paste the JSON key into the Service Account JSON field in Zeotap.

Configuration

FieldTypeRequiredDescription
Service Account JSONFileYesThe GCP service account key JSON. Stored encrypted.
Issuer IDTextYesYour numeric Google Wallet issuer account ID (also the prefix of every object ID).
Default pass typeSelectNoThe pass object collection to target when a sync or row does not supply one: loyaltyObject, offerObject, genericObject, giftCardObject, or eventTicketObject. Defaults to loyaltyObject.
Requests per secondNumberNoClient-side throttle ceiling. Defaults to Google’s quota of 20 requests/second.

Target Settings

These are sync-level settings (they render in the sync’s Target Settings, not the field mapping):

FieldTypeRequiredDescription
ActionSelectYesWhat to do to the pass: Activate geofences, Clear geofences, or Send message. In audience mirror mode, activate also clears automatically when a member exits the audience.
Message typeSelectNoTEXT_AND_NOTIFY pushes a device notification; TEXT adds the message silently (Send message only).

The message content (header, body) is per-record data and lives in field mapping, not here — map a column to personalize per user, or set a fixed value. This keeps every field in exactly one place.

Supported Operations

Sync Modes: Update

Audience Sync Modes: Add, Remove, Mirror, Upsert

Audience mirror mode is the natural fit for the geofence lifecycle: a user entering the audience activates their geofences, and exiting clears them — no orchestration required. For event-driven campaigns (activate, wait, then clear, with an optional message), use a journey with Send to Destination steps.

Features

  • Field Mapping: Yes
  • Schema Introspection: No

Required Mapping Fields

Required fields are action-aware — the mapping enforces exactly what the selected action needs:

FieldRequired forDescription
wallet_object_idall actionsThe pass object ID to modify (e.g. 3388000000012345678.user-abc). Used as the API path — never sent in the request body.
merchant_locationsactivateThe geofence coordinates: an array of { latitude, longitude }. Only the first 10 are used.
headersend_messageNotification title. A notification needs both a title and body.
bodysend_messageNotification body.

Default Destination Fields

FieldTypeApplies toDescription
pass_typestringall actionsPer-user override of the default pass type. Optional — leave unmapped to use the connection default; a row with no value and no default fails.
message_idstringsend_messageOptional Message.id. Use a stable value for idempotency so a re-running journey step does not push a duplicate notification.
display_start_timestringsend_messageOptional ISO-8601 timestamp — the message becomes visible on the pass from this time.
display_end_timestringsend_messageOptional ISO-8601 timestamp — the message stops showing after this time.

How It Works

All three actions target the same object, addressed by wallet_object_id in the URL path:

  • Activate — PATCH /{passType}/{objectId} with the mapped merchant_locations (capped at 10). The OS then surfaces the pass on the lock screen when the device dwells near one of those points.
  • Clear — PATCH /{passType}/{objectId} with an empty merchantLocations array, switching the geofence off. Only the geofence is removed; the pass itself is untouched.
  • Send message — POST /{passType}/{objectId}/addMessage with a custom header and body. This is an immediate push, not location-triggered.

Every call is a single per-object request (the Wallet API has no bulk endpoint). A PATCH replaces the whole merchantLocations array — there is no append — so Zeotap always sends the complete desired set.

Rate Limits

Google enforces roughly 20 requests per second per issuer. Zeotap paces outbound calls to the configured Requests per second ceiling and retries on 429 responses with exponential backoff. A large audience activation is therefore throughput-bound: 500,000 users at 20 req/s takes roughly 7 hours, so prefer journey-triggered activations for timely campaigns and reserve always-on audiences for smaller segments.

Send message caps. addMessage is separately limited to roughly 3 messages per object per 24 hours, and each TEXT_AND_NOTIFY message pushes a real device notification. Excessive or repetitive messaging can put the issuer account under review by Google, so treat send_message conservatively: map a stable message_id for idempotency (so re-runs don’t re-push), prefer TEXT over TEXT_AND_NOTIFY while testing to avoid live pushes, and test against a small set of dedicated test objects rather than the production issuer at volume.

Best Practices

  • Order coordinates by relevance. Only the first 10 merchant_locations are sent, so put the most relevant stores first.
  • Always clear. For offers, clearing after redemption is required; for other campaigns it keeps stale geofences from firing indefinitely. Audience mirror mode clears automatically on exit.
  • Keep object IDs fresh. A user who removes the pass yields a 404; those rows are skipped and logged, not fatal.

Troubleshooting

403 Permission denied on every call

The service account has not been invited as a Developer on your issuer, or the Google Wallet API is not enabled for the project. Fix the invitation in the Google Pay & Wallet Console and re-run the connection test.

404 Pass object not found

The wallet_object_id does not exist — commonly because the user removed the pass from their wallet, or the ID convention feeding Zeotap is wrong. These rows are skipped and reported per-row; the batch continues.

400 Bad request on activate

Usually more than 10 locations, or malformed coordinates. Zeotap truncates to 10 automatically, so a 400 here typically means a coordinate value was non-numeric.

Geofence notification never appears on the device

Geofencing is Android-only and requires the user to have granted precise location access to Google Wallet. Detection is also not instant — Android batches location checks to save battery, so there can be a delay of several minutes after entering the ~150m radius.

The notification text can’t be customized

The geofence notification is system-generated (“You have a pass nearby”) and cannot be changed. For custom copy, use the Send message action, which delivers your own header and body (but is not location-triggered).

A user near many stores misses some notifications

Google caps geofenced notifications at 4 per user per day. A user passing more than four geofenced stores will only be notified at four of them.

Last updated on