Skip to content

Payer enrollment

The separate payer OpenAPI 0.5.0 and generated/payer-typescript SDK now include preparation/completion. After phone verification, send the unexpired enrollment grant token and a six-digit Futa passcode to POST /v1/payer/enrollment-challenges. Sign its decoded signing_bytes with the same device key, then submit grant_token, the identical passcode and signature to POST /v1/payer/enrollment-challenges/{id}/complete.

The payer API runs only in the local sandbox: the hosted sandbox does not serve it yet.

Every request uses an Idempotency-Key UUID. Keep the exact request after a lost response; never change the passcode under the same key. The challenge and its retries expire with the original grant token. The server allows five preparations and ten verifications per token. Sensitive parameters must not appear in logs, URLs or analytics.

The successful response contains payer_id, device_id, locale, state=ENROLLED and session_issued=false. It does not authenticate subsequent requests. Exact retries return the same result while the grant remains valid. Changed bodies conflict; expired grants fail. Concurrent completion creates one profile/device and consumes the grant once. Existing phone/device profiles reject enrollment; this flow cannot reset credentials or add a replacement device using SMS alone.

The Futa passcode is distinct from the operator’s PIN and the bank password. Issuer credentials are never sent to Futa. Storage uses Argon2id with a random salt and an independent secret; the passcode cannot be recovered. Sessions, recovery, new devices and account linking follow separate steps.

Only configured synthetic phone fixtures work in loopback sandbox. Enrollment does not issue a session; see payer sessions for the separate unlock flow. No real SMS, money, live recovery or hardware attestation is implied. Android and iOS implement their own native flows; Android remains Retrofit/Room/Hilt.