Digital Wallets
Push-provision cards into Apple Pay, Google Pay, and Samsung Pay, then
manage the network tokens those wallets create. Token objects return
last_four and DPAN last four only, never PAN or CVV.
In-app provisioning
From your mobile app, collect wallet SDK material and call
POST /v1/cards/{card_id}/provision.
digital_wallet | Body | SDK consumes |
|---|---|---|
APPLE_PAY | certificate, nonce, nonce_signature from PassKit | provisioning_payload as PKAddPaymentPassRequest |
GOOGLE_PAY | digital_wallet only | provisioning_payload as an opaque payment card (OPC) |
SAMSUNG_PAY | digital_wallet only | provisioning_payload as an OPC |
object is card_provision). It is not a
persisted tokenization. The wallet talks to the network; the token
appears on GET /v1/tokenizations after the network confirms.
{
"object": "card_provision",
"card_id": "0c4e8f16-2a7b-4d93-b5e1-8f3a6c9d0142",
"digital_wallet": "APPLE_PAY",
"provisioning_payload": "eyJwYXlsb2FkIjoiLi4uIn0"
}
Send Idempotency-Key. A retried provision with the same key returns
the original payload instead of minting a second one.
Web provisioning
POST /v1/cards/{card_id}/web-provision is the browser equivalent
(Apple Pay on the Web). The body is { "digital_wallet": "APPLE_PAY" }.
The response is a compact jws plus opaque state. Pass both to the
wallet JavaScript API. Echo state unchanged; do not parse it.
{
"object": "card_web_provision",
"card_id": "0c4e8f16-2a7b-4d93-b5e1-8f3a6c9d0142",
"digital_wallet": "APPLE_PAY",
"jws": "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ3ZWItcHJvdmlzaW9uIn0.signature",
"state": "9c2e4a71-6d8b-4f03-b5e1-0a7c8d9f1246"
}
The JWS never contains PAN or CVV.
Token lifecycle
GET /v1/tokenizations lists tokens. Filter on card_id, wallet_id,
status, and wallet (APPLE_PAY, GOOGLE_PAY, SAMSUNG_PAY).
GET /v1/tokenizations/{tokenization_id} returns the snapshot,
including token_requestor_name, device, last_four, dpan.last_four,
and events[].
status | Meaning |
|---|---|
INACTIVE | Created at the network; ineligible to authorize until activated. |
PENDING_ACTIVATION | Waiting on the cardholder to complete wallet activation. |
PENDING_2FA | Waiting on an activation code (SMS or EMAIL). |
ACTIVE | Authorizes. |
PAUSED | Temporarily declines wallet presentations. |
DEACTIVATED | Terminal. Cannot be reversed. |
POST sub-resources. Each takes Idempotency-Key.
| Call | From | To |
|---|---|---|
POST .../activate | INACTIVE, PENDING_ACTIVATION, PENDING_2FA | ACTIVE |
POST .../pause | ACTIVE | PAUSED |
POST .../unpause | PAUSED | ACTIVE |
POST .../deactivate | any non-terminal | DEACTIVATED |
POST .../resend-activation-code | PENDING_ACTIVATION, PENDING_2FA | same status; new code |
resend-activation-code body is { "channel": "SMS" } or
{ "channel": "EMAIL" }. The cardholder contact comes from the wallet
wallet entity. Do not send a phone number or email in this body.
POST .../update-digital-card-art assigns art from
GET /v1/digital-card-art. The art must match the token's network
and have is_enabled true.
Every status change emits tokenization.updated. Subscribe with a
webhook subscription. payload is the Tokenization snapshot.
Digital card art
GET /v1/digital-card-art lists artwork the wallet can display.
GET /v1/digital-card-art/{digital_card_art_id} returns network,
is_enabled, description, and images (front, logo, icon) as
HTTPS URLs. Those URLs are image assets, not PAN.
Tokenization Decisioning
Enroll an HTTPS URL with POST /v1/responder-endpoints and
type TOKENIZATION_DECISIONING. Rook POSTs a tokenizationRequest
callback to that URL when a cardholder adds a card to a wallet.
Respond within 3 seconds with:
{
"object": "tokenization_decision",
"result": "APPROVED",
"authentication_channels": null
}
result is APPROVED, DECLINED, or
REQUIRE_ADDITIONAL_AUTHENTICATION. When stepping up, set
authentication_channels to SMS and/or EMAIL:
{
"object": "tokenization_decision",
"result": "REQUIRE_ADDITIONAL_AUTHENTICATION",
"authentication_channels": ["SMS", "EMAIL"]
}
The request body is device and wallet data (object is
tokenization_request): digital_wallet, wallet.wallet_id,
device.device_id, device.device_type, device.ip_address, and
device.location. It never includes PAN or CVV.
Timeout and fallback
If your endpoint does not return HTTP 200 with a valid decision body
within 3 seconds (including connection errors, TLS failures, 5xx,
and malformed JSON), Rook declines the provisioning request. Prefer
failing closed: keep the responder fast and reachable.
Signature
Callbacks are signed with the same HMAC-SHA256 scheme as Event
deliveries. Retrieve the secret with
GET /v1/tokenization-decisioning/secret. Use the entire whsec_...
string as the key.
| Header | Value |
|---|---|
Rook-Timestamp | Unix time in seconds when the signature was computed. |
Rook-Signature | v1=. Multiple v1= values may be comma-separated during rotation. |
{timestamp}.{raw_body}. Reject a callback whose
timestamp is more than 300 seconds from the current time. After
POST /v1/tokenization-decisioning/secret/rotate, the previous secret
remains valid for 24 hours.
Getting Started → Webhook signing covers the same scheme.
A program may enroll at most one TOKENIZATION_DECISIONING responder.
DELETE /v1/responder-endpoints/{responder_endpoint_id} stops
callbacks immediately.