cpf and brlaEnabled; foreign profiles use taxId / taxIdCountry and usdEnabled.
EUR capability is planned but not available yet. Poll
eurEnabled on status responses only for forward compatibility — it stays false today.Prerequisites
You need to understand these integration values:
Send all requests from your backend with
x-api-key. Never expose the API key in browser or mobile clients.
End-to-end flow
1
Complete Sumsub verification
The applicant finishes your Sumsub WebSDK level. Confirm
reviewStatus: completed and reviewResult.reviewAnswer: GREEN before generating a share token.2
Submit share token to Pods
POST /api/v1/kyc/foreign/sumsub-share-token with taxId, taxIdCountry, shareToken, sumsubApplicantId, email, and walletAddress.3
Poll KYC status
GET /api/v1/kyc/status?kycUserId=… until status is approved. Level 1 approval does not enable USD ramps yet — usdEnabled stays false. Public Pix (BRL) and public USD are separate identities — a user typically has one or the other.4
Unlock USD
For Avenia:
POST /api/v1/kyc/currency-unlock with { "currency": "usd", "kycUserId": "…" }. Poll until usdEnabled is true. For UnblockPay, first provision an individual with POST /api/v1/kyc/sessions/:kycUserId/submit and rampProvider=unblockpay using taxId + taxIdCountry (and the home address). Finish UnblockPay KYC via hosted verificationLink or POST /api/v1/kyc/sessions/:kycUserId/documents — see UnblockPay KYC. Then POST /api/v1/kyc/currency-unlock with rampProvider=unblockpay refreshes rails and, when the bank fields in ramps.unblockpay.unlock.requiredBodyFields are sent, registers a wire External Account for offramp. That path never sets top-level usdEnabled. When the UnblockPay nest is non-terminal, GET /api/v1/kyc/status live-refreshes UnblockPay and may trigger /check after document uploads. capabilities.USD is the source of truth after review — LIGHT create alone is not enough.5
Quote and settle onramp
See Move Money with Pods Ramp for quote examples and deposit instructions.
GET /v2/swap/quote with originChain=fiat, destinationChain (ethereum | base | polygon), tokenIn=USD, USDC tokenOut, amountIn or amountOut, destinationAddress, and optional usdPaymentMethod=ACH or WIRE. With destinationAddress, the response includes ACH/WIRE deposit instructions — no EVM tx to sign. Poll GET /v2/swap/status/{quoteId} until fulfilled. Avenia (default) supports WIRE and ACH on ethereum, base, and polygon. Pin rampProvider=unblockpay only for USD WIRE on polygon or base — ACH and ethereum return RAMP_PROVIDER_NOT_ELIGIBLE. UnblockPay onramp is ready when ramps.unblockpay.capabilities.USD is true.6
Quote and settle offramp
See Move Money with Pods Ramp for the full quote examples and execution details.
GET /v2/swap/quote with originChain (ethereum | base | polygon), destinationChain=fiat, USDC tokenIn, tokenOut=USD, amountIn or amountOut, originAddress, USD bank fields, and optional usdPaymentMethod. Sign every item in transactionData using that item’s chainId. Poll status until fulfilled. UnblockPay offramp additionally requires ramps.unblockpay.unlock.offrampReady.1. Submit foreign share token
approved, retries with the same customer, applicant, tax ID, and an already linked wallet return the original kycUserId and status: approved without creating or changing a profile or importing another token. Legacy approvals, including copied approvals and profiles without import metadata, follow the same rule. The request still requires a share token, but Pods does not validate or consume it on this approved retry. Pods trusts the authenticated integration’s identifiers; your backend must authenticate the end user and authorize their use of that KYC profile.
Changing the applicant while claiming a tax ID already approved for your customer returns 409 KYC_VERIFIED_BINDING_REQUIRED without creating a profile. Changing an existing profile’s wallet returns 409 SUMSUB_WALLET_MISMATCH; changing its tax ID returns 409 SUMSUB_TAX_ID_MISMATCH. An approved profile without a stored identity hash cannot be matched and returns 409 KYC_VERIFIED_BINDING_REQUIRED. A duplicate-tax-ID rejection does not establish approval for the current applicant.
2. Poll status (Level 1 approved, USD still locked)
status is approved. For rejections, read the normalized reason object (not providerResult).
3. Unlock USD capability
usdEnabled is often still false while Avenia processes the USD KYC attempt:
GET /api/v1/kyc/status until usdEnabled is true:
Currency-unlock errors
Example — missing identification document:
POST /currency-unlock does not accept document uploads in the body.
4. USD beneficiary
Offramp resolve-or-create
Pass bank account fields onGET /v2/swap/quote with originAddress. Pods lists existing Avenia beneficiaries for the KYC subaccount; if account number + routing match, it reuses that id, otherwise it creates one and stores it on the quote (rawQuote.beneficiaryUsdBankAccountId, internal).
Required query fields:
Inspect is not exposed as a separate KYC API — beneficiaries are created or reused automatically on offramp quote from the flat bank fields (Pix-style destination).
5. USD↔USDC ramps (summary)
Supported USDC networks for v1 follow Avenia’s USD→USDC allowlist:ethereum, base, and polygon. When Avenia supports the destination chain, it delivers USDC directly to the user’s wallet (no Pods inventory hop).
For full quotes, deposit instructions, and execution examples, see the Move Money guide.
Token addresses (USDC)
Pass exactly one of
amountIn or amountOut — same contract as the onramp, inverted:
With
amountOut, Pods asks Avenia once (outputAmount); tokenIn.amount is the USDC to transfer (Out Fee included). Optional usdPaymentMethod is WIRE (default) or ACH.
Live quote smoke (2026-09-10, Polygon USDC, Picnic usdEnabled wallet — quotes only, nothing signed):
A
5 USDC amountIn covers ACH but not WIRE (~10 USDC Out Fee). Prefer amountOut when the product promise is “receive $N”.
Preferred offramp quote (bank fields → resolve-or-create, then executable payload). Use ASCII bankBeneficiaryName (example John Smith, not accented names):
amountOut=400 with amountIn=5000000 (5 USDC). WIRE: keep amountOut=400 and set usdPaymentMethod=WIRE (expects ~14 USDC in).
Track progress with GET /v2/swap/status/{quoteId} and GET /actions/{id}.
Money movement and quotes
Onramp/offramp quote examples, deposit instructions, and executabletransactionData live in the Move Money guide: Move Money with Pods Ramp. Use that guide for GET /v2/swap/quote, GET /v2/swap/status/{quoteId}, and execution details.
Status fields reference
API reference
Open the Ramp group in the API Reference tab for full request/response schemas:POST /api/v1/kyc/foreign/sumsub-share-tokenPOST /api/v1/kyc/currency-unlockGET /api/v1/kyc/statusGET /v2/swap/quoteGET /v2/swap/status/{quoteId}GET /actions/{id}
Captured examples
Internal live captures used to author this guide (do not ship secrets from local.env):