Skip to content

How the partner API is secured and what each control enforces. Day-to-day key handling is in Authentication; a questionnaire map is at the end.

The complete API key, sent as x-api-key, is the credential. We store only a SHA-256 hash and the public lookup prefix, and never persist or log the key, so it is shown once. SHA-256 needs no password KDF because the secret is 256 random bits.

A key is bound to one organization. avvio_test_ and avvio_live_ keys resolve to separate organizations, and the environment comes from the key’s prefix, never a database column, so a stale row cannot promote a test key to live money.

Three settings are fixed at issue, enforced server-side on every request, and carried unchanged through rotation. No endpoint edits them, so issue a second key rather than widening the first.

Control Also called What it enforces
Scopes: read / write, plus the consents crypto_payouts and refunds Scoped tokens, least privilege A read key is refused any method but GET, and refused full account details even on a GET. A consent is off until granted; refunds can be granted only by an owner or admin
Allowed source addresses IP allowlisting, IP pinning A request from any other address is refused with KEY_IP_NOT_ALLOWED
Expiry Credential lifetime 365 days by default, 730 at most

There are no per-resource scopes, because a permission matrix is easy to get subtly wrong and “reads only” can be verified from the HTTP method. The two consents come only with write: crypto_payouts spends from your own wallet, and refunds returns a buyer’s money. For a finer boundary, use a separate organization. Source addresses must be exact; issuance rejects a CIDR block.

A key authenticates as a machine member of your organization behind a default-deny route allowlist, which only the payout surface has joined. Team management, KYB documents, provider terms, wallet operations and key management are unreachable, so a stolen key cannot mint more. The API reference is the complete list of what a key can touch.

Rotation (POST /organizations/{orgId}/api-keys/{apiKeyId}/rotate, from a signed-in dashboard session only; an API key cannot call it) mints a successor and gives the predecessor a deadline, 24 hours by default; both work during the overlap. The successor keeps the scopes and addresses, so rotation cannot turn a read-only key into a spending key, and gets a full lifetime, so rotation never shrinks a key into its own overlap window.

Rotation refuses an expired or revoked key, which it would otherwise revive. A second rotation, such as a retry after a timeout, returns KEY_ALREADY_ROTATED with the existing successor’s id.

Issuing, rotating and revoking happen in the dashboard, so rotation cannot be automated end to end. Revocation is immediate. Each key’s event trail (issued, rotated, revoked) names the actor and any successor; expiry records no event. If a key may be exposed, revoke it, issue a successor, and tell [email protected].

A key’s machine member holds the operator role, which may propose money movement but cannot sign a treasury transfer; owner and admin members sign on their own passkeys.

Above an amount threshold, your organization can require M-of-N approval on API payouts. POST /payouts and batch confirm then answer 202 with an approval, a batch holds at awaiting_confirmation whatever autoCommit said, and nothing is priced or sent until owner or admin members reach quorum in the dashboard. Votes need a human session and the initiator cannot approve their own request, so a leaked write key can only propose (Approvals).

Every payout path is gated server-side: POST /payouts, batch confirm, quote-and-accept, and payout links at mint and submit. With a threshold or cap on, quote-and-accept answers 403 USE_POST_PAYOUTS, so POST /payouts is the one door for API calls. Payout links answer USE_POST_PAYOUTS only when the amount would need approval, and enforce caps at submit (422 PAYOUT_LIMIT_EXCEEDED).

Control On What it enforces
Route allowlist, write scope, operator role Always Required by the payout routes
Idempotency-Key Always Replays a retry; a 15-minute detector catches the same body under a new key (Idempotency)
Source addresses, expiry Always Per key
Approvals With a threshold M-of-N human approval
Velocity caps When we set them, at your request Per payout, per day and per end user per day, in USD, on USD-sourced payouts only today. 422 PAYOUT_LIMIT_EXCEEDED; nothing is sent
Screening Always Destination-country list; sanctions and name screening delegated. 422 PAYOUT_REFUSED, final
Purpose of payment Always purposeOfPayment required for INR, GHS, CNY and BRL, validated against the corridor’s catalog, never defaulted

GET /payments/organizations/{orgId}/audit-events records every audited mutation, succeeded or refused: payouts created or canceled; batches submitted, confirmed or canceled; approvals decided; recipients created, changed or deleted; keys issued, rotated or revoked; webhook endpoints created, deleted, paused, re-signed or replayed. Each row carries the key prefix or dashboard user, the source IP, the outcome, the error type on a refusal, and the requestId that matches x-request-id and error bodies. The API never returns a key’s internal id, and a row holds no request body or bank field.

Results are newest first, cursor on id, filterable by action, resourceId, apiKey (prefix), actorUserId, createdAfter and createdBefore. A read-only key can read it, so your SIEM needs no credential that moves money. A row is written after the request settles, outside the money transaction; the payout and its event prove the movement.

The API is served over HTTPS. Personal data is encrypted at rest field by field with AES-256-GCM, under a data key wrapped by AWS KMS, and bound by additional authenticated data to its row, so a copied ciphertext does not decrypt against another record.

Encrypted Holds
Recipient bank details The full destination account: CLABE, IBAN, account and routing numbers
Bank details on invoices and checkout links Account number, routing number, nostro account
KYB documents, reviews and research Fields read from uploaded documents (government id number, date of birth, full name, tax id, address), review findings with their evidence, and public-register research on officers and beneficial owners
KYB associated persons Tax id, government id number, date of birth, email, phone, address
KYC profiles Tax id, phone, address
Custom bank accounts Account number, ABA routing number, nostro account

Records a payment network sends back, and contact fields on your organization and its members, are stored as received; ask about any field. Listings return last4; full details are a separate call a read-only key is refused. The API key is never returned after creation. A webhook signing secret is returned once, when the endpoint is created and when its secret is rotated, and never again.

Data Kept Then
Batch line instruction (items and CSV export) 90 days after the batch ends null; status, errors and payoutId stay
Payout link sender (endUser.name, endUser.email) Until the receipt email is sent, or the link expires unused Removed from the link; the address the receipt went to is kept as the delivery record
Webhook delivery log 30 days after delivery or exhaustion; pending retries kept Deleted
Idempotency-Key records 7 days; unresolved ones until support resolves them Deleted
Recipients Until you delete them Soft-deleted, unpayable (Recipients)
A recipient’s single payment method Until you delete it Deleted (the row is erased)
Payouts and their events Retained Never deleted through the API
Audit events At least five years (BSA record-keeping) Nothing deletes them today

Deliveries are signed with Standard Webhooks (HMAC-SHA256); Webhooks covers verification. An endpoint URL must be HTTPS without credentials. Its address is resolved at registration and pinned for the connection, so a hostname cannot pass the check with one address and connect to another. Deliveries time out after 10 seconds.

Keys are managed in the dashboard, so it is part of your attack surface. Members sign in with a passkey (WebAuthn) bound to the origin, with no password to phish; signup verifies the email with a one-time code. Roles (owner, admin, operator, viewer) are enforced server-side.

The dashboard signs money-moving requests in the browser with the session’s own key, over the method, path, body, idempotency key, timestamp and nonce. The server requires a fresh timestamp and a single-use nonce, held by a uniqueness constraint. The partner API never asks for a signature.

Rate limits apply per credential and per source address; the numbers are in Environments.

  • No OAuth 2.0 or OpenID Connect: there is no end-user consent step to solve.
  • No request signing or mTLS on the partner API. Anyone holding the key can use it from any allowed address, and we cannot detect a request altered by a proxy you control.
  • No per-resource scopes, no editing a key in place, and no API-driven issuance or rotation.
  • No published egress addresses; verify our deliveries by signature.
  • No SSO, SAML or SCIM, so no directory integration or automated deprovisioning.
  • No streaming audit export; poll the audit trail.
  • No name screening of our own. It is delegated in writing to the payment network; ask for the delegation letter during your review.

We use a bearer key because every HTTP client supports it. If your risk assessment needs one of the above, raise it before you integrate. Keeping the key from leaking is on your side: Authentication has the rules.

Email [email protected] and do not disclose until a fix has shipped. We acknowledge within 2 business days, assess severity within 5, and credit you when the fix ships unless you ask us not to. Anything that requires a compromised API key is out of scope.

If you are filling in a security questionnaire

Section titled “If you are filling in a security questionnaire”
The questionnaire asks about Answer
OAuth 2.0 / OIDC, SSO / SAML / SCIM Not offered
Scoped tokens, IP allowlisting Scopes and allowed addresses
API key rotation Rotation with overlap
Credential storage at rest SHA-256 hash
Encryption at rest and in transit Field-level AES-256-GCM, HTTPS
Webhook authenticity HMAC-SHA256
Our egress addresses Not published
MFA, role-based access Passkeys and four roles
Audit logging Audit API, kept at least five years
Rate limiting Environments
Vulnerability disclosure [email protected]

Was this page helpful?