Claim a Transfer, the fallback route
This page documents the claim-code fallback for collecting a cross-game transfer at the destination. It is not the primary route. It is kept for the case the stronger route cannot serve: a player who has no account in the destination title yet, or no Invo passkey.
How collecting actually works
The player’s client lists what is waiting for her with GET /api/sdk/transfers/pending (her destination-title player token), reads the item’s flow field, and settles with POST /api/sdk/transfers/{id}/confirm-receipt using a passkey or a device grant. No code, nothing typed.
Collecting, stage by stage
Both rails, both surfaces, every call in curl, JavaScript and Python, including the flow field that decides which endpoint to call.
Why the code is the fallback
Receiving is meant to be exactly as strong as sending. A code authorises whoever holds it; a passkey authorises the person. On a transfer the exposure is smaller than on a peer send, the claim code is returned in-band to the caller at approve time, rather than into a message, but it is still the weaker proof, so it should not be the button players reach for first.
Use it when confirm-receipt answers 409 receiver_not_enrolled_use_claim_code, there is no player row for this identity in the destination title, and this route creates one as part of collecting.
The endpoint
POST $BASE/api/transfers/claim-transfer
X-Game-Secret-Key: <DESTINATION game secret>
Content-Type: application/json
{
"claim_code": "KJMRS-47281", // returned by /api/sdk/transfers/{id}/approve
"target_player_name": "Ada",
"target_player_email": "ada@example.com",
"target_player_phone": "+15555550100", // E.164; must match the number the transfer was addressed to
"target_currency_id": 34, // which of your currencies to credit
"target_player_id": 4321 // optional; only when resolving an account-selection prompt
}
200 OK
{
"status": "success",
"transaction_id": "TXN_...",
"new_balance": "1045.00", // canonical post-write balance — display this
"currency_name": "Gold",
"transfer_details": { "amount_received": "45.00", "source_game": "Ship Busters",
"target_currency": "Gold", "target_player": "Ada", "new_balance": "1045.00" },
"completion_time": "2026-09-04T18:22:00+00:00",
"order_id": "TFRO_..."
}On success it credits the player, completes the transaction, and fires transfer.received to your title and transfer.sent to the source title, identical to the confirm-receipt route. Fees were stamped when the transfer was initiated; nothing is recomputed here.
| Answer | Means | Action |
|---|---|---|
200 needs_account_selection | Not an error, despite the 200. The phone matches more than one of your players. | Show the masked candidates and re-submit with target_player_id. |
400 invalid claim code | Wrong code. Carries attempts_remaining. | Show the remaining attempts, and stop before the lockout. |
400 expired | The claim window closed; the sender is refunded by the sweep. | The player must start a new transfer from the source title. |
400 WRONG_CLAIM_ENDPOINT | That code belongs to a peer send, not a transfer. | The body names expected_endpoint (/api/currency-sends/claim-currency) and the fields it wants. |
403 phone mismatch | The submitted phone is not the number the transfer was addressed to. | Stop. This is the check that stops a code being redeemed by whoever found it. |
409 PHONE_SHARE_APPROVAL_REQUIRED | The number belongs network-wide to a different Invo identity; that person must consent. | Follow the consent flow in the body, then retry. Consent is requested by email where a verified address exists. |
429 CLAIM_LOCKED | Too many failed attempts on this phone, email or network. Carries locked_dimension, retry_after_seconds and a Retry-After header. | Stop and show the wait. |
404 | No transfer with that code for your title. | Check the code and the destination title. |
The lockout is deliberately aggressive and fails closed. Never let a player try codes in a loop, and never retry automatically on an invalid code, you will lock out the legitimate player.
To find inbound transfers waiting for one of your players without knowing the transaction id, use GET /api/transfers/inbound-pending with your title's secret key and player_email or player_phone. It never returns claim codes, documented on Collecting, stage by stage.
If you are reading this to build a collect screen
You are on the wrong page. Build the screen from GET /api/sdk/transfers/pending. Branch on the item’s flow, and settle with confirm-receipt. Keep this endpoint behind the 409 receiver_not_enrolled_use_claim_code branch.