Approve in App

The sender approves a transfer or send from inside your app. The device polls the pending list, renders the prompt, and posts a hardware signature instead of an SMS PIN.

1. Poll the pending list

GET

/api/sdk/transfers/pending

The authoritative list of actions awaiting this player

Poll this — there is no push to wire up

Call it on app open / login and periodically while foregrounded. Always render prompts from this response (amount, currency, whether a step-up is needed) — never from anything cached. Authorization: Bearer <player token>

Response

{
  "pending": [
    {
      "transfer_id": "TX_abc123",
      "kind": "identity_gate",        // sender must approve
      "flow": "transfer",             // "transfer" → /transfers/{id}/approve
      "amount": "100.00",             //   "send"   → /send/{id}/approve
      "currency": "GoldCoins",
      "counterparty_game": "Game B",  // destination
      "expires_at": "2026-01-01T18:05:00Z",  // display only
      "step_up_required": false,      // only present when risk step-up is enabled for your game;
                                      //   if true, prompt biometric/PIN before approving
      "held": false,                  // true → not actionable yet (e.g. guardian pending)
      "hold_reason": null
    }
  ]
}

Items with kind: "receiving_confirm" are incoming sends to confirm — see Confirm Receipt. An item with held: true is awaiting something else (e.g. a guardian) — show it as pending, not approvable.

Detecting completion (poll /status)

GET /api/sdk/transfers/pending is for discovery — it's the player's to-do list, authed with the player token. To detect that a specific transfer's sender approval has completed (so you can dismiss a waiting panel), poll that one transfer's /status instead.

GET
/api/transfers/{id}/status

Status of one self-transfer

GET
/api/currency-sends/{id}/status

Status of one player-to-player send

These are server-side endpoints — NOT the SDK player token

Unlike the /api/sdk/* calls, both /status endpoints are authed with your X-Game-Secret-Key from your server — never the device player token. Poll them server-side.

They return a verification_state that flips awaiting → approved the moment the sender clears the gate — whether in-app or via SMS:

verification_stateMeaning
awaitingSender hasn't cleared the gate yet — keep the waiting panel up
approvedSender cleared the gate (in-app or SMS) — dismiss the waiting panel
completedFully resolved (claimed / credited)
expiredWindow lapsed — stop polling
failedDid not succeed — stop polling

Use /status for a waiting panel keyed to one transfer; use /pending for discovery of what's awaiting the player.

2. Approve with a device signature

Pick the endpoint by the item's flow. The body is identical for both.

POST
/api/sdk/transfers/{id}/approve

Self-transfer (your own balance between your games)

POST
/api/sdk/send/{id}/approve

Player-to-player send (sender side)

Authenticated with the player token

Authorization: Bearer <player token>

Request Body

ParameterTypeRequiredDescription
device_fingerprintstringYesWhich enrolled device is approving
device_signalobjectYesSignature over the action — see Device Enrollment
biometric_verifiedbooleanIf stepped upHonest result of the biometric / PIN step-up, when required

Success Response

{
  "status": "approved",
  "next": "pending_claim",
  "transaction_id": "TX_abc123"
}

Other responses to handle

StatusMeaning / what to do
202 STEP_UP_REQUIREDMay be returned when risk step-up is enabled for your game — prompt biometric / PIN, then retry with biometric_verified: true. A no-op when the flag is off.
202 RISK_HOLDMay be returned when risk step-up is enabled for your game — held for review; do not retry, show a pending state. A no-op when the flag is off.
202 pending_guardian_approvalAwaiting the guardian (minor) — show pending
410 GUARDIAN_APPROVAL_REJECTEDGuardian rejected the action — stop; do not retry
410 GUARDIAN_APPROVAL_EXPIREDGuardian approval window lapsed — stop; do not retry
503 GUARDIAN_APPROVAL_CHECK_UNAVAILABLETransient — the guardian check is temporarily unavailable; retry shortly
503 sdk_verification_disabledIn-app verification is off (feature / flag) for this game — fall back to the SMS flow
401 SIGNAL_*Bad/stale/replayed signature — re-sign with a fresh device_signal
400 (not pending)Already resolved — treat as "already done"

After approval

A self-transfer moves to pending_claim and you claim it as usual. A send moves to pending_claim and the receiver is notified to confirm (Confirm Receipt). The downstream claim flow is unchanged.

Example — approve a transfer (Unity)

IEnumerator ApproveTransfer(string playerToken, string transferId,
    string deviceFingerprint, object deviceSignal)
{
    var url  = "https://invo.network/api/sdk/transfers/" + transferId + "/approve";
    var body = JsonConvert.SerializeObject(new {
        device_fingerprint = deviceFingerprint,
        device_signal      = deviceSignal,     // { transfer_id, nonce, timestamp, signature }
        biometric_verified = true
    });
    using (var req = new UnityWebRequest(url, "POST"))
    {
        req.uploadHandler   = new UploadHandlerRaw(System.Text.Encoding.UTF8.GetBytes(body));
        req.downloadHandler = new DownloadHandlerBuffer();
        req.SetRequestHeader("Authorization", "Bearer " + playerToken);
        req.SetRequestHeader("Content-Type", "application/json");
        yield return req.SendWebRequest();
        // 202 STEP_UP_REQUIRED → run biometric, re-sign, retry.
    }
}

Report biometric_verified honestly. If the step-up fails or the user cancels, send false — Invo decides what happens. Never complete an action locally.