Account linking
The payer API 0.7 and payer SDK add institution discovery, consent-bound account-link requests and safe linked-account pages. GET /v1/payer/institutions lists only explicitly configured synthetic institutions; an empty list means none is enabled. Configured synthetic issuers now provide a separate explicit approval channel; live issuers remain unavailable.
The payer API runs only in the local sandbox: the hosted sandbox does not serve it yet.
Send {institution, currency, account_selector} to POST /v1/payer/account-links with an active DPoP session, a fresh proof and an Idempotency-Key UUID. The local institutions are sim-wallet and sim-bank, the currencies CDF and USD. The test selectors are synthetic-{institution}-{approved|declined|pending}. Never collect the issuer’s PIN, password or OTP.
Show the selected institution/account intent to the payer, then sign the returned LINK_ACCOUNT signing_bytes with the enrolled device key using DER SHA256withECDSA. Submit {signature} to POST /v1/payer/account-links/{id}/consent with a separate mutation UUID and fresh DPoP proof. Only the original active session may consent. The consent challenge lasts two minutes; the request lasts five. Preserve signature and logical mutation UUID for retries, while generating a fresh DPoP proof each time. The SDK does not generate device signatures.
PENDING confirms the consent only. Only a proof signed by the configured issuer can produce VERIFIED or DECLINED. Read GET /v1/payer/account-links/{id} for the current state; an exact retry of creation or consent keeps its earlier result. Reads do not extend the session’s idle time.
GET /v1/payer/accounts returns up to twenty records with opaque link ID, institution, currency, masked identifier, holder name, creation time and VERIFIED/REVIEW_REQUIRED state. Pass next_cursor as the exclusive before UUID for another page. Account tokens, raw selectors and issuer evidence never appear in this response. REVIEW_REQUIRED records must not be treated as usable account authority. Linking provides no balance or debit permission.
The persistent limits are five creations per device per minute, twenty per payer per hour, ten consent attempts per request and fifty per device per minute. An expiry, a revoked device or a contradictory decision creates no new link. The status’s approval_url opens the simulated channel while issuer_channel is WAITING. Opening it gives no issuer consent; that page needs an explicit action. Return to Futa and read the protected status. Real bank and operator scenarios, recovery and link removal remain separate steps. Android uses Retrofit, Room and Hilt; iOS keeps its own native logic.