Push Provisioning

Adding a card to a wallet from inside your own app, and what GenerateTimeBasedSecret is actually for.

Push provisioning, also called in-app provisioning, is the "Add to Google Pay" button inside your own app. The cardholder taps once and the card lands in the wallet. No card number typed, no OTP.

It is the better experience by a wide margin, and wallet programmes increasingly require it rather than merely allowing it.

Why there is no OTP

Manual provisioning needs a one-time code because the wallet has no idea who typed the card number in. Push provisioning does not have that problem: the cardholder is inside your app, already authenticated by you. That authentication is what replaces the OTP.

This puts a requirement on you. The button must sit behind real authentication. If a user can reach "Add to Google Pay" without having properly logged in, you have removed the only control protecting the flow.

The path

%%{init: {"sequence": {"actorMargin": 8, "boxMargin": 6, "noteMargin": 6, "messageMargin": 26, "width": 110, "diagramMarginX": 8, "diagramMarginY": 8}}}%%
sequenceDiagram
    autonumber
    participant CH as Cardholder
    participant APP as Your app
    participant BE as Your backend
    participant UDT as UnDosTres
    participant W as Wallet
    participant MC as Mastercard MDES

    CH->>APP: Authenticates
    CH->>APP: Taps Add to Google Pay
    APP->>BE: Requests provisioning data
    BE->>UDT: GenerateTimeBasedSecret
    UDT-->>BE: secret, valid 60s
    BE-->>APP: card_id + secret
    APP->>W: Push provisioning via SDK
    W->>MC: Checks eligibility
    MC-->>W: Terms and conditions
    W-->>CH: Displays the terms
    CH->>W: Accepts
    W->>MC: Starts digitization
    MC->>UDT: Token auth request
    UDT-->>MC: Approved
    MC->>MC: Activates the token
    MC->>UDT: Digitization complete
    UDT->>BE: digitization.complete
    MC-->>W: Provisioning complete
    W-->>CH: Card appears in the wallet

What you build

PieceWho builds it
The "Add to wallet" button and its auth gateYou
Calling your backend for provisioning dataYou
Calling GenerateTimeBasedSecretYou (backend)
Handing card_id + secret to the SDKYou (app)
The provisioning SDK itselfSupplied by UnDosTres
TAV calculationUnDosTres
Card data encryption to the walletUnDosTres and the SDK
The provisioning decisionUnDosTres
digitization.complete handlingYou (backend)

Two things are worth saying plainly, because they are the parts partners most often assume they have to build:

  • You do not calculate the TAV. The Token Authentication Value is an encrypted signature derived from the card number, expiry and CVV, which authenticates the push request. UnDosTres calculates it and passes it to MDES. You never see the card data it is derived from.
  • You do not implement the card-data encryption. The encrypted package that reaches MDES through the wallet provider is produced by UnDosTres and the SDK. Your app passes an opaque payload through.

GenerateTimeBasedSecret

Endpoint: POST /debit/v1/digitization/generate-time-based-secret

This is the one tokenization endpoint whose purpose is not obvious from its name, so it is worth being explicit.

Push provisioning needs to prove to UnDosTres that the request genuinely came from your authenticated app, without your app ever handling the card number. The mechanism is a short-lived shared secret bound to a specific card.

You call it with a card_id and get back a secret:

{
  "text": "Success",
  "timestamp": "2026-08-19T10:25:21.857267676-06:00",
  "endpoint": "/debit/v1/digitization/generate-time-based-secret",
  "error": {},
  "payload": {
    "secret": "123#45236521"
  }
}

The secret has two parts separated by #:

PartMeaning
123Key ID. Identifies which shared key was used, so keys can be rotated without downtime
45236521A time-based one-time password, derived from the shared key and the card_id

The secret is valid for 60 seconds. Generate it at the moment the cardholder taps the button, not in advance, and never cache it.

Rules

  • Generate it server side. The shared key must never reach the app.
  • One secret per provisioning attempt. If the cardholder abandons and retries, generate a new one.
  • Pass card_id and secret together. Neither is useful alone.
  • Clock accuracy matters. The secret is time-based, so a backend whose clock has drifted will produce secrets that fail validation. Keep NTP running. An incorrect clock is the most common cause of unexplained failures on this call.
🚧

Parameters still to be confirmed. The shared key for your programme, its key ID, and the exact secret length, hashing algorithm and validity window are being confirmed and will be issued to you directly, not published here. Until you have them you can integrate against the endpoint's shape, but you cannot complete an end-to-end push provisioning test. We will send the key material through a secure channel, never by email.

Availability

Push provisioning depends on the provisioning SDK and on the shared key material above. Both are pending. The backend endpoint is documented and stable; the mobile side is not yet ready to build against.

If you are sequencing work: build the backend call and your digitization.complete handling now, and hold the app-side integration until the SDK and key are issued.

Related


Did this page help you?