Claim Sent Currency, the fallback route
This page documents the claim-code fallback for collecting a peer send. It is not how a recipient collects in your title, and you should not build an “enter your code” screen. It is kept for one case: a recipient with no Invo passkey, who therefore needs a route that also creates their player row.
How collecting actually works
The recipient’s client lists what is waiting for her with GET /api/sdk/transfers/pending (her player token), reads the item’s flow field, and settles with POST /api/sdk/send/{id}/confirm-receipt using a passkey or a device grant. She proves it is her, on a device that is hers, the same class of proof the sender gave.
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 in a message is bearer value: it belongs to whoever reads the message first, and it cannot tell the difference between the person it was meant for and the person holding the phone. A passkey can. That is why in-app code entry was removed from the recommended flow, and why this endpoint is documented here as the fallback rather than as the main event.
Use it when, and only when, the recipient has no Invo passkey, which is also exactly what 409 receiver_not_enrolled_use_claim_code from confirm-receipt is telling you. A recipient who is not in your title at all should instead follow the link Invo sent them to the hosted claim page, which takes an email, mints them a passkey and collects, the same proof, run on Invo’s own domain because there is no client of yours to run it in.
The endpoint
POST $BASE/api/currency-sends/claim-currency
X-Game-Secret-Key: <RECEIVING game secret>
Content-Type: application/json
{
"claim_code": "KJMRS-47281",
"receiver_player_name": "Bo",
"receiver_player_email": "bo@example.com",
"receiver_player_phone": "+15555550111", // E.164; must match the number the send was addressed to
"receiver_player_id": 4321 // optional; only when resolving an account-selection prompt
}
200 OK
{
"status": "success",
"message": "Currency send claimed successfully.",
"transaction_id": "TXN_...",
"new_balance": "1045.00", // canonical post-write balance — display this
"currency_name": "Gold",
"send_details": { "amount_received": "45.00", "sending_game": "Ship Busters",
"receiving_currency": "Gold", "receiver_player": "Bo", "new_balance": "1045.00" },
"completion_time": "2026-09-04T18:22:00+00:00",
"order_id": "ORD_1757000000_A1B2C3D4"
}On success it credits the recipient, completes the transaction, and fires transfer.received to your title and transfer.sent to the sending title, identical to the confirm-receipt route. It also creates the receiving player if they do not exist, which is the one thing confirm-receipt cannot do.
| 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 from the body and re-submit with receiver_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. | Tell them to ask the sender to send again. |
400 WRONG_CLAIM_ENDPOINT | That code belongs to a cross-game transfer, not a peer send. | The body names expected_endpoint (/api/transfers/claim-transfer) and the fields it wants. |
403 phone mismatch | The submitted phone is not the number the send 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. Repeated wrong codes is the exact pattern this exists to stop. |
404 | No send with that code for your title. | Check the code and the receiving title. |
The lockout is deliberately aggressive and fails closed. Never build a UI that lets a player try codes in a loop, and never retry automatically on an invalid code, you will lock out the legitimate recipient.
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 and settle with confirm-receipt. Keep this endpoint behind the 409 receiver_not_enrolled_use_claim_code branch, where it belongs.