# Add a party role
Source: https://docs.venlyfinance.com/api-reference/Finance-API/accounts/add-a-party-to-an-account
api-reference/Finance-API-Specs.yaml POST /accounts/{accountId}/party-roles
Link an existing party to an account in a given role.
Associates a party with the account in a role. A party can hold only one role per account.
# Create an account
Source: https://docs.venlyfinance.com/api-reference/Finance-API/accounts/create-a-new-account
api-reference/Finance-API-Specs.yaml POST /accounts
Open an account and provision its wallet on the chosen chain.
Creates an account and its wallet. Link an existing party with `partyId`, or create one inline with the `party` object. Self-custody accounts also supply the wallet `address` — see [Venly-managed vs self-custody](/guides/finance/managed-vs-self-custody). A new account starts unverified and can't move money until it is [verified](/guides/finance/kyc-verification).
# Get an account
Source: https://docs.venlyfinance.com/api-reference/Finance-API/accounts/get-account-details
api-reference/Finance-API-Specs.yaml GET /accounts/{accountId}
Retrieve a single account by ID.
Returns the account's `status`, verification status (`kycStatus`), and `version`.
# List accounts
Source: https://docs.venlyfinance.com/api-reference/Finance-API/accounts/list-all-accounts
api-reference/Finance-API-Specs.yaml GET /accounts
Page through the accounts in your organisation.
Returns a paginated list of accounts. Filter by `status` or `externalId`, and page with `page`/`size` (see [Pagination](/getting-started/conventions#pagination)). Each [account](/guides/finance/glossary) belongs to a party and holds wallets and virtual bank accounts.
# List party roles
Source: https://docs.venlyfinance.com/api-reference/Finance-API/accounts/list-party-roles-for-an-account
api-reference/Finance-API-Specs.yaml GET /accounts/{accountId}/party-roles
List the parties linked to an account and the role each one holds.
Returns the [party-role](/guides/finance/glossary) links for an account (for example, the `ACCOUNT_HOLDER`). This is a plain array — it is not paginated.
# Remove a party role
Source: https://docs.venlyfinance.com/api-reference/Finance-API/accounts/remove-a-party-from-an-account
api-reference/Finance-API-Specs.yaml DELETE /accounts/{accountId}/party-roles/{partyId}
Unlink a party from an account.
Removes a party's role from the account. The last `ACCOUNT_HOLDER` cannot be removed. Returns `204 No Content`.
# Get wallet allowances
Source: https://docs.venlyfinance.com/api-reference/Finance-API/allowances/get-wallet-token-allowances
api-reference/Finance-API-Specs.yaml GET /accounts/{accountId}/wallets/{walletId}/allowances
Read the ERC-20 token allowances granted from a self-custody wallet.
Returns the token allowances granted from a self-custody wallet to the orchestration wallet. Filter by `asset`. Amounts are decimal strings; a uint256-max value indicates an unlimited allowance. Allowances are established with [permits](/guides/finance/permits-and-allowances).
**Self-custody companies only.** On a Venly-managed company this returns `400 invalid-request` — "Allowances are only applicable for SELF\_CUSTODY companies" — since managed wallets have no allowance to read.
# Create a pay-in session
Source: https://docs.venlyfinance.com/api-reference/Finance-API/fiat-to-crypto-payment-sessions/create-a-fiat-to-crypto-payment-session
api-reference/Finance-API-Specs.yaml POST /accounts/{accountId}/fiat-to-crypto/payment-sessions
Start a hosted fiat-to-crypto pay-in and get a payment URL.
Creates a hosted pay-in session. Redirect the payer to the returned `paymentUrl`; on completion the fiat is converted to the chosen cryptocurrency and credited to the account's wallet. Provide a `callbackUrl` and a unique `idempotencyKey` ([safe retries](/getting-started/conventions#idempotency)).
The account must be **verified** before a pay-in session can be created. See [Account verification](/guides/finance/kyc-verification).
# Create a party
Source: https://docs.venlyfinance.com/api-reference/Finance-API/parties/create-a-new-party
api-reference/Finance-API-Specs.yaml POST /parties
Onboard an individual or organisation — the root entity that holds accounts.
Creates a party. Use `partyType: INDIVIDUAL` with `firstName`/`lastName`, or `ORGANISATION` with `name` (and optional `vatNumber`). The returned `id` is what you pass when [opening an account](/api-reference/Finance-API/accounts/create-a-new-account). Identity verification runs asynchronously after creation — track it on `kycStatus` (individuals) or `kybStatus` (organisations); see [Account verification](/guides/finance/kyc-verification).
# Delete a party
Source: https://docs.venlyfinance.com/api-reference/Finance-API/parties/delete-party
api-reference/Finance-API-Specs.yaml DELETE /parties/{partyId}
Permanently delete a party that has no linked accounts.
Deletes a party. Only allowed when the party has no associated accounts — remove or close its [accounts](/api-reference/Finance-API/accounts/list-all-accounts) first. Returns `204 No Content` on success.
# Get a party
Source: https://docs.venlyfinance.com/api-reference/Finance-API/parties/get-party-details
api-reference/Finance-API-Specs.yaml GET /parties/{partyId}
Retrieve a single party by ID, including verification status and address.
Returns the full party record, including `kycStatus`/`kybStatus`, address, and `version`. Send the `version` back when [updating the party](/api-reference/Finance-API/parties/update-party-details) — see [safe updates](/getting-started/conventions#versioning).
# List parties
Source: https://docs.venlyfinance.com/api-reference/Finance-API/parties/list-all-parties
api-reference/Finance-API-Specs.yaml GET /parties
Page through the parties (individuals and organisations) in your organisation.
Returns a paginated list of parties. Filter by `partyType`, `status`, or `externalId`, and page with `page`/`size` (see [Pagination](/getting-started/conventions#pagination)). A [party](/guides/finance/glossary) is the root entity in the Finance API — each one can hold one or more accounts.
# Update a party
Source: https://docs.venlyfinance.com/api-reference/Finance-API/parties/update-party-details
api-reference/Finance-API-Specs.yaml PATCH /parties/{partyId}
Update an existing party's name, VAT number, or address.
Patches only the fields you send. Include the current `version` (from a prior read); a stale `version` returns `409` so you can refetch and retry (see [Versioning](/getting-started/conventions#versioning)). `partyType` cannot be changed after creation.
# Create a payment request by card provider
Source: https://docs.venlyfinance.com/api-reference/Finance-API/payment-requests/create-payment-request-by-card-provider
api-reference/Finance-API-Specs.yaml POST /payment-requests
Create a payment request, resolving the account from a card-provider reference.
Creates a payment request without an account ID in the path — the account is resolved from `cardProviderReference` (`type` + `referenceId`). The nested `paymentRequest` body matches the [per-account endpoint](/api-reference/Finance-API/payment-requests/create-payment-request-for-account).
**Concept guide:** [Payment requests](/guides/finance/payment-requests)
The resolved account must be **verified**, and (self-custody) its wallet **`ACTIVE`** with an allowance, before a payment can be reserved. See [Account verification](/guides/finance/kyc-verification).
There is **no `chain` field** in the request — the settlement chain is determined by the wallet pair of the account resolved from `cardProviderReference`. The reference must map to an account that has a wallet on that chain, otherwise the request fails to find a matching wallet pair. The response shape matches the [per-account endpoint](/api-reference/Finance-API/payment-requests/create-payment-request-for-account) (`amount`/`originalAmount` objects; no GET endpoint).
# Create a payment request
Source: https://docs.venlyfinance.com/api-reference/Finance-API/payment-requests/create-payment-request-for-account
api-reference/Finance-API-Specs.yaml POST /accounts/{accountId}/payment-requests
Request settlement of a payment from an account's crypto balance.
Creates a payment request for an account, reserving funds from its wallet for settlement. The response carries the request `status` (`PENDING`/`RESERVED`) and an `executions` array with the on-chain `transactionHash`; the amount moves to the wallet's `reserved` balance. Send a unique `idempotencyKey` per request ([safe retries](/getting-started/conventions#idempotency)).
**Concept guide:** [Payment requests](/guides/finance/payment-requests)
The account must be **verified**, and (self-custody) its wallet **`ACTIVE`** with an allowance, before a payment can be reserved. See [Account verification](/guides/finance/kyc-verification) and [Approving transfers without gas](/guides/finance/permits-and-allowances).
`amount` and `originalAmount` are returned as **objects** — `{ "fiat": , "crypto": "" }` — not scalars. There is **no GET endpoint** for payment requests: the full object (including `executions`) is only returned on this create call, so persist the response if you need it later.
# Reverse a payment request
Source: https://docs.venlyfinance.com/api-reference/Finance-API/payment-requests/reverse-a-payment-request
api-reference/Finance-API-Specs.yaml POST /payment-requests/{paymentRequestId}/reversal
Unwind a reserved payment request and return all escrowed funds to the account.
Reverses a reserved payment request, returning the full escrow balance to the account wallet through a `REVERSAL` execution. The call returns `202 Accepted` with `status: REVERSING`, and the request becomes `REVERSED` — a final state — once the transfer confirms on-chain. Pass a `reason` (`CUSTOMER_CANCELLATION`, `MERCHANT_VOID`, `ACQUIRER_FAILURE`, `NETWORK_DECLINE`, or `OTHER`); it's recorded on the request.
Send a unique `idempotencyKey`; repeating the same key and body returns the original result.
**Concept guide:** [Payment requests](/guides/finance/payment-requests)
To reverse a request by its card-provider reference instead of its ID, use [reverse by reference](/api-reference/Finance-API/payment-requests/reverse-a-payment-request-by-reference).
# Reverse a payment request by reference
Source: https://docs.venlyfinance.com/api-reference/Finance-API/payment-requests/reverse-a-payment-request-by-reference
api-reference/Finance-API-Specs.yaml POST /payment-requests/reversals
Reverse a payment request located by its card-provider reference.
Reverses a payment request you identify by its card-provider reference instead of its ID: the account comes from `paymentRequestReference.cardProviderReference` (`type` + `referenceId`) and the request from its `externalId`. Behavior and response — including the `{ "fiat": , "crypto": "" }` amount objects — match [reversing by ID](/api-reference/Finance-API/payment-requests/reverse-a-payment-request).
Send a unique `idempotencyKey`; repeating the same key and body returns the original result.
**Concept guide:** [Payment requests](/guides/finance/payment-requests)
# Settle a payment request
Source: https://docs.venlyfinance.com/api-reference/Finance-API/payment-requests/settle-a-payment-request
api-reference/Finance-API-Specs.yaml POST /payment-requests/{paymentRequestId}/settlements
Finalize a reserved payment request — move funds from escrow to the company's settlement wallet.
Settles a reserved payment request. The call returns `202 Accepted` with `status: SETTLING` and its executions `PENDING`; the request becomes `SETTLED` once those transfers confirm on-chain. `amount` is the final figure in the authorized `currency`, and the executions that run follow from how it compares to the authorized amount:
| Settlement `amount` | Executions |
| ------------------------------ | ------------------------------------------------------------------------------------------------------------- |
| Equal to the authorized amount | one `SETTLEMENT` |
| Below the authorized amount | `SETTLEMENT` + `REFUND` returning the difference to the account wallet |
| Above the authorized amount | `SETTLEMENT` (the full authorized amount) + `SETTLEMENT_OVERAGE` collecting the extra from the account wallet |
Send a unique `idempotencyKey`; repeating the same key and body returns the original result.
**Concept guide:** [Payment requests](/guides/finance/payment-requests)
`amount`, `settlementAmount`, and `settledAmount` come back as objects — `{ "fiat": , "crypto": "" }`. To settle a request by its card-provider reference instead of its ID, use [settle by reference](/api-reference/Finance-API/payment-requests/settle-a-payment-request-by-reference).
# Settle a payment request by reference
Source: https://docs.venlyfinance.com/api-reference/Finance-API/payment-requests/settle-a-payment-request-by-reference
api-reference/Finance-API-Specs.yaml POST /payment-requests/settlements
Settle a payment request located by its card-provider reference.
Settles a payment request you identify by its card-provider reference instead of its ID: the account comes from `paymentRequestReference.cardProviderReference` (`type` + `referenceId`) and the request from its `externalId`. Behavior and response — including the `{ "fiat": , "crypto": "" }` amount objects — match [settling by ID](/api-reference/Finance-API/payment-requests/settle-a-payment-request).
Send a unique `idempotencyKey`; repeating the same key and body returns the original result.
**Concept guide:** [Payment requests](/guides/finance/payment-requests)
# Update a payment request
Source: https://docs.venlyfinance.com/api-reference/Finance-API/payment-requests/update-a-payment-request
api-reference/Finance-API-Specs.yaml PATCH /payment-requests/{paymentRequestId}
Set a new authorized amount on a reserved payment request.
Sets a new absolute authorized `amount` on a reserved payment request. The execution that runs depends on how the new amount compares to the current one:
| New `amount` | Execution |
| ------------------- | -------------------------------------------------------------------------------------------- |
| Lower than current | `AUTHORIZATION_ADJUSTMENT` — releases the difference from escrow back to the account wallet |
| Higher than current | `INCREMENTAL_AUTHORIZATION` — pulls the additional funds from the account wallet into escrow |
The call returns `200 OK`. The request keeps `status: RESERVED`, `amount` reflects the new value, and `originalAmount` keeps the amount set at creation. Send a unique `idempotencyKey`.
**Concept guide:** [Payment requests](/guides/finance/payment-requests)
# Get permit messages
Source: https://docs.venlyfinance.com/api-reference/Finance-API/permits/get-permit-messages
api-reference/Finance-API-Specs.yaml GET /accounts/{accountId}/wallets/{walletId}/permits
Fetch the EIP-712 typed-data messages to sign for gasless token approvals.
Returns the EIP-2612 permit messages for a **self-custody** account wallet — one per supported asset, each with a `supportedAssetId` and the `typedData` to sign. Sign `typedData` with the wallet **owner's** key, then [submit the signature](/api-reference/Finance-API/permits/submit-signed-permit) to grant a gasless allowance. Full flow: [Approving transfers without gas](/guides/finance/permits-and-allowances).
Self-custody account wallets only — Venly-managed and escrow wallets are permitted automatically. Calling this on a Venly-managed company returns `400 invalid-request` ("Permits are only applicable for SELF\_CUSTODY companies"). See [Approving transfers without gas](/guides/finance/permits-and-allowances).
# Submit a signed permit
Source: https://docs.venlyfinance.com/api-reference/Finance-API/permits/submit-signed-permit
api-reference/Finance-API-Specs.yaml POST /accounts/{accountId}/wallets/{walletId}/permits
Submit an EIP-712 signature to grant a gasless token allowance.
Submits the `v`/`r`/`s` signature for a [permit message](/api-reference/Finance-API/permits/get-permit-messages). It moves `PENDING → SUBMITTED → CONFIRMED` (poll `GET .../permits`); once all of a wallet's permits are `CONFIRMED` the wallet becomes `ACTIVE`. Re-submitting an already-confirmed permit returns `409`.
The signature must recover to the wallet `owner`, or the permit settles as `FAILED`. The call returns HTTP `200` with `result.status` — poll `SUBMITTED → CONFIRMED`. See [Approving transfers without gas](/guides/finance/permits-and-allowances).
# Create a crypto transfer
Source: https://docs.venlyfinance.com/api-reference/Finance-API/transfers/create-crypto-transfer
api-reference/Finance-API-Specs.yaml POST /accounts/{senderAccountId}/transfers/crypto
Send a crypto transfer between two accounts.
Transfers a crypto `asset` on the given `chain` from the sender to a receiver account. Retrying with the same `idempotencyKey` returns the original transfer — no double-spend (see [Idempotency](/getting-started/conventions#idempotency)).
**Concept guide:** [Transfers](/guides/finance/transfers)
The sender account must be **verified**, and (self-custody) its wallet **`ACTIVE`** with an allowance to the orchestration wallet. See [Account verification](/guides/finance/kyc-verification) and [Approving transfers without gas](/guides/finance/permits-and-allowances).
# Create a fiat transfer
Source: https://docs.venlyfinance.com/api-reference/Finance-API/transfers/create-fiat-transfer
api-reference/Finance-API-Specs.yaml POST /accounts/{senderAccountId}/transfers/fiat
Send a fiat-denominated transfer between two accounts.
Transfers a fiat amount from the sender to a receiver (`receiverAccountId` or `receiverExternalId`). The amount settles in the underlying stablecoin; the response includes a `fiatOrigin` block with the original currency and exchange rate. Send a unique `idempotencyKey` ([safe retries](/getting-started/conventions#idempotency)).
**Concept guide:** [Transfers](/guides/finance/transfers)
The sender account must be **verified**, and (self-custody) its wallet **`ACTIVE`** with an allowance to the orchestration wallet. See [Account verification](/guides/finance/kyc-verification) and [Approving transfers without gas](/guides/finance/permits-and-allowances).
# Get a transfer
Source: https://docs.venlyfinance.com/api-reference/Finance-API/transfers/get-transfer-details
api-reference/Finance-API-Specs.yaml GET /accounts/{accountId}/transfers/{transferId}
Retrieve a single transfer by ID.
Returns the transfer details, including `status` (`PENDING`/`COMPLETED`/`FAILED`) and, for fiat transfers, the `fiatOrigin` block. The account must be the sender or receiver, otherwise the API returns `404`.
**Concept guide:** [Transfers](/guides/finance/transfers)
# List transfers
Source: https://docs.venlyfinance.com/api-reference/Finance-API/transfers/list-transfers-for-account
api-reference/Finance-API-Specs.yaml GET /accounts/{accountId}/transfers
Page through an account's transfers — sent and received, fiat and crypto.
Returns the account's transfers. Filter by `accountRole` (`SENDER`/`RECEIVER`) and `status`, and page with `page`/`size` (see [Pagination](/getting-started/conventions#pagination)).
**Concept guide:** [Transfers](/guides/finance/transfers)
# Create a virtual bank account
Source: https://docs.venlyfinance.com/api-reference/Finance-API/virtual-bank-accounts/create-a-virtual-bank-account
api-reference/Finance-API-Specs.yaml POST /accounts/{accountId}/virtual-bank-accounts
Assign a virtual IBAN to an account for fiat pay-ins.
Provisions a virtual bank account. Provide a display `name`, the fiat `inCurrency` to receive (EUR provisions a EUR\_SEPA IBAN), the `targetCryptocurrency` incoming funds convert to, and a unique `idempotencyKey` ([safe retries](/getting-started/conventions#idempotency)). The response includes the IBAN/BIC and a `referenceCode` the payer must quote so the wire is matched to this account.
The account must be **verified** (and have a linked account-holder party) before a virtual bank account can be created. See [Account verification](/guides/finance/kyc-verification).
# Get a virtual bank account
Source: https://docs.venlyfinance.com/api-reference/Finance-API/virtual-bank-accounts/get-virtual-bank-account-details
api-reference/Finance-API-Specs.yaml GET /accounts/{accountId}/virtual-bank-accounts/{virtualBankAccountId}
Retrieve a single virtual bank account by ID.
Returns the virtual bank account, including its IBAN/BIC and the `referenceCode` to quote on incoming transfers so settlement is matched to this account.
# List virtual bank accounts
Source: https://docs.venlyfinance.com/api-reference/Finance-API/virtual-bank-accounts/list-virtual-bank-accounts
api-reference/Finance-API-Specs.yaml GET /accounts/{accountId}/virtual-bank-accounts
List the virtual IBANs assigned to an account.
Returns the account's [virtual bank accounts](/guides/finance/glossary) (for example, EUR SEPA IBANs) used to receive fiat pay-ins.
# List wallets
Source: https://docs.venlyfinance.com/api-reference/Finance-API/wallets/list-wallets-for-an-account
api-reference/Finance-API-Specs.yaml GET /accounts/{accountId}/wallets
List an account's wallets with their per-asset balances.
Returns the account's wallets, each with its `address` and per-asset balances. Balance amounts (`total`, `available`, `reserved`) are decimal strings — `reserved` is the portion held against pending payment requests. Wallet `type` is `VENLY_MANAGED` or `SELF_CUSTODY` (see [custody models](/guides/finance/managed-vs-self-custody)).
**Concept guide:** [Wallets & balances](/guides/finance/wallets)
# Get bank account configuration
Source: https://docs.venlyfinance.com/api-reference/Fundflow-API/bank-account-configuration/get-bank-account-configuration
api-reference/Fundflow-API.yaml GET /v1/bank-accounts/config
Retrieve enabled bank account types, supported countries, and currencies.
Returns configuration for bank accounts: the enabled account types (SEPA, ACH, SWIFT, and more), supported countries, and supported currencies.
**Concept guide:** [Account management](/guides/payments/accounts)
# Get supported blockchain networks
Source: https://docs.venlyfinance.com/api-reference/Fundflow-API/blockchain-networks/get-supported-blockchain-networks
api-reference/Fundflow-API.yaml GET /v1/chains
Retrieve the blockchain networks supported for crypto operations.
Returns all blockchain networks supported by the platform for cryptocurrency operations.
**Concept guide:** [Getting started with Fundflow](/guides/payments/getting-started)
# Whitelist a company bank account
Source: https://docs.venlyfinance.com/api-reference/Fundflow-API/company-bank-accounts/create-a-company-bank-account
api-reference/Fundflow-API.yaml POST /v1/company-bank-accounts
Register a company bank account for fiat settlement in ramp requests.
Registers a new company bank account in `PENDING` status. Provide the fields for your account type — `EUR_SEPA`, `USD_WIRE`, `USD_ACH`, `USD_SWIFT`, `GBP_FPS`, `GBP_CHAPS`, or `OTHER_SWIFT`. The account must be in your company's legal name.
**Concept guide:** [Account management](/guides/payments/accounts)
Bank accounts are reviewed manually and may take 1–2 business days to reach `VERIFIED`. Only verified accounts can be used in ramp requests.
# Get company bank account by ID
Source: https://docs.venlyfinance.com/api-reference/Fundflow-API/company-bank-accounts/get-company-bank-account-by-id
api-reference/Fundflow-API.yaml GET /v1/company-bank-accounts/{id}
Fetch details for a specific company bank account.
Returns detailed information about a single company bank account.
**Concept guide:** [Account management](/guides/payments/accounts)
# List company bank accounts
Source: https://docs.venlyfinance.com/api-reference/Fundflow-API/company-bank-accounts/list-company-bank-accounts
api-reference/Fundflow-API.yaml GET /v1/company-bank-accounts
Retrieve your company bank accounts, with optional filtering.
Returns your company's bank accounts with optional filtering by verification status and supported ramp type.
**Concept guide:** [Account management](/guides/payments/accounts)
# Update company bank account
Source: https://docs.venlyfinance.com/api-reference/Fundflow-API/company-bank-accounts/update-company-bank-account
api-reference/Fundflow-API.yaml PATCH /v1/company-bank-accounts/{id}
Update the name of a company bank account.
Updates the name of a company bank account. Send the current `version` for optimistic locking.
**Concept guide:** [Account management](/guides/payments/accounts)
# Whitelist a company wallet
Source: https://docs.venlyfinance.com/api-reference/Fundflow-API/company-wallets/create-a-company-wallet
api-reference/Fundflow-API.yaml POST /v1/company-wallets
Register a company crypto wallet for use in ramp requests.
Registers a new company wallet in `PENDING` status. To verify ownership, send 1 USDC from the wallet to the deposit address returned by [Get deposit wallets](/api-reference/Fundflow-API/deposit-wallets/list-deposit-wallets).
**Concept guide:** [Account management](/guides/payments/accounts)
New wallets start as `PENDING` and must be verified before use. Never share private keys or seed phrases — only the wallet address is required.
# Get company wallet by ID
Source: https://docs.venlyfinance.com/api-reference/Fundflow-API/company-wallets/get-company-wallet-by-id
api-reference/Fundflow-API.yaml GET /v1/company-wallets/{id}
Fetch details for a specific company wallet.
Returns detailed information about a single company wallet.
**Concept guide:** [Account management](/guides/payments/accounts)
# List company wallets
Source: https://docs.venlyfinance.com/api-reference/Fundflow-API/company-wallets/list-company-wallets
api-reference/Fundflow-API.yaml GET /v1/company-wallets
Retrieve your company crypto wallets, filterable by status, chain, and address.
Returns your company's cryptocurrency wallets with optional filtering by verification status, blockchain network, and wallet address.
**Concept guide:** [Account management](/guides/payments/accounts)
# Update company wallet
Source: https://docs.venlyfinance.com/api-reference/Fundflow-API/company-wallets/update-company-wallet
api-reference/Fundflow-API.yaml PATCH /v1/company-wallets/{id}
Update the description of a company wallet.
Updates the description of a company wallet.
**Concept guide:** [Account management](/guides/payments/accounts)
# Get company details
Source: https://docs.venlyfinance.com/api-reference/Fundflow-API/company/get-company-details
api-reference/Fundflow-API.yaml GET /v1/company
Retrieve your company's details and KYB status.
Returns details about the authenticated user's company, including `kybStatus` and the invoices URL.
**Concept guide:** [Getting started with Fundflow](/guides/payments/getting-started)
Your company must have `kybStatus: VERIFIED` before you can create ramp requests.
# Get crypto currency by ID
Source: https://docs.venlyfinance.com/api-reference/Fundflow-API/crypto-currencies/get-crypto-currency-by-id
api-reference/Fundflow-API.yaml GET /v1/crypto-currencies/{id}
Fetch details for a specific cryptocurrency.
Returns detailed information about a single cryptocurrency.
**Concept guide:** [Getting started with Fundflow](/guides/payments/getting-started)
# List all crypto currencies
Source: https://docs.venlyfinance.com/api-reference/Fundflow-API/crypto-currencies/list-all-crypto-currencies
api-reference/Fundflow-API.yaml GET /v1/crypto-currencies
Retrieve the cryptocurrencies supported for ramp operations.
Returns all cryptocurrencies supported by the platform for ramp operations, organised by blockchain network.
**Concept guide:** [Getting started with Fundflow](/guides/payments/getting-started)
# Get deposit wallets
Source: https://docs.venlyfinance.com/api-reference/Fundflow-API/deposit-wallets/list-deposit-wallets
api-reference/Fundflow-API.yaml GET /v1/deposit-wallets
Retrieve Venly deposit wallet addresses for verification and off-ramp settlement.
Returns the Venly deposit wallet addresses per chain. Send 1 USDC here to verify ownership of a company wallet, and send crypto here when settling an off-ramp request.
**Concept guide:** [Account management](/guides/payments/accounts)
# Calculate fee for a ramp request
Source: https://docs.venlyfinance.com/api-reference/Fundflow-API/fees/calculate-fee-for-a-ramp-request
api-reference/Fundflow-API.yaml POST /v1/fees/calculate
Preview the fee for a given ramp amount before creating a request.
Calculates the fee amount and percentage for a given amount and ramp type, based on your company's configured fee tiers. Call this before creating large requests to understand the cost.
**Concept guide:** [Fee structure](/guides/payments/fees)
# Get company fee configuration
Source: https://docs.venlyfinance.com/api-reference/Fundflow-API/fees/get-company-fee-configuration
api-reference/Fundflow-API.yaml GET /v1/fees
Retrieve your company's fee tiers.
Returns the fee configuration for your company, including any volume-based tiers.
**Concept guide:** [Fee structure](/guides/payments/fees)
# Get fiat currency by ID
Source: https://docs.venlyfinance.com/api-reference/Fundflow-API/fiat-currencies/get-fiat-currency-by-id
api-reference/Fundflow-API.yaml GET /v1/fiat-currencies/{id}
Fetch details for a specific fiat currency.
Returns detailed information about a single fiat currency.
**Concept guide:** [Getting started with Fundflow](/guides/payments/getting-started)
# List all fiat currencies
Source: https://docs.venlyfinance.com/api-reference/Fundflow-API/fiat-currencies/list-all-fiat-currencies
api-reference/Fundflow-API.yaml GET /v1/fiat-currencies
Retrieve the fiat currencies supported for ramp operations.
Returns all fiat currencies supported by the platform for ramp operations (EUR, USD, GBP).
**Concept guide:** [Getting started with Fundflow](/guides/payments/getting-started)
# Approve a ramp request
Source: https://docs.venlyfinance.com/api-reference/Fundflow-API/ramp-requests/approve-a-ramp-request
api-reference/Fundflow-API.yaml POST /v1/ramp-requests/{id}/approve
Approve a pending request to move it to AWAITING_FUNDS.
A Company Admin approves a request created by a Manager. After approval the status changes to `AWAITING_FUNDS` and deposit details are returned — a bank account for on-ramp, a wallet address for off-ramp. Send the current `version` for optimistic locking.
**Concept guide:** [Transactions](/guides/payments/transactions)
Requires the `COMPANY_ADMIN` role. Once approved, a request moves to `AWAITING_FUNDS` and can no longer be cancelled.
# Cancel a ramp request
Source: https://docs.venlyfinance.com/api-reference/Fundflow-API/ramp-requests/cancel-a-ramp-request
api-reference/Fundflow-API.yaml POST /v1/ramp-requests/{id}/cancel
Cancel your own pending request before it is approved.
The Company Manager or Admin that created a request can cancel it while it is still in `AWAITING_APPROVAL`; the status changes to `CANCELLED`. Send the current `version` for optimistic locking.
**Concept guide:** [Transactions](/guides/payments/transactions)
# Create a ramp request
Source: https://docs.venlyfinance.com/api-reference/Fundflow-API/ramp-requests/create-a-new-ramp-request
api-reference/Fundflow-API.yaml POST /v1/ramp-requests
Start an on-ramp (fiat to crypto) or off-ramp (crypto to fiat) request.
Creates a new ramp request in `AWAITING_APPROVAL` status. For **ON\_RAMP**, specify the fiat amount, the fiat and crypto currencies, and a verified company wallet; for **OFF\_RAMP**, specify the crypto amount, the currencies, and a verified company bank account. A unique payment reference is generated so Venly can match your transfer.
**Concept guide:** [Transactions](/guides/payments/transactions)
Your company must be KYB-**VERIFIED**, and the target company wallet (ON\_RAMP) or bank account (OFF\_RAMP) must be **VERIFIED**. See [Account management](/guides/payments/accounts).
# Edit the amount of a ramp request
Source: https://docs.venlyfinance.com/api-reference/Fundflow-API/ramp-requests/edit-the-amount-of-a-ramp-request
api-reference/Fundflow-API.yaml PUT /v1/ramp-requests/{id}/amount
Update the incoming amount of a pending ramp request.
Updates the incoming amount — fiat for on-ramp, crypto for off-ramp — while the request is still in `AWAITING_APPROVAL`. The outgoing amount is recalculated from current exchange rates and fees. Send the current `version` for optimistic locking.
**Concept guide:** [Transactions](/guides/payments/transactions)
# Export ramp requests
Source: https://docs.venlyfinance.com/api-reference/Fundflow-API/ramp-requests/export-ramp-requests
api-reference/Fundflow-API.yaml GET /v1/ramp-requests/export
Download all your ramp requests as a file for accounting and auditing.
Exports your company's ramp requests as a downloadable file (CSV/Excel) for accounting, auditing, and record-keeping.
**Concept guide:** [Transactions](/guides/payments/transactions)
# Get available off-ramp currency pairs
Source: https://docs.venlyfinance.com/api-reference/Fundflow-API/ramp-requests/get-available-off-ramp-currency-pairs
api-reference/Fundflow-API.yaml GET /v1/ramp-requests/off-ramp/pairs
List supported crypto-to-fiat currency pairs for off-ramp requests.
Returns the combinations of supported crypto currencies and the fiat currencies they can be converted to. Check the available pairs before creating an off-ramp request.
**Concept guide:** [Transactions](/guides/payments/transactions)
# Get available on-ramp currency pairs
Source: https://docs.venlyfinance.com/api-reference/Fundflow-API/ramp-requests/get-available-on-ramp-currency-pairs
api-reference/Fundflow-API.yaml GET /v1/ramp-requests/on-ramp/pairs
List supported fiat-to-crypto currency pairs for on-ramp requests.
Returns the combinations of supported fiat currencies and the crypto currencies they can be converted to. Check the available pairs before creating an on-ramp request.
**Concept guide:** [Transactions](/guides/payments/transactions)
# Get ramp request by ID
Source: https://docs.venlyfinance.com/api-reference/Fundflow-API/ramp-requests/get-ramp-request-by-id
api-reference/Fundflow-API.yaml GET /v1/ramp-requests/{id}
Fetch full details, amounts, status, and event history for one ramp request.
Returns the current status, fiat and crypto amounts, fees, the associated wallet or bank account, payment information, and the complete event history for a ramp request.
**Concept guide:** [Transactions](/guides/payments/transactions)
# Initiate an off-ramp request with transaction hash
Source: https://docs.venlyfinance.com/api-reference/Fundflow-API/ramp-requests/initiate-a-ramp-request-with-transaction-hash
api-reference/Fundflow-API.yaml PATCH /v1/ramp-requests/{id}/initiate
Mark an off-ramp request as initiated by submitting its on-chain transaction hash.
After sending crypto to the Venly deposit wallet, submit the `blockchainTransactionHash` to initiate processing of an off-ramp request.
**Concept guide:** [Transactions](/guides/payments/transactions)
# List all ramp requests
Source: https://docs.venlyfinance.com/api-reference/Fundflow-API/ramp-requests/list-all-ramp-requests
api-reference/Fundflow-API.yaml GET /v1/ramp-requests
Retrieve a paginated, filterable list of your on-ramp and off-ramp requests.
Returns ramp requests for your company with optional filtering by `rampType`, `status`, date range, and `paymentReference`, plus sorting and pagination.
**Concept guide:** [Transactions](/guides/payments/transactions)
# Reject a ramp request
Source: https://docs.venlyfinance.com/api-reference/Fundflow-API/ramp-requests/reject-a-ramp-request
api-reference/Fundflow-API.yaml POST /v1/ramp-requests/{id}/reject
Reject a pending request created by a Manager.
A Company Admin rejects a request that is in `AWAITING_APPROVAL`; the status changes to `REJECTED`. Send the current `version` for optimistic locking.
**Concept guide:** [Transactions](/guides/payments/transactions)
# Update transaction hash
Source: https://docs.venlyfinance.com/api-reference/Fundflow-API/ramp-requests/update-transaction-hash
api-reference/Fundflow-API.yaml PATCH /v1/ramp-requests/{id}/tx-hash
Add or update the blockchain transaction hash for a ramp request.
Sets or corrects the `blockchainTransactionHash` for a ramp request so Venly can match your on-chain transfer. Send the current `version` for optimistic locking.
**Concept guide:** [Transactions](/guides/payments/transactions)
# Delete a company user
Source: https://docs.venlyfinance.com/api-reference/Fundflow-API/users/delete-a-company-user
api-reference/Fundflow-API.yaml DELETE /v1/company/users/{userId}
Permanently remove a user from your company.
Removes a user from your company.
**Concept guide:** [Getting started with Fundflow](/guides/payments/getting-started)
This action is permanent and cannot be undone. Requires the `COMPANY_ADMIN` role.
# Invite a user to the company
Source: https://docs.venlyfinance.com/api-reference/Fundflow-API/users/invite-a-user-to-the-company
api-reference/Fundflow-API.yaml POST /v1/company/users/invite
Send an email invitation for a new user to join your company.
Invites a new user by email and assigns their role. The user receives an invitation link to complete their registration.
**Concept guide:** [Getting started with Fundflow](/guides/payments/getting-started)
Requires the `COMPANY_ADMIN` role (the `manage:company-users` scope).
# List company users
Source: https://docs.venlyfinance.com/api-reference/Fundflow-API/users/list-company-users
api-reference/Fundflow-API.yaml GET /v1/company/users
Retrieve all users in your company with their roles and status.
Returns every user associated with your company, including each user's role (`COMPANY_ADMIN`, `COMPANY_MANAGER`, or `COMPANY_VIEWER`) and account status.
**Concept guide:** [Getting started with Fundflow](/guides/payments/getting-started)
# Update user role
Source: https://docs.venlyfinance.com/api-reference/Fundflow-API/users/update-user-role
api-reference/Fundflow-API.yaml PUT /v1/company/users/{userId}/role
Change a company user's role.
Updates a user's role — `COMPANY_ADMIN` (full access plus user management), `COMPANY_MANAGER` (create and manage ramp requests), or `COMPANY_VIEWER` (read-only access).
**Concept guide:** [Getting started with Fundflow](/guides/payments/getting-started)
Requires the `COMPANY_ADMIN` role (the `manage:company-users` scope).
# Update user status
Source: https://docs.venlyfinance.com/api-reference/Fundflow-API/users/update-user-status
api-reference/Fundflow-API.yaml PATCH /v1/company/users/{userId}/status
Enable or disable a company user account.
Enables or disables a user account. Disabled users cannot access the system.
**Concept guide:** [Getting started with Fundflow](/guides/payments/getting-started)
Requires the `COMPANY_ADMIN` role (the `manage:company-users` scope).
# Finance API
Source: https://docs.venlyfinance.com/api-reference/introduction
Embedded financial infrastructure — parties, accounts, wallets, IBANs, and transfers.
The Finance API lets you onboard parties, open accounts, assign IBANs, generate blockchain wallets, and execute fiat and crypto transfers through a single RESTful API.
## Base URLs
| Environment | URL |
| ----------- | ----------------------------------------- |
| Production | `https://api.venlyfinance.com/v1` |
| Staging | `https://api-staging.venlyfinance.com/v1` |
***
## Authentication
All endpoints require a Bearer token in the `Authorization` header. Obtain one using OAuth2 client credentials:
```bash theme={null}
curl -X POST https://login.venly.io/auth/realms/VenlyFinance/protocol/openid-connect/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET"
```
Then pass the token on every request:
```bash theme={null}
curl -X POST https://api.venlyfinance.com/v1/parties \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"partyType": "INDIVIDUAL",
"firstName": "Jane",
"lastName": "Doe"
}'
```
Tokens expire after **5 minutes**. See the [Authentication Guide](/getting-started/authentication) for token refresh patterns.
***
## Idempotency, pagination, versioning
Both APIs follow shared conventions for idempotent retries, list pagination, and version stability. See the [API Conventions](/getting-started/conventions) page for the full rules.
***
## Data model
Every Finance API resource hangs off a **party**. Parties hold accounts; accounts hold wallets and virtual bank accounts; wallets and IBANs are the entry points for crypto and fiat respectively.
```mermaid theme={null}
flowchart TD
Company[Your Company] --> PartyA[Party A · individual/organisation]
Company --> PartyB[Party B · individual/organisation]
PartyA --> AccountA[Account A]
PartyB --> AccountB[Account B]
AccountA --> VBA_A[Virtual Bank Account · IBAN]
AccountA --> WalletA[Account wallet · per chain]
AccountB --> VBA_B[Virtual Bank Account · IBAN]
AccountB --> WalletB[Account wallet · per chain]
VBA_A -. SEPA credits .-> AccountA
WalletA -. Crypto transfers .-> AccountA
VBA_B -. SEPA credits .-> AccountB
WalletB -. Crypto transfers .-> AccountB
```
New here? Start with [Getting started](/guides/finance/getting-started) for the party → account → verification → IBAN flow, read the [data model](/guides/finance/data-model) in depth, or follow the full [Integration Walkthrough](/guides/finance/integration-walkthrough).
***
## Resources
Onboard individuals and organisations. The foundation of every account.
Create and manage financial accounts with role-based party access.
Assign IBANs for EUR SEPA pay-ins linked to accounts.
Generate blockchain wallets (Base, Avalanche, Polygon) for crypto settlement.
Execute fiat and crypto transfers between accounts.
Generate pay-in sessions that convert fiat deposits to crypto.
Create payment requests for account or card provider integrations.
Manage EIP-712 permit signatures for token approvals.
Query token allowances for wallets.
***
## Next Steps
Create a party, open an account, and get verified — with managed and self-custody examples.
The full end-to-end flow, from onboarding to settling a transfer.
Why accounts start unverified and how a Venly admin approves them.
Token exchange, refresh patterns, and environment URLs.
***
## Support
Visit [venlyfinance.com/contact](https://venlyfinance.com/contact) to reach our team.
# Authentication
Source: https://docs.venlyfinance.com/getting-started/authentication
Obtain and use OAuth2 Bearer tokens for the Fundflow API and Finance API.
Both APIs use **OAuth2 client credentials flow**. Every request requires a short-lived Bearer token in the `Authorization` header.
***
## Get an Access Token
Exchange your Client ID and Secret at the token endpoint for your environment:
| Environment | URL |
| ----------- | --------------------------------------------------------------------------------------- |
| Staging | `https://login-staging.venly.io/auth/realms/VenlyFinance/protocol/openid-connect/token` |
| Production | `https://login.venly.io/auth/realms/VenlyFinance/protocol/openid-connect/token` |
```bash cURL theme={null}
curl -X POST https://login-staging.venly.io/auth/realms/VenlyFinance/protocol/openid-connect/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET"
```
```javascript Node.js theme={null}
const response = await fetch(
'https://login-staging.venly.io/auth/realms/VenlyFinance/protocol/openid-connect/token',
{
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'client_credentials',
client_id: process.env.CLIENT_ID,
client_secret: process.env.CLIENT_SECRET,
}),
}
);
const { access_token, expires_in } = await response.json();
```
```python Python theme={null}
import os
import requests
response = requests.post(
'https://login-staging.venly.io/auth/realms/VenlyFinance/protocol/openid-connect/token',
data={
'grant_type': 'client_credentials',
'client_id': os.environ['CLIENT_ID'],
'client_secret': os.environ['CLIENT_SECRET'],
}
)
access_token = response.json()['access_token']
```
**Response:**
```json theme={null}
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"expires_in": 300,
"token_type": "Bearer"
}
```
Tokens expire after **5 minutes** (300 seconds). Build token refresh into your client — see [Token Refresh](#token-refresh) below.
***
## Use the Token
Pass the `access_token` as a Bearer token on every request:
**Fundflow API:**
```bash theme={null}
curl -X GET https://api-fundflow-staging.venly.io/v1/company \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
```
**Finance API:**
```bash theme={null}
curl -X GET https://api-staging.venlyfinance.com/v1/parties \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
```
***
## Token Refresh
Request a new token before the current one expires. A 30-second buffer is sufficient:
```javascript theme={null}
let accessToken = null;
let tokenExpiresAt = 0;
async function getToken() {
if (Date.now() < tokenExpiresAt - 30_000) return accessToken;
const res = await fetch(TOKEN_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'client_credentials',
client_id: process.env.CLIENT_ID,
client_secret: process.env.CLIENT_SECRET,
}),
});
const data = await res.json();
accessToken = data.access_token;
tokenExpiresAt = Date.now() + data.expires_in * 1000;
return accessToken;
}
```
A `401 Unauthorized` response means the token has expired — re-authenticate and retry the request once.
***
## Environments
| | Staging | Production |
| ------------------ | ---------------------------------- | -------------------------- |
| **Token endpoint** | `login-staging.venly.io` | `login.venly.io` |
| **Fundflow API** | `api-fundflow-staging.venly.io/v1` | `api-fundflow.venly.io/v1` |
| **Finance API** | `api-staging.venlyfinance.com/v1` | `api.venlyfinance.com/v1` |
Staging credentials and production credentials are separate. Staging calls do not move real funds.
See [Endpoints & URLs](/getting-started/endpoints) for the complete base URL reference.
***
## Security
* Store `CLIENT_ID` and `CLIENT_SECRET` in environment variables or a secrets manager — never in source code or version control.
* Never log or expose tokens in client-side code.
* Treat a leaked secret as compromised immediately — rotate it via your Venly account and invalidate any outstanding tokens.
# API Conventions
Source: https://docs.venlyfinance.com/getting-started/conventions
Idempotency, pagination, and versioning rules that apply to every Venly API endpoint.
These conventions apply uniformly across the **Fundflow API** and **Finance API**. Endpoint references link here rather than restating the rules — bookmark this page.
***
## Idempotency
State-changing endpoints (`POST` requests that create a resource) accept an `idempotencyKey` field in the request **body**. It is not a header.
```json theme={null}
{
"idempotencyKey": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"amount": 100.00,
"currency": "EUR",
"...": "other fields"
}
```
Use a fresh UUID v4 for every new business operation. Reuse the **same** key only when retrying the **same** request.
### Behaviour
| You send | You get |
| ------------------------------- | --------------------------------------------------------- |
| A key for the first time | The operation runs |
| The same key with the same body | The original response, returned again — never a duplicate |
### When to use
| Required | Optional | Not applicable |
| ---------------------------------------------------------- | --------------------------- | ---------------------------------------------------------------------------- |
| Transfers (fiat / crypto / A2A) | Most other `POST` endpoints | `GET` requests (already idempotent) |
| Payment requests — create, settle, reverse, **and update** | | `PATCH` on parties/accounts (use the `version` field for optimistic locking) |
| Virtual bank account creation | | `DELETE` requests |
| Fiat-to-crypto payment sessions | | |
**Store the key client-side until you receive a `2xx`.** If your process crashes mid-flight, the same key on retry guarantees the request lands at most once.
A key is bound to one request body. To run a different operation — a new amount or recipient — generate a new key.
***
## Pagination
List endpoints (`GET /parties`, `GET /accounts`, `GET /transfers`, etc.) accept four query parameters:
| Parameter | Type | Default | Description |
| ----------- | ------- | ----------- | -------------------------- |
| `page` | integer | `1` | 1-based page number |
| `size` | integer | `100` | Items per page (minimum 1) |
| `sortOn` | string | `createdAt` | Field to sort by |
| `sortOrder` | string | `ASC` | `ASC` or `DESC` |
### Request
```bash theme={null}
curl "https://api.venlyfinance.com/v1/accounts?page=2&size=50&sortOrder=DESC" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
```
### Response shape
Every paginated response wraps the result list with a `pagination` object:
```json theme={null}
{
"success": true,
"result": [
{ "id": "...", "...": "..." }
],
"pagination": {
"pageNumber": 2,
"pageSize": 50,
"numberOfElements": 384,
"numberOfPages": 8,
"hasNextPage": true,
"hasPreviousPage": true
}
}
```
**Iterate using `hasNextPage`**, not by computing `pageNumber * pageSize >= numberOfElements`. The total count can shift between requests; the boolean is authoritative.
***
## Versioning
Both APIs use **URL path versioning**. The major version is in the base URL:
| API | Base URL |
| ------------------------ | ----------------------------------------- |
| Fundflow API | `https://api-fundflow.venly.io/v1` |
| Finance API (production) | `https://api.venlyfinance.com/v1` |
| Finance API (staging) | `https://api-staging.venlyfinance.com/v1` |
### What counts as a breaking change
Breaking changes ship in a **new major version** (e.g. `/v2`). The old version stays live throughout the deprecation window.
| Breaking | Non-breaking (ships within the current version) |
| ---------------------------------- | ----------------------------------------------- |
| Removing a field from a response | Adding a new field to a response |
| Renaming a field | Adding a new optional request field |
| Changing a field's type | Adding a new endpoint |
| Making an optional input required | Adding a new enum value |
| Removing an endpoint | Adding a new error code |
| Renaming or removing an enum value | Tightening a previously undocumented validation |
**Treat unknown enum values gracefully.** New enum values are *not* breaking — your client should ignore values it doesn't recognise rather than throwing. This is the most common cause of integrations failing on minor releases.
### Deprecation policy
* New major versions are announced **at least 6 months** before the old version is retired
* Both versions run in parallel during the deprecation window
* Migration guides are published alongside the new version
* Deprecated endpoints return a `Deprecation` HTTP header pointing to the replacement
***
## See also
OAuth2 token exchange, refresh, and environment URLs.
Full base URL reference for every environment.
# Endpoints & URLs
Source: https://docs.venlyfinance.com/getting-started/endpoints
All base URLs and authentication endpoints for Fundflow API and Finance API — staging and production.
Use staging credentials and URLs during development. Staging calls do not move real funds.
***
## Authentication
Both the Fundflow API and Finance API use the same OAuth2 token endpoint:
| Environment | URL |
| ----------- | --------------------------------------------------------------------------------------- |
| Staging | `https://login-staging.venly.io/auth/realms/VenlyFinance/protocol/openid-connect/token` |
| Production | `https://login.venly.io/auth/realms/VenlyFinance/protocol/openid-connect/token` |
**Request** (`application/x-www-form-urlencoded`):
| Parameter | Value |
| --------------- | -------------------- |
| `grant_type` | `client_credentials` |
| `client_id` | Your client ID |
| `client_secret` | Your client secret |
Tokens are valid for **5 minutes** (300 seconds). See the [Authentication guide](/getting-started/authentication) for refresh patterns.
***
## Fundflow API
| Environment | Base URL |
| ----------- | ------------------------------------------ |
| Staging | `https://api-fundflow-staging.venly.io/v1` |
| Production | `https://api-fundflow.venly.io/v1` |
### Key endpoints
| Endpoint | Method | Description |
| ------------------------------- | ---------- | --------------------------------- |
| `/company` | GET | Verify KYB status |
| `/ramp-requests` | GET / POST | List or create ramp requests |
| `/ramp-requests/{id}` | GET | Get ramp request by ID |
| `/ramp-requests/{id}/approve` | POST | Approve a ramp request |
| `/ramp-requests/{id}/reject` | POST | Reject a ramp request |
| `/ramp-requests/{id}/cancel` | POST | Cancel a ramp request |
| `/ramp-requests/on-ramp/pairs` | GET | Available on-ramp currency pairs |
| `/ramp-requests/off-ramp/pairs` | GET | Available off-ramp currency pairs |
| `/fees/calculate` | POST | Calculate fee for a ramp request |
| `/company-bank-accounts` | GET / POST | Manage company bank accounts |
| `/company-wallets` | GET / POST | Manage company wallets |
***
## Finance API
| Environment | Base URL |
| ----------- | ----------------------------------------- |
| Staging | `https://api-staging.venlyfinance.com/v1` |
| Production | `https://api.venlyfinance.com/v1` |
### Key endpoints
| Endpoint | Method | Description |
| ------------------------------------------------------- | -------------------- | ------------------------------------- |
| `/parties` | GET / POST | List or create parties |
| `/parties/{id}` | GET / PATCH / DELETE | Get, update, or delete a party |
| `/accounts` | GET / POST | List or create accounts |
| `/accounts/{id}` | GET | Get account details |
| `/accounts/{id}/party-roles` | GET / POST | List or add party roles on an account |
| `/accounts/{id}/wallets` | GET | List wallets for an account |
| `/accounts/{id}/virtual-bank-accounts` | GET / POST | List or create IBANs |
| `/accounts/{id}/transfers` | GET | List transfers for an account |
| `/accounts/{senderId}/transfers/crypto` · `/fiat` | POST | Create a crypto or fiat transfer |
| `/accounts/{id}/payment-requests` · `/payment-requests` | POST | Create a payment request |
Relevant Finance API endpoints accept an `idempotencyKey` field in the request body to prevent duplicate operations on retry. Supply a unique UUID for every new request.
***
## Quick Copy
```bash Staging token theme={null}
curl -X POST https://login-staging.venly.io/auth/realms/VenlyFinance/protocol/openid-connect/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET"
```
```bash Production token theme={null}
curl -X POST https://login.venly.io/auth/realms/VenlyFinance/protocol/openid-connect/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET"
```
# Quick Start
Source: https://docs.venlyfinance.com/getting-started/quickstart
Authenticate, send a request, and read the response — your first Venly API call in under 5 minutes.
Venly Finance offers two separate products — **Fundflow API** for multi-rail payment orchestration, and **Finance API** for embedded financial infrastructure. Both use OAuth2 client credentials for authentication.
***
## Step 1 — Get your credentials
Your **Client ID** and **Client Secret** are provisioned by Venly and sent to you directly. If you haven't received them, [contact us](https://venlyfinance.com/contact).
Use your staging credentials while testing. Staging calls do not move real funds.
***
## Step 2 — Get an access token
Exchange your credentials for a short-lived Bearer token:
```mermaid theme={null}
sequenceDiagram
autonumber
participant App as Your App
participant Auth as login.venly.io
participant API as Venly API
App->>Auth: POST /token (client_credentials)
Auth-->>App: access_token (5 min TTL)
App->>API: GET /company (Bearer token)
API-->>App: company details
App->>API: First domain call (party / ramp request)
API-->>App: 200 OK + resource
```
```bash cURL theme={null}
curl -X POST https://login-staging.venly.io/auth/realms/VenlyFinance/protocol/openid-connect/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET"
```
```javascript Node.js theme={null}
const response = await fetch(
'https://login-staging.venly.io/auth/realms/VenlyFinance/protocol/openid-connect/token',
{
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'client_credentials',
client_id: 'YOUR_CLIENT_ID',
client_secret: 'YOUR_CLIENT_SECRET',
}),
}
);
const { access_token } = await response.json();
```
Response:
```json theme={null}
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"expires_in": 300,
"refresh_expires_in": 0,
"token_type": "Bearer",
"not-before-policy": 0,
"scope": "email profile"
}
```
Tokens expire after **5 minutes** (300 seconds). Implement token refresh logic in your client so requests don't fail mid-session.
Copy the `access_token` — you'll pass it as a Bearer token in every subsequent request.
***
## Step 3 — First Fundflow API call
Call `GET /v1/company` to confirm your Fundflow credentials are working and check your KYB verification status:
```bash cURL theme={null}
curl -X GET https://api-fundflow-staging.venly.io/v1/company \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json"
```
```javascript Node.js theme={null}
const response = await fetch('https://api-fundflow-staging.venly.io/v1/company', {
headers: {
'Authorization': `Bearer ${access_token}`,
'Content-Type': 'application/json',
},
});
const data = await response.json();
```
A successful response:
```json theme={null}
{
"result": {
"id": "b7e2c1a3-4d5f-6e7a-8b9c-0d1e2f3a4b5c",
"name": "Your Company",
"kybStatus": "VERIFIED"
},
"success": true
}
```
`kybStatus: VERIFIED` means your company is approved to create ramp requests. If it shows `PENDING`, KYB review is still in progress — [contact us](https://venlyfinance.com/contact).
***
## Step 4 — First Finance API call
Call `POST /v1/parties` to create your first party — the foundational record that will hold accounts and wallets:
```bash cURL theme={null}
curl -X POST https://api-staging.venlyfinance.com/v1/parties \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"partyType": "INDIVIDUAL",
"firstName": "Jane",
"lastName": "Doe"
}'
```
```javascript Node.js theme={null}
const response = await fetch('https://api-staging.venlyfinance.com/v1/parties', {
method: 'POST',
headers: {
'Authorization': `Bearer ${access_token}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
partyType: 'INDIVIDUAL',
firstName: 'Jane',
lastName: 'Doe',
}),
});
const data = await response.json();
```
A successful `201` response:
```json theme={null}
{
"success": true,
"result": {
"id": "f3a2b1c4-8d9e-4f5a-b6c7-d8e9f0a1b2c3",
"partyType": "INDIVIDUAL",
"status": "ACTIVE",
"firstName": "Jane",
"lastName": "Doe",
"createdAt": "2026-01-15T09:30:00",
"updatedAt": "2026-01-15T09:30:00",
"version": 0
}
}
```
Save the returned `id` — you'll use it to create an account and assign wallets in the next steps.
A party is created **`ACTIVE`** immediately — no verification step. The **account** you open under it, however, starts unverified and can't move money until a Venly admin verifies it. See [Account verification](/guides/finance/kyc-verification).
***
## Next Steps
Create a party, open and verify an account, fund it, and send your first transfer
Set up bank accounts, wallets, and create your first ramp request
Token refresh, environment switching, and credential security
Ramp requests, wallets, fees, currencies, and more
Parties, accounts, wallets, transfers, and IBANs
# Card Program Setup
Source: https://docs.venlyfinance.com/guides/card-issuance/card-program-setup
Prepare a cardholder account so card authorizations can reserve and settle funds — the Venly-managed and self-custody flows side by side.
When a cardholder pays, the network sends Venly an **authorization** — Venly reserves the amount from the cardholder's wallet, then **settles** it (money leaves to the company's settlement wallet) or **reverses** it (money returns to the cardholder) as the transaction clears. On the Finance API, that authorization **is a [payment request](/guides/finance/payment-requests)**.
This guide takes a cardholder account from creation to a working authorization, and calls out exactly where **Venly-managed** (`VENLY_MANAGED`) and **self-custody** (`SELF_CUSTODY`) companies differ. The difference is one extra step — self-custody wallets need a one-time permit before they can be charged.
**Base URL (staging):** `https://api-staging.venlyfinance.com/v1`
**Auth:** OAuth2 Bearer token in the `Authorization` header. Tokens expire after 5 minutes — see the [Authentication guide](/getting-started/authentication).
Dedicated card-management endpoints (issue, freeze, list transactions) are on the [roadmap](/guides/card-issuance/introduction). The authorization → settlement plumbing this guide uses is **live today** on the Finance API.
***
## Prerequisites
Your `client_id` must carry the **`finance-api-card`** role plus **`manage:payment-requests`** (and **`manage:all-payment-requests`** if you authorize by card-provider reference). Your Venly contact enables these.
Examples use `curl`. Money-moving calls need an `idempotencyKey` (UUID v4) — `uuidgen`, `[guid]::NewGuid()`, or `crypto.randomUUID()`.
A wallet `address` you'll register on the account, plus access to its **owner key** to sign one permit.
The **`finance-api-card`** role is what provisions the **escrow wallet** every card authorization needs. An account created by a client *without* that role is **non-custodial-only** and rejects authorizations with `escrow-wallet-missing`. The role is applied at **account-create time** — grant it *before* creating the cardholder account; it is not back-filled onto existing accounts.
***
## The flow
```mermaid theme={null}
sequenceDiagram
autonumber
participant App as Your App
participant API as Finance API
participant Ops as Venly Admin
App->>API: 1. POST /accounts (cardholder)
API-->>App: accountId (kycStatus VERIFICATION_PENDING)
Ops-->>API: 2. Verify account
App->>API: 3. Fund the account wallet
Note over App,API: 4. SELF_CUSTODY only — sign + submit permits
(wallet PENDING → ACTIVE)
App->>API: 5. POST payment-request (authorization)
API-->>App: status RESERVED
App->>API: 6. Settle or reverse
```
Venly-managed accounts skip step 4 entirely — their wallets are permitted automatically.
***
## Step 1 — Authenticate
```bash theme={null}
curl -X POST https://login-staging.venly.io/auth/realms/VenlyFinance/protocol/openid-connect/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET"
```
```json Response theme={null}
{ "access_token": "eyJhbGciOi...", "expires_in": 300, "token_type": "Bearer" }
```
Cache the token. Refresh on `401` or shortly before `expires_in` — don't re-authenticate on every call.
***
## Step 2 — Create the cardholder account
The account represents the cardholder; its wallet funds the card. Optionally attach a **`cardProviderReference`** so authorizations arriving by card-provider reference resolve to this account.
The only structural difference between company types is the wallet `address`:
* **Venly-managed** — Venly creates and holds the wallet. **Omit `address`.**
* **Self-custody** — the cardholder controls the wallet. **Send their `address`** (required).
```bash Venly-managed theme={null}
curl -X POST https://api-staging.venlyfinance.com/v1/accounts \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"externalId": "cardholder-12345",
"name": "Jane Doe — Card",
"chain": "BASE",
"cardProviderReference": { "type": "PAYMENTOLOGY", "referenceId": "ACC-12345" }
}'
```
```bash Self-custody theme={null}
curl -X POST https://api-staging.venlyfinance.com/v1/accounts \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"externalId": "cardholder-12345",
"name": "Jane Doe — Card",
"chain": "BASE",
"address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F",
"cardProviderReference": { "type": "PAYMENTOLOGY", "referenceId": "ACC-12345" }
}'
```
```json Response (201) theme={null}
{
"success": true,
"result": {
"id": "b2a1f0e9-8c7d-4e3a-9f21-0a1b2c3d4e5f",
"externalId": "cardholder-12345",
"name": "Jane Doe — Card",
"kycStatus": "VERIFICATION_PENDING",
"status": "ACTIVE",
"createdAt": "2026-01-15T09:30:00",
"version": 0
}
}
```
`cardProviderReference` can only be set when the account is **created**. Decide the card link up front.
***
## Step 3 — Verify the account
A new account is `kycStatus: VERIFICATION_PENDING`. A **Venly admin** reviews and verifies it — there's no API call to trigger this. Poll until it flips:
```bash theme={null}
curl https://api-staging.venlyfinance.com/v1/accounts/{accountId} \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
```
```json Response (200) theme={null}
{ "success": true, "result": { "id": "b2a1f0e9-...", "kycStatus": "VERIFIED", "status": "ACTIVE", "version": 1 } }
```
Until `VERIFIED`, authorizations fail with `account-not-active` ("KYC status must be VERIFIED"). See [Account verification](/guides/finance/kyc-verification).
***
## Step 4 — Fund the wallet
The account wallet must hold the stablecoin the card spends. Read its address and balance:
```bash theme={null}
curl https://api-staging.venlyfinance.com/v1/accounts/{accountId}/wallets \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
```
```json Response (200) theme={null}
{
"success": true,
"result": [
{
"id": "9f8e7d6c-5b4a-4938-8271-6a5b4c3d2e1f",
"chain": "BASE",
"type": "VENLY_MANAGED",
"address": "0x01DA4aa698B545D6A32ef44DB37139D3b27eAF61",
"balances": [
{ "asset": "USDC", "contractAddress": "0x036CbD53842c5426634e7929541eC2318f3dCF7e", "amount": { "total": "0", "available": "0", "reserved": "0" } }
],
"amlStatus": "APPROVED"
}
]
}
```
* **Venly-managed** — fund the returned Venly address with the stablecoin. Gas is covered by Venly's orchestration wallet; the account wallet only needs the token.
* **Self-custody** — the cardholder funds their own `address` with the stablecoin.
***
## Step 5 — Activate the wallet (self-custody only)
Venly-managed wallets are permitted automatically — **skip to Step 6.**
A self-custody wallet is created `PENDING`. Before it can be charged, the owner signs a one-time **permit** for **every** supported asset on the wallet, and the wallet becomes **`ACTIVE` only once all of them are `CONFIRMED`**. Until then authorizations fail with `account-wallet-not-active`.
A raw on-chain `approve()` sets the ERC-20 allowance but does **not** activate the wallet — only a **confirmed permit** does. And it's **all** assets: a wallet that supports USDC *and* EURC needs **both** permits confirmed before it goes `ACTIVE`.
`GET /accounts/{accountId}/wallets/{walletId}/permits` returns, per asset, a `supportedAssetId` and an EIP-712 `typedData` object.
Sign `typedData` with the wallet **owner** key (off-chain, no gas). The signature must recover to the `owner` or the permit becomes `FAILED`. Produces `v`, `r`, `s`.
`POST .../permits` with the `supportedAssetId` and signature → HTTP 200 with `result.status`.
Poll `GET .../permits` until each asset is `CONFIRMED`. When the last one confirms, the wallet activates.
```bash theme={null}
curl -X POST https://api-staging.venlyfinance.com/v1/accounts/{accountId}/wallets/{walletId}/permits \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"supportedAssetId": "5d4c5b99-2ce8-40a1-bc1d-173dd400fa89",
"signature": { "v": "28", "r": "0x...", "s": "0x..." }
}'
```
Full signing example (ethers.js) and the allowance check are in [Approving transfers without gas](/guides/finance/permits-and-allowances).
***
## Step 6 — Create the authorization
With the account `VERIFIED`, funded, and (self-custody) `ACTIVE`, reserve funds. There are two endpoints:
```bash By account theme={null}
curl -X POST https://api-staging.venlyfinance.com/v1/accounts/{accountId}/payment-requests \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"amount": 25.0,
"currency": "USD",
"externalId": "auth-67890",
"description": "Card authorization #67890",
"idempotencyKey": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
}'
```
```bash By card-provider reference theme={null}
curl -X POST https://api-staging.venlyfinance.com/v1/payment-requests \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"cardProviderReference": { "type": "PAYMENTOLOGY", "referenceId": "ACC-12345" },
"paymentRequest": {
"amount": 25.0,
"currency": "USD",
"externalId": "auth-67890",
"description": "Card authorization #67890",
"idempotencyKey": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
}
}'
```
```json Response theme={null}
{
"success": true,
"result": {
"id": "d4e5f6a7-b8c9-4012-8345-6789abcdef01",
"accountId": "b2a1f0e9-8c7d-4e3a-9f21-0a1b2c3d4e5f",
"amount": { "fiat": 25.0, "crypto": "25.000000" },
"originalAmount": { "fiat": 25.0, "crypto": "25.000000" },
"currency": "USD",
"status": "RESERVED",
"executions": [
{ "type": "AUTHORIZATION", "chain": "BASE", "asset": "USDC", "amount": 25.0, "status": "RESERVED", "transactionHash": "0xa1b2..." }
]
}
}
```
The reserved amount now shows in the wallet's `reserved` balance. Amounts carry both `fiat` and `crypto` — see [Payment requests](/guides/finance/payment-requests).
The reservation runs on-chain. On fast chains the response is `RESERVED` straight away; on others it returns `PENDING` and flips to `RESERVED` once the authorization transaction confirms. There's **no GET endpoint** — re-send the create with the **same `idempotencyKey` and body** to read the latest state, and match on your `externalId`.
***
## Step 7 — Settle or reverse
When the card transaction clears, resolve the hold:
* **[Settle](/api-reference/Finance-API/payment-requests/settle-a-payment-request)** — money moves from escrow to the company's settlement wallet (`SETTLING` → `SETTLED`). The settle amount can be equal to, below, or above the authorized amount.
* **[Reverse](/api-reference/Finance-API/payment-requests/reverse-a-payment-request)** — the full reserved amount returns to the cardholder (`REVERSING` → `REVERSED`). Use it to release a hold you won't charge.
Both have **by-reference** variants that take the same `cardProviderReference` instead of the `accountId`.
***
## Managed vs self-custody at a glance
| Step | Venly-managed (`VENLY_MANAGED`) | Self-custody (`SELF_CUSTODY`) |
| ---------------------------- | ------------------------------- | ------------------------------------------- |
| Create account | No `address` | `address` **required** |
| Wallet custody | Venly holds the key | Cardholder holds the key |
| Funding | Fund the Venly-created address | Cardholder funds their own address |
| Gas | Paid by Venly orchestration | Paid by Venly orchestration |
| **Wallet activation** | Automatic | **Sign a permit for every supported asset** |
| Verify KYC | Required | Required |
| Authorize / settle / reverse | Identical | Identical |
***
## Common pitfalls
The account was created by a client **without `finance-api-card`**, so it's non-custodial-only and has no escrow wallet. Grant the role, then create a **new** cardholder account (escrow isn't back-filled onto existing accounts).
A self-custody wallet that isn't `ACTIVE` yet. Confirm a permit for **every** supported asset on the wallet — the wallet only activates once they're all `CONFIRMED`. A raw `approve()` doesn't count. See [Permits & allowances](/guides/finance/permits-and-allowances).
The account is still `VERIFICATION_PENDING`. A Venly admin must verify it — poll `GET /accounts/{id}` until `kycStatus` is `VERIFIED`.
Self-custody accounts must include the cardholder's wallet `address` on creation. Venly-managed accounts must not.
Tokens last 5 minutes. Catch `401`, refresh, and retry — don't pre-authenticate every request.
***
## Next steps
The full reserve → settle/reverse/adjust lifecycle.
Gasless wallet activation for self-custody accounts.
Endpoint reference, fields, and error codes.
The white-label card program and its roadmap.
# Card Issuance (Coming Soon)
Source: https://docs.venlyfinance.com/guides/card-issuance/introduction
White-label Mastercard debit cards linked to USDC wallets
**Coming Soon** - Card Issuance is currently in development and will be available in Q2 2026. This documentation provides an overview of the upcoming features.
## What is Card Issuance?
Venly's Card Issuance product enables you to issue white-label Mastercard debit cards directly linked to USDC wallets. Your users can spend their cryptocurrency holdings anywhere Mastercard is accepted, while you capture interchange revenue on every transaction.
Instant issuance for online and mobile payments
Branded plastic cards for in-person transactions
Direct spending from stablecoin wallets
Earn revenue on every card transaction
***
## Key Features
### 💳 White-Label Card Program
Issue cards under your own brand with full customization:
* **Custom Card Design**: Your logo, colors, and branding
* **Branded Cardholder Experience**: Custom mobile app integration
* **Your Business Name**: Cards issued in your company name
* **Direct Program Management**: Full control over card operations
### 🔗 USDC Wallet Integration
Seamless connection to Venly Finance wallets:
* **Real-Time Balance**: Cards linked directly to USDC wallet balances
* **Instant Settlements**: Transactions settle immediately from wallet
* **Multi-Currency Support**: Automatic conversion at point of sale
* **Unified Treasury**: Single view of wallet and card balances
### 💰 Interchange Revenue Model
Capture interchange fees on every card transaction:
* **Typical Interchange**: 1.5% - 2.5% per transaction
* **Monthly Revenue**: Captured on every cardholder transaction
* **Transparent Reporting**: Real-time interchange tracking
* **Direct Settlement**: Revenue paid directly to your account
### 🌍 Global Acceptance
Mastercard network coverage:
* **200+ Countries**: Accepted worldwide
* **40M+ Merchants**: Online and offline acceptance
* **ATM Withdrawals**: Cash access at Mastercard ATMs
* **Contactless Payments**: NFC-enabled for tap-to-pay
***
## How It Works
Partner with Venly to establish your card program
* Complete Mastercard program application
* Configure card design and branding
* Set up compliance and KYC requirements
* Define spending limits and controls
Your users complete KYC and request cards
* User completes identity verification
* Links USDC wallet to card program
* Selects virtual or physical card
* Card issued instantly (virtual) or shipped (physical)
Cardholders activate and start spending
* Virtual cards: Active immediately
* Physical cards: Activate upon receipt
* Set PIN for ATM and chip transactions
* Configure spending limits and controls
Real-time authorization and settlement
```
1. Cardholder makes purchase
2. Merchant requests authorization
3. Venly checks USDC wallet balance
4. Transaction approved/declined
5. USDC converted to fiat at POS
6. Settlement to merchant
7. Interchange fee captured
```
Earn interchange on every transaction
* Interchange fees calculated automatically
* Revenue tracked in real-time dashboard
* Monthly settlement to your account
* Detailed reporting and analytics
***
## Card Types
### Virtual Cards
**Instant Issuance for Digital Payments**
* **Instant Activation**: Available immediately upon approval
* **Online Shopping**: Use for e-commerce and subscriptions
* **Mobile Wallets**: Add to Apple Pay, Google Pay
* **Secure Transactions**: 3D Secure authentication
* **No Physical Shipping**: Zero delivery time or cost
**Ideal For:**
* Online marketplaces
* Subscription services
* Digital-first businesses
* Quick user onboarding
### Physical Cards
**Branded Plastic Cards for In-Person Use**
* **Custom Design**: Your logo and branding
* **Contactless Enabled**: NFC tap-to-pay
* **Chip & PIN**: EMV chip security
* **Magnetic Stripe**: Legacy terminal support
* **ATM Access**: Cash withdrawals worldwide
**Ideal For:**
* Retail spending
* Travel and hospitality
* Cash access needs
* Premium user experience
***
## Use Cases
### 🎮 Gaming & iGaming Platforms
Enable players to spend winnings instantly:
* Issue cards to verified players
* Link to player wallet balances
* Instant access to winnings
* Capture interchange on player spending
**Revenue Potential**: Capture interchange revenue on every player transaction
### 💱 Crypto Exchanges & Trading Platforms
Let traders spend crypto holdings:
* Convert crypto to spendable cards
* Real-time balance updates
* Multi-currency wallet support
* Seamless fiat off-ramp
### 🏦 Neobanks & Fintechs
Complete banking experience:
* Accounts + Wallets + Cards in one platform
* Unified customer experience
* Additional revenue stream
* Competitive differentiation
### 💼 Corporate Expense Management
Issue cards for business spending:
* Employee expense cards
* Department budget controls
* Real-time spend tracking
* Automated reconciliation
***
## Interchange Revenue Model
### How Interchange Works
Every card transaction generates interchange fees paid by merchants:
```
Transaction: $100 purchase
Interchange Rate: 1.8%
Interchange Fee: $1.80
Your Revenue: Captured per transaction
```
### Revenue Potential
Interchange revenue scales with monthly card spend. Larger programs unlock both higher absolute revenue and improved per-card economics. Actual interchange rates vary by merchant category, card type, and transaction type — typical range is 1.5% – 2.5%.
***
## Card Controls & Security
### Spending Limits
Flexible controls for risk management:
* **Per-Transaction Limits**: Maximum single transaction amount
* **Daily Limits**: Total daily spending cap
* **Monthly Limits**: Monthly spending budget
* **ATM Withdrawal Limits**: Cash withdrawal restrictions
* **Merchant Category Restrictions**: Block specific merchant types
### Security Features
Multi-layer security protection:
* **3D Secure**: Additional authentication for online purchases
* **Real-Time Fraud Detection**: AI-powered transaction monitoring
* **Instant Card Freeze**: Users can freeze cards instantly
* **Biometric Authentication**: Fingerprint/Face ID for mobile
* **Tokenization**: Secure token-based transactions
### Compliance
Built-in regulatory compliance:
* **KYC/AML**: Automated identity verification
* **Transaction Monitoring**: Real-time suspicious activity detection
* **Sanctions Screening**: Automatic sanctions list checking
* **Regulatory Reporting**: Automated compliance reports
* **PCI DSS Compliant**: Secure card data handling
***
## Integration Overview
### API Endpoints (Coming Soon)
```bash theme={null}
# Issue a new card
POST /v1/cards
{
"cardholderAccountId": "account-id",
"cardType": "VIRTUAL",
"walletId": "usdc-wallet-id",
"spendingLimits": {
"daily": 1000,
"monthly": 10000
}
}
# Get card details
GET /v1/cards/{cardId}
# Freeze/Unfreeze card
POST /v1/cards/{cardId}/freeze
POST /v1/cards/{cardId}/unfreeze
# List transactions
GET /v1/cards/{cardId}/transactions
# Get interchange revenue
GET /v1/cards/interchange-revenue
```
### Webhook Events
Real-time notifications for card events:
* `card.issued` - New card created
* `card.activated` - Card activated by user
* `card.frozen` - Card frozen
* `transaction.authorized` - Transaction approved
* `transaction.declined` - Transaction declined
* `transaction.settled` - Transaction completed
* `interchange.earned` - Interchange revenue captured
***
## Mastercard Program Manager
Venly is a **Mastercard Program Manager**, providing:
✅ **Direct Issuance Capability**: Issue cards without intermediaries\
✅ **Program Management**: Full control over card operations\
✅ **Compliance Support**: Regulatory guidance and support\
✅ **Technical Integration**: Complete API and webhook infrastructure\
✅ **Settlement Services**: Direct settlement to your accounts
***
## Roadmap
### Q2 2026 - Initial Launch
* Virtual card issuance
* USDC wallet integration
* Basic spending controls
* Interchange revenue tracking
* API and webhooks
### Q3 2026 - Enhanced Features
* Physical card issuance
* Multi-currency support (EURC, USDT)
* Advanced fraud detection
* Mobile SDK for card management
* Enhanced reporting and analytics
### Q4 2026 - Enterprise Features
* Corporate card programs
* Multi-level approval workflows
* Advanced spending controls
* Custom card designs
* White-label mobile app
***
## Getting Started
### Prerequisites
To participate in the Card Issuance program, you'll need:
✅ **Active Venly Finance Account**: Verified company account\
✅ **Mastercard Program Approval**: Complete program application\
✅ **Compliance Requirements**: KYC/AML procedures in place\
✅ **Minimum Volume**: €500K+ monthly expected card spend\
✅ **Technical Integration**: API integration capability
### Early Access Program
Register your interest for early access to Card Issuance
**Benefits:**
* Priority onboarding when available
* Discounted launch pricing
* Dedicated integration support
* Beta testing opportunity
**Contact**: [venlyfinance.com/contact](https://venlyfinance.com/contact)
***
## Comparison: Card Issuance vs Traditional PSPs
| Feature | Traditional PSPs | Venly Card Issuance |
| -------------------------- | ----------------------- | --------------------- |
| **Setup Time** | 6-12 months | 2-4 weeks |
| **Integration Complexity** | High (multiple vendors) | Simple (one API) |
| **Interchange Revenue** | 0-30% share | 70-85% share |
| **Crypto Integration** | Limited/None | Native USDC support |
| **Monthly Fees** | €5-10 per card | €2.50 per card |
| **Settlement Time** | T+2 to T+5 | Real-time |
| **White-Label** | Limited customization | Full branding control |
***
## Frequently Asked Questions
At launch, cards will be linked to USDC wallets on Base blockchain. Support for EURC and USDT is planned for Q3 2026.
Virtual cards are issued instantly upon approval. Physical cards are produced and shipped within 5-7 business days.
Default limits are €1,000 per transaction, €5,000 daily, and €20,000 monthly. You can configure custom limits per cardholder.
Interchange is calculated as a percentage of each transaction (typically 1.5-2.5%) and varies by merchant category. You receive 70-85% of the interchange fee based on your volume tier.
Cardholders must complete KYC verification. Your company must have AML procedures and transaction monitoring in place. Venly provides compliance tools and support.
Yes, physical cards can be fully customized with your logo, colors, and branding. Virtual cards display your branding in mobile wallets.
Transactions are declined in real-time if the USDC wallet balance is insufficient. Users receive instant notifications to add funds.
Yes, cardholders can withdraw cash at any Mastercard-enabled ATM worldwide. Standard ATM fees apply (€2.00 per withdrawal).
***
## Next Steps
Register for early access
Explore wallet integration
Discuss your card program
Estimate your revenue (coming soon)
***
## Support
Questions about Card Issuance?
* **Contact**: [venlyfinance.com/contact](https://venlyfinance.com/contact)
* **Documentation**: [docs.venlyfinance.com](https://docs.venlyfinance.com)
# Compliance Engine (Coming Soon)
Source: https://docs.venlyfinance.com/guides/compliance/introduction
Automated screening, transaction monitoring, and regulatory reporting across all payment rails
**Coming Soon** - Compliance Engine is currently in development and will be available in Q4 2026. This documentation provides an overview of the upcoming features.
## What is Compliance Engine?
Compliance Engine is Venly's automated compliance and risk management system that provides real-time transaction monitoring, sanctions screening, and regulatory reporting across all payment rails. Stay compliant without the operational overhead of manual compliance processes.
Real-time AML and sanctions screening
AI-powered suspicious activity detection
Automated compliance report generation
Complete transaction history and evidence
***
## Key Features
### 🔍 Real-Time Screening
Automated screening for every transaction:
* **Sanctions Lists**: OFAC, UN, EU, and 200+ global lists
* **PEP Screening**: Politically Exposed Persons identification
* **Adverse Media**: Negative news and reputational risk
* **Watchlists**: Custom internal watchlists
* **Fuzzy Matching**: Advanced name matching algorithms
### 📊 Transaction Monitoring
AI-powered pattern detection:
* **Behavioral Analysis**: Detect unusual transaction patterns
* **Velocity Checks**: Monitor transaction frequency and volume
* **Geographic Risk**: Flag high-risk jurisdictions
* **Structuring Detection**: Identify potential smurfing
* **Peer Group Analysis**: Compare against similar entities
### 📝 Regulatory Reporting
Automated compliance documentation:
* **SAR/STR Generation**: Suspicious Activity Reports
* **CTR Filing**: Currency Transaction Reports
* **Travel Rule Compliance**: FATF Travel Rule adherence
* **Audit Reports**: Comprehensive compliance audits
* **Regulator Submissions**: Direct filing capabilities
### ⚙️ Configurable Rules
Customize compliance to your needs:
* **Risk-Based Rules**: Tailor screening based on risk levels
* **Threshold Configuration**: Set custom alert thresholds
* **Workflow Automation**: Define approval processes
* **Escalation Paths**: Automatic escalation for high-risk cases
* **False Positive Tuning**: Machine learning optimization
***
## How It Works
Every transaction is screened in real-time
```
Transaction Initiated
↓
Compliance Engine Activated
↓
Screening Checks:
✓ Sanctions lists (OFAC, UN, EU)
✓ PEP databases
✓ Adverse media
✓ Custom watchlists
✓ Geographic risk
↓
Risk Score Calculated
```
**Processing Time**: \<100ms per transaction
AI analyzes transaction risk factors
**Risk Factors Analyzed:**
* Sender/receiver identity and history
* Transaction amount and frequency
* Geographic locations involved
* Payment rail and method
* Historical behavior patterns
* Industry risk profile
**Risk Score**: 0-100 (Low to High)
System takes action based on risk score
```
Risk Score 0-30 (Low):
→ Auto-approve transaction
→ Continue processing
Risk Score 31-70 (Medium):
→ Flag for review
→ Notify compliance team
→ Hold transaction pending review
Risk Score 71-100 (High):
→ Block transaction
→ Immediate escalation
→ Generate alert
→ Require manual approval
```
Flagged transactions reviewed by compliance team
* Access complete transaction context
* Review screening results and evidence
* Add notes and documentation
* Approve, reject, or escalate
* Generate reports if needed
Ongoing monitoring and reporting
* Daily transaction monitoring
* Periodic account reviews
* Automated report generation
* Regulatory filing preparation
* Audit trail maintenance
***
## Screening Capabilities
### Sanctions Lists
**Global Coverage:**
* **OFAC** (US Office of Foreign Assets Control)
* **UN Security Council** Consolidated List
* **EU Sanctions** List
* **UK HM Treasury** Sanctions
* **DFAT** (Australia)
* **200+ Additional Lists** from jurisdictions worldwide
**Update Frequency**: Real-time updates as lists change
### PEP Databases
**Politically Exposed Persons Screening:**
* Current and former government officials
* Senior executives of state-owned enterprises
* Political party officials
* Immediate family members
* Close associates
**Coverage**: 240+ countries and territories
### Adverse Media Screening
**Negative News Monitoring:**
* Financial crime allegations
* Fraud and corruption
* Money laundering
* Terrorist financing
* Regulatory violations
* Reputational risks
**Sources**: 100,000+ global news sources in 50+ languages
### Custom Watchlists
**Internal Risk Management:**
* Blocked customers
* High-risk merchants
* Suspicious entities
* Internal investigations
* Compliance holds
***
## Transaction Monitoring Rules
### Pre-Configured Rules
**Out-of-the-box monitoring scenarios:**
1. **High-Value Transactions**
* Alert on transactions exceeding thresholds
* Configurable by currency and time period
* Automatic escalation for very large amounts
2. **Rapid Movement of Funds**
* Detect quick in-and-out patterns
* Flag potential pass-through accounts
* Monitor velocity across accounts
3. **Structuring Detection**
* Identify transactions just below reporting thresholds
* Pattern recognition for smurfing
* Multiple small transactions from same source
4. **Geographic Risk**
* Flag transactions to/from high-risk jurisdictions
* Monitor cross-border patterns
* Detect unusual geographic activity
5. **Unusual Activity**
* Deviation from normal behavior
* Sudden changes in transaction patterns
* Dormant account reactivation
6. **Round Amount Transactions**
* Flag suspiciously round amounts
* Detect potential money laundering indicators
* Pattern analysis across accounts
### Custom Rule Builder
**Create Your Own Rules:**
```json theme={null}
{
"ruleName": "Large Crypto Conversion",
"conditions": [
{
"field": "amount",
"operator": "greater_than",
"value": 50000
},
{
"field": "type",
"operator": "equals",
"value": "CRYPTO_TO_FIAT"
},
{
"field": "accountAge",
"operator": "less_than",
"value": 30
}
],
"action": "FLAG_FOR_REVIEW",
"severity": "HIGH",
"assignTo": "senior-compliance-team"
}
```
**Rule Components:**
* **Conditions**: Define what triggers the rule
* **Actions**: Specify what happens when triggered
* **Severity**: Set alert priority level
* **Assignment**: Route to appropriate team
* **Notifications**: Configure alert recipients
***
## Risk Scoring
### Multi-Factor Risk Assessment
Each transaction receives a comprehensive risk score:
```
Risk Score Calculation:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Identity Risk: 25%
- KYC/KYB status
- PEP/Sanctions screening
- Adverse media findings
Transaction Risk: 25%
- Amount and frequency
- Geographic factors
- Payment rail used
Behavioral Risk: 25%
- Historical patterns
- Deviation from norm
- Peer comparison
Contextual Risk: 25%
- Industry risk
- Relationship risk
- External intelligence
Final Score: 0-100
```
### Risk Categories
| Score Range | Risk Level | Action |
| ----------- | -------------- | ------------------------ |
| 0-30 | **Low** | Auto-approve |
| 31-50 | **Medium-Low** | Enhanced monitoring |
| 51-70 | **Medium** | Manual review required |
| 71-85 | **High** | Senior approval required |
| 86-100 | **Critical** | Block + escalate |
### Dynamic Risk Adjustment
Risk scores adapt based on:
* **Account History**: Lower risk for established accounts
* **Successful Reviews**: Reduce false positives over time
* **Industry Benchmarks**: Compare against sector norms
* **Geographic Trends**: Adjust for regional risk changes
* **Regulatory Updates**: Incorporate new compliance requirements
***
## Compliance Dashboard
### Real-Time Monitoring
**Live Compliance Overview:**
* Active alerts and pending reviews
* Transaction volume and risk distribution
* Screening hit rates
* Team workload and response times
* Regulatory deadline tracking
### Alert Management
**Efficient Case Handling:**
* Prioritized alert queue
* One-click case assignment
* Bulk actions for similar cases
* Collaborative investigation tools
* Evidence collection and documentation
### Reporting & Analytics
**Comprehensive Insights:**
* Compliance metrics and KPIs
* False positive rates
* Team performance analytics
* Trend analysis and forecasting
* Regulatory reporting status
***
## Regulatory Reporting
### Automated Report Generation
**Suspicious Activity Reports (SAR/STR)**
* Auto-populate from flagged transactions
* Include all supporting evidence
* Narrative generation assistance
* Regulatory format compliance
* Direct filing capability
**Currency Transaction Reports (CTR)**
* Automatic threshold monitoring
* Batch report generation
* Aggregation of related transactions
* Exemption management
* Electronic filing
**Travel Rule Compliance**
* FATF Travel Rule adherence
* Originator/beneficiary information
* Cross-border data exchange
* VASP communication
* Audit trail maintenance
### Audit Reports
**Comprehensive Documentation:**
* Transaction audit trails
* Screening results history
* Decision documentation
* Policy compliance evidence
* Regulator-ready formats
***
## Use Cases
### 🏦 Financial Institutions
**Challenge**: Complex regulatory requirements across jurisdictions
**Solution**: Automated multi-jurisdiction compliance
* Simultaneous screening against global lists
* Jurisdiction-specific rule sets
* Automated regulatory reporting
* Audit-ready documentation
**Results:**
* 90% reduction in manual screening time
* 99.9% screening accuracy
* Zero regulatory violations
* Faster transaction processing
### 🎮 Gaming & iGaming Platforms
**Challenge**: High transaction volumes with AML risk
**Solution**: Real-time monitoring at scale
* Automated player screening
* Behavioral pattern detection
* Rapid deposit/withdrawal monitoring
* Bonus abuse detection
**Results:**
* Process 100K+ transactions daily
* Detect suspicious patterns in real-time
* Reduce false positives by 70%
* Maintain gaming license compliance
### 💱 Crypto Exchanges
**Challenge**: VASP compliance and Travel Rule
**Solution**: Crypto-specific compliance tools
* Blockchain address screening
* Travel Rule data exchange
* Crypto-to-fiat monitoring
* DeFi interaction tracking
**Results:**
* Full VASP compliance
* Travel Rule adherence
* Reduced regulatory risk
* Improved customer trust
### 💼 Payment Service Providers
**Challenge**: Multi-rail compliance complexity
**Solution**: Unified compliance across rails
* Single compliance layer for all rails
* Consistent risk assessment
* Centralized reporting
* Cross-rail pattern detection
**Results:**
* Simplified compliance operations
* Substantially reduced compliance costs
* Faster market expansion
* Enhanced risk management
***
## Integration
### API Endpoints (Coming Soon)
```bash theme={null}
# Screen a transaction before processing
POST /v1/compliance/screen
{
"transactionId": "txn-123",
"sender": {
"name": "John Doe",
"country": "US",
"accountId": "acc-456"
},
"receiver": {
"name": "Jane Smith",
"country": "GB",
"accountId": "acc-789"
},
"amount": 10000,
"currency": "USD"
}
# Response
{
"riskScore": 25,
"riskLevel": "LOW",
"decision": "APPROVED",
"screeningResults": {
"sanctions": "CLEAR",
"pep": "CLEAR",
"adverseMedia": "CLEAR"
},
"processingTime": "87ms"
}
# Get compliance alerts
GET /v1/compliance/alerts?status=PENDING
# Review and resolve alert
POST /v1/compliance/alerts/{alertId}/resolve
{
"decision": "APPROVED",
"notes": "Verified legitimate business transaction",
"reviewedBy": "compliance-officer-id"
}
# Generate compliance report
POST /v1/compliance/reports
{
"type": "SAR",
"transactionIds": ["txn-123", "txn-456"],
"narrative": "Suspicious pattern detected..."
}
# Get audit trail
GET /v1/compliance/audit-trail/{transactionId}
```
### Webhook Events
Real-time compliance notifications:
* `compliance.alert_created` - New alert generated
* `compliance.high_risk_detected` - Critical risk identified
* `compliance.review_required` - Manual review needed
* `compliance.decision_made` - Alert resolved
* `compliance.report_generated` - Compliance report ready
* `compliance.threshold_exceeded` - Monitoring threshold breached
***
## Compliance Workflows
### Automated Workflows
**Pre-Configured Processes:**
1. **Low-Risk Auto-Approval**
```
Transaction → Screen → Low Risk → Auto-Approve → Process
```
2. **Medium-Risk Review**
```
Transaction → Screen → Medium Risk → Queue for Review
→ Compliance Officer Review → Decision → Process/Block
```
3. **High-Risk Escalation**
```
Transaction → Screen → High Risk → Block → Alert Senior Team
→ Investigation → MLRO Review → Decision → SAR if needed
```
### Custom Workflows
**Build Your Own:**
* Define approval hierarchies
* Set escalation triggers
* Configure notification rules
* Specify documentation requirements
* Integrate with external systems
***
## Regulatory Coverage
### Supported Jurisdictions
✅ **European Union**: MLD5, MLD6, MiCA\
✅ **United States**: BSA/AML, FinCEN, OFAC\
✅ **United Kingdom**: MLR 2017, FCA requirements\
✅ **Singapore**: MAS AML/CFT requirements\
✅ **Hong Kong**: AMLO, HKMA guidelines\
✅ **Australia**: AML/CTF Act\
✅ **Canada**: FINTRAC requirements\
✅ **Switzerland**: FINMA AML regulations
### Compliance Standards
✅ **FATF Recommendations**: Full compliance\
✅ **Travel Rule**: FATF Travel Rule adherence\
✅ **GDPR**: Data protection compliance\
✅ **ISO 27001**: Information security\
✅ **SOC 2 Type II**: Security controls
***
## Security & Privacy
### Data Protection
* **Encryption**: End-to-end encryption for all compliance data
* **Access Controls**: Role-based access with audit logging
* **Data Retention**: Configurable retention policies
* **Right to Erasure**: GDPR-compliant data deletion
* **Data Localization**: Regional data storage options
### Audit & Compliance
* **Immutable Logs**: Tamper-proof audit trails
* **Compliance Certifications**: SOC 2, ISO 27001
* **Regular Audits**: Third-party security audits
* **Penetration Testing**: Quarterly security testing
* **Incident Response**: 24/7 security monitoring
***
## Roadmap
### Q4 2026 - Initial Launch
* Real-time sanctions screening
* Basic transaction monitoring
* Manual alert review
* Standard reporting
* API access
### Q1 2027 - Enhanced Features
* AI-powered risk scoring
* Custom rule builder
* Automated workflows
* SAR/STR generation
* Advanced analytics
### Q2 2027 - Advanced Features
* Behavioral analytics
* Network analysis
* Predictive risk modeling
* Blockchain analytics
* Regulator portal integration
***
## Getting Started
### Prerequisites
To access Compliance Engine, you'll need:
✅ **Active Venly Finance Account**: Verified company account\
✅ **Compliance Officer**: Designated compliance personnel\
✅ **AML Program**: Documented AML/CFT program\
✅ **Risk Assessment**: Completed business risk assessment\
✅ **Training**: Compliance team training completed
### Early Access Program
Register your interest for early access to Compliance Engine
**Benefits:**
* Priority onboarding when available
* Free compliance consultation
* Discounted pricing for first 6 months
* Beta testing opportunity
* Dedicated compliance support
**Contact**: [venlyfinance.com/contact](https://venlyfinance.com/contact)
***
## Comparison: Compliance Engine vs Manual Processes
| Feature | Manual Compliance | Third-Party Tools | Venly Compliance Engine |
| ------------------------ | ----------------- | ----------------- | ----------------------- |
| **Screening Speed** | Hours | Minutes | \<100ms |
| **Coverage** | Limited | Good | Comprehensive |
| **False Positives** | High (30-40%) | Medium (15-20%) | Low (5-10%) |
| **Integration** | Manual | API | Native |
| **Cost per Transaction** | €0.50-€2.00 | €0.10-€0.30 | €0.05 |
| **Reporting** | Manual | Semi-automated | Fully automated |
| **Updates** | Manual | Periodic | Real-time |
| **Multi-Rail Support** | No | Limited | Yes |
***
## Frequently Asked Questions
Screening is performed in real-time with an average processing time of \<100ms per transaction. This includes sanctions, PEP, and adverse media screening.
Flagged transactions are held pending review. Your compliance team is notified immediately and can review the case in the dashboard. You can approve, reject, or escalate based on your assessment.
Yes, you can configure risk thresholds, create custom rules, and define workflows that match your risk appetite and compliance requirements.
Our AI learns from your decisions to reduce false positives over time. You can also whitelist known good entities and fine-tune rules to match your business.
Yes, Compliance Engine is fully GDPR compliant with data encryption, access controls, retention policies, and right to erasure capabilities.
Yes, the system can generate SARs/STRs, CTRs, audit reports, and other regulatory filings. Reports are pre-populated with transaction data and evidence.
We screen against 200+ global sanctions lists including OFAC, UN, EU, UK HM Treasury, and jurisdiction-specific lists. Lists are updated in real-time.
Yes, while Compliance Engine automates screening and monitoring, you still need qualified compliance personnel to review alerts, make decisions, and maintain your AML program.
***
## Next Steps
Register for early access
Schedule a consultation
Review security practices
Discuss your needs
***
## Support
Questions about Compliance Engine?
* **Contact**: [venlyfinance.com/contact](https://venlyfinance.com/contact)
* **Documentation**: [docs.venlyfinance.com](https://docs.venlyfinance.com)
* **Compliance Hotline**: Available 24/7 for urgent matters
# Finance API changelog
Source: https://docs.venlyfinance.com/guides/finance/changelog
Releases and updates to the Venly Finance API — new endpoints, parameters, supported chains, and improvements.
Version 1.1.0 completes the payment-request lifecycle — settle, reverse, and adjust — adds Polygon as a supported chain, and returns each amount with its crypto equivalent.
**New endpoints — payment lifecycle**
* **Settle a payment request** — `POST /payment-requests/{paymentRequestId}/settlements`. Moves reserved funds from escrow to the company's settlement wallet; the settlement amount can equal, fall below, or exceed the authorized amount. [Reference](/api-reference/Finance-API/payment-requests/settle-a-payment-request)
* **Settle by card-provider reference** — `POST /payment-requests/settlements`. Settles a request located by its `cardProviderReference` and `externalId`. [Reference](/api-reference/Finance-API/payment-requests/settle-a-payment-request-by-reference)
* **Reverse a payment request** — `POST /payment-requests/{paymentRequestId}/reversal`. Returns the full reserved amount to the account wallet. [Reference](/api-reference/Finance-API/payment-requests/reverse-a-payment-request)
* **Reverse by card-provider reference** — `POST /payment-requests/reversals`. Reverses a request located by its `cardProviderReference` and `externalId`. [Reference](/api-reference/Finance-API/payment-requests/reverse-a-payment-request-by-reference)
* **Update a payment request** — `PATCH /payment-requests/{paymentRequestId}`. Sets a new authorized `amount`; a lower amount releases the difference from escrow, a higher amount reserves more. [Reference](/api-reference/Finance-API/payment-requests/update-a-payment-request)
**New supported chain**
* **Polygon** (`POLYGON`) is now available for accounts, wallets, balances, and payments. See [Supported chains & assets](/guides/finance/supported-chains-and-assets).
**Amounts now carry fiat and crypto**
* Payment-request amount fields return an object with both sides of the conversion — `{ "fiat": , "crypto": "" }` — across `amount`, `originalAmount`, `settlementAmount`, `settledAmount`, and `shortfallAmount`. Update any client that reads these fields to expect the nested object. See [Payment requests](/guides/finance/payment-requests#amounts-carry-fiat-and-crypto).
**New payment-request fields**
* `settlementAmount`, `settledAmount`, `shortfallAmount`, `settledAt`, `reversalReason`, `reversalDescription`, and `reversedAt` are now returned, capturing the settlement and reversal lifecycle.
**New statuses and execution types**
* Statuses added: `SETTLING`, `SETTLED_WITH_SHORTFALL`, `REVERSING`.
* Execution types added: `SETTLEMENT`, `SETTLEMENT_OVERAGE`, `REFUND`, `REVERSAL`, `INCREMENTAL_AUTHORIZATION`, `AUTHORIZATION_ADJUSTMENT`.
**Non-custodial accounts**
* Self-custody tenants can register an end-customer's own wallet by passing `address` when creating an account. See [Managed vs. self-custody](/guides/finance/managed-vs-self-custody).
**Improvements**
* Idempotency keys now apply across the full payment lifecycle — create, settle, reverse, and update. Retrying with the same key and body returns the original result. See [Idempotency](/guides/finance/idempotency).
* Account-to-account crypto transfers are now supported for Venly-managed accounts.
# Data model
Source: https://docs.venlyfinance.com/guides/finance/data-model
How parties, accounts, wallets, and virtual bank accounts relate — the object hierarchy behind every Finance API call.
Every Finance API resource hangs off a **party**. Once the hierarchy clicks, the rest of the API is predictable: you create entities top-down, and most operations are scoped to an account.
```mermaid theme={null}
flowchart TD
Company[Your company] --> Party[Party · individual or organisation]
Party -->|party role| Account[Account · one chain]
Account --> Wallet[Wallets · account + escrow]
Account --> VBA[Virtual bank account · IBAN]
Account --> Transfer[Transfers]
Account --> PayReq[Payment requests]
Wallet --> Permit[Permits and allowances]
```
## The entities
| Entity | What it is | Key relationships |
| -------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
| **[Party](/api-reference/Finance-API/parties/list-all-parties)** | The legal identity — an `INDIVIDUAL` or `ORGANISATION`. Carries KYC/KYB status. | Linked to one or more accounts via party roles. |
| **[Account](/api-reference/Finance-API/accounts/list-all-accounts)** | The container for money movement, pinned to one chain (`BASE`, `AVALANCHE`, or `POLYGON`) at creation. | Belongs to a party (or parties); holds wallets, VBAs, transfers, and payment requests. |
| **Party role** | The link between a party and an account (`ACCOUNT_HOLDER`). | Many parties can share one account (joint accounts). |
| **[Wallet](/guides/finance/wallets)** | Custodial crypto wallet (`VENLY_MANAGED` or `SELF_CUSTODY`). Each account has an account wallet plus an escrow wallet. | Belongs to an account; holds per-asset balances. |
| **[Virtual bank account](/guides/finance/virtual-bank-accounts)** | An IBAN for receiving fiat (EUR SEPA), auto-converted to crypto. | Belongs to an account. |
## How they're created
You build top-down, and verification gates the money-movement steps:
The root identity. KYC/KYB starts after creation — see [Account verification](/guides/finance/kyc-verification).
Link the party (`partyId`, or an inline `party`) and choose the chain. Venly provisions the wallets.
A Venly admin moves the account to `VERIFIED`. Until then, money movement is blocked.
Assign a [virtual bank account](/guides/finance/virtual-bank-accounts), then [transfer](/guides/finance/transfers) or take [payment requests](/guides/finance/payment-requests).
## IDs and external IDs
Every entity has a Venly UUID `id`. You can also set your own `externalId` on parties and accounts and use it as a shortcut — for example `receiverExternalId` on a transfer, instead of looking up the Venly UUID.
## Next steps
Build the hierarchy end to end.
Definitions for every entity and status.
# Errors & error codes
Source: https://docs.venlyfinance.com/guides/finance/errors
The response envelope, the HTTP status and error code each failure returns, and how to handle them.
Every Finance API response uses the same envelope, so you can handle success and failure uniformly.
## Response envelope
A successful response sets `success: true` and carries the payload in `result` (list endpoints also include a `pagination` object):
```json Success theme={null}
{ "success": true, "result": { "id": "..." } }
```
A failure sets `success: false` and returns one or more `errors`, each with a stable `code` and a human-readable `message`:
```json Error theme={null}
{
"success": false,
"errors": [
{ "code": "invalid-request", "message": "The request contains invalid parameters." }
]
}
```
Branch on the `code`, not the `message` — messages may change, codes are stable.
## Standard errors
These apply across endpoints:
| HTTP | `code` | When it happens | What to do |
| ----- | ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
| `400` | `invalid-request` | Malformed body or invalid parameters. | Fix the request; don't retry it unchanged. |
| `401` | `unauthenticated` | Missing or expired token. | Refresh the token and retry — see [Authentication](/getting-started/authentication). |
| `403` | `forbidden` | The operation isn't available to your company setup. | Contact Venly to enable it. |
| `404` | `-not-found` | The resource (or one it references) doesn't exist — e.g. `account-not-found`, `payment-request-not-found`. | Check the ID; for transfers, confirm the account is the sender or receiver. |
| `409` | `concurrent-modification` | Stale `version` on an update. | Re-fetch, reapply your change, retry — see [Versioning](/guides/finance/versioning). |
| `422` | `idempotency-conflict` / *(varies)* | An idempotency key was reused with a different body, or replays a call that originally failed; or a semantically invalid input. | Branch on the `code`; to retry a genuine failure, use a **new** [idempotency key](/guides/finance/idempotency). |
| `500` | `internal-error` | Unexpected server error. | Retry with backoff; if it persists, contact Venly. |
## Verification & activation gates
A new account can't move money until it's verified, and a self-custody wallet can't until its permit confirms. These gates return **different** codes per operation — treat any of them as "not ready yet" rather than matching a single code:
| Operation | HTTP | `code` |
| --------------------------------------------------- | ----- | --------------------------- |
| Create a virtual bank account | `400` | `kyc-not-verified` |
| Create a pay-in session | `422` | `kyc-required` |
| Create a payment request | `400` | `account-not-active` |
| Transfer/payment on an inactive self-custody wallet | `400` | `account-wallet-not-active` |
See [Account verification](/guides/finance/kyc-verification) and [Approving transfers without gas](/guides/finance/permits-and-allowances).
## Payment request errors
[Settling](/api-reference/Finance-API/payment-requests/settle-a-payment-request), [reversing](/api-reference/Finance-API/payment-requests/reverse-a-payment-request), and [updating](/api-reference/Finance-API/payment-requests/update-a-payment-request) a payment request can return these in addition to the standard errors:
| HTTP | `code` | When it happens |
| ----- | --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `400` | `invalid-amount` | Amount ≤ 0, or (on update) equal to the current amount. |
| `400` | `currency-mismatch` | `currency` doesn't match the authorized currency. |
| `402` | `insufficient-funds` | Account wallet balance is below the upward adjustment delta. |
| `402` | `insufficient-allowance` | Self-custody allowance is below the upward adjustment delta. |
| `403` | `company-not-active` | Company isn't `ACTIVE` (settlement and upward adjustments only). |
| `404` | `payment-request-not-found` | No payment request with that ID/reference for your company. |
| `404` | `account-not-found` | No account matches the supplied card-provider reference (by-reference endpoints). |
| `409` | `invalid-payment-status` | The request isn't `RESERVED`, so it can't be settled, reversed, or adjusted. |
| `409` | `modification-in-progress` | A previous adjustment or incremental authorization is still pending. |
| `409` | `wallet-not-active` | A wallet involved in the operation isn't ready — for self-custody, confirm the [permit](/guides/finance/permits-and-allowances); otherwise the wallet's `amlStatus` isn't `APPROVED` yet. |
| `422` | `idempotency-conflict` | The `idempotencyKey` was reused with a different body, or replays a call that originally failed. |
`wallet-not-active` and the transfer/payment-create gate `account-wallet-not-active` describe the **same condition** — the account wallet isn't ready to move funds. The exact `code` and HTTP status vary by endpoint, so treat any `*-not-active` code as "not ready yet" (see [Account verification](/guides/finance/kyc-verification) and, for self-custody, [permits](/guides/finance/permits-and-allowances)) rather than matching a single one.
## Rate limits
The Finance API doesn't publish fixed numeric rate limits. Build for resilience regardless:
* Cache your access token and reuse it until it nears expiry — don't fetch one per request.
* Back off and retry on `500` (and on `429`, if returned), using exponential backoff with jitter.
* Make retries safe with an [idempotency key](/guides/finance/idempotency) so a replay never double-charges.
If you expect high call volumes, confirm current limits with your Venly contact — they aren't enumerated in the API contract.
## Next steps
Idempotency, pagination, and versioning rules.
The most common reason an otherwise-correct request is rejected.
# Getting started
Source: https://docs.venlyfinance.com/guides/finance/getting-started
Create a party, open an account, get it verified, and issue an IBAN — with managed and self-custody examples.
This is the shortest path to a working Finance API integration. You'll create a **party**, open an **account** linked to it, get the account **verified**, and then issue a **virtual bank account (IBAN)**.
```mermaid theme={null}
flowchart LR
A[Create party] --> B[Create account
linked to party]
B --> C[Venly admin
verifies account]
C --> D[Create virtual
bank account]
```
**Base URL (staging):** `https://api-staging.venlyfinance.com/v1` · **Auth:** OAuth2 Bearer token — see [Authentication](/getting-started/authentication).
Whether your company is **Venly-managed** or **self-custody** changes one step below — see [Venly-managed vs self-custody](/guides/finance/managed-vs-self-custody).
## Step 1 — Create a party
A **party** is the person or organisation behind an account. It's created **`ACTIVE` immediately** — there's no verification step for a party.
```bash theme={null}
curl -X POST https://api-staging.venlyfinance.com/v1/parties \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"partyType": "INDIVIDUAL",
"externalId": "user-12345",
"firstName": "Jane",
"lastName": "Doe"
}'
```
```json Response (201) theme={null}
{
"success": true,
"result": {
"id": "7e3b9c2a-1f4d-4a8b-9c11-2d6e8f0a1b22",
"externalId": "user-12345",
"partyType": "INDIVIDUAL",
"status": "ACTIVE",
"firstName": "Jane",
"lastName": "Doe",
"createdAt": "2026-01-15T09:30:00",
"updatedAt": "2026-01-15T09:30:00",
"version": 0
}
}
```
Save the returned `id` — it's the `partyId` you link in the next step. For an organisation, send `partyType: ORGANISATION` with `name` (and optional `vatNumber`) instead of `firstName`/`lastName`.
## Step 2 — Open an account linked to the party
An **account** holds the wallet, IBANs, and transfer history. Pass the `partyId` from Step 1 to link the party as `ACCOUNT_HOLDER`. The wallet is provisioned automatically.
The only difference between company types is the wallet address:
* **Venly-managed** — Venly creates and holds the wallet. Don't send an `address`.
* **Self-custody** — the customer controls the wallet. You **must** send their `address`.
```bash Venly-managed theme={null}
curl -X POST https://api-staging.venlyfinance.com/v1/accounts \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"externalId": "acct-12345",
"name": "Jane Doe — Main",
"chain": "BASE",
"partyId": "7e3b9c2a-1f4d-4a8b-9c11-2d6e8f0a1b22"
}'
```
```bash Self-custody theme={null}
curl -X POST https://api-staging.venlyfinance.com/v1/accounts \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"externalId": "acct-12345",
"name": "Jane Doe — Main",
"chain": "BASE",
"address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F",
"partyId": "7e3b9c2a-1f4d-4a8b-9c11-2d6e8f0a1b22"
}'
```
```json Response (201) theme={null}
{
"success": true,
"result": {
"id": "b2a1f0e9-8c7d-4e3a-9f21-0a1b2c3d4e5f",
"externalId": "acct-12345",
"name": "Jane Doe — Main",
"kycStatus": "VERIFICATION_PENDING",
"status": "ACTIVE",
"createdAt": "2026-01-15T09:30:00",
"version": 0
}
}
```
The account is created with `kycStatus: VERIFICATION_PENDING`. It exists and can be set up, but it **can't move money yet**.
Self-custody omitting `address` returns `400 "Address is required for SELF_CUSTODY wallet type"`. See [Venly-managed vs self-custody](/guides/finance/managed-vs-self-custody) for the full difference (including permits).
## Step 3 — Get the account verified
Account verification is reviewed and approved by a **Venly admin** — there's no API call to trigger it. Once approved, the account's `kycStatus` becomes `VERIFIED`.
Poll the account until it flips:
```bash theme={null}
curl https://api-staging.venlyfinance.com/v1/accounts/b2a1f0e9-8c7d-4e3a-9f21-0a1b2c3d4e5f \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
```
```json Response (200) theme={null}
{
"success": true,
"result": { "id": "b2a1f0e9-8c7d-4e3a-9f21-0a1b2c3d4e5f", "kycStatus": "VERIFIED", "status": "ACTIVE", "version": 1 }
}
```
Until `kycStatus` is `VERIFIED`, creating virtual bank accounts, transfers, payment requests, and pay-in sessions all fail with a KYC error — the exact `code` and HTTP status depend on the operation (e.g. `400 kyc-not-verified` for virtual bank accounts, `422 kyc-required` for pay-in sessions). See [Account verification](/guides/finance/kyc-verification).
## Step 4 — Create a virtual bank account
With the account verified, issue a EUR IBAN so it can be funded via SEPA. Incoming euros are converted to the `targetCryptocurrency` and credited to the wallet.
```bash theme={null}
curl -X POST https://api-staging.venlyfinance.com/v1/accounts/b2a1f0e9-8c7d-4e3a-9f21-0a1b2c3d4e5f/virtual-bank-accounts \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Jane Doe — EUR",
"inCurrency": "EUR",
"targetCryptocurrency": "USDC",
"idempotencyKey": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
}'
```
```json Response (201) theme={null}
{
"success": true,
"result": {
"id": "4d5e6f70-8192-4a3b-9c4d-5e6f7081920a",
"accountId": "b2a1f0e9-8c7d-4e3a-9f21-0a1b2c3d4e5f",
"bankAccountType": "EUR_SEPA",
"status": "ACTIVE",
"currency": "EUR",
"targetCryptocurrency": "USDC",
"iban": "DE89370400440532013000",
"bic": "DEUTDEDB",
"referenceCode": "VFY-7K2Q-931"
}
}
```
Give the `iban` and `referenceCode` to your customer — the `referenceCode` is what links their incoming SEPA payment to this account.
## Next steps
Funding, transfers, and tracking — end to end.
Sign a permit so a self-custody account can move funds.
States, gating, and what works before verification.
Every endpoint, field, and example.
# Glossary
Source: https://docs.venlyfinance.com/guides/finance/glossary
Definitions for parties, accounts, party roles, virtual bank accounts, custodial wallets, transfers, permits, and other Finance API concepts.
Terms used throughout the Finance API reference and guides. Each definition links to the primary endpoint or guide where the concept is used.
## Identity
### Party
The legal identity behind every account. Two types:
* **`INDIVIDUAL`** — a natural person (requires `firstName`, `lastName`)
* **`ORGANISATION`** — a company or business (requires `name`, optionally `vatNumber`)
A party is created independently of accounts; KYC/KYB runs asynchronously after creation. See [Create a new party](/api-reference/Finance-API/parties/create-a-new-party).
### Party Role
The relationship between a party and an account. Currently only one role type exists:
* **`ACCOUNT_HOLDER`** — the party owns or co-owns the account
A single account can have multiple party roles, enabling joint accounts. See [Add a party to an account](/api-reference/Finance-API/accounts/add-a-party-to-an-account).
### KYC / KYB
**Know Your Customer** (individuals) and **Know Your Business** (organisations). Identity verification that runs after party creation, tracked on two separate fields:
* **`kycStatus`** (individuals & accounts) — `VERIFICATION_PENDING → VERIFIED` (or `REJECTED`)
* **`kybStatus`** (organisations) — `PENDING → VERIFIED` (or `DENIED`)
Outbound money movement is blocked until the account is `VERIFIED`. See [Account verification](/guides/finance/kyc-verification).
***
## Account structure
### Account
The container that holds wallets, virtual bank accounts, and transfer history for a party (or set of parties). Pinned to a single blockchain network at creation. Statuses: `ACTIVE`, `SUSPENDED`, `CLOSED`.
### External ID
A merchant-supplied unique identifier for an account or party (`externalId` field). Use it as a shortcut in transfer requests (`receiverExternalId`) instead of looking up the Venly UUID.
### Account wallet
The wallet that holds an account's balance, bound to one chain. Its `type` is either **`VENLY_MANAGED`** (Venly holds the keys; funds move via API calls) or **`SELF_CUSTODY`** (your customer holds the keys and signs a one-time [permit](/guides/finance/permits-and-allowances) so Venly can move funds). See [Wallets & balances](/guides/finance/wallets).
### Escrow wallet
A second, always Venly-managed wallet on the account that holds funds in flight during settlement — for example, amounts reserved by a [payment request](/guides/finance/payment-requests). You never sign for it.
### Orchestration wallet
The Venly-controlled wallet that pulls funds from a self-custody account wallet via ERC-20 `transferFrom`. It is the **spender** a self-custody permit authorises, and it's returned as `orchestrationWallet` on the [allowances](/api-reference/Finance-API/allowances/get-wallet-token-allowances) response.
### Virtual Bank Account (VBA)
A bank account reference (IBAN + BIC for EUR\_SEPA) attached to a Venly account. Used to receive fiat funding that's auto-converted to crypto and credited to the wallet. See [Create a virtual bank account](/api-reference/Finance-API/virtual-bank-accounts/create-a-virtual-bank-account).
### IBAN / BIC
**International Bank Account Number** and **Bank Identifier Code** — the standard EUR\_SEPA addressing format returned on a virtual bank account.
### Reference Code
A unique string returned with each VBA. The end user must include this in their SEPA payment message — it's how the incoming wire is matched to the right account. Without it, settlement falls back to manual reconciliation.
### Beneficiary Name
The legal name on the bank account record (typically a Venly custody entity). Display this to end users alongside the IBAN when they initiate a wire.
***
## Money movement
### Transfer
A value movement from one account to another, addressed by `receiverAccountId` or `receiverExternalId`. Two flavors, depending on how you denominate the amount:
* **Fiat transfer** — you send a fiat `currency` + `amount`; it's resolved to the underlying stablecoin and settled on-chain. The response carries a `fiatOrigin` block (original currency, amount, exchange rate).
* **Crypto transfer** — you send a crypto `asset` + `chain` + `amount`, moved directly between the accounts on-chain.
See [Transfers](/guides/finance/transfers).
### Transfer Status
Lifecycle states: `PENDING → COMPLETED` (or `FAILED` with an `errorMessage`).
### Payment Session (Fiat-to-Crypto)
A hosted checkout flow that converts a card or bank payment into crypto credited to an account's wallet. Returns a `paymentUrl` you redirect the user to. See [Create a fiat-to-crypto payment session](/api-reference/Finance-API/fiat-to-crypto-payment-sessions/create-a-fiat-to-crypto-payment-session).
### Payment Request
A pre-authorised request for funds, used in card-provider integrations. Two endpoints exist: `/payment-requests` (for card providers) and `/accounts/{id}/payment-requests` (account-scoped).
***
## On-chain primitives
### Permit (EIP-2612)
A signed message that grants a spender permission to move tokens from a wallet, without an on-chain approval transaction. Used to delegate spending authority cheaply. See [Get permit messages](/api-reference/Finance-API/permits/get-permit-messages).
### Allowance (ERC-20)
The amount of a token that a third party is approved to spend from a wallet. Queried per wallet + token. See [Get wallet token allowances](/api-reference/Finance-API/allowances/get-wallet-token-allowances).
### Stablecoin
A cryptocurrency pegged to a fiat currency. Supported assets: `USDC`, `EURC`, `USDT`, `USDS`.
### Blockchain Network
The chain an account's wallet is provisioned on, fixed at account creation. The API supports `BASE`, `AVALANCHE`, and `POLYGON`; the chains available to **your** company are configured by Venly. Requesting a chain your company isn't set up for returns `400 invalid-request` with a message listing your supported chains. See [Supported chains & assets](/guides/finance/supported-chains-and-assets).
***
## API mechanics
### Idempotency Key
A UUID supplied in the request body of state-changing endpoints to make retries safe. Same key + same body returns the original response; same key + different body returns `422`. See the [Idempotency](/getting-started/conventions#idempotency) rules.
### Optimistic Locking (`version`)
On update endpoints, the request body includes a `version` integer matching the resource's current version. Concurrent updates with a stale `version` return `409 Conflict`. Refetch, increment, retry.
### Pagination
List endpoints accept `page` (1-based), `size`, `sortOn`, and `sortOrder` query parameters and return a `pagination` object in the response. See [Pagination conventions](/getting-started/conventions#pagination).
### Error handling
Every response carries a `success` flag and, on failure, an `errors` array of `{ code, message }`. Branch on the stable `code`. See the [Errors & error codes](/guides/finance/errors) reference.
***
## Status enums (quick reference)
| Resource | Statuses |
| ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| Party (`status`) | `ACTIVE`, `SUSPENDED`, `BLOCKED` |
| Party Role | `ACTIVE`, `INACTIVE` |
| KYC (`kycStatus` — individuals & accounts) | `VERIFICATION_PENDING`, `VERIFIED`, `REJECTED` |
| KYB (`kybStatus` — organisations) | `PENDING`, `VERIFIED`, `DENIED` |
| Account (`status`) | `ACTIVE`, `SUSPENDED`, `CLOSED` |
| Wallet AML (`amlStatus`) | `PENDING`, `APPROVED`, `REJECTED` |
| Virtual Bank Account | `ACTIVE`, `CLOSED` |
| Transfer | `PENDING`, `COMPLETED`, `FAILED` |
| Payment Request | `PENDING`, `RESERVED`, `SETTLING`, `SETTLED`, `SETTLED_WITH_SHORTFALL`, `REVERSING`, `REVERSED`, `FAILED` |
| Payment Execution | `PENDING`, `RESERVED`, `SETTLED`, `REVERSED`, `FAILED` |
| Permit | `PENDING`, `SUBMITTED`, `CONFIRMED`, `FAILED` |
| Payment Session | `CREATED`, `PENDING_PAYMENT`, `PAYMENT_RECEIVED`, `CONVERTING`, `MINTING`, `COMPLETED`, `FAILED`, `EXPIRED`, `CANCELLED`, `REFUNDING`, `REFUNDED` |
A wallet has **no `status` field** — `GET .../wallets` returns `amlStatus` only. Readiness isn't a single returned value: a **Venly-managed** wallet is ready once `amlStatus` is `APPROVED`; a **self-custody** wallet is ready once its [permit](/guides/finance/permits-and-allowances) `status` is `CONFIRMED`.
***
## See also
Watch every term above used in context, end to end.
Idempotency, pagination, and versioning rules.
# Safe retries with idempotency keys
Source: https://docs.venlyfinance.com/guides/finance/idempotency
Send a unique key with each request so a retry never creates a duplicate.
## Why
You send a request, but the network drops the response before it reaches you. Did it go through? With an idempotency key you can just retry: the same key returns the original result instead of doing the work a second time.
## How it works
Every write takes an `idempotencyKey` — a unique ID you generate, like a UUID — in the request body:
```bash theme={null}
curl --request POST \
--url https://api.venlyfinance.com/v1/accounts/{senderAccountId}/transfers/crypto \
--header 'Authorization: Bearer ' \
--header 'Content-Type: application/json' \
--data '{
"receiverAccountId": "c3b2a1f0-9d8c-4e3a-bf21-1a2b3c4d5e60",
"chain": "BASE",
"asset": "USDC",
"amount": 25,
"idempotencyKey": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
}'
```
* The **first** call with a key runs the operation.
* The **same key with the same body** returns that original result — the operation runs once, however many times you retry.
## Two rules
1. Generate **one new key per operation** — each transfer, payment, settlement, reversal, adjustment, and pay-in gets its own.
2. Reuse a key **only to retry that exact call**. For a genuinely new operation, generate a new key.
A key is required on transfers, payment requests (create, settle, reverse, and update), pay-in sessions, and virtual bank accounts.
Save the key before you send the request. If your process restarts mid-flight, the retry reuses the same key and lands exactly once.
## Next steps
Pagination, versioning, and the shared idempotency rules.
Reserve, settle, reverse — each with its own key.
# Integration Walkthrough
Source: https://docs.venlyfinance.com/guides/finance/integration-walkthrough
Onboard a user, get their account verified, fund it, and send a transfer using the Finance API.
This guide walks the Finance API end-to-end — from creating your first party to settling a transfer. Every step uses real request and response shapes. Run it against staging and you'll have a working integration.
**Base URL (staging):** `https://api-staging.venlyfinance.com/v1`
**Auth:** OAuth2 Bearer token in the `Authorization` header. Tokens expire after 5 minutes — see the [Authentication guide](/getting-started/authentication).
## What you'll build
1. Onboard a **party** (your customer) — created `ACTIVE` immediately
2. Open an **account** for them (its custodial wallet is provisioned automatically)
3. Get the account **verified** by a Venly admin
4. Issue a **EUR IBAN** so they can fund via SEPA
5. Send an **outbound transfer**
```mermaid theme={null}
sequenceDiagram
autonumber
participant App as Your App
participant Auth as login-staging.venly.io
participant API as Finance API
participant Ops as Venly Admin
App->>Auth: POST /token (client_credentials)
Auth-->>App: access_token (5 min TTL)
App->>API: POST /parties (INDIVIDUAL)
API-->>App: partyId (status ACTIVE)
App->>API: POST /accounts (partyId, chain=BASE)
API-->>App: accountId (kycStatus VERIFICATION_PENDING, wallet auto-created)
Ops-->>API: Review & verify account
App->>API: GET /accounts/{id} → kycStatus VERIFIED
App->>API: POST /accounts/{id}/virtual-bank-accounts
API-->>App: IBAN + BIC + referenceCode
App->>API: POST /accounts/{id}/transfers/crypto
API-->>App: transferId, status COMPLETED
```
The big gate to design around: an **account** is created unverified (`kycStatus: VERIFICATION_PENDING`) and a **Venly admin** must verify it before it can move money. A **party**, by contrast, is `ACTIVE` right away. See [Account verification](/guides/finance/kyc-verification).
***
## Prerequisites
A `client_id` and `client_secret` from your Venly contact. Staging calls don't move real money.
All examples use `curl`. Postman, HTTPie, or any SDK works equally well.
Money-moving endpoints require an `idempotencyKey` (UUID v4) — `uuidgen`, `[guid]::NewGuid()`, or `crypto.randomUUID()`.
***
## Step 1 — Authenticate
Exchange your client credentials for a Bearer token. Every subsequent call needs it in the `Authorization` header.
```bash theme={null}
curl -X POST https://login-staging.venly.io/auth/realms/VenlyFinance/protocol/openid-connect/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET"
```
```json Response theme={null}
{ "access_token": "eyJhbGciOi...", "expires_in": 300, "token_type": "Bearer" }
```
Cache the token. Refresh on `401 Unauthorized` or a few seconds before `expires_in` elapses — don't request a new token on every call.
***
## Step 2 — Create a party
A **party** is the person or organisation behind an account — `INDIVIDUAL` (natural person) or `ORGANISATION` (company). It's created **`ACTIVE` immediately**; there's no verification step for a party.
```bash theme={null}
curl -X POST https://api-staging.venlyfinance.com/v1/parties \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"partyType": "INDIVIDUAL",
"externalId": "user-12345",
"firstName": "Jane",
"lastName": "Doe",
"address": { "addressLine1": "1 Example Street", "city": "Amsterdam", "postalCode": "1011AB", "country": "NL" }
}'
```
```json Response (201) theme={null}
{
"success": true,
"result": {
"id": "7e3b9c2a-1f4d-4a8b-9c11-2d6e8f0a1b22",
"externalId": "user-12345",
"partyType": "INDIVIDUAL",
"status": "ACTIVE",
"firstName": "Jane",
"lastName": "Doe",
"createdAt": "2026-01-15T09:30:00",
"updatedAt": "2026-01-15T09:30:00",
"version": 0
}
}
```
For an **organisation**, swap the body:
```json theme={null}
{ "partyType": "ORGANISATION", "externalId": "org-67890", "name": "Acme B.V.", "vatNumber": "NL123456789B01" }
```
***
## Step 3 — Open an account
An **account** holds the wallet, IBANs, and transfer history. Link the party from Step 2 with `partyId` (it becomes the `ACCOUNT_HOLDER`). The custodial wallet is **provisioned automatically** — there's no separate "create wallet" call.
The only difference between company types is the wallet `address`:
* **Venly-managed** — Venly creates and holds the wallet. Omit `address`.
* **Self-custody** — the customer controls the wallet. Send their `address` (required).
```bash Venly-managed theme={null}
curl -X POST https://api-staging.venlyfinance.com/v1/accounts \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"externalId": "acct-12345",
"name": "Jane Doe — Main",
"chain": "BASE",
"partyId": "7e3b9c2a-1f4d-4a8b-9c11-2d6e8f0a1b22"
}'
```
```bash Self-custody theme={null}
curl -X POST https://api-staging.venlyfinance.com/v1/accounts \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"externalId": "acct-12345",
"name": "Jane Doe — Main",
"chain": "BASE",
"address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F",
"partyId": "7e3b9c2a-1f4d-4a8b-9c11-2d6e8f0a1b22"
}'
```
```json Response (201) theme={null}
{
"success": true,
"result": {
"id": "b2a1f0e9-8c7d-4e3a-9f21-0a1b2c3d4e5f",
"externalId": "acct-12345",
"name": "Jane Doe — Main",
"kycStatus": "VERIFICATION_PENDING",
"status": "ACTIVE",
"createdAt": "2026-01-15T09:30:00",
"version": 0
}
}
```
Set a meaningful `externalId` — your own user/customer ID. It doubles as a receiver shortcut in transfers (`receiverExternalId`), so you don't have to look up the Venly UUID every time.
### Add a second account holder (optional)
```bash theme={null}
curl -X POST https://api-staging.venlyfinance.com/v1/accounts/{accountId}/party-roles \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "partyId": "ANOTHER_PARTY_UUID", "roleType": "ACCOUNT_HOLDER" }'
```
***
## Step 4 — Get the account verified
The account is created with `kycStatus: VERIFICATION_PENDING`. A **Venly admin** reviews and verifies it — there's no API call to trigger this. Once approved, `kycStatus` becomes `VERIFIED`.
Poll the account until it flips:
```bash theme={null}
curl https://api-staging.venlyfinance.com/v1/accounts/{accountId} \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
```
```json Response (200) theme={null}
{ "success": true, "result": { "id": "b2a1f0e9-...", "kycStatus": "VERIFIED", "status": "ACTIVE", "version": 1 } }
```
Until then, creating IBANs, transfers, payment requests, and pay-in sessions all fail with a KYC error — the exact `code` and HTTP status vary by operation (e.g. `400 kyc-not-verified` for IBANs, `422 kyc-required` for pay-in sessions). See [Account verification](/guides/finance/kyc-verification) for the full list of what's gated.
***
## Step 5 — View the wallet
The wallet was created with the account. Read it (and its balances) any time:
```bash theme={null}
curl https://api-staging.venlyfinance.com/v1/accounts/{accountId}/wallets \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
```
```json Response (200) theme={null}
{
"success": true,
"result": [
{
"id": "9f8e7d6c-5b4a-4938-8271-6a5b4c3d2e1f",
"chain": "BASE",
"type": "SELF_CUSTODY",
"address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F",
"balances": [
{ "asset": "USDC", "contractAddress": "0x036CbD53842c5426634e7929541eC2318f3dCF7e", "amount": { "total": "0", "available": "0", "reserved": "0" } }
],
"amlStatus": "PENDING"
}
]
}
```
Balance amounts are decimal strings. `type` is `VENLY_MANAGED` or `SELF_CUSTODY` depending on your company (this example shows self-custody). A wallet has **no `status` field** — readiness shows as `amlStatus: APPROVED` (Venly-managed) or a `CONFIRMED` permit (self-custody).
**Venly-managed:** nothing to do here — the wallet is ready once its `amlStatus` is `APPROVED` (handled during onboarding).
**Self-custody:** before this wallet can send funds, the customer signs a one-time [permit](/guides/finance/permits-and-allowances) so Venly can move their tokens (do this once after the account is set up). The wallet is ready once that permit is `CONFIRMED`.
***
## Step 6 — Issue a virtual bank account (IBAN)
Once the account is `VERIFIED`, attach an IBAN so it can be funded via SEPA. Incoming euros are auto-converted to the `targetCryptocurrency` (`USDC`, `EURC`, `USDT`, or `USDS`) and credited to the wallet.
```bash theme={null}
curl -X POST https://api-staging.venlyfinance.com/v1/accounts/{accountId}/virtual-bank-accounts \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Jane Doe — EUR Funding",
"inCurrency": "EUR",
"targetCryptocurrency": "USDC",
"idempotencyKey": "f47ac10b-58cc-4372-a567-0e02b2c3d479"
}'
```
```json Response (201) theme={null}
{
"success": true,
"result": {
"id": "4d5e6f70-8192-4a3b-9c4d-5e6f7081920a",
"accountId": "b2a1f0e9-8c7d-4e3a-9f21-0a1b2c3d4e5f",
"bankAccountType": "EUR_SEPA",
"status": "ACTIVE",
"currency": "EUR",
"targetCryptocurrency": "USDC",
"iban": "DE89370400440532013000",
"bic": "DEUTDEDB",
"referenceCode": "VFY-7K2Q-931"
}
}
```
Surface the **`referenceCode`** to your end user when they initiate a SEPA transfer — it's what links the incoming wire to this account. Without it, settlement falls back to manual reconciliation.
***
## Step 7 — Fund the account
### Option A — SEPA transfer to the IBAN
The customer sends EUR from their bank to the IBAN from Step 6, including the `referenceCode` in the payment reference. On receipt, Venly converts EUR → the target crypto and credits the wallet.
### Option B — Hosted fiat-to-crypto pay-in
Create a pay-in session and redirect the customer to the returned `paymentUrl`.
```bash theme={null}
curl -X POST https://api-staging.venlyfinance.com/v1/accounts/{accountId}/fiat-to-crypto/payment-sessions \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"inAmount": "100.00",
"inCurrency": "EUR",
"outCryptocurrency": "USDC",
"callbackUrl": "https://your-app.com/webhooks/pay-in",
"successRedirectUrl": "https://your-app.com/onboarding/funded",
"failureRedirectUrl": "https://your-app.com/onboarding/retry",
"idempotencyKey": "c7e8d9f0-1a2b-3c4d-5e6f-7a8b9c0d1e2f"
}'
```
The response carries a `paymentUrl`. When the customer completes payment, the wallet is credited and your `callbackUrl` is invoked.
***
## Step 8 — Send a transfer
Transfers move funds **between two Venly accounts** — identify the receiver by `receiverAccountId` or by your own `receiverExternalId`. Both the sender **and** the receiver accounts must be `VERIFIED`; sending to an unverified receiver fails with `422 receiver-kyc-not-verified`.
### Crypto transfer
```bash theme={null}
curl -X POST https://api-staging.venlyfinance.com/v1/accounts/{senderAccountId}/transfers/crypto \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"receiverExternalId": "acct-67890",
"chain": "BASE",
"asset": "USDC",
"amount": 25,
"description": "Invoice #1138 settlement",
"idempotencyKey": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}'
```
```json Response (201) theme={null}
{
"success": true,
"result": {
"id": "a1b2c3d4-e5f6-4789-9abc-def012345678",
"senderAccountId": "b2a1f0e9-8c7d-4e3a-9f21-0a1b2c3d4e5f",
"receiverAccountId": "c3b2a1f0-9d8c-4e3a-bf21-1a2b3c4d5e60",
"chain": "BASE",
"asset": "USDC",
"amount": 25,
"status": "COMPLETED",
"transactionHash": "0xa1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2",
"createdAt": "2026-01-15T09:30:00Z",
"updatedAt": "2026-01-15T09:30:02Z"
}
}
```
### Fiat transfer
A fiat-denominated transfer settles in the underlying stablecoin and returns a `fiatOrigin` block with the original currency and exchange rate.
```bash theme={null}
curl -X POST https://api-staging.venlyfinance.com/v1/accounts/{senderAccountId}/transfers/fiat \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"receiverExternalId": "acct-67890",
"currency": "USD",
"amount": 25,
"description": "Q2 supplier payment",
"idempotencyKey": "e9f0a1b2-3c4d-5e6f-7a8b-9c0d1e2f3a4b"
}'
```
**Self-custody senders** also need a `CONFIRMED` permit and a granted allowance before a transfer succeeds — see [Approving transfers without gas](/guides/finance/permits-and-allowances). Venly-managed accounts don't.
***
## Step 9 — Track the transfer
Crypto and fiat transfers usually complete synchronously, but you can always fetch the latest state:
```bash theme={null}
curl https://api-staging.venlyfinance.com/v1/accounts/{accountId}/transfers/{transferId} \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
```
| `status` | Meaning |
| ----------- | ----------------------------------------------------- |
| `PENDING` | Accepted, settlement in progress |
| `COMPLETED` | Final — funds delivered (`transactionHash` populated) |
| `FAILED` | Final — see `errorMessage` |
List all transfers for an account with `GET /accounts/{accountId}/transfers` plus [pagination](/getting-started/conventions#pagination) parameters. Retrying a create with the same `idempotencyKey` returns the original transfer — no double-spend.
***
## Common pitfalls
The **account** is still `VERIFICATION_PENDING`. A Venly admin must verify it first — poll `GET /accounts/{id}` until `kycStatus` is `VERIFIED`. (The party being `ACTIVE` is not enough.)
The customer hasn't signed the token permit yet, so Venly has no allowance to move funds. Run the [permit flow](/guides/finance/permits-and-allowances) once, then retry.
Self-custody accounts must include the customer's wallet `address` on creation. Venly-managed accounts must not.
The `receiverAccountId` / `receiverExternalId` doesn't resolve to an account in your company. Transfers are account-to-account — both sides must be Venly accounts you own.
Tokens last 5 minutes. Catch `401`, refresh, and retry the original call. Don't pre-authenticate every request — cache the token.
***
## Next steps
The condensed party → account → verify → IBAN flow.
Every endpoint, field, and error code.
Gasless token approvals for self-custody accounts.
Stuck? Get in touch with your `accountId` and the failing request.
# Account verification
Source: https://docs.venlyfinance.com/guides/finance/kyc-verification
Why a new account can't move money yet, and how it becomes verified.
Every account starts **unverified** and must be verified before it can move money. This is the most common reason an otherwise-correct request is rejected, so it's worth understanding early.
## The states
An account's `kycStatus` (returned by [Get an account](/api-reference/Finance-API/accounts/get-account-details)) is one of:
| `kycStatus` | Meaning |
| ---------------------- | ----------------------------------------------------- |
| `VERIFICATION_PENDING` | New account. Can be set up, but can't move money yet. |
| `VERIFIED` | Approved. All operations are available. |
| `REJECTED` | Verification was declined. |
## Individuals and organisations (KYC & KYB)
The account's `kycStatus` above is what gates money movement. The underlying **party** is verified too, on a field that depends on its type:
| Party type | Field | States |
| -------------- | ----------- | ------------------------------------------------- |
| `INDIVIDUAL` | `kycStatus` | `VERIFICATION_PENDING → VERIFIED` (or `REJECTED`) |
| `ORGANISATION` | `kybStatus` | `PENDING → VERIFIED` (or `DENIED`) |
**KYB** (Know Your Business) is the organisation equivalent of KYC — it verifies the company itself (and, typically, its representatives). Read `kybStatus` from [Get a party](/api-reference/Finance-API/parties/get-party-details). Like KYC, it's reviewed by a Venly admin and runs asynchronously after you create the organisation party.
## How an account gets verified
Verification is reviewed and approved by a **Venly admin** — it does not happen through the API, and there's no endpoint to trigger it. After you create an account, your Venly contact reviews it; once approved, the account's `kycStatus` becomes `VERIFIED`.
Check the current status at any time with [Get an account](/api-reference/Finance-API/accounts/get-account-details) and read the `kycStatus` field.
## Wallet readiness (AML, and permits for self-custody)
A `VERIFIED` `kycStatus` clears the **account**, but funds move through the account's **wallet**, which has its own gate. Each wallet returned by [list wallets](/api-reference/Finance-API/wallets/list-wallets-for-an-account) carries an `amlStatus` (`PENDING` → `APPROVED`). An account is ready to move money when:
| Custody | Ready when |
| ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Venly-managed** | `kycStatus` is `VERIFIED` **and** the wallet's `amlStatus` is `APPROVED` (both happen during onboarding — no further action). |
| **Self-custody** | the above **plus** a `CONFIRMED` [permit](/guides/finance/permits-and-allowances) on the account wallet — the one-time signature that lets Venly move its funds. |
The wallet has **no `status` field**, so use `amlStatus` (Venly-managed) and permit `status` (self-custody) as your readiness signals. See [Wallets & balances](/guides/finance/wallets).
## What's blocked until `VERIFIED`
These calls fail while an account is `VERIFICATION_PENDING`:
* [Create a crypto transfer](/api-reference/Finance-API/transfers/create-crypto-transfer) and [Create a fiat transfer](/api-reference/Finance-API/transfers/create-fiat-transfer)
* [Create a payment request](/api-reference/Finance-API/payment-requests/create-payment-request-for-account)
* [Create a pay-in session](/api-reference/Finance-API/fiat-to-crypto-payment-sessions/create-a-fiat-to-crypto-payment-session)
* [Create a virtual bank account](/api-reference/Finance-API/virtual-bank-accounts/create-a-virtual-bank-account)
Each returns an error that means "this account isn't verified yet" — but the error `code` and HTTP status **depend on the operation**, so handle any of them as not-verified rather than matching a single code:
* **Virtual bank account** → `400` with code `kyc-not-verified`:
```json theme={null}
{
"success": false,
"errors": [
{ "code": "kyc-not-verified", "message": "Account KYC status must be VERIFIED to create a virtual bank account. Current status: VERIFICATION_PENDING" }
]
}
```
* **Pay-in session** → `422` with code `kyc-required`:
```json theme={null}
{
"success": false,
"errors": [
{ "code": "kyc-required", "message": "Account {accountId} KYC status is not verified" }
]
}
```
* **Payment request** → `400` with code `account-not-active`:
```json theme={null}
{
"success": false,
"errors": [
{ "code": "account-not-active", "message": "Account KYC status must be VERIFIED to authorize payments. Current status: VERIFICATION_PENDING" }
]
}
```
Transfers are gated the same way; check the [transfer endpoints](/api-reference/Finance-API/transfers/create-crypto-transfer) for the exact status code.
## What you can do before verification
Plenty of setup doesn't require a verified account:
* Create parties and accounts
* Add and remove party roles
* Read wallets, balances, permits, and allowances
* For self-custody, sign and submit the token permit — see [Approving transfers without gas](/guides/finance/permits-and-allowances)
Build the pending state into your flow: create the account, then wait for your Venly contact to verify it (poll [Get an account](/api-reference/Finance-API/accounts/get-account-details) until `kycStatus` is `VERIFIED`) before attempting transfers, payments, pay-ins, or virtual bank accounts.
## Next steps
Activate a self-custody wallet so Venly can move its funds.
See verification within the full end-to-end flow.
# Venly-managed vs self-custody
Source: https://docs.venlyfinance.com/guides/finance/managed-vs-self-custody
Two ways an account's wallet is controlled — and what changes for your integration.
When you create an account, Venly also sets up a crypto wallet for it. That wallet is controlled in one of two ways. Which one you use is fixed by your company setup, and it changes a few things in how you build.
## The two models
| | Venly-managed | Self-custody |
| ---------------------------------- | ------------------------------------- | ------------------------------------------------------------- |
| Who holds the wallet's keys | Venly | Your customer |
| `address` when creating an account | Not needed — Venly creates the wallet | **Required** — you pass the customer's wallet address |
| Moving funds | Venly moves them directly | Venly moves them using a one-time approval the customer signs |
| Permits & allowances endpoints | Not used | Used to set up and check that approval |
## What this means in practice
**Venly-managed** is the simpler path. Venly creates and holds the wallet, so transfers and payments work with no extra setup from the customer.
**Self-custody** means your customer keeps control of their own wallet and keys. Before Venly can move their funds, the customer grants a one-time approval by signing a message — see [Approving transfers without gas](/guides/finance/permits-and-allowances).
The permit and allowance endpoints only apply to self-custody accounts. Calling them on a Venly-managed account returns:
```json theme={null}
{
"success": false,
"errors": [
{ "code": "invalid-request", "message": "Permits are only applicable for SELF_CUSTODY companies" }
]
}
```
A wallet's `type` field tells you which model it uses — `VENLY_MANAGED` or `SELF_CUSTODY`. You'll see it in the [list wallets](/api-reference/Finance-API/wallets/list-wallets-for-an-account) response.
## Next steps
The one-time approval a self-custody wallet signs.
Read a wallet's `type` to confirm its custody model.
# Payment requests
Source: https://docs.venlyfinance.com/guides/finance/payment-requests
Reserve money from an account, then settle, reverse, or adjust it — with a per-step breakdown.
A payment request holds money aside from an account's wallet, then settles it. You create one, the amount is reserved, and later you **settle** it (the money moves to the company's settlement wallet), **reverse** it (the money goes back to the account), or **adjust** the amount. Every on-chain step is recorded as an `execution` you can read back.
Two wallets are involved: the account's wallet, where the money starts, and a Venly-held *escrow* wallet that holds the reserved amount until it settles. Settling moves the money to the **company's settlement wallet** — your platform's wallet for collected payments; reversing returns it to the account wallet.
## Payment request vs. transfer
A [transfer](/guides/finance/transfers) sends money to another account in one move. A payment request reserves the money first and resolves it later — the pattern card and merchant payments need, where the final amount is known only after authorization.
## The flow
1. **Create** — money is reserved from the account wallet into escrow. The request is `RESERVED`.
2. **Adjust** *(optional)* — raise or lower the reserved amount while it's `RESERVED`.
3. **Settle or reverse** — settle sends the money to the company's settlement wallet; reverse sends it back to the account. Either way the request reaches a final state.
## Create a payment request
```bash theme={null}
curl -X POST https://api.venlyfinance.com/v1/accounts/{accountId}/payment-requests \
-H "Authorization: Bearer " \
-H "Content-Type: application/json" \
-d '{
"amount": 25.0,
"currency": "USD",
"externalId": "order-67890",
"description": "Order #67890",
"idempotencyKey": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
}'
```
```json Response theme={null}
{
"success": true,
"result": {
"id": "d4e5f6a7-b8c9-4012-8345-6789abcdef01",
"accountId": "b2a1f0e9-8c7d-4e3a-9f21-0a1b2c3d4e5f",
"amount": { "fiat": 25.0, "crypto": "25.000000" },
"originalAmount": { "fiat": 25.0, "crypto": "25.000000" },
"currency": "USD",
"status": "RESERVED",
"executions": [
{
"id": "e5f6a7b8-c9d0-4123-9456-789abcdef012",
"type": "AUTHORIZATION",
"chain": "BASE",
"asset": "USDC",
"amount": 25.0,
"exchangeRate": 1,
"status": "RESERVED",
"transactionHash": "0xa1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2"
}
]
}
}
```
The reserved amount now appears in the wallet's `reserved` [balance](/guides/finance/wallets). There are two ways to create a request:
| Endpoint | Use when |
| ------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------- |
| [For an account](/api-reference/Finance-API/payment-requests/create-payment-request-for-account) — `POST /accounts/{accountId}/payment-requests` | you have the Venly `accountId`. |
| [By card provider](/api-reference/Finance-API/payment-requests/create-payment-request-by-card-provider) — `POST /payment-requests` | you have a card-provider reference; the account is resolved from `cardProviderReference`. |
## Settle
[Settle](/api-reference/Finance-API/payment-requests/settle-a-payment-request) moves the money from escrow to the company's settlement wallet. The response is `status: SETTLING`, and the request becomes `SETTLED` once the on-chain transfers confirm. The settlement `amount` doesn't have to equal the authorized amount:
| Settlement `amount` | What happens |
| ------------------- | ------------------------------------------------------------------------------ |
| Equal to authorized | the reserved amount settles |
| Below authorized | the difference goes back to the account wallet; the rest settles |
| Above authorized | the reserved amount settles and the extra is collected from the account wallet |
## Reverse
[Reverse](/api-reference/Finance-API/payment-requests/reverse-a-payment-request) sends the full reserved amount back to the account wallet. The response is `status: REVERSING`, becoming `REVERSED` once the transfer confirms. Use it to release a hold you no longer need to charge.
## Adjust the amount
[Update](/api-reference/Finance-API/payment-requests/update-a-payment-request) sets a new authorized `amount` while the request is `RESERVED`. A lower amount sends the difference back to the account; a higher amount reserves more from it. After the update, `amount` shows the new value and `originalAmount` keeps the amount you started with.
## Amounts carry fiat and crypto
Every amount on a payment request is an object that shows both sides of the conversion:
```json theme={null}
"amount": { "fiat": 25.0, "crypto": "25.000000" }
```
`fiat` is the value in the request `currency`; `crypto` is the stablecoin amount that actually moves on-chain. This applies to `amount`, `originalAmount`, `settlementAmount`, `settledAmount`, and `shortfallAmount`.
## Status at a glance
| `status` | Meaning |
| ------------------------ | --------------------------------------------------------------------------------------- |
| `RESERVED` | money is held — ready to settle, reverse, or adjust |
| `SETTLING` → `SETTLED` | settlement is processing, then complete |
| `SETTLED_WITH_SHORTFALL` | settled, but less than the full settlement amount was collected — see `shortfallAmount` |
| `REVERSING` → `REVERSED` | reversal is processing, then complete |
Each `execution` carries its own `type` (`AUTHORIZATION`, `INCREMENTAL_AUTHORIZATION`, `AUTHORIZATION_ADJUSTMENT`, `SETTLEMENT`, `SETTLEMENT_OVERAGE`, `REFUND`, `REVERSAL`), `status`, and `transactionHash`.
There's no GET endpoint for a payment request. The full object — including `executions` — comes back on create, settle, reverse, and update, so store the response and match on your own `externalId`.
## Safe retries
Send a fresh `idempotencyKey` for each new request. To retry, reuse the same key with the same body and you'll get the original result back instead of a second charge. See [Idempotency](/guides/finance/idempotency).
## Next steps
Finalize a reserved payment, with exact, lower, and higher amounts.
How reserved money shows up in a wallet balance.
# Approving transfers without gas
Source: https://docs.venlyfinance.com/guides/finance/permits-and-allowances
How self-custody accounts let Venly move their tokens — permits, allowances, and wallet activation.
Applies to **self-custody** accounts. (New to that term? See [Venly-managed vs self-custody](/guides/finance/managed-vs-self-custody).) Do this **after** the account is [verified](/guides/finance/kyc-verification) and its wallet's AML check is approved.
## Why an allowance is needed
A self-custody account holder controls their own wallet. For Venly to move that wallet's tokens during a payment or transfer, the wallet must grant Venly's **orchestration wallet** an ERC-20 **allowance** — permission to pull funds via `transferFrom`. Supported stablecoins are **USDC, EURC, USDS, and USDT** (all support gasless permits).
## Two wallets, two responsibilities
Each account has **two** wallets, and each needs an allowance to the orchestration wallet:
| Wallet | Who grants the permit |
| ------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
| **Account wallet** (holds the customer's balance) | **You** — the account holder signs it (self-custody). On Venly-managed accounts Venly signs it automatically. |
| **Escrow wallet** (used during settlement) | **Venly, automatically** — the escrow wallet is always Venly-managed. |
So on a self-custody account the **only** permit you sign is the **account wallet's**. The escrow wallet — and, on Venly-managed accounts, the account wallet too — is permitted for you automatically.
## Why a permit instead of a plain `approve`
A normal `approve()` costs gas and needs the wallet to hold the chain's native coin. Instead, the holder **signs** an EIP-2612 message (off-chain, no gas) and Venly's orchestration wallet submits it on-chain and pays the gas.
A direct on-chain `approve(spender, amount)` *does* set the allowance — but only a **confirmed permit** moves the wallet to `ACTIVE` (see below). An `approve` alone leaves the wallet `PENDING`, so payments stay blocked. Use the permit flow.
## The permit flow (self-custody account wallet)
`GET /accounts/{accountId}/wallets/{walletId}/permits` returns, per asset, a `supportedAssetId` and an EIP-712 `typedData` object. `walletId` sets the chain (e.g. Base vs Avalanche). The nonce and the token's domain `name`/`version` are read from the contract for you.
Sign `typedData` with the key for the wallet's **owner** address. **The signature must recover to the `owner`** — a signature from any other wallet makes the permit `FAILED`. Produces `v`, `r`, `s`.
`POST .../permits` with the `supportedAssetId` and the signature. Returns **HTTP 200 with `result.status`** — check the status, not just the code. Re-submitting an already-confirmed permit returns `409`.
Settlement is asynchronous — poll `GET .../permits` until `CONFIRMED` (or `FAILED`). On `CONFIRMED` the wallet activates and the allowance goes live.
### Permit status lifecycle
```
PENDING ──submit──▶ SUBMITTED ──on-chain confirmed──▶ CONFIRMED
│ │
└────────── FAILED ◀─┘
```
| `status` | Meaning |
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `PENDING` | Not yet submitted |
| `SUBMITTED` | Signature accepted; settling on-chain |
| `CONFIRMED` | Confirmed on-chain — triggers wallet activation |
| `FAILED` | Execution/confirmation failed — most often the signature didn't recover to the wallet `owner`. Re-fetch the permit and sign again with the correct key. |
### Wallet status lifecycle
A wallet starts `PENDING` and becomes **`ACTIVE` only once *all* its permits are `CONFIRMED`**:
```
PENDING ──all permits CONFIRMED──▶ ACTIVE
```
**Payments and transfers require the wallet to be `ACTIVE`** — until then they're rejected with `account-wallet-not-active`.
The wallet's `status` isn't currently exposed by `GET .../wallets` (which shows `amlStatus` only) — use the **permit status** as your activation signal: once the account wallet's permit is `CONFIRMED`, the wallet is `ACTIVE`.
## Signing the message
Take the `typedData` from the permit response and sign it with the **owner's** key. With [ethers.js](https://docs.ethers.org):
```javascript theme={null}
import { ethers } from "ethers";
// `typedData` is result[].typedData from GET .../permits
const { domain, types, message } = typedData;
// ethers builds the domain separator itself, so remove EIP712Domain before signing
const { EIP712Domain, ...signTypes } = types;
const wallet = new ethers.Wallet(PRIVATE_KEY); // MUST be the wallet `owner` key
const signature = await wallet.signTypedData(domain, signTypes, message);
const { v, r, s } = ethers.Signature.from(signature); // submit these below
```
The signature **must recover to the wallet `owner`**. Signing with a different wallet (or signing the JSON as a personal message instead of EIP-712 typed data) produces a signature that the token contract rejects — the permit silently becomes `FAILED`.
Then submit it. Send `v`, `r`, and `s` as **strings** in the `signature` body — `ethers` returns `v` as a number, so convert it (`String(v)`). Use the `supportedAssetId` from the `GET .../permits` response:
```bash theme={null}
curl --request POST \
--url https://api.venlyfinance.com/v1/accounts/{accountId}/wallets/{walletId}/permits \
--header 'Authorization: Bearer ' \
--header 'Content-Type: application/json' \
--data '{
"supportedAssetId": "7c32877a-cd0c-422a-a0fd-5af0815fc280",
"signature": { "v": "27", "r": "0x...", "s": "0x..." }
}'
```
## Verifying the allowance
Before initiating a payment or transfer, confirm the allowance is in place:
```bash theme={null}
curl https://api.venlyfinance.com/v1/accounts/{accountId}/wallets/{walletId}/allowances \
-H "Authorization: Bearer "
```
Each entry returns the asset, the `orchestrationWallet` that holds the allowance, and the `allowance` as a **human-readable decimal** (on-chain raw value ÷ 10^`decimals`). The authoritative activation signal is the **permit `status: CONFIRMED`** (above) — not the allowance figure. An unlimited permit reports a very large `allowance` (uint256-max), but the value can also be finite; use this endpoint to read the current spending headroom and the permit status to confirm the wallet is active.
Once a permit is `CONFIRMED`, the allowance persists until it's used up — the holder doesn't sign again for every transfer.
## Next steps
Confirm the allowance is live before moving funds.
Move funds once the wallet is `ACTIVE`.
# Supported chains & assets
Source: https://docs.venlyfinance.com/guides/finance/supported-chains-and-assets
The blockchain networks, stablecoins, and fiat currencies the Finance API supports, and how they relate.
A quick reference for the networks and currencies you can use. These are the values the API accepts today; more are added over releases.
## Blockchain networks
An account is pinned to one network when it's created, and its wallet lives there.
| `chain` | Notes |
| ----------- | ------------ |
| `BASE` | Ethereum L2. |
| `AVALANCHE` | EVM C-Chain. |
| `POLYGON` | Polygon PoS. |
These are the chains the **API** supports; the chains available to **your company** are configured by Venly. Creating an account on a chain your company isn't set up for returns `400 invalid-request` with a message listing your supported chains — for example, *"Chain 'POLYGON' is not supported by this company. Supported chains: \[AVALANCHE, BASE]"*.
On-ramp [virtual bank accounts](/guides/finance/virtual-bank-accounts) are provided through banking partners, and partner coverage rolls out per chain. Confirm availability for your chain with your Venly contact.
## Stablecoins
Crypto balances, transfers, and permits use these assets (the `asset` field):
| `asset` | Pegged to |
| ------- | --------- |
| `USDC` | USD |
| `EURC` | EUR |
| `USDT` | USD |
| `USDS` | USD |
The contract address for an asset on a given chain is returned by the API — see `contractAddress` in [list wallets](/api-reference/Finance-API/wallets/list-wallets-for-an-account) balances and in [wallet allowances](/api-reference/Finance-API/allowances/get-wallet-token-allowances). Read addresses from the API rather than hard-coding them.
## Fiat currencies
Fiat-denominated operations (fiat transfers, payment requests, pay-in sessions) accept:
| `currency` |
| ---------- |
| `EUR` |
| `USD` |
| `GBP` |
**Virtual bank accounts currently support EUR only** — creating one provisions a `EUR_SEPA` IBAN. The other currencies are accepted for fiat-denominated operations, but not yet for IBAN provisioning.
## How fiat converts to crypto
Fiat-denominated operations resolve to a stablecoin and settle on-chain. You name the target stablecoin — for example `targetCryptocurrency` on a [virtual bank account](/api-reference/Finance-API/virtual-bank-accounts/create-a-virtual-bank-account), or the asset a [pay-in session](/api-reference/Finance-API/fiat-to-crypto-payment-sessions/create-a-fiat-to-crypto-payment-session) converts to. A [fiat transfer](/guides/finance/transfers) reports the conversion it used in its `fiatOrigin` block (currency, amount, exchange rate).
## Next steps
Per-asset balances on an account's wallet.
Move these assets between accounts.
# Transfers
Source: https://docs.venlyfinance.com/guides/finance/transfers
Move funds from one account to another — fiat-denominated or crypto-denominated — and track them to completion.
A transfer moves funds from one account to another. You always send to a **receiver account** — by its Venly `receiverAccountId`, or by your own `receiverExternalId` if you set one on the account. There are two endpoints, differing only in how you denominate the amount.
## Fiat vs crypto
| | [Fiat transfer](/api-reference/Finance-API/transfers/create-fiat-transfer) | [Crypto transfer](/api-reference/Finance-API/transfers/create-crypto-transfer) |
| -------------- | -------------------------------------------------------------------------- | ------------------------------------------------------------------------------ |
| You specify | a fiat `currency` + `amount` | a crypto `asset` + `chain` + `amount` |
| Settles in | the underlying stablecoin, on-chain | the named asset, on-chain |
| Response extra | a `fiatOrigin` block (currency, amount, exchange rate) | — |
Both settle on-chain and return a `transactionHash`.
## Prerequisites
The **sender** account must be [verified](/guides/finance/kyc-verification). For **self-custody** senders, the wallet must also be active with an allowance to the orchestration wallet — see [Approving transfers without gas](/guides/finance/permits-and-allowances).
**Both** the sender **and** the receiver account must be KYC `VERIFIED`. A transfer to an unverified receiver is rejected with `422 receiver-kyc-not-verified` — verify the receiver before sending. Transfers are also scoped to a single company; you cannot transfer to an account in another company.
## Create a fiat transfer
```bash theme={null}
curl -X POST https://api.venlyfinance.com/v1/accounts/{senderAccountId}/transfers/fiat \
-H "Authorization: Bearer " \
-H "Content-Type: application/json" \
-d '{
"receiverAccountId": "c3b2a1f0-9d8c-4e3a-bf21-1a2b3c4d5e60",
"currency": "USD",
"amount": 25.0,
"description": "Invoice settlement",
"idempotencyKey": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
}'
```
```json Response theme={null}
{
"success": true,
"result": {
"id": "a1b2c3d4-e5f6-4789-9abc-def012345678",
"senderAccountId": "b2a1f0e9-8c7d-4e3a-9f21-0a1b2c3d4e5f",
"receiverAccountId": "c3b2a1f0-9d8c-4e3a-bf21-1a2b3c4d5e60",
"chain": "BASE",
"asset": "USDC",
"amount": 25.0,
"fiatOrigin": { "currency": "USD", "amount": 25.0, "exchangeRate": 1 },
"status": "COMPLETED",
"transactionHash": "0xa1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2"
}
}
```
A **crypto transfer** is the same call against `/transfers/crypto`, sending `chain` + `asset` instead of `currency` (and the response omits `fiatOrigin`).
## Status lifecycle
A transfer's `status` is `PENDING → COMPLETED`, or `FAILED` (with an `errorMessage`). Settlement is on-chain, so poll [Get a transfer](/api-reference/Finance-API/transfers/get-transfer-details) — or [List transfers](/api-reference/Finance-API/transfers/list-transfers-for-account), filtering by `accountRole` (`SENDER`/`RECEIVER`) and `status`.
## Idempotency
Every transfer takes a unique `idempotencyKey`; retrying with the same key returns the original transfer instead of sending again. See [Safe retries with idempotency keys](/guides/finance/idempotency).
## Next steps
The endpoint reference and full schema.
Reserve and settle a payment from an account's balance.
# Versioning & safe updates
Source: https://docs.venlyfinance.com/guides/finance/versioning
Use the version field so two edits never silently overwrite each other.
Every party and account carries a `version` number that goes up by one each time the resource changes. You use it to update safely.
## Why it matters
If two people — or two of your own processes — edit the same party at the same time, the second save could quietly wipe out the first. The `version` field prevents this: an update only succeeds if you're working from the latest copy.
## How to update
Fetch it and note the `version` (for example, `0`).
Include the `version` you just read in your `PATCH` request body.
If someone changed the resource after you read it, the API returns `409`. Re-fetch to get the new `version`, reapply your change, and send it again.
```bash theme={null}
curl --request PATCH \
--url https://api.venlyfinance.com/v1/parties/{partyId} \
--header 'Authorization: Bearer ' \
--header 'Content-Type: application/json' \
--data '{ "version": 0, "firstName": "Janet" }'
```
A stale `version` returns:
```json theme={null}
{
"success": false,
"errors": [
{ "code": "concurrent-modification", "message": "This request has been modified by another user. Please refresh and try again." }
]
}
```
Always send the `version` from your most recent read — never a cached or hard-coded value.
## API version
The Finance API is at **v1.1.0**, which adds the payment-request [settle, reverse, and update](/guides/finance/payment-requests) endpoints and `POLYGON` as a [supported chain](/guides/finance/supported-chains-and-assets).
Payment-request amounts are objects that carry both sides of the conversion — `{ "fiat": , "crypto": "" }` — across `amount`, `originalAmount`, `settlementAmount`, `settledAmount`, and `shortfallAmount`. See [Payment requests](/guides/finance/payment-requests#amounts-carry-fiat-and-crypto).
## Next steps
Send the `version` with your PATCH request.
The other half of safe writes — duplicate-proof creates.
# Virtual bank accounts (IBANs)
Source: https://docs.venlyfinance.com/guides/finance/virtual-bank-accounts
Assign an IBAN to an account to receive fiat by SEPA, auto-converted to crypto — and how the reference code routes the funds.
A virtual bank account (VBA) gives an account its own **IBAN** to receive fiat. Incoming SEPA credits are automatically converted to a stablecoin and credited to the account's wallet.
## Prerequisites
The account must be [verified](/guides/finance/kyc-verification) and have a linked account-holder party. Today VBAs are **EUR only** — creating one provisions a `EUR_SEPA` IBAN.
## Create a virtual bank account
Provide a display `name`, the fiat `inCurrency` (`EUR`), the `targetCryptocurrency` to convert to, and a unique `idempotencyKey`:
```bash theme={null}
curl -X POST https://api.venlyfinance.com/v1/accounts/{accountId}/virtual-bank-accounts \
-H "Authorization: Bearer " \
-H "Content-Type: application/json" \
-d '{
"name": "EUR Payouts",
"inCurrency": "EUR",
"targetCryptocurrency": "USDC",
"idempotencyKey": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
}'
```
```json Response theme={null}
{
"success": true,
"result": {
"id": "4d5e6f70-8192-4a3b-9c4d-5e6f7081920a",
"bankAccountType": "EUR_SEPA",
"status": "ACTIVE",
"currency": "EUR",
"targetCryptocurrency": "USDC",
"iban": "DE89370400440532013000",
"bic": "DEUTDEDB",
"bankName": "Example Bank",
"beneficiaryName": "Jane Doe",
"referenceCode": "VFY-7K2Q-931"
}
}
```
## The fields that matter
| Field | Why it matters |
| ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `iban` / `bic` | The account coordinates you show the payer. |
| `beneficiaryName` | The legal name on the account — display it next to the IBAN. |
| `referenceCode` | **Critical.** The payer must quote this in the SEPA payment reference so the incoming wire is matched to this account. Without it, settlement falls back to manual reconciliation. |
| `targetCryptocurrency` | The stablecoin incoming EUR is converted to. |
| `status` | `ACTIVE` or `CLOSED`. |
Always surface the `referenceCode` to the end user and tell them to include it in their transfer. It's how an incoming SEPA credit is routed to the right account.
## Reading them back
* [List virtual bank accounts](/api-reference/Finance-API/virtual-bank-accounts/list-virtual-bank-accounts) for an account.
* [Get a virtual bank account](/api-reference/Finance-API/virtual-bank-accounts/get-virtual-bank-account-details) by ID.
## Next steps
Where converted funds land.
Which fiat currencies and stablecoins are supported.
# Wallets & balances
Source: https://docs.venlyfinance.com/guides/finance/wallets
The custodial wallets behind every account — the two-wallet model, balance fields, and how funds get reserved.
When you [create an account](/api-reference/Finance-API/accounts/create-a-new-account), Venly provisions the crypto wallets that hold its funds. You don't manage keys or contracts directly — you read balances and move funds through the API.
## The two-wallet model
Each account has **two** wallets, both bound to the account's chain:
| Wallet | Holds | Who grants the permit |
| ------------------ | --------------------------------- | -------------------------------------------------------------------- |
| **Account wallet** | the customer's balance | Self-custody: the holder signs. Venly-managed: signed automatically. |
| **Escrow wallet** | funds in flight during settlement | Always Venly-managed — permitted automatically. |
For self-custody accounts the only permit you handle is the account wallet's — see [Approving transfers without gas](/guides/finance/permits-and-allowances). On Venly-managed accounts both wallets are handled for you.
## Custody type
A wallet's `type` is either **`VENLY_MANAGED`** (Venly holds the keys) or **`SELF_CUSTODY`** (your customer holds them). This is fixed by your company setup and changes how funds move — see [Venly-managed vs self-custody](/guides/finance/managed-vs-self-custody).
## Reading wallets
[List wallets for an account](/api-reference/Finance-API/wallets/list-wallets-for-an-account) returns each wallet with its address, per-asset balances, and AML status:
```json Response theme={null}
{
"success": true,
"result": [
{
"id": "9f8e7d6c-5b4a-4938-8271-6a5b4c3d2e1f",
"chain": "BASE",
"type": "SELF_CUSTODY",
"address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F",
"balances": [
{
"asset": "USDC",
"contractAddress": "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
"amount": { "total": "125.00", "available": "100.00", "reserved": "25.00" }
}
],
"amlStatus": "APPROVED"
}
]
}
```
## Balance fields
Each asset balance has three amounts, returned as **decimal strings**:
| Field | Meaning |
| ----------- | ------------------------------------------------------------------------------------------------------------------------- |
| `total` | Everything in the wallet. |
| `available` | Free to spend on a new transfer or payment. |
| `reserved` | Held against in-flight [payment requests](/guides/finance/payment-requests) — not spendable until they settle or reverse. |
`total = available + reserved`. Creating a payment request moves its amount from `available` to `reserved`; on settlement it leaves the wallet entirely.
## AML status
`amlStatus` reflects the wallet's screening: `PENDING`, `APPROVED`, or `REJECTED`. A wallet must clear AML (and, for self-custody, have a confirmed permit) before it can move funds.
The wallet's activation `status` isn't currently returned by [list wallets](/api-reference/Finance-API/wallets/list-wallets-for-an-account) — the response exposes `amlStatus` only. For **self-custody**, use the **permit status** as your activation signal: once the account wallet's permit is `CONFIRMED`, the wallet is active. For **Venly-managed** wallets (which have no permits), `amlStatus: APPROVED` is the activation signal. See [Approving transfers without gas](/guides/finance/permits-and-allowances).
## Next steps
Activate a self-custody wallet with a gasless permit.
The endpoint reference, with the full response schema.
# Multi-Rail Routing (Coming Soon)
Source: https://docs.venlyfinance.com/guides/multi-rail-routing/introduction
Intelligent payment routing across SEPA, SWIFT, stablecoins, and local rails for optimal speed
**Coming Soon** - Multi-Rail Routing is currently in development and will be available soon. This documentation provides an overview of the upcoming features.
## What is Multi-Rail Routing?
Multi-Rail Routing is Venly's intelligent payment orchestration system that automatically selects the optimal payment rail for each transaction. Instead of being locked into a single payment method, the system dynamically routes payments through SEPA, SWIFT, stablecoin networks, or local rails based on speed, cost, and destination requirements.
SEPA, SWIFT, Faster Payments, and more
USDC, USDT, EURC on multiple blockchains
PIX, FPS, CHAPS, ACH, and regional networks
AI-powered routing for best speed and cost
***
## The Problem with Single-Rail Systems
Traditional payment systems force you to choose one rail and live with its limitations:
### Traditional Wire Transfers (SWIFT)
❌ **3-5 days settlement time**\
❌ **High correspondent banking fees**\
❌ **Limited transparency**\
❌ **Frequent holds and blocks**\
❌ **Business hours only**
### Single Payment Processors
❌ **Locked into one provider's network**\
❌ **No flexibility for optimization**\
❌ **Higher costs due to lack of competition**\
❌ **Limited corridor coverage**
### The Cost of Inefficiency
| Issue | Impact |
| ------------------------------------------------ | ------------------------- |
| **3+ days average settlement** | Support tickets pile up |
| **Direct operational losses per corridor block** | Eats into margin |
| **72% false positive holds** | Legitimate volume flagged |
***
## How Multi-Rail Routing Works
You submit a payment request via API
```bash theme={null}
POST /v1/payout
{
"amount": 50000,
"currency": "USD",
"destination": "MX",
"recipient": {
"accountNumber": "123456789",
"bankCode": "BANAMEX"
}
}
```
Venly's routing engine analyzes multiple factors
**Factors Considered:**
* Destination country and currency
* Payment amount and urgency
* Current rail availability and costs
* Recipient bank capabilities
* Regulatory requirements
* Historical performance data
* Real-time network status
System selects the best available rail
```
Analysis Results:
✓ SWIFT: 3 days, €25 fee
✓ Stablecoin: 15 minutes, €2 fee
✓ Local Rail (SPEI): 2 hours, €5 fee
Selected: Stablecoin Rail
Reason: Fastest + Lowest Cost
```
Payment is routed and executed
* Funds converted to optimal stablecoin if needed
* Transaction submitted to selected network
* Real-time status updates via webhooks
* Automatic fallback if primary rail fails
Recipient receives funds
* Settlement time: Seconds to minutes (stablecoin) or hours (local rails)
* Confirmation sent to both parties
* Transaction recorded for compliance
* Detailed reporting available
***
## Supported Payment Rails
### 🏦 Bank Rails
**SEPA (Single Euro Payments Area)**
* **Coverage**: 36 European countries
* **Settlement**: T+1 (1 business day)
* **Cost**: €0.50 - €2.00 per transaction
* **Best For**: EUR payments within Europe
**SWIFT (International Wire)**
* **Coverage**: 200+ countries
* **Settlement**: T+2 to T+5 (2-5 business days)
* **Cost**: €15 - €50 per transaction
* **Best For**: Large international transfers, exotic corridors
**Faster Payments (UK)**
* **Coverage**: United Kingdom
* **Settlement**: Minutes to hours
* **Cost**: €1 - €3 per transaction
* **Best For**: GBP payments within UK
**ACH (Automated Clearing House)**
* **Coverage**: United States
* **Settlement**: T+1 to T+2
* **Cost**: €0.50 - €2.00 per transaction
* **Best For**: USD payments within US
### 💎 Stablecoin Rails
**USDC (USD Coin)**
* **Blockchains**: Ethereum, Base, Polygon, Arbitrum
* **Settlement**: 15 seconds to 5 minutes
* **Cost**: €0.10 - €2.00 per transaction
* **Best For**: Fast USD transfers, crypto-native recipients
**EURC (Euro Coin)**
* **Blockchains**: Ethereum, Base
* **Settlement**: 15 seconds to 5 minutes
* **Cost**: €0.10 - €2.00 per transaction
* **Best For**: Fast EUR transfers, European crypto users
**USDT (Tether)**
* **Blockchains**: Ethereum, Tron, Polygon
* **Settlement**: 1 minute to 10 minutes
* **Cost**: €0.10 - €3.00 per transaction
* **Best For**: High liquidity corridors, Asian markets
### 🌍 Local Rails
**PIX (Brazil)**
* **Coverage**: Brazil
* **Settlement**: Instant (24/7)
* **Cost**: €0.50 - €1.50 per transaction
* **Best For**: BRL payments in Brazil
**SPEI (Mexico)**
* **Coverage**: Mexico
* **Settlement**: Minutes to hours
* **Cost**: €1 - €3 per transaction
* **Best For**: MXN payments in Mexico
**UPI (India)**
* **Coverage**: India
* **Settlement**: Instant
* **Cost**: €0.20 - €1.00 per transaction
* **Best For**: INR payments in India
**FPS (Hong Kong)**
* **Coverage**: Hong Kong
* **Settlement**: Instant
* **Cost**: €0.50 - €2.00 per transaction
* **Best For**: HKD payments in Hong Kong
***
## Routing Optimization Strategies
### Speed-Optimized Routing
**Priority: Fastest Settlement**
```
Use Case: Urgent vendor payment
Amount: €10,000
Destination: Brazil
Selected Rail: PIX (Instant)
Alternative: SWIFT (3-5 days)
Time Saved: 3-5 days
Cost Difference: +€2
```
**Best For:**
* Urgent payments
* Time-sensitive transactions
* Customer satisfaction priorities
* Competitive advantage scenarios
### Cost-Optimized Routing
**Priority: Lowest Transaction Cost**
```
Use Case: Bulk payroll processing
Amount: €500,000 (1000 payments)
Destination: Europe
Selected Rail: SEPA (€1 per txn)
Alternative: SWIFT (€25 per txn)
Cost Saved: Substantial
Settlement: T+1 (acceptable)
```
**Best For:**
* High-volume operations
* Non-urgent payments
* Margin optimization
* Predictable cash flow
### Balanced Routing
**Priority: Best Speed/Cost Ratio**
```
Use Case: Standard cross-border payment
Amount: €5,000
Destination: United States
Selected Rail: Stablecoin (USDC)
Settlement: 15 minutes
Cost: €2
Alternative 1: SWIFT (3 days, €30)
Alternative 2: ACH (2 days, €1)
```
**Best For:**
* Standard operations
* Mixed payment types
* General use cases
* Default routing strategy
***
## 40+ Supported Corridors
### Major Corridors
| From | To | Primary Rail | Settlement Time | Typical Cost |
| ---- | --- | ------------ | --------------- | ------------ |
| EUR | USD | Stablecoin | 15 minutes | €2 |
| EUR | GBP | SEPA/FPS | 2-4 hours | €3 |
| USD | EUR | Stablecoin | 15 minutes | €2 |
| USD | MXN | SPEI | 1-2 hours | €5 |
| EUR | BRL | PIX | Instant | €3 |
| USD | INR | UPI | Instant | €2 |
| GBP | EUR | SEPA | T+1 | €2 |
| USD | PHP | Local Bank | 2-4 hours | €4 |
### Regional Coverage
**Europe (SEPA Zone)**
* 36 countries
* EUR payments
* T+1 settlement
* €0.50 - €2 per transaction
**Americas**
* US (ACH, Wire)
* Mexico (SPEI)
* Brazil (PIX)
* Canada (EFT)
* Argentina, Chile, Colombia
**Asia-Pacific**
* India (UPI, IMPS)
* Philippines (InstaPay)
* Hong Kong (FPS)
* Singapore (FAST)
* Thailand, Vietnam, Indonesia
**Middle East & Africa**
* UAE (UAEFTS)
* South Africa (EFT)
* Nigeria (NIBSS)
* Kenya (RTGS)
***
## Automatic Failover & Redundancy
### Multi-Rail Redundancy
If the primary rail fails, the system automatically falls back:
```
Payment Request: €10,000 EUR → USD
Primary Rail: Stablecoin (USDC)
Status: Network congestion detected
Automatic Failover:
→ Secondary Rail: SWIFT Wire
→ Notification sent to sender
→ Payment completes via backup rail
→ No manual intervention required
```
### Intelligent Retry Logic
```javascript theme={null}
// Automatic retry with exponential backoff
Attempt 1: Stablecoin (failed - network issue)
Wait: 30 seconds
Attempt 2: Stablecoin (failed - still congested)
Wait: 2 minutes
Attempt 3: Switch to SWIFT (success)
Total Time: 3 minutes to fallback
User Experience: Seamless
```
***
## Real-Time Monitoring & Analytics
### Live Dashboard
Track all payments in real-time:
* **Active Payments**: See payments in progress
* **Rail Performance**: Monitor each rail's success rate
* **Cost Analytics**: Track savings vs traditional methods
* **Settlement Times**: Average time per corridor
* **Failure Rates**: Identify problematic routes
### Performance Metrics
```
Today's Statistics:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Total Payments: 1,247
Stablecoin Rail: 856 (68.6%)
Bank Rails: 312 (25.0%)
Local Rails: 79 (6.3%)
Average Settlement: 24 minutes
Cost Savings vs SWIFT: Significant
Success Rate: 99.2%
```
***
## Use Cases
### 🎮 Gaming & iGaming Payouts
**Challenge**: Pay winners globally, instantly
**Solution**: Multi-rail routing
* Small payouts (\<€1K): Stablecoin rails (instant)
* Large payouts (>€10K): Local rails or SWIFT
* Regional optimization: PIX for Brazil, UPI for India
* 24/7 availability: No banking hours restrictions
**Results:**
* 95% faster payouts
* Meaningful cost reduction
* Higher player satisfaction
* Competitive advantage
### 💼 Cross-Border B2B Payments
**Challenge**: Pay international vendors efficiently
**Solution**: Intelligent routing
* Urgent payments: Stablecoin rails
* Standard payments: Local rails
* Large transfers: SWIFT with best rates
* Automatic currency conversion
**Results:**
* 3-5 days → 15 minutes average
* Substantially reduced average transaction cost
* Improved vendor relationships
* Better cash flow management
### 💰 Remittances & Money Transfer
**Challenge**: Send money home affordably
**Solution**: Cost-optimized routing
* High-volume corridors: Stablecoin rails
* Emerging markets: Local rail partnerships
* Competitive FX rates
* Transparent pricing
**Results:**
* Substantially lower fees than traditional remittance
* Instant to same-day delivery
* Better exchange rates
* Increased customer loyalty
### 🏦 Treasury Management
**Challenge**: Optimize corporate treasury operations
**Solution**: Balanced routing strategy
* Liquidity management: Fast stablecoin rails
* Vendor payments: Cost-optimized routing
* Payroll: Reliable local rails
* Multi-currency support
**Results:**
* Improved working capital
* Reduced treasury costs
* Better forecasting
* Centralized control
***
## Integration
### Simple API
One API call, automatic routing:
```bash theme={null}
POST /v1/payout
Authorization: Bearer {token}
Content-Type: application/json
{
"amount": 50000,
"currency": "USD",
"destination": {
"country": "MX",
"currency": "MXN",
"accountNumber": "123456789",
"bankCode": "BANAMEX"
},
"routing": {
"strategy": "BALANCED", // SPEED, COST, or BALANCED
"maxCost": 10, // Optional: Maximum acceptable cost
"maxTime": 3600 // Optional: Maximum time in seconds
}
}
```
### Response
```json theme={null}
{
"success": true,
"result": {
"payoutId": "payout_abc123",
"status": "PROCESSING",
"selectedRail": "STABLECOIN_USDC",
"estimatedSettlement": "2026-03-31T16:15:00Z",
"estimatedCost": {
"amount": 2.50,
"currency": "EUR"
},
"alternativeRails": [
{
"rail": "SWIFT",
"estimatedTime": "3-5 days",
"cost": 25.00
},
{
"rail": "SPEI",
"estimatedTime": "2 hours",
"cost": 5.00
}
]
}
}
```
### Webhook Notifications
```json theme={null}
{
"event": "payout.completed",
"payoutId": "payout_abc123",
"rail": "STABLECOIN_USDC",
"status": "COMPLETED",
"settlementTime": "14 minutes",
"actualCost": 2.50,
"timestamp": "2026-03-31T16:14:23Z"
}
```
***
## Comparison: Multi-Rail vs Single-Rail
| Feature | Traditional PSPs | Single Stablecoin | Venly Multi-Rail |
| -------------------------- | ------------------ | --------------------------- | --------------------------- |
| **Available Rails** | 1-2 | 1 | 40+ corridors |
| **Settlement Time** | T+2 to T+5 | 5-15 minutes | Optimized per payment |
| **Cost per Transaction** | €15-€50 | €1-€3 | €0.50-€5 (optimized) |
| **Corridor Coverage** | Limited | Global but limited adoption | Global + local optimization |
| **Automatic Optimization** | No | No | Yes |
| **Failover/Redundancy** | Manual | No | Automatic |
| **Business Hours** | Yes | No | No |
| **Compliance** | Provider-dependent | Self-managed | Built-in |
***
## Best Practices
### 1. Choose the Right Strategy
```javascript theme={null}
// Speed-critical payments
{
"routing": {
"strategy": "SPEED",
"maxTime": 600 // 10 minutes max
}
}
// Cost-sensitive bulk payments
{
"routing": {
"strategy": "COST",
"maxCost": 2 // €2 max per transaction
}
}
// Balanced approach (recommended)
{
"routing": {
"strategy": "BALANCED"
}
}
```
### 2. Set Appropriate Limits
* **Max Cost**: Prevent expensive routing for small payments
* **Max Time**: Ensure SLA compliance
* **Preferred Rails**: Specify preferred rails when needed
* **Fallback Rules**: Define acceptable alternatives
### 3. Monitor Performance
* Track rail performance metrics
* Analyze cost savings
* Review settlement times
* Identify optimization opportunities
### 4. Handle Webhooks
```javascript theme={null}
// Webhook handler example
app.post('/webhooks/venly', (req, res) => {
const event = req.body;
switch(event.type) {
case 'payout.processing':
// Update internal status
break;
case 'payout.completed':
// Notify recipient
break;
case 'payout.failed':
// Handle failure, retry if needed
break;
}
res.status(200).send('OK');
});
```
***
## Security & Compliance
### Regulatory Compliance
✅ **EU VASP Registration**: Licensed virtual asset service provider\
✅ **SOC 2 Type II**: Independently audited security controls\
✅ **ISO 27001**: Information security management\
✅ **GDPR Compliant**: Data protection and privacy\
✅ **MiCA-Aligned**: Preparing for EU crypto regulations
### Transaction Monitoring
* Real-time AML screening
* Sanctions list checking
* Fraud detection algorithms
* Suspicious activity reporting
* Audit trail for all transactions
### Data Security
* End-to-end encryption
* Secure API authentication (OAuth2)
* PCI DSS compliance for card data
* Regular security audits
* Incident response procedures
***
## Frequently Asked Questions
The engine analyzes multiple factors including destination, amount, urgency, cost, rail availability, and historical performance. It then selects the optimal rail based on your chosen strategy (SPEED, COST, or BALANCED).
The system automatically falls back to the next best available rail without manual intervention. You'll receive a webhook notification about the rail change, but the payment continues seamlessly.
Yes, you can specify a preferred rail in your API request. The system will use that rail if available, or notify you if it's not possible for that corridor.
Stablecoins are automatically converted to the recipient's local currency at competitive exchange rates. The recipient receives fiat in their bank account or can opt to receive stablecoins directly.
Stablecoin rails: 15 seconds to 5 minutes. Local rails: Instant to 4 hours. SEPA: T+1. SWIFT: T+2 to T+5. Exact times depend on the specific corridor and rail.
For standard multi-rail routing, there's no minimum volume. However, access to certain premium corridors and custom routing strategies may require €500K+ monthly volume.
The Fundflow Dashboard provides detailed analytics showing cost savings compared to traditional SWIFT-only operations, broken down by corridor and rail type.
Currently, multi-rail routing is optimized for payouts. Collection (pay-in) support with intelligent routing is planned for Q3 2026.
***
## Next Steps
Start integrating multi-rail routing
Complete integration guide
Monitor rail performance
Discuss your use case
***
## Support
Questions about Multi-Rail Routing?
* **Contact**: [venlyfinance.com/contact](https://venlyfinance.com/contact)
* **Documentation**: [docs.venlyfinance.com](https://docs.venlyfinance.com)
* **API Status**: Check real-time rail availability
# Account Management
Source: https://docs.venlyfinance.com/guides/payments/accounts
Configure company bank accounts and crypto wallets that source and receive funds during Fundflow ramp requests.
## Overview
Fundflow requires you to set up both **bank accounts** and **crypto wallets** to facilitate on-ramp and off-ramp transactions:
For fiat currency transactions (EUR, USD, GBP)
For cryptocurrency transactions across multiple blockchains
**Both account types are required:**
* **On-Ramp** (Fiat → Crypto): Bank account → Crypto wallet
* **Off-Ramp** (Crypto → Fiat): Crypto wallet → Bank account
***
## Bank Accounts
### Supported Bank Account Types
Fundflow supports multiple payment networks across different regions:
| Type | Region | Description | Required Fields |
| ---------------- | -------------- | -------------------------- | ------------------------------------------ |
| **EUR\_SEPA** | Europe | SEPA transfers | IBAN, BIC |
| **USD\_WIRE** | United States | Wire transfers | Account number, Routing number |
| **USD\_ACH** | United States | ACH transfers | Account number, Routing number |
| **USD\_SWIFT** | United States | SWIFT transfers | BIC, Account number, Bank address |
| **GBP\_FPS** | United Kingdom | Faster Payments | Account number, Sort code |
| **GBP\_CHAPS** | United Kingdom | CHAPS transfers | Account number, Sort code |
| **OTHER\_SWIFT** | International | Other currencies via SWIFT | Currency code, BIC, IBAN or Account number |
### Adding a Bank Account
Use the [Create Company Bank Account](/api-reference/Fundflow-API/company-bank-accounts/create-a-company-bank-account) endpoint
Provide required information based on account type:
* Account holder details (company name, address)
* Bank details (name, country, account numbers)
* Contact information (email, phone)
* Supported ramp type (ON\_RAMP, OFF\_RAMP, or both)
Your bank account will be created with **PENDING** verification status
The Venly team will manually review and verify the account details
Once verified, the status changes to **VERIFIED** and the account can be used for transactions
Bank account verification is done manually to ensure security and compliance with financial regulations.
### Bank Account Requirements
* Account must be in your company's legal name
* Valid account numbers in the correct format for the account type
* Bank must be in a supported country
* Complete and accurate beneficiary address information
### Managing Bank Accounts
**List all bank accounts:**
```bash theme={null}
GET /v1/company-bank-accounts
```
**Get specific account:**
```bash theme={null}
GET /v1/company-bank-accounts/{id}
```
**Update account name:**
```bash theme={null}
PATCH /v1/company-bank-accounts/{id}
```
Updates use optimistic locking. Include the current `version` number to prevent concurrent modification conflicts.
***
## Crypto Wallets
### Supported Blockchain Networks
Fundflow supports wallets on the following blockchain networks:
* **Ethereum** (ETH, USDC, EURC, USDS)
* **Polygon** (POL)
* **Base**
* **Arbitrum**
* **Sui**
### Adding a Crypto Wallet
Use the [Create Company Wallet](/api-reference/Fundflow-API/company-wallets/create-a-company-wallet) endpoint
Provide:
* Wallet address (e.g., 0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb)
* Blockchain network (ETHEREUM, POLYGON, BASE, ARBITRUM, or SUI)
* Optional description for identification
Your wallet will be created with **PENDING** verification status
Complete the verification process to prove wallet ownership
Once verified, the status changes to **VERIFIED** and the wallet can be used for on-ramp transactions
### Managing Crypto Wallets
**List all wallets:**
```bash theme={null}
GET /v1/company-wallets
```
Filter by:
* Verification status (PENDING, VERIFIED, DENIED)
* Blockchain network
* Wallet address
**Get specific wallet:**
```bash theme={null}
GET /v1/company-wallets/{id}
```
**Update wallet description:**
```bash theme={null}
PATCH /v1/company-wallets/{id}
```
***
## Account Statuses
| Status | Meaning | Actions Available |
| ------------ | --------------------- | ---------------------------- |
| **PENDING** | Awaiting verification | Wait for review |
| **VERIFIED** | Ready to use | Can be used in ramp requests |
| **DENIED** | Verification failed | Review details and resubmit |
***
## Supported Ramp Types
When creating a bank account, specify which operations it supports:
* **ON\_RAMP**: Can receive fiat deposits (for buying crypto)
* **OFF\_RAMP**: Can send fiat withdrawals (for selling crypto)
* **ON\_AND\_OFF\_RAMP**: Supports both operations
Use descriptive names for your accounts like "EUR SEPA - Operations" or "Main Treasury Wallet" to easily identify them when creating ramp requests.
***
## API Reference
Manage company bank accounts
Manage company crypto wallets
View supported fiat currencies
View supported cryptocurrencies
***
## Best Practices
**Prepare Accounts Early**: Add and verify your bank accounts and wallets during your company onboarding process, before you need to create ramp requests.
**Multiple Accounts**: You can add multiple bank accounts and wallets to support different currencies and use cases.
**Security**: Never share private keys or seed phrases. Fundflow only needs your wallet address for verification.
***
## Next Steps
Start creating on-ramp and off-ramp transactions
Understand fee calculations
# API Authentication
Source: https://docs.venlyfinance.com/guides/payments/authentication
Authenticate with Venly Fundflow API using OAuth2 client credentials
## Overview
Venly Fundflow API uses **OAuth2 client credentials flow**. All API requests require a bearer token in the `Authorization` header.
***
## Get an Access Token
Send a `POST` request to the token endpoint for your environment:
| Environment | Endpoint |
| :---------- | :------------------------------------------------------------------------------------------- |
| Staging | `POST https://login-staging.venly.io/auth/realms/VenlyFinance/protocol/openid-connect/token` |
| Production | `POST https://login.venly.io/auth/realms/VenlyFinance/protocol/openid-connect/token` |
### Request Body
| Parameter | Value |
| :-------------- | :------------------- |
| `grant_type` | `client_credentials` |
| `client_id` | Your client ID |
| `client_secret` | Your client secret |
### Response
```json theme={null}
{
"access_token": "eyJhbGciOiJSUzI1NiIsIn......",
"expires_in": 300,
"refresh_expires_in": 0,
"token_type": "Bearer",
"not-before-policy": 0,
"scope": "email profile"
}
```
The response includes an `access_token` valid for **5 minutes** (300 seconds). Once expired, repeat the call above to get a new one.
***
## Use the Token
Pass the `access_token` as a bearer token in the `Authorization` header of every API call:
```bash theme={null}
curl -X GET https://api-fundflow.venly.io/v1/company \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json"
```
***
## Best Practices
* **Never** expose client secrets in client-side code, logs, or version control.
* Store credentials in environment variables or a secrets manager.
* Implement auto-refresh logic to request a new token before the current one expires.
# Dashboard
Source: https://docs.venlyfinance.com/guides/payments/dashboard
Fundflow API architecture — resource model, data types, response envelope, and the integration patterns that make production calls reliable.
## API Architecture
Fundflow API follows RESTful principles with a clear resource-based structure. All endpoints are accessible via the base URL:
```
https://api-fundflow.venly.io/v1
```
All requests require a Bearer token in the `Authorization` header. See [Authentication](/guides/payments/authentication) for how to obtain one.
For a full endpoint cheat sheet with examples, pagination, filtering, and status codes, see the [Quick Reference](/guides/payments/quick-reference).
***
## Data Types
### Common Fields
**Identifiers:**
* `id`: UUID format (e.g., `123e4567-e89b-12d3-a456-426614174000`)
**Timestamps:**
* `createdAt`, `updatedAt`, `verifiedAt`: ISO 8601 format (e.g., `2024-01-15T10:30:00Z`)
**Amounts:**
* Decimal numbers with up to 8 decimal places
* Minimum: 0.00000001
**Versions:**
* Integer for optimistic locking
* Increments with each update
***
## Best Practices
### Security
✅ **Do:**
* Store credentials securely (environment variables, vaults)
* Use HTTPS for all requests
* Implement token refresh logic
* Validate all input data
* Log API interactions for audit
❌ **Don't:**
* Expose credentials in client-side code
* Store tokens in version control
* Share access tokens between environments
* Ignore error responses
### Performance
✅ **Do:**
* Use pagination for large datasets
* Cache reference data
* Implement connection pooling
* Use webhooks for real-time updates
* Batch operations when possible
❌ **Don't:**
* Poll frequently for status updates
* Fetch all data without pagination
* Make unnecessary API calls
* Ignore rate limits
### Error Handling
✅ **Do:**
* Handle all HTTP status codes
* Implement retry logic with backoff
* Log errors for debugging
* Provide meaningful error messages to users
* Handle version conflicts gracefully
❌ **Don't:**
* Ignore error responses
* Retry indefinitely
* Expose technical errors to end users
* Skip validation
***
## Quick Reference
Integration guide
Full API docs
Bank accounts & wallets
Ramp requests
Fee structure
Security practices
***
## Support
Need help with the API?
* **Contact**: [venlyfinance.com/contact](https://venlyfinance.com/contact)
* **API Status**: Monitor system status for any issues
# Fee Structure
Source: https://docs.venlyfinance.com/guides/payments/fees
How Fundflow ramp fees are calculated — fee tiers, exchange-rate spreads, the calculate-fee endpoint, and what shows up on the invoice.
## Overview
Fundflow applies fees to both on-ramp and off-ramp transactions. Fees are **company-specific** and may include volume-based tiers to provide better rates for higher transaction volumes.
Applied when converting fiat to crypto
Applied when converting crypto to fiat
***
## Fee Structure
### How Fees Work
Fees are calculated as a **percentage** of the transaction amount and are deducted from the total:
* **On-Ramp**: Fee is deducted from the fiat amount before conversion
* **Off-Ramp**: Fee is deducted from the crypto amount before conversion
### Fee Components
Each ramp request includes detailed fee information:
| Field | Description |
| ------------------- | ---------------------------------- |
| **Fiat Amount** | Total fiat amount (including fees) |
| **Fiat Net Amount** | Net fiat after deducting fees |
| **Crypto Amount** | Cryptocurrency amount |
| **Fiat Fee Amount** | Fee amount in fiat currency |
| **Fee Percentage** | Percentage rate applied |
| **Exchange Rate** | Conversion rate used |
***
## Calculating Fees
### Using the API
Use the [Calculate Fee](/api-reference/Fundflow-API/fees/calculate-fee-for-a-ramp-request) endpoint to determine fees before creating a ramp request:
```bash theme={null}
POST /v1/fees/calculate
Content-Type: application/json
{
"amount": 1000.00,
"type": "ON_RAMP"
}
```
**Response:**
```json theme={null}
{
"success": true,
"result": {
"amount": 10.00,
"percentage": 1.0
}
}
```
### Calculation Examples
#### On-Ramp Example (1% fee)
```
Fiat Amount (sent): €1,000.00
Fee (1%): €10.00
Net Amount (converted to crypto): €990.00
Exchange Rate: 1 USDC = €1.00
Crypto Received: 990 USDC
```
#### Off-Ramp Example (1% fee)
```
Crypto Amount (sent): 1,000 USDC
Fee (1%): 10 USDC
Net Amount (converted to fiat): 990 USDC
Exchange Rate: 1 USDC = €1.00
Fiat Received: €990.00
```
***
## Volume Tiers
### Tiered Pricing
Companies may have volume-based fee tiers that provide lower rates for higher transaction volumes:
| Tier | Volume Range | Fee Percentage |
| ---------- | ----------------- | -------------- |
| **Tier 1** | €0 - €10,000 | 1.5% |
| **Tier 2** | €10,001 - €50,000 | 1.0% |
| **Tier 3** | €50,001+ | 0.75% |
Fee tiers are configured per company. [Contact Venly](https://venlyfinance.com/contact) to discuss custom pricing for your business needs.
### Viewing Your Fee Configuration
Use the [Get Company Fee Configuration](/api-reference/Fundflow-API/fees/get-company-fee-configuration) endpoint:
```bash theme={null}
GET /v1/fees
```
**Response:**
```json theme={null}
{
"success": true,
"result": [
{
"id": "fee-tier-1-id",
"companyId": "your-company-id",
"name": "Standard Tier",
"type": "ON_RAMP",
"minVolume": 0,
"maxVolume": 10000,
"percentage": 1.5,
"version": 1
},
{
"id": "fee-tier-2-id",
"companyId": "your-company-id",
"name": "Volume Tier",
"type": "ON_RAMP",
"minVolume": 10001,
"maxVolume": 50000,
"percentage": 1.0,
"version": 1
}
]
}
```
***
## Fee Application
### When Fees Are Applied
Fees are applied at different stages depending on the ramp type:
```mermaid theme={null}
flowchart LR
subgraph On["On-ramp (fiat → crypto)"]
A1[Customer sends fiat] --> B1[Fee deducted from fiat]
B1 --> C1[Convert remaining fiat at FX rate]
C1 --> D1[Crypto credited to wallet]
end
subgraph Off["Off-ramp (crypto → fiat)"]
A2[Customer sends crypto] --> B2[Fee deducted from crypto]
B2 --> C2[Convert remaining crypto at FX rate]
C2 --> D2[Fiat credited to bank]
end
```
In both directions the fee is taken in the **input** currency, before conversion.
**On-Ramp:**
1. Fiat is sent to Venly deposit account
2. Fee is deducted from the fiat amount
3. Net amount is converted to crypto at current exchange rate
4. Crypto is sent to company wallet
**Off-Ramp:**
1. Crypto is sent to Venly deposit wallet
2. Fee is deducted from the crypto amount
3. Net amount is converted to fiat at current exchange rate
4. Fiat is sent to company bank account
### Fee Transparency
All fee information is clearly displayed in the ramp request:
```json theme={null}
{
"id": "ramp-request-id",
"rampType": "ON_RAMP",
"fiatAmount": 1000.00,
"fiatNetAmount": 990.00,
"fiatFeeAmount": 10.00,
"feePercentage": 1.0,
"cryptoAmount": 990.00,
"exchangeRate": 1.0,
...
}
```
***
## Exchange Rates
### How Rates Are Determined
Exchange rates are determined at the time of conversion and reflect current market conditions:
* Rates are sourced from reliable market data providers
* Rates include a small spread to account for market volatility
* Rates are locked when the transaction enters PROCESSING status
### Rate Visibility
The exchange rate used for each transaction is included in the ramp request details:
```bash theme={null}
GET /v1/ramp-requests/{id}
```
```json theme={null}
{
"exchangeRate": 1.0012,
"fiatAmount": 1000.00,
"cryptoAmount": 998.80,
...
}
```
Exchange rates may fluctuate between request creation and processing. The final rate is determined when the payment is received and conversion begins.
***
## Best Practices
### Before Creating Requests
**Calculate Fees First**: Always use the fee calculation endpoint before creating large ramp requests to understand the total cost.
**Check Volume Tiers**: If you're close to a tier threshold, consider batching transactions to benefit from lower fees.
### Optimizing Costs
**Batch Transactions**: Combine multiple smaller transactions into larger ones to potentially benefit from volume tier pricing.
**Plan Ahead**: Schedule large transactions during periods of lower market volatility to minimize exchange rate risk.
### Transparency
**Review Breakdowns**: Always review the complete fee and amount breakdown before approving ramp requests.
**Export Records**: Use the export functionality to maintain detailed records for accounting and tax purposes.
***
## Fee-Related API Endpoints
Calculate fees for a specific amount
View your company's fee tiers
Create a new transaction
Export transaction records
***
## Understanding Your Invoice
### What's Included
Your Fundflow invoice includes:
* Total transaction volume for the billing period
* Number of transactions processed
* Total fees collected
* Breakdown by transaction type (on-ramp vs off-ramp)
### Accessing Invoices
View your invoices through the company details:
```bash theme={null}
GET /v1/company
```
```json theme={null}
{
"success": true,
"result": {
"id": "company-id",
"name": "Your Company",
"invoicesUrl": "https://portal.venly.io/invoices",
...
}
}
```
***
## Custom Pricing
### Enterprise Pricing
For high-volume businesses, Venly offers custom pricing arrangements:
* **Volume Discounts**: Lower fees for consistent high-volume usage
* **Custom Tiers**: Tailored tier structures for your business model
* **Fixed Pricing**: Predictable costs for budgeting purposes
[Contact Venly](https://venlyfinance.com/contact) to discuss enterprise pricing options for your business.
***
## Frequently Asked Questions
Fees can be configured differently for on-ramp and off-ramp operations. Check your fee configuration to see the specific rates for each type.
Yes, companies with high transaction volumes can [contact Venly](https://venlyfinance.com/contact) to discuss custom pricing arrangements.
No. All fees are transparently displayed in the fee calculation and ramp request details. The only costs are the percentage-based fees shown.
Exchange rates are updated in real-time based on market conditions. The rate used for your transaction is locked when processing begins.
The exchange rate is locked when your transaction enters PROCESSING status (after payment is received). Any rate changes before that point will be reflected in the final conversion.
If a transaction fails before processing begins, no fees are charged. If it fails during processing, [contact us](https://venlyfinance.com/contact) to review the specific case.
***
## Next Steps
Start creating transactions
Set up bank accounts and wallets
Understand key terms
# Getting Started with Fundflow
Source: https://docs.venlyfinance.com/guides/payments/getting-started
End-to-end guide to integrate Fundflow — authentication, creating ramp requests, settlement, and going live with the on-ramp/off-ramp API.
## What is Fundflow?
Fundflow is Venly's enterprise API platform that enables businesses to seamlessly convert between traditional fiat currency and cryptocurrency through a comprehensive REST API.
Convert fiat to cryptocurrency via API
Convert cryptocurrency to fiat via API
## Key Features
### 🔒 Enterprise-Grade Security
* OAuth2 authentication
* KYB (Know Your Business) verification
* Optimistic locking for concurrent updates
* Wallet ownership verification
* Role-based access control
### 💰 Transparent Pricing
* Company-specific fee tiers
* Volume-based discounts
* Real-time fee calculation API
* Clear exchange rates
### 🌍 Multi-Currency Support
**Fiat Currencies:** EUR, USD, GBP
**Payment Networks:**
* EUR\_SEPA (European SEPA transfers)
* USD\_WIRE, USD\_ACH, USD\_SWIFT (US transfers)
* GBP\_FPS, GBP\_CHAPS (UK transfers)
* OTHER\_SWIFT (International transfers)
**Cryptocurrencies:**
* USDC (Ethereum)
* EURC (Ethereum)
* USDS (Ethereum)
* ETH (Ethereum)
* POL (Polygon)
**Blockchain Networks:**
* Ethereum
* Polygon
* Base
* Arbitrum
* Sui
***
## Prerequisites
Before you begin, ensure you have:
✅ **Company Account**: [Contact Venly](https://venlyfinance.com/contact) to set up your company account\
✅ **OAuth2 Credentials**: Client ID and secret for authentication\
✅ **API Access**: Staging: `https://api-fundflow-staging.venly.io/v1` · Production: `https://api-fundflow.venly.io/v1`\
✅ **Development Environment**: REST API client or SDK
***
## Integration Steps
```mermaid theme={null}
flowchart TD
A[Company onboarded] --> B[POST /company-bank-accounts]
B --> C{Bank account VERIFIED?}
C -- No --> C
C -- Yes --> D[POST /company-wallets]
D --> E{Wallet VERIFIED?}
E -- No --> E
E -- Yes --> F{Direction?}
F -- On-ramp --> G[POST /ramp-requests rampType=ON_RAMP]
F -- Off-ramp --> H[POST /ramp-requests rampType=OFF_RAMP]
G --> I[Approve → AWAITING_FUNDS]
H --> I
I --> J[Transaction lifecycle
see transactions guide]
```
Obtain an OAuth2 access token from Venly Identity Platform
```bash theme={null}
POST https://login-staging.venly.io/auth/realms/VenlyFinance/protocol/openid-connect/token
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials
&client_id=YOUR_CLIENT_ID
&client_secret=YOUR_CLIENT_SECRET
```
Use the access token in all API requests:
```bash theme={null}
Authorization: Bearer YOUR_ACCESS_TOKEN
```
Check your company's KYB verification status
```bash theme={null}
GET /v1/company
```
**Response:**
```json theme={null}
{
"success": true,
"result": {
"id": "company-id",
"name": "Your Company",
"kybStatus": "VERIFIED",
"invoicesUrl": "https://portal.venly.io/invoices"
}
}
```
Your company must have `kybStatus: "VERIFIED"` to create ramp requests.
Register company bank accounts for fiat transactions
```bash theme={null}
POST /v1/company-bank-accounts
Content-Type: application/json
{
"bankAccountType": "EUR_SEPA",
"name": "Primary EUR Account",
"bankName": "Deutsche Bank",
"companyName": "Your Company Ltd",
"iban": "DE89370400440532013000",
"bic": "COBADEFFXXX",
"bankCountry": "DE",
"beneficiaryAddressLine1": "123 Main Street",
"beneficiaryCity": "Berlin",
"beneficiaryPostalCode": "10115",
"beneficiaryCountry": "DE",
"supportedRampType": "ON_AND_OFF_RAMP"
}
```
**Status Flow:** PENDING → VERIFIED (manual review by Venly)
Bank accounts require manual verification. This process may take 1-2 business days.
Register company cryptocurrency wallets
```bash theme={null}
POST /v1/company-wallets
Content-Type: application/json
{
"address": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
"chain": "ETHEREUM",
"description": "Main treasury wallet"
}
```
**Status Flow:** PENDING → VERIFIED
Complete the verification process to prove wallet ownership.
Retrieve supported currency pairs for your operations
**For On-Ramp:**
```bash theme={null}
GET /v1/ramp-requests/on-ramp/pairs
```
**For Off-Ramp:**
```bash theme={null}
GET /v1/ramp-requests/off-ramp/pairs
```
**Response:**
```json theme={null}
{
"success": true,
"result": [
{
"from": {
"id": "eur-id",
"currency": "EUR",
"label": "Euro"
},
"to": {
"id": "usdc-id",
"currency": "USDC",
"chain": "ETHEREUM",
"label": "USD Coin"
}
}
]
}
```
Calculate fees before creating ramp requests
```bash theme={null}
POST /v1/fees/calculate
Content-Type: application/json
{
"amount": 1000.00,
"type": "ON_RAMP"
}
```
**Response:**
```json theme={null}
{
"success": true,
"result": {
"amount": 10.00,
"percentage": 1.0
}
}
```
Create on-ramp or off-ramp transactions
**On-Ramp Example:**
```bash theme={null}
POST /v1/ramp-requests
Content-Type: application/json
{
"rampType": "ON_RAMP",
"amount": 1000.00,
"fiatCurrencyId": "eur-currency-id",
"cryptoCurrencyId": "usdc-ethereum-id",
"companyWalletId": "your-wallet-id"
}
```
**Off-Ramp Example:**
```bash theme={null}
POST /v1/ramp-requests
Content-Type: application/json
{
"rampType": "OFF_RAMP",
"amount": 0.5,
"cryptoCurrencyId": "usdc-ethereum-id",
"fiatCurrencyId": "eur-currency-id",
"companyBankAccountId": "your-bank-account-id"
}
```
Request is created in **AWAITING\_APPROVAL** status.
Approve the ramp request to proceed
```bash theme={null}
POST /v1/ramp-requests/{id}/approve
Content-Type: application/json
{
"version": 1
}
```
Status changes to **AWAITING\_FUNDS**.
* **On-Ramp**: Customer sends fiat to provided deposit bank account
* **Off-Ramp**: Customer sends crypto to provided deposit wallet
Poll or use webhooks to monitor ramp request status
```bash theme={null}
GET /v1/ramp-requests/{id}
```
**Status Flow:**
```
AWAITING_APPROVAL → AWAITING_FUNDS → PROCESSING → SUCCEEDED
```
***
## User Management
### Invite Users
```bash theme={null}
POST /v1/company/users/invite
Content-Type: application/json
{
"email": "user@example.com",
"role": "COMPANY_MANAGER",
"firstName": "John",
"lastName": "Doe"
}
```
### User Roles
| Role | Permissions |
| -------------------- | ------------------------------------- |
| **COMPANY\_ADMIN** | Full access including user management |
| **COMPANY\_MANAGER** | Create and manage ramp requests |
| **COMPANY\_VIEWER** | Read-only access |
### Update User Role
```bash theme={null}
PUT /v1/company/users/{userId}/role
Content-Type: application/json
{
"role": "COMPANY_ADMIN"
}
```
***
## Best Practices
### Authentication
**Token Management**: Implement token refresh logic to handle expired tokens gracefully.
```javascript theme={null}
// Example: Token refresh logic
async function getAccessToken() {
if (tokenExpired()) {
return await refreshToken();
}
return currentToken;
}
```
### Error Handling
**Optimistic Locking**: Always handle HTTP 409 conflicts by fetching the latest version and retrying.
```javascript theme={null}
async function updateResource(id, data) {
try {
return await api.patch(`/resource/${id}`, data);
} catch (error) {
if (error.status === 409) {
// Fetch latest version and retry
const latest = await api.get(`/resource/${id}`);
data.version = latest.version;
return await api.patch(`/resource/${id}`, data);
}
throw error;
}
}
```
### Pagination
**Efficient Pagination**: Use appropriate page sizes and implement cursor-based pagination for large datasets.
```bash theme={null}
GET /v1/ramp-requests?page=1&size=50&sortOn=createdAt&sortOrder=DESC
```
### Webhooks
**Real-time Updates**: Configure webhooks for real-time notifications instead of polling.
Configure webhooks to receive notifications for:
* Ramp request status changes
* Payment received confirmations
* Transaction completions
***
## Testing
### Staging Environment
Use the staging environment for testing:
* Test OAuth2 authentication
* Create test ramp requests
* Verify webhook integrations
* Test error scenarios
### Test Scenarios
1. **Successful On-Ramp**: Create, approve, and complete an on-ramp request
2. **Successful Off-Ramp**: Create, approve, and complete an off-ramp request
3. **Cancellation**: Create and cancel a ramp request
4. **Rejection**: Create and reject a ramp request
5. **Version Conflict**: Test optimistic locking behavior
***
## Common Integration Patterns
### Pattern 1: Automated On-Ramp
```javascript theme={null}
// 1. Create ramp request
const request = await createRampRequest({
rampType: 'ON_RAMP',
amount: 1000,
fiatCurrencyId: eurId,
cryptoCurrencyId: usdcId,
companyWalletId: walletId
});
// 2. Auto-approve if within limits
if (request.amount <= autoApprovalLimit) {
await approveRampRequest(request.id, request.version);
}
// 3. Monitor status via webhook
// Webhook handler will process status updates
```
### Pattern 2: Batch Processing
```javascript theme={null}
// Process multiple ramp requests efficiently
const requests = await listRampRequests({
status: 'AWAITING_APPROVAL',
page: 1,
size: 100
});
for (const request of requests.result) {
if (shouldApprove(request)) {
await approveRampRequest(request.id, request.version);
}
}
```
***
## Security Considerations
**Never expose:**
* OAuth2 client secrets
* Access tokens in client-side code
* Private keys or seed phrases
* API credentials in version control
### Secure Storage
* Store credentials in environment variables or secure vaults
* Use HTTPS for all API communications
* Implement proper access controls
* Rotate credentials regularly
### API Scopes
Request only the OAuth2 scopes you need:
* `view:ramp-request` - View ramp requests
* `create:ramp-request` - Create ramp requests
* `approve:ramp-request` - Approve ramp requests
* `manage:company-wallet` - Manage wallets
* `manage:company-bank-account` - Manage bank accounts
***
## Next Steps
Explore full API documentation
Manage bank accounts & wallets
Create and manage ramp requests
Understand fee structure
Security best practices
Quick API overview
Understand how payments are automatically routed across rails
***
## Support
Need help with integration?
* **Contact**: [venlyfinance.com/contact](https://venlyfinance.com/contact)
* **API Status**: Check system status for any ongoing issues
# Glossary
Source: https://docs.venlyfinance.com/guides/payments/glossary
Definitions for ramp requests, fees, KYC/KYB, on-ramp, off-ramp, and other Fundflow concepts you'll see in the docs and dashboard.
## Platform Terms
### 2FA (Two-Factor Authentication)
Security feature requiring password plus time-based code from authenticator app.
### Account Verification
Process of confirming ownership of bank accounts or wallets.
### Business Approval
KYB verification confirming business legitimacy before full platform access.
### Dashboard
Main overview page showing metrics, account status, and quick actions.
## Transaction Terms
### On-Ramp
Converting fiat currency into cryptocurrency.
### Off-Ramp
Converting cryptocurrency into fiat currency.
### Reference Code
Unique identifier for on-ramp transactions that must be included in bank transfers.
### Transaction ID
Unique identifier for any transaction in the platform.
### Transaction Status
Current state of a ramp request: `AWAITING_APPROVAL`, `AWAITING_FUNDS`, `PROCESSING`, `SUCCEEDED`, `FAILED`, `CANCELLED`, `REJECTED`, `DENIED`, `BLOCKED`.
## Banking Terms
### IBAN
International Bank Account Number - standardized bank account identifier.
### Bank Transfer
Moving money from one bank account to another.
### Beneficiary
The person or business receiving a bank transfer.
## Blockchain & Crypto Terms
### Blockchain
Distributed digital ledger that records cryptocurrency transactions.
### Wallet
Digital account for storing, sending, and receiving cryptocurrency.
### Wallet Address
Unique identifier for a crypto wallet, starting with 0x followed by 40 characters.
### Private Key
Secret code proving wallet ownership. Never share this.
### Seed Phrase
Recovery phrase for a wallet. Never share this.
### Gas Fees
Transaction fees paid to blockchain validators.
### Blockchain Network
The specific blockchain infrastructure (Ethereum, Polygon, etc.).
### Confirmation
Validation of a transaction on the blockchain.
## Cryptocurrency Terms
### Stablecoin
Cryptocurrency pegged to a stable asset to minimize price volatility.
### USDC (USD Coin)
Stablecoin pegged to USD, issued by Circle.
### EURC (Euro Coin)
Stablecoin pegged to EUR.
### ETH (Ethereum)
Native cryptocurrency of the Ethereum blockchain.
### POL (Polygon)
Native cryptocurrency of the Polygon network.
## Compliance Terms
### KYB (Know Your Business)
Verification process to confirm business identity and legitimacy.
### KYC (Know Your Customer)
Identity verification process for individuals.
### AML (Anti-Money Laundering)
Regulations to prevent money laundering.
### Compliance Monitoring
Automated checks on transactions to ensure regulatory compliance.
## Exchange Terms
### Exchange Rate
Ratio at which one currency converts to another.
### Rate Lock
Exchange rate is fixed when transaction is confirmed.
## Status Terms
### Verified
Account passed verification and is ready to use.
### Active
Account is operational and ready for transactions.
### Pending
Awaiting review, confirmation, or processing.
### Failed
Transaction or verification encountered an error.
### In Progress
Process is currently being reviewed.
## Abbreviations
| Abbreviation | Full Term |
| ------------ | --------------------------------- |
| 2FA | Two-Factor Authentication |
| AML | Anti-Money Laundering |
| IBAN | International Bank Account Number |
| KYB | Know Your Business |
| KYC | Know Your Customer |
| EUR | Euro |
| USD | United States Dollar |
| GBP | British Pound |
| ETH | Ethereum |
| POL | Polygon |
## Support Contacts
* **Contact us**: [venlyfinance.com/contact](https://venlyfinance.com/contact)
* **Platform**: [venlyfinance.com](https://venlyfinance.com)
## Still Have Questions?
Explore documentation
Get in touch with our team
# Quick Reference Guide
Source: https://docs.venlyfinance.com/guides/payments/quick-reference
Cheat sheet for Fundflow — base URLs, auth flow, ramp request lifecycle, and the most-used endpoints on a single page.
## Platform Overview
Venly Fundflow enables businesses to convert between fiat and crypto through a comprehensive API with enterprise-grade security and compliance.
## Key Concepts
Fiat → Crypto conversion
Crypto → Fiat conversion
## Supported Currencies
### Fiat Currencies
**EUR, USD, GBP** - via multiple payment networks (SEPA, ACH, SWIFT, FPS, CHAPS)
### Cryptocurrencies
* **USDC** (Ethereum)
* **EURC** (Ethereum)
* **USDS** (Ethereum)
* **ETH** (Ethereum)
* **POL** (Polygon)
### Blockchain Networks
Ethereum, Polygon, Base, Arbitrum, Sui
## Quick Start Flow
Obtain OAuth2 access token via Venly Identity Platform
Verify company KYB status: `GET /v1/company`
Create company bank accounts: `POST /v1/company-bank-accounts`
Status: PENDING → VERIFIED (manual review)
Register company wallets: `POST /v1/company-wallets`
Status: PENDING → VERIFIED
Create on-ramp or off-ramp: `POST /v1/ramp-requests`
## Ramp Request Lifecycle
```
AWAITING_APPROVAL → AWAITING_FUNDS → PROCESSING → SUCCEEDED
↓ ↓
CANCELLED REJECTED
REJECTED DENIED
DENIED BLOCKED
BLOCKED
```
## Bank Account Types
| Type | Region | Required Fields |
| ---------------- | ------------- | ----------------------------- |
| **EUR\_SEPA** | Europe | IBAN, BIC |
| **USD\_WIRE** | US | Account #, Routing # |
| **USD\_ACH** | US | Account #, Routing # |
| **USD\_SWIFT** | US | BIC, Account #, Bank address |
| **GBP\_FPS** | UK | Account #, Sort code |
| **GBP\_CHAPS** | UK | Account #, Sort code |
| **OTHER\_SWIFT** | International | Currency, BIC, IBAN/Account # |
## Common API Endpoints
### Authentication
```bash theme={null}
# Staging token endpoint
POST https://login-staging.venly.io/auth/realms/VenlyFinance/protocol/openid-connect/token
# Production token endpoint
POST https://login.venly.io/auth/realms/VenlyFinance/protocol/openid-connect/token
```
### Company & Users
```bash theme={null}
GET /v1/company
GET /v1/company/users
POST /v1/company/users/invite
```
### Bank Accounts
```bash theme={null}
GET /v1/company-bank-accounts
POST /v1/company-bank-accounts
GET /v1/company-bank-accounts/{id}
PATCH /v1/company-bank-accounts/{id}
```
### Crypto Wallets
```bash theme={null}
GET /v1/company-wallets
POST /v1/company-wallets
GET /v1/company-wallets/{id}
PATCH /v1/company-wallets/{id}
```
### Ramp Requests
```bash theme={null}
GET /v1/ramp-requests
POST /v1/ramp-requests
GET /v1/ramp-requests/{id}
POST /v1/ramp-requests/{id}/approve
POST /v1/ramp-requests/{id}/reject
POST /v1/ramp-requests/{id}/cancel
PUT /v1/ramp-requests/{id}/amount
PATCH /v1/ramp-requests/{id}/tx-hash
```
### Currency Pairs
```bash theme={null}
GET /v1/ramp-requests/on-ramp/pairs
GET /v1/ramp-requests/off-ramp/pairs
```
### Fees
```bash theme={null}
GET /v1/fees
POST /v1/fees/calculate
```
### Reference Data
```bash theme={null}
GET /v1/fiat-currencies
GET /v1/crypto-currencies
GET /v1/chains
GET /v1/bank-accounts/config
```
## On-Ramp Example
```bash theme={null}
# 1. Get available pairs
GET /v1/ramp-requests/on-ramp/pairs
# 2. Create request
POST /v1/ramp-requests
{
"rampType": "ON_RAMP",
"amount": 1000.00,
"fiatCurrencyId": "eur-id",
"cryptoCurrencyId": "usdc-id",
"companyWalletId": "wallet-id"
}
# 3. Approve request
POST /v1/ramp-requests/{id}/approve
{
"version": 1
}
# 4. Send fiat from company bank account to Venly deposit account
# (use depositBankAccount details from response + paymentReference)
# 5. System processes and sends crypto to company wallet
```
## Off-Ramp Example
```bash theme={null}
# 1. Get available pairs
GET /v1/ramp-requests/off-ramp/pairs
# 2. Create request
POST /v1/ramp-requests
{
"rampType": "OFF_RAMP",
"amount": 1000,
"cryptoCurrencyId": "usdc-id",
"fiatCurrencyId": "eur-id",
"companyBankAccountId": "bank-id"
}
# 3. Approve request
POST /v1/ramp-requests/{id}/approve
{
"version": 1
}
# 4. Send crypto from company wallet to Venly deposit wallet
# (use depositWallet address from response)
# 5. Add transaction hash
PATCH /v1/ramp-requests/{id}/tx-hash
{
"blockchainTransactionHash": "0x...",
"version": 2
}
# 6. System processes and sends fiat to company bank account
```
## User Roles
| Role | Permissions |
| -------------------- | ----------------------------- |
| **COMPANY\_ADMIN** | Full access + user management |
| **COMPANY\_MANAGER** | Create/manage ramp requests |
| **COMPANY\_VIEWER** | Read-only access |
## Optimistic Locking
All update operations require a `version` field:
```json theme={null}
{
"version": 1,
// ... other fields
}
```
**Version conflict (HTTP 409)?** → Fetch latest version and retry
## Status Codes
| Code | Meaning |
| ------- | ---------------- |
| **200** | Success |
| **201** | Created |
| **400** | Bad Request |
| **401** | Unauthorized |
| **403** | Forbidden |
| **404** | Not Found |
| **409** | Version Conflict |
| **500** | Server Error |
## Pagination
```bash theme={null}
GET /v1/ramp-requests?page=1&size=50&sortOn=createdAt&sortOrder=DESC
```
**Response includes:**
* `pagination`: Page info
* `sort`: Sort configuration
* `result`: Array of items
## Filtering
```bash theme={null}
# Filter ramp requests
GET /v1/ramp-requests?rampType=ON_RAMP&status=AWAITING_APPROVAL&fromDate=2024-01-01&toDate=2024-12-31
# Filter wallets
GET /v1/company-wallets?chain=ETHEREUM&verificationStatus=VERIFIED
# Filter bank accounts
GET /v1/company-bank-accounts?verificationStatus=VERIFIED
```
## Security Best Practices
**Never expose:**
* OAuth2 access tokens
* Client secrets
* Private keys
* Seed phrases
✅ **Do:**
* Use OAuth2 with appropriate scopes
* Implement token refresh
* Store credentials securely
* Use HTTPS only
* Validate webhook signatures
## Common Issues
**Version conflict (409)?**
→ Fetch latest resource and retry with new version
**Request stuck in AWAITING\_FUNDS?**
→ Verify payment was sent with correct reference
**Wallet verification failed?**
→ Check verification process requirements
**Cannot create ramp request?**
→ Ensure company KYB is VERIFIED and accounts are VERIFIED
## Rate Limits
Follow standard API rate limiting practices:
* Implement exponential backoff
* Cache reference data
* Use pagination efficiently
## Webhooks
Configure webhooks for real-time updates on:
* Ramp request status changes
* Payment received notifications
* Transaction completions
## Quick Links
Complete setup guide
Full API documentation
Bank accounts & wallets
Ramp requests guide
Fee structure
Security best practices
## Support
**Need help?** [Contact us](https://venlyfinance.com/contact)
# Security & Best Practices
Source: https://docs.venlyfinance.com/guides/payments/security
Credential management, token security, and defensive patterns for Fundflow API integrations
## Credentials
Your **Client ID** and **Client Secret** are the root of access to both APIs. Treat them like passwords.
Never hard-code credentials in source code, commit them to version control, or include them in client-side bundles. A leaked secret provides full API access under your account.
**Do:**
* Store credentials in environment variables (`CLIENT_ID`, `CLIENT_SECRET`)
* Use a secrets manager (AWS Secrets Manager, HashiCorp Vault, Azure Key Vault) in production
* Rotate secrets on a regular schedule and immediately if a leak is suspected
* Use separate credentials for staging and production
**Don't:**
* Log credential values anywhere
* Pass secrets through URL query parameters
* Share credentials between team members — provision individual service accounts where possible
***
## Token Security
Access tokens are short-lived (5 minutes) Bearer tokens. They are equivalent to session credentials.
* Never log token values — they grant full API access for their lifetime
* Do not store tokens persistently (database, disk) — request a fresh one as needed
* After a `401 Unauthorized` response, re-authenticate once and retry; do not retry indefinitely
* Use HTTPS on all requests — tokens sent over plain HTTP can be intercepted
***
## Transport Security
All API and token endpoint traffic must use **HTTPS**. The endpoints enforce TLS — plain HTTP connections are rejected.
Verify your HTTP client does not disable certificate validation. Disabling it (e.g. `verify=False` in Python requests) exposes you to man-in-the-middle attacks in production.
***
## Optimistic Locking
Fundflow uses **optimistic locking** to prevent race conditions on shared resources. Every mutable resource carries a `version` integer.
Include the current `version` on all update requests:
```json theme={null}
{
"version": 2,
"amount": 1500.00
}
```
If two processes update the same resource concurrently, the second write returns **HTTP 409 Conflict**:
```json theme={null}
{
"success": false,
"errors": [{
"code": "OPTIMISTIC_LOCK_EXCEPTION",
"message": "The resource has been modified. Please fetch the latest version and retry."
}]
}
```
On a 409, fetch the resource again to get the latest `version`, apply your changes, and retry.
***
## Idempotency (Finance API)
Relevant Finance API endpoints accept an `idempotencyKey` field in the request body — a UUID you generate per request:
```json theme={null}
{
"idempotencyKey": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"...": "other fields"
}
```
Use a fresh UUID for each new logical operation. On a network failure, retry with the **same key** — the API returns the original response without creating a duplicate.
Re-using a key with a different request body returns **HTTP 422**.
***
## Environment Isolation
Never mix staging and production credentials or base URLs. Maintain separate configuration for each environment and gate the switch explicitly — do not infer the environment from other runtime state.
```bash theme={null}
# Staging
TOKEN_URL=https://login-staging.venly.io/auth/realms/VenlyFinance/protocol/openid-connect/token
FUNDFLOW_BASE_URL=https://api-fundflow-staging.venly.io/v1
FINANCE_BASE_URL=https://api-staging.venlyfinance.com/v1
# Production
TOKEN_URL=https://login.venly.io/auth/realms/VenlyFinance/protocol/openid-connect/token
FUNDFLOW_BASE_URL=https://api-fundflow.venly.io/v1
FINANCE_BASE_URL=https://api.venlyfinance.com/v1
```
***
## Audit Logging
Log the following for every API call your system makes:
* Timestamp
* HTTP method and path (no query strings containing sensitive data)
* HTTP status code
* Request ID from the response (if present)
* Duration
Do **not** log request bodies containing credentials, tokens, or PII.
***
## Reporting Security Issues
**Contact:** [venlyfinance.com/contact](https://venlyfinance.com/contact) — response within 2 hours for security issues.
API error codes and common fixes
Token management and refresh patterns
# Transactions
Source: https://docs.venlyfinance.com/guides/payments/transactions
Create, approve, and track Fundflow ramp requests — the lifecycle of an on-ramp or off-ramp transaction from initiation to settlement.
## Overview
Ramp requests are the core transactions in Fundflow that enable conversion between fiat currencies and cryptocurrencies.
**Fiat → Crypto**: Convert fiat currency to cryptocurrency
**Crypto → Fiat**: Convert cryptocurrency to fiat currency
***
## Prerequisites
Before creating ramp requests, ensure you have:
✅ **Company verified** (KYB completed)\
✅ **Bank account verified** (for receiving/sending fiat)\
✅ **Crypto wallet verified** (for receiving/sending crypto)\
✅ **Appropriate user role** (COMPANY\_ADMIN or COMPANY\_MANAGER)
***
## Ramp Request Lifecycle
### Status Flow
```mermaid theme={null}
graph LR
A[AWAITING_APPROVAL] --> B[AWAITING_FUNDS]
A --> C[CANCELLED]
A --> D[REJECTED]
A --> E[DENIED]
A --> F[BLOCKED]
B --> G[PROCESSING]
G --> H[SUCCEEDED]
G --> I[FAILED]
```
| Status | Description | Next Actions |
| ---------------------- | ---------------------------------------- | ---------------------------------------------- |
| **AWAITING\_APPROVAL** | Request created, pending approval | Approve, Reject, or Cancel |
| **AWAITING\_FUNDS** | Approved, waiting for payment | Customer sends payment |
| **PROCESSING** | Payment received, conversion in progress | Wait for completion |
| **SUCCEEDED** | Transaction completed successfully | None |
| **FAILED** | Transaction failed | Review and retry |
| **CANCELLED** | Cancelled by requester | None |
| **REJECTED** | Rejected by company admin | None |
| **DENIED** | Denied by Venly admin | [Contact us](https://venlyfinance.com/contact) |
| **BLOCKED** | Blocked by Venly admin | [Contact us](https://venlyfinance.com/contact) |
### On-Ramp Lifecycle
The actor sequence that drives an on-ramp request from creation to settlement:
```mermaid theme={null}
sequenceDiagram
autonumber
participant Dev as Your App
participant API as Fundflow API
participant Customer
participant Chain as Crypto Network
Dev->>API: POST /ramp-requests (rampType=ON_RAMP)
API-->>Dev: rampRequestId, status=AWAITING_APPROVAL
Dev->>API: POST /ramp-requests/{id}/approve
API-->>Dev: status=AWAITING_FUNDS, bankReference
Customer->>API: SEPA/wire transfer with bankReference
API->>API: Match reference, convert at FX rate
API->>Chain: Send crypto to company wallet
API-->>Dev: status=SUCCEEDED, txHash
```
### Off-Ramp Lifecycle
The actor sequence for an off-ramp request — note the developer-provided `blockchainTransactionHash` step:
```mermaid theme={null}
sequenceDiagram
autonumber
participant Dev as Your App
participant API as Fundflow API
participant Chain as Blockchain
participant Bank as SEPA/SWIFT
Dev->>API: POST /ramp-requests (rampType=OFF_RAMP)
API-->>Dev: rampRequestId, status=AWAITING_APPROVAL
Dev->>API: POST /ramp-requests/{id}/approve
API-->>Dev: status=AWAITING_FUNDS, depositAddress
Dev->>Chain: Send crypto to depositAddress
Dev->>API: PATCH /ramp-requests/{id}/tx-hash
Chain->>API: On-chain confirmation
API->>API: Convert at FX rate
API->>Bank: Fiat credit to company bank
API-->>Dev: status=SUCCEEDED
```
***
## Creating On-Ramp Requests
### Process Overview
Use the [Create Ramp Request](/api-reference/Fundflow-API/ramp-requests/create-a-new-ramp-request) endpoint
```json theme={null}
{
"rampType": "ON_RAMP",
"amount": 1000.00,
"fiatCurrencyId": "uuid-of-eur",
"cryptoCurrencyId": "uuid-of-usdc",
"companyWalletId": "uuid-of-your-wallet"
}
```
The request is created in **AWAITING\_APPROVAL** status
Use the [Approve Ramp Request](/api-reference/Fundflow-API/ramp-requests/approve-a-ramp-request) endpoint
Status changes to **AWAITING\_FUNDS**
You'll receive deposit bank account details with a unique payment reference
Transfer the fiat amount to the provided Venly deposit bank account
**Important**: Include the payment reference in your bank transfer
Once Venly receives the payment, status changes to **PROCESSING**
The system converts fiat to crypto at the current exchange rate
Crypto is sent to your company wallet
Status changes to **SUCCEEDED**
**Always include the payment reference** in your bank transfer. This ensures proper matching of your payment to the ramp request.
### On-Ramp Example
```bash theme={null}
# 1. Get available currency pairs
GET /v1/ramp-requests/on-ramp/pairs
# 2. Create on-ramp request
POST /v1/ramp-requests
{
"rampType": "ON_RAMP",
"amount": 1000.00,
"fiatCurrencyId": "eur-currency-id",
"cryptoCurrencyId": "usdc-ethereum-id",
"companyWalletId": "your-wallet-id"
}
# 3. Approve the request
POST /v1/ramp-requests/{id}/approve
{
"version": 1
}
# 4. Customer sends EUR 1000 to deposit account with payment reference
# 5. System processes and sends USDC to company wallet
```
***
## Creating Off-Ramp Requests
### Process Overview
Use the [Create Ramp Request](/api-reference/Fundflow-API/ramp-requests/create-a-new-ramp-request) endpoint
```json theme={null}
{
"rampType": "OFF_RAMP",
"amount": 0.5,
"cryptoCurrencyId": "uuid-of-usdc",
"fiatCurrencyId": "uuid-of-eur",
"companyBankAccountId": "uuid-of-your-bank-account"
}
```
The request is created in **AWAITING\_APPROVAL** status
Use the [Approve Ramp Request](/api-reference/Fundflow-API/ramp-requests/approve-a-ramp-request) endpoint
Status changes to **AWAITING\_FUNDS**
You'll receive the Venly deposit wallet address
Transfer the crypto amount from your company wallet to the Venly deposit wallet
Use the [Update Transaction Hash](/api-reference/Fundflow-API/ramp-requests/update-transaction-hash) endpoint
```json theme={null}
{
"blockchainTransactionHash": "0x1234...",
"version": 2
}
```
Once blockchain confirms the transaction, status changes to **PROCESSING**
The system converts crypto to fiat at the current exchange rate
Fiat is sent to your company bank account
Status changes to **SUCCEEDED**
### Off-Ramp Example
```bash theme={null}
# 1. Get available currency pairs
GET /v1/ramp-requests/off-ramp/pairs
# 2. Create off-ramp request
POST /v1/ramp-requests
{
"rampType": "OFF_RAMP",
"amount": 0.5,
"cryptoCurrencyId": "usdc-ethereum-id",
"fiatCurrencyId": "eur-currency-id",
"companyBankAccountId": "your-bank-account-id"
}
# 3. Approve the request
POST /v1/ramp-requests/{id}/approve
{
"version": 1
}
# 4. Customer sends 0.5 USDC to deposit wallet
# 5. Add transaction hash
PATCH /v1/ramp-requests/{id}/tx-hash
{
"blockchainTransactionHash": "0x1234...",
"version": 2
}
# 6. System processes and sends EUR to company bank account
```
***
## Managing Ramp Requests
### Listing Requests
Use the [List Ramp Requests](/api-reference/Fundflow-API/ramp-requests/list-all-ramp-requests) endpoint with filters:
```bash theme={null}
GET /v1/ramp-requests?rampType=ON_RAMP&status=AWAITING_APPROVAL&page=1&size=50
```
**Available filters:**
* `rampType`: ON\_RAMP or OFF\_RAMP
* `status`: Filter by status
* `fromDate`: Start date (YYYY-MM-DD)
* `toDate`: End date (YYYY-MM-DD)
* `paymentReference`: Specific payment reference
* `sortOn`: Field to sort by
* `sortOrder`: ASC or DESC
### Getting Request Details
```bash theme={null}
GET /v1/ramp-requests/{id}
```
Returns complete details including:
* Current status and timestamps
* Amount breakdown (fiat, crypto, fees)
* Exchange rate used
* Associated accounts/wallets
* Complete event history
* Payment information
### Modifying Requests
**Edit amount** (only in AWAITING\_APPROVAL status):
```bash theme={null}
PUT /v1/ramp-requests/{id}/amount
{
"amount": 1500.00,
"version": 1
}
```
**Cancel request** (requester, in AWAITING\_APPROVAL):
```bash theme={null}
POST /v1/ramp-requests/{id}/cancel
{
"version": 1
}
```
**Reject request** (admin, in AWAITING\_APPROVAL):
```bash theme={null}
POST /v1/ramp-requests/{id}/reject
{
"version": 1
}
```
***
## Optimistic Locking
Fundflow uses optimistic locking to prevent concurrent updates:
Every update request must include the current `version` number
If the version has changed (HTTP 409), another user modified the resource
Fetch the latest version and retry your operation
```json theme={null}
// Version conflict response (HTTP 409)
{
"success": false,
"errors": [{
"code": "OPTIMISTIC_LOCK_EXCEPTION",
"message": "The resource has been modified. Please fetch the latest version and retry."
}]
}
```
***
## Fees and Exchange Rates
### Fee Calculation
Fees are company-specific and may include volume tiers. Use the [Calculate Fee](/api-reference/Fundflow-API/fees/calculate-fee-for-a-ramp-request) endpoint:
```bash theme={null}
POST /v1/fees/calculate
{
"amount": 1000.00,
"type": "ON_RAMP"
}
```
Response:
```json theme={null}
{
"success": true,
"result": {
"amount": 10.00,
"percentage": 1.0
}
}
```
### Amount Breakdown
For each ramp request:
* **Fiat Amount**: Total fiat amount (including fees)
* **Fiat Net Amount**: Net fiat after deducting fees
* **Crypto Amount**: Cryptocurrency amount
* **Fiat Fee Amount**: Fee in fiat currency
* **Fee Percentage**: Percentage applied
* **Exchange Rate**: Conversion rate used
***
## Exporting Requests
Export all ramp requests for accounting and auditing:
```bash theme={null}
GET /v1/ramp-requests/export
```
Returns a downloadable file (CSV/Excel) with all transaction data.
***
## User Roles and Permissions
| Role | Create | Approve | Reject | Cancel | View |
| -------------------- | ------ | ------- | ------ | ------- | ---- |
| **COMPANY\_ADMIN** | ✅ | ✅ | ✅ | ✅ | ✅ |
| **COMPANY\_MANAGER** | ✅ | ❌ | ❌ | ✅ (own) | ✅ |
| **COMPANY\_VIEWER** | ❌ | ❌ | ❌ | ❌ | ✅ |
***
## Best Practices
**Check Currency Pairs**: Always verify available currency pairs before creating requests using the `/on-ramp/pairs` or `/off-ramp/pairs` endpoints.
**Calculate Fees First**: Use the fee calculation endpoint to understand costs before creating large requests.
**Track Payment References**: Save payment references for your records to easily match bank transfers with ramp requests.
**Cannot Cancel After Approval**: Once a request is approved and moves to AWAITING\_FUNDS, it cannot be cancelled. Ensure all details are correct before approving.
**Blockchain Confirmations**: Off-ramp requests require blockchain confirmation before processing. This may take several minutes depending on network congestion.
***
## Troubleshooting
### On-Ramp Issues
**Request stuck in AWAITING\_FUNDS?**
* Verify you sent the exact amount specified
* Confirm you included the payment reference
* Check if the bank transfer has been processed
* [Contact us](https://venlyfinance.com/contact) if payment was sent correctly
**Wrong amount sent?**
* [Contact us](https://venlyfinance.com/contact) immediately
* Do not create a new request
* Provide transaction details for reconciliation
### Off-Ramp Issues
**Request not processing?**
* Verify you added the transaction hash
* Confirm the transaction is confirmed on the blockchain
* Check you sent to the correct deposit wallet address
* Ensure you sent the correct amount and token
**Wrong network used?**
* [Contact us](https://venlyfinance.com/contact) immediately
* Provide transaction hash and details
* Do not send additional transactions
***
## API Reference
Create new on-ramp or off-ramp
View all ramp requests
Approve a ramp request
Get available currency pairs
***
## Next Steps
Understand fee calculations
Manage bank accounts and wallets
Security best practices
# Troubleshooting
Source: https://docs.venlyfinance.com/guides/payments/troubleshooting
API error codes, common integration failures, and how to fix them
## HTTP Error Reference
### 400 Bad Request
The request body or parameters failed validation.
**Common causes:**
* Missing required fields
* Invalid field format (e.g. wrong UUID format, unsupported enum value)
* Finance API endpoint requiring `idempotencyKey` called without it in the request body
Check the `errors` array in the response body for field-level details:
```json theme={null}
{
"success": false,
"errors": [
{ "code": "REQUIRED_FIELD", "field": "fiatCurrencyId", "message": "Field is required" }
]
}
```
***
### 401 Unauthorized
The Bearer token is missing, expired, or malformed.
```json theme={null}
{ "success": false, "errors": [{ "code": "UNAUTHORIZED" }] }
```
**Fix:** Re-authenticate using the token endpoint and retry the request with the new token. Implement proactive refresh — request a new token \~30 seconds before the 5-minute expiry rather than waiting for a 401.
***
### 403 Forbidden
The token is valid but the caller lacks permission for this operation.
**Common causes:**
* User role is insufficient (e.g. `COMPANY_VIEWER` attempting to create a ramp request)
* Company KYB status is not `VERIFIED` — required before creating ramp requests
* Resource belongs to a different company
**Fix:** Check the role assigned to the credentials you are using, and verify `GET /v1/company` returns `kybStatus: "VERIFIED"`.
***
### 404 Not Found
The requested resource does not exist.
**Common causes:**
* Incorrect or stale ID in the URL path
* Resource was deleted
**Fix:** Verify the ID against a list endpoint (`GET /v1/ramp-requests`, `GET /v1/company-wallets`, etc.) to confirm the resource exists.
***
### 409 Conflict — Optimistic Lock
A concurrent modification was detected. Another process updated the resource between your read and write.
```json theme={null}
{
"success": false,
"errors": [{ "code": "OPTIMISTIC_LOCK_EXCEPTION", "message": "..." }]
}
```
**Fix:** Fetch the resource again (`GET /v1/ramp-requests/{id}`), read the current `version`, apply your change with the new version, and retry.
***
### 422 Unprocessable Entity (Finance API)
An `idempotencyKey` value was reused with a different request body.
**Fix:** Generate a new UUID for the new logical request. Only reuse a key when retrying the exact same operation after a network failure.
***
### 500 Internal Server Error
An unexpected error occurred on the server.
**Fix:** Retry with exponential backoff. If the error persists, [contact us](https://venlyfinance.com/contact) with the request timestamp and any request ID from the response headers.
***
## Common Integration Issues
### Ramp request stuck in AWAITING\_FUNDS
**On-ramp:** Confirm the bank transfer was sent for the exact amount specified, and that the unique payment reference was included. Missing the reference is the most common cause — the payment cannot be matched without it.
**Off-ramp:** Confirm the transaction hash has been submitted via `PATCH /v1/ramp-requests/{id}/tx-hash`, and that the blockchain transaction is confirmed (check a block explorer). Processing begins only after on-chain confirmation.
***
### Ramp request not moving to PROCESSING
* Blockchain congestion can delay confirmation — check the transaction status on a block explorer before [contacting us](https://venlyfinance.com/contact).
* For on-ramp, bank transfers can take 1-2 business days depending on the payment network. SEPA same-day cut-offs apply.
***
### Cannot create a ramp request
* `GET /v1/company` must return `kybStatus: "VERIFIED"`.
* The bank account or wallet used must have `verificationStatus: "VERIFIED"`. Accounts in `PENDING` status are not eligible.
* Check your user role — `COMPANY_VIEWER` cannot create requests.
***
### Wallet verification not completing (Fundflow)
Wallet ownership verification requires completing the verification process after submitting the wallet address. [Contact us](https://venlyfinance.com/contact) if the status has not moved from `PENDING` after the process is complete.
***
### 409 on every update attempt
You are sending a stale `version`. Always read the resource immediately before writing to get the current version — do not cache or hardcode version numbers.
***
## Contacting Support
Get in touch — response within 24 hours
Get in touch — response within 2 hours
When contacting support, include:
* Your company ID
* The affected resource ID (ramp request, wallet, etc.)
* The exact error response body
* Timestamps of the failed requests
Credential and token best practices
Status codes and endpoint list
Status values and terminology
# Treasury Yield (Coming Soon)
Source: https://docs.venlyfinance.com/guides/treasury-yield/introduction
Earn yield on idle stablecoin reserves through curated DeFi and tokenized vaults
**Coming Soon** - Treasury Yield is currently in development and will be available in Q3 2026. This documentation provides an overview of the upcoming features.
## What is Treasury Yield?
Treasury Yield enables you to earn passive income on idle stablecoin reserves without leaving the Venly Finance platform. Access curated DeFi protocols and tokenized real-world asset vaults to generate yield on your USDC, EURC, and USDT holdings while maintaining liquidity and security.
Access to vetted DeFi yield protocols
Real-world asset-backed yield products
Set-and-forget yield optimization
Withdraw funds anytime without penalties
***
## Key Features
### 💰 Multiple Yield Strategies
Access diverse yield-generating opportunities:
* **Lending Protocols**: Aave, Compound, and other blue-chip DeFi platforms
* **Liquidity Pools**: Provide liquidity to DEX pools with optimized risk/reward
* **Tokenized T-Bills**: US Treasury-backed stablecoin yields
* **Money Market Funds**: Institutional-grade tokenized money markets
* **Stablecoin Farming**: Optimized stablecoin-to-stablecoin strategies
### 🔒 Institutional-Grade Security
Built with enterprise security standards:
* **Curated Protocols**: Only vetted, audited protocols
* **Risk Assessment**: Continuous monitoring and risk scoring
* **Insurance Options**: Optional coverage for select strategies
* **Multi-Sig Controls**: Secure fund management
* **Audit Trail**: Complete transaction history
### 📊 Transparent Reporting
Real-time visibility into your yield performance:
* **Live APY Tracking**: Current and historical yields
* **Performance Analytics**: Compare strategies and optimize
* **Tax Reporting**: Automated yield reporting for compliance
* **Risk Metrics**: Understand exposure and diversification
* **Withdrawal Forecasting**: Predict liquidity needs
### ⚡ Seamless Integration
Works with your existing Venly Finance setup:
* **One-Click Allocation**: Deploy funds to vaults instantly
* **Automatic Compounding**: Reinvest yields automatically
* **Unified Dashboard**: Manage all assets in one place
* **API Access**: Programmatic yield management
* **Webhook Notifications**: Real-time yield updates
***
## How It Works
Link your Venly Finance accounts to Treasury Yield
* Select accounts with idle stablecoin balances
* Set minimum operating balance thresholds
* Configure automatic allocation rules
* Define risk tolerance preferences
Select from curated yield opportunities
**Available Strategies:**
* Conservative: 3-5% APY (T-Bills, Money Markets)
* Moderate: 5-8% APY (Lending Protocols)
* Aggressive: 8-15% APY (Liquidity Pools, Farming)
**Risk Ratings:**
* Low Risk: Tokenized RWAs, established protocols
* Medium Risk: Blue-chip DeFi with track record
* Higher Risk: Newer protocols with higher yields
Deploy stablecoins to selected vaults
```bash theme={null}
POST /v1/treasury-yield/allocations
{
"accountId": "account-id",
"vaultId": "aave-usdc-lending",
"amount": 100000,
"currency": "USDC",
"autoCompound": true
}
```
* Funds transferred to yield vault
* Position tracked in real-time
* Yield accrual begins immediately
Track yields and optimize allocation
* View real-time APY and earnings
* Compare strategy performance
* Receive alerts for significant changes
* Rebalance based on performance
Access your funds when needed
```bash theme={null}
POST /v1/treasury-yield/withdrawals
{
"allocationId": "allocation-id",
"amount": 50000,
"destinationAccountId": "account-id"
}
```
* Withdraw partial or full amounts
* Funds returned to account within minutes
* Accrued yield included in withdrawal
* No penalties or lock-up periods
***
## Yield Strategies
### Conservative Strategies (3-5% APY)
**Tokenized US Treasury Bills**
* **Risk Level**: Very Low
* **Typical APY**: 4-5%
* **Liquidity**: T+1 settlement
* **Minimum**: \$10,000
* **Best For**: Capital preservation with yield
**Money Market Funds**
* **Risk Level**: Very Low
* **Typical APY**: 3-4%
* **Liquidity**: Same-day
* **Minimum**: \$5,000
* **Best For**: Operating reserves, short-term holdings
**Stablecoin Savings**
* **Risk Level**: Low
* **Typical APY**: 3-5%
* **Liquidity**: Instant
* **Minimum**: \$1,000
* **Best For**: Emergency funds, flexible liquidity
***
### Moderate Strategies (5-8% APY)
**Aave Lending**
* **Risk Level**: Low-Medium
* **Typical APY**: 5-7%
* **Liquidity**: Instant
* **Minimum**: \$1,000
* **Best For**: Balanced risk/reward
**Compound Finance**
* **Risk Level**: Low-Medium
* **Typical APY**: 5-6%
* **Liquidity**: Instant
* **Minimum**: \$1,000
* **Best For**: Established DeFi exposure
**Curve Stablecoin Pools**
* **Risk Level**: Medium
* **Typical APY**: 6-8%
* **Liquidity**: Instant
* **Minimum**: \$5,000
* **Best For**: Stablecoin-only exposure
***
### Aggressive Strategies (8-15% APY)
**Liquidity Provision**
* **Risk Level**: Medium-High
* **Typical APY**: 10-15%
* **Liquidity**: Instant
* **Minimum**: \$10,000
* **Best For**: Higher risk tolerance
**Yield Farming**
* **Risk Level**: High
* **Typical APY**: 12-20%
* **Liquidity**: Variable
* **Minimum**: \$5,000
* **Best For**: Experienced DeFi users
**Leveraged Strategies**
* **Risk Level**: High
* **Typical APY**: 15-25%
* **Liquidity**: Variable
* **Minimum**: \$25,000
* **Best For**: Sophisticated treasury management
**Risk Disclosure**: Higher yields come with increased risk. Aggressive strategies may experience volatility and potential loss of principal. Only allocate funds you can afford to have at risk.
***
## Supported Assets
### Stablecoins
| Asset | Supported Chains | Yield Strategies Available |
| -------- | --------------------------------- | -------------------------- |
| **USDC** | Ethereum, Base, Polygon, Arbitrum | All strategies |
| **EURC** | Ethereum, Base | Conservative, Moderate |
| **USDT** | Ethereum, Tron, Polygon | Moderate, Aggressive |
| **DAI** | Ethereum | All strategies |
| **USDS** | Ethereum | Conservative, Moderate |
### Coming Soon
* **PYUSD** (PayPal USD)
* **FDUSD** (First Digital USD)
* **GBP Stablecoins**
* **Tokenized Commodities**
***
## Risk Management
### Protocol Vetting Process
Every yield strategy undergoes rigorous evaluation:
✅ **Security Audits**: Multiple independent audits required\
✅ **Track Record**: Minimum 12 months operational history\
✅ **TVL Requirements**: Minimum \$100M total value locked\
✅ **Smart Contract Review**: Internal security team assessment\
✅ **Insurance Coverage**: Optional insurance for select protocols
### Risk Scoring System
Each strategy receives a comprehensive risk score:
```
Risk Score Components:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Smart Contract Risk: 20%
Protocol Maturity: 20%
Liquidity Risk: 15%
Market Risk: 15%
Counterparty Risk: 15%
Regulatory Risk: 15%
Overall Score: 1-100
< 30: Low Risk
30-60: Medium Risk
> 60: High Risk
```
### Diversification Recommendations
**Conservative Portfolio (3-5% APY)**
* 60% Tokenized T-Bills
* 30% Money Market Funds
* 10% Stablecoin Savings
**Balanced Portfolio (5-8% APY)**
* 40% Lending Protocols (Aave, Compound)
* 30% Tokenized RWAs
* 20% Curve Stablecoin Pools
* 10% Cash Reserve
**Growth Portfolio (8-12% APY)**
* 40% Liquidity Provision
* 30% Lending Protocols
* 20% Yield Farming
* 10% Cash Reserve
***
## Use Cases
### 🏦 Corporate Treasury Management
**Challenge**: Idle cash earning 0% in bank accounts
**Solution**: Treasury Yield allocation
* Move operating reserves to money market funds (3-4% APY)
* Allocate excess cash to lending protocols (5-7% APY)
* Maintain liquidity for operational needs
* Automated rebalancing based on cash flow
**Results:**
* Idle treasury generating passive yield
* Full liquidity maintained
* Better than traditional bank rates
* Transparent reporting for CFO
### 🎮 Gaming Platform Float Management
**Challenge**: Player deposits sitting idle between deposits and withdrawals
**Solution**: Automated yield on float
* Conservative strategy for player funds
* Instant liquidity for withdrawals
* Yield shared with players or retained
* Compliance-friendly approach
**Results:**
* Player float generating passive yield
* No impact on withdrawal times
* Additional revenue stream
* Enhanced player value proposition
### 💱 Exchange Reserve Optimization
**Challenge**: Large stablecoin reserves earning nothing
**Solution**: Multi-strategy allocation
* Hot wallet: 10% (instant liquidity)
* Warm wallet: 40% in lending protocols (instant withdrawal)
* Cold storage: 50% in higher-yield strategies
**Results:**
* Reserves generating passive yield while preserving trading liquidity
* Liquidity maintained for trading operations
* Risk-adjusted returns
* Competitive advantage
### 💼 Payment Platform Working Capital
**Challenge**: Settlement float between payment receipt and payout
**Solution**: Short-term yield optimization
* Allocate float to overnight strategies
* Automatic withdrawal for scheduled payouts
* Predictive allocation based on payout schedule
* Zero operational impact
**Results:**
* Daily float generating passive yield without operational impact
* Seamless integration with payout operations
* Improved unit economics
* Scalable revenue stream
***
## Integration Overview
### API Endpoints (Coming Soon)
```bash theme={null}
# List available yield vaults
GET /v1/treasury-yield/vaults
# Get vault details and current APY
GET /v1/treasury-yield/vaults/{vaultId}
# Allocate funds to vault
POST /v1/treasury-yield/allocations
{
"accountId": "account-id",
"vaultId": "vault-id",
"amount": 100000,
"currency": "USDC",
"autoCompound": true,
"minAPY": 5.0 // Optional: minimum acceptable APY
}
# List active allocations
GET /v1/treasury-yield/allocations
# Get allocation performance
GET /v1/treasury-yield/allocations/{allocationId}
# Withdraw from vault
POST /v1/treasury-yield/withdrawals
{
"allocationId": "allocation-id",
"amount": 50000,
"destinationAccountId": "account-id"
}
# Get yield earnings history
GET /v1/treasury-yield/earnings
```
### Webhook Events
Real-time notifications for yield events:
* `yield.allocated` - Funds deployed to vault
* `yield.earned` - Yield accrued (daily)
* `yield.compounded` - Yield reinvested
* `yield.withdrawn` - Funds withdrawn from vault
* `yield.apy_changed` - Significant APY change
* `yield.risk_alert` - Risk score change detected
***
## Automated Yield Optimization
### Auto-Allocation Rules
Set rules for automatic yield deployment:
```json theme={null}
{
"rules": [
{
"condition": "balance > 100000",
"action": "allocate",
"strategy": "conservative",
"percentage": 80,
"minAPY": 3.0
},
{
"condition": "balance < 50000",
"action": "withdraw",
"amount": "to_minimum",
"priority": "high"
}
]
}
```
### Smart Rebalancing
Automatic portfolio optimization:
* **Performance-Based**: Move funds from underperforming to better vaults
* **Risk-Adjusted**: Rebalance based on risk score changes
* **APY Threshold**: Automatically switch if APY drops below threshold
* **Liquidity Management**: Maintain minimum liquid reserves
### Yield Compounding
Maximize returns through automatic reinvestment:
* **Daily Compounding**: Reinvest yields daily
* **Threshold-Based**: Compound when yield reaches minimum amount
* **Gas-Optimized**: Batch compounding to minimize fees
* **Tax-Efficient**: Optional strategies for tax optimization
***
## Security & Compliance
### Smart Contract Security
* **Multi-Sig Wallets**: All vault contracts use multi-signature controls
* **Time-Locks**: Withdrawal delays for large amounts
* **Emergency Pause**: Ability to pause operations if risks detected
* **Upgrade Controls**: Secure upgrade mechanisms for contracts
* **Bug Bounty**: Active bug bounty program for security researchers
### Insurance Options
**Optional Coverage Available:**
* **Protocol Risk Insurance**: Coverage for smart contract exploits
* **Custody Insurance**: Protection for assets in custody
* **Slashing Insurance**: Coverage for validator slashing (staking strategies)
**Coverage Limits:**
* Up to \$5M per vault
* Annual premium: 0.5-2% of insured amount
* Claims processed within 30 days
### Regulatory Compliance
✅ **MiFID II Aligned**: Suitable for regulated entities\
✅ **GDPR Compliant**: Data protection and privacy\
✅ **AML/KYC**: Integrated compliance checks\
✅ **Tax Reporting**: Automated yield reporting\
✅ **Audit Trail**: Complete transaction history
***
## Roadmap
### Q3 2026 - Initial Launch
* Conservative strategies (T-Bills, Money Markets)
* Moderate strategies (Aave, Compound)
* USDC and EURC support
* Basic API and dashboard
* Manual allocation and withdrawal
### Q4 2026 - Enhanced Features
* Aggressive strategies (Liquidity pools, Farming)
* USDT and DAI support
* Auto-allocation rules
* Smart rebalancing
* Mobile app integration
### Q1 2027 - Advanced Features
* Leveraged strategies
* Custom vault creation
* Advanced analytics and forecasting
* Tax optimization tools
* Institutional-grade reporting
***
## Getting Started
### Prerequisites
To access Treasury Yield, you'll need:
✅ **Active Venly Finance Account**: Verified company account\
✅ **Minimum Balance**: \$10,000 in stablecoins\
✅ **Risk Assessment**: Complete risk tolerance questionnaire\
✅ **Compliance Approval**: KYC/AML verification complete\
✅ **API Access**: For programmatic management (optional)
### Early Access Program
Register your interest for early access to Treasury Yield
**Benefits:**
* Priority onboarding when available
* Waived management fees for first 3 months
* Dedicated yield strategist consultation
* Beta testing opportunity
**Contact**: [venlyfinance.com/contact](https://venlyfinance.com/contact)
***
## Comparison: Treasury Yield vs Traditional Options
| Feature | Bank Savings | Traditional DeFi | Venly Treasury Yield |
| ------------------- | -------------- | ---------------- | -------------------- |
| **APY Range** | 0.1-1% | 3-20% | 3-15% (curated) |
| **Risk Assessment** | None | Self-managed | Professional vetting |
| **Liquidity** | Instant | Variable | Instant to T+1 |
| **Insurance** | FDIC (limited) | Rare | Optional coverage |
| **Minimum** | \$0 | Variable | $1,000-$10,000 |
| **Management** | None | Manual | Automated |
| **Tax Reporting** | Manual | Manual | Automated |
| **Integration** | Limited | None | Full API |
***
## Frequently Asked Questions
Yields vary by strategy: Conservative (3-5% APY), Moderate (5-8% APY), Aggressive (8-15% APY). Actual yields fluctuate based on market conditions and protocol performance.
Most strategies offer instant withdrawal. Some conservative strategies (T-Bills) may require T+1 settlement. There are no lock-up periods or withdrawal penalties.
Risks include smart contract vulnerabilities, protocol failures, market volatility, and impermanent loss (for liquidity strategies). All protocols are vetted, but risk cannot be eliminated entirely.
No. Yields are variable and depend on market conditions, protocol performance, and utilization rates. Historical yields are not indicative of future performance.
Yields accrue continuously and are calculated daily. You can choose to compound yields automatically or withdraw them to your account. Yields are paid in the same currency as your deposit.
We monitor all protocols 24/7. If a security incident occurs, we can pause operations and withdraw funds if possible. Optional insurance coverage is available for additional protection.
Yes, you can allocate funds across multiple vaults, set auto-allocation rules, and configure rebalancing preferences. Advanced users can create custom strategies.
Yield earnings are automatically tracked and reported. We provide detailed transaction history and yield statements for tax filing. Consult your tax advisor for specific guidance.
***
## Next Steps
Register for early access
Explore account integration
Schedule consultation
Estimate your earnings (coming soon)
***
## Support
Questions about Treasury Yield?
* **Contact**: [venlyfinance.com/contact](https://venlyfinance.com/contact)
* **Documentation**: [docs.venlyfinance.com](https://docs.venlyfinance.com)
* **Risk Disclosure**: [venlyfinance.com/risk-disclosure](https://venlyfinance.com/risk-disclosure)
# Venly Finance Developer Documentation
Source: https://docs.venlyfinance.com/index
Build with stablecoin settlement orchestration. One API. Multiple rails. Your economics.
# Build with Venly Finance
Cross-border settlement orchestration for high-volume operators. Integrate multi-rail payouts, embedded finance, and card issuance with one API.
## Products
Multi-rail payout orchestration. Route payments through SEPA, SWIFT, stablecoin, or local rails — automatically.
Accounts, wallets, IBANs, KYC/KYB, and transfers — one RESTful API to embed financial infrastructure.
## Quick Start
Make your first API call in under five minutes
Learn how to authenticate with Venly APIs
## Use Cases
Replace correspondent banking with stablecoin settlement. 40+ corridors, minutes not days.
Embed accounts, wallets, IBANs, and payouts into your product with one API.
Convert, hold, and route stablecoins with approval workflows and full audit trails.
Skip 2 years of vendor integration. Get accounts, wallets, IBANs, and cards from day one.
## Why Venly Finance?
Seconds to minutes instead of T+2 to T+5
0.3–0.8% per transaction vs 1.5–3% traditional
Automatic routing through best available rail
Licensed and supervised
Independently audited security
EUR, USD, GBP, BRL, PHP, INR, MXN and more
## Resources
Visit our main website
Stay updated with insights
Get in touch with our team