Confirm Receipt
The in-app way to claim incoming value with a device signature or passkey instead of typing a claim code. There are two flavours, with the same request/response shape:
- Send — the receiver (a different person) confirms an incoming player-to-player send.
- Transfer — the same person claims their own cross-game transfer into the destination game (a self-claim). This replaces the claim-code + SMS step for enrolled users.
/api/sdk/send/{id}/confirm-receipt
Receiver confirms an incoming send; the funds are credited and the send completes
Authenticated with the RECEIVER's player token
The token is minted by the receiving game for the receiver. The receiver's enrolled phone must match the one the send was addressed to.
Authorization: Bearer <receiver's player token>Request Body
| Parameter | Type | Required | Description |
|---|---|---|---|
| device_fingerprint | string | Yes | Which enrolled device is confirming |
| device_signal | object | Yes | Signature over the action — see Device Enrollment |
| biometric_verified | boolean | If stepped up | Honest result of the step-up, when required |
Success Response
{
"status": "completed",
"transaction_id": "TX_send789",
"amount_received": "90.00"
}/api/sdk/transfers/{id}/confirm-receipt
The same person claims their own cross-game transfer into the destination game — no claim code, no SMS
Authenticated with the claimer's player token in the DESTINATION game
A cross-game transfer is a self-claim: the same identity that sent it claims it on the other side. Use the player token minted by the destination game; the enrolled phone must match the one the transfer was addressed to.
Authorization: Bearer <claimer's destination-game player token>Same request body and success shape as the send endpoint above (device_fingerprint + device_signal, or a webauthn_assertion for passkey platforms; optional biometric_verified). On success the destination balance is credited and the transfer completes.
{
"status": "completed",
"transaction_id": "TX_transfer456",
"amount_received": "100.00"
}Passkey challenge (WebAuthn platforms)
For a passkey assertion, first get a challenge from POST /api/sdk/transfers/{id}/confirm-receipt/webauthn/begin, complete it, then send the result as webauthn_assertion. The device-signature path needs no begin call.
How the app discovers something to confirm
SENDS (someone sent to your player): the app polls GET /api/sdk/transfers/pending; an incoming send appears as an item with kind: "receiving_confirm" (amount, source game, expiry). Render the prompt, then call /api/sdk/send/{id}/confirm-receipt.
⚠️ TRANSFERS are NOT in /sdk/transfers/pending's receiver list — that list is peer-sends only. A transfer is a self-claim, so discover it one of two ways: (1) your backend subscribes to the transfer.claim_pending webhook and/or polls the server-side GET /api/transfers/inbound-pending?player_email=… list (game-secret authed) to enumerate inbound transfers for a player; or (2) the sender's app already holds the claim_code returned in-band from /api/sdk/transfers/{id}/approve. Then call /api/sdk/transfers/{id}/confirm-receipt to collect.
Other responses to handle
| Status | Meaning / what to do |
|---|---|
| 403 not_intended_receiver | This player/phone isn't the addressed recipient |
| 404 receiving_tenant_unavailable | The receiving game can't be resolved right now — retry shortly |
| 409 receiver_not_enrolled_use_claim_code | No account in the receiving game yet — fall back to the claim-code flow |
| 400 no_registered_device_key | This receiver has no enrolled device key — register the device first (Device Enrollment) |
| 202 STEP_UP_REQUIRED | May be returned when risk step-up is enabled for your game — run biometric / PIN, then retry with biometric_verified: true. A no-op when the flag is off. |
| 503 sdk_verification_disabled | In-app verification is off for this game — fall back to the claim-code flow |
| 401 SIGNAL_* | Bad/stale/replayed signature — re-sign with a fresh device_signal |
| 400 (cannot be confirmed) | Already resolved — treat as "already done" |
Users without the app are unaffected
Anyone not enrolled (no account/app in the destination game) simply uses the existing claim-code flow — the send or transfer still completes. For transfers, the claim code is also returned in-band from /transfers/{id}/approve, so the app never needs to read it from an SMS. In-app confirm is the upgrade for enrolled users, not a requirement for everyone. If the endpoint returns 503 for your game, in-app confirm isn't enabled yet — fall back to the claim code.