# Add Assets to Account
Source: https://docs.borderless.xyz/api-reference/accounts/add-assets-to-account
https://sandbox-api.borderless.xyz/v1/api-json post /v1/accounts/{id}/assets
Add Assets to Account using the data provided in the request body.
# Add Fiats to PFI Account
Source: https://docs.borderless.xyz/api-reference/accounts/add-fiats-to-pfi-account
https://sandbox-api.borderless.xyz/v1/api-json post /v1/accounts/{id}/fiats
Add fiat currencies and assets to a PFI Account using the data provided in the request body.
# Create a new Account
Source: https://docs.borderless.xyz/api-reference/accounts/create-a-new-account
https://sandbox-api.borderless.xyz/v1/api-json post /v1/accounts
Create a new Account using the data provided in the request body.
# Create a PFI Account (deprecated)
Source: https://docs.borderless.xyz/api-reference/accounts/create-a-pfi-account-deprecated
https://sandbox-api.borderless.xyz/v1/api-json post /v1/accounts/pfi
Deprecated. Will be removed by September 1st, 2026. Use `POST /accounts` with `provider` set to a PFI (e.g. `Infinia`, `Finity`) instead.
# Create a Subaccount (deprecated)
Source: https://docs.borderless.xyz/api-reference/accounts/create-a-subaccount-deprecated
https://sandbox-api.borderless.xyz/v1/api-json post /v1/accounts/subaccounts
Deprecated. Will be removed by September 1st, 2026. Use `POST /accounts` instead; the wallet/subaccount distinction has been removed.
# Delete v1accounts
Source: https://docs.borderless.xyz/api-reference/accounts/delete-v1accounts
https://sandbox-api.borderless.xyz/v1/api-json delete /v1/accounts/{id}
# Get account balances
Source: https://docs.borderless.xyz/api-reference/accounts/get-account-balances
https://sandbox-api.borderless.xyz/v1/api-json get /v1/accounts/{id}/balances
Retrieve balances for an Account. Returns 404 if the Account does not exist.
# Get Accounts
Source: https://docs.borderless.xyz/api-reference/accounts/get-accounts
https://sandbox-api.borderless.xyz/v1/api-json get /v1/accounts
Retrieve a list of Accounts with pagination support. Use query parameters `startingAfter` and `limit` to navigate results.
# Get an Account by id
Source: https://docs.borderless.xyz/api-reference/accounts/get-an-account-by-id
https://sandbox-api.borderless.xyz/v1/api-json get /v1/accounts/{id}
Retrieve an Account by its unique identification. Returns 404 if the Account does not exist.
# Authentication
Source: https://docs.borderless.xyz/api-reference/authentication
## Access to Borderless
Please contact us via email if you are not already in touch for onboarding. Borderless will configure your organization in our system and invite your first user via email or Slack.
Once you receive this invitation, you can use it to set a password, and invite additional team members to the organization via your Borderless dashboard. Here you will have options to manage roles, configure organizational settings, and reset your password.
## Create API Keys
In the Borderless admin dashbaord, you'll be able to generate your API keys to continue the integration and testing.
Look for the `Developers` section on the left hand navigation panel. Click the `Generate` button and copy your API keys.
**Please ensure you store your API keys in a safe place and do not share them.**
## Generating API Access Token
With your API keys from the previous step, you can generate an access token to authenticate future API requests. Authentication is enforced via OAuth 2.0. All endpoints require verified bearer tokens, and webhook communications are signed for end-to-end trust.
In your request body, include your `Client ID` and `Client Secret`, which you generated in the `Developers` section of the Borderless Dashboard.
Endpoint: [`POST /auth/m2m/token`](/api-reference/authentication/obtain-authentication-m2m-tokens)
```bash request expandable theme={null}
curl -X POST "https://sandbox-api.borderless.xyz/v1/auth/m2m/token" \
-H "Content-Type: application/json" \
-d '{
"clientId": "your-client-id",
"clientSecret": "your-client-secret"
}'
```
```json response expandable theme={null}
{
"accessToken": "your-access-token",
"tokenType": "Bearer",
"expiresIn": 3600
}
```
### Video of access token generation
If you have any questions, please don't hesitate to reach out to us via [email](mailto:support@borderless.xyz) or slack.
# Obtain authentication M2M tokens
Source: https://docs.borderless.xyz/api-reference/authentication/obtain-authentication-m2m-tokens
https://sandbox-api.borderless.xyz/v1/api-json post /v1/auth/m2m/token
Obtain an authentication M2M token with the access token.
# Create a new Compliance Check
Source: https://docs.borderless.xyz/api-reference/compliance-checks/create-a-new-compliance-check
https://sandbox-api.borderless.xyz/v1/api-json post /v1/identities/{identityId}/compliance-checks/{slug}
Create a new Compliance Check using the data provided in the request body.
# Deletes the customer for a compliance at the provider and clears the local check
Source: https://docs.borderless.xyz/api-reference/compliance-checks/deletes-the-customer-for-a-compliance-at-the-provider-and-clears-the-local-check
https://sandbox-api.borderless.xyz/v1/api-json delete /v1/identities/{identityId}/compliance-checks/{slug}
# Get a Compliance Check by id
Source: https://docs.borderless.xyz/api-reference/compliance-checks/get-a-compliance-check-by-id
https://sandbox-api.borderless.xyz/v1/api-json get /v1/identities/{identityId}/compliance-checks
Retrieve a Compliance Check by its unique identification. Returns 404 if the Compliance Check does not exist.
# Get compliance requirements for a compliance
Source: https://docs.borderless.xyz/api-reference/compliance-checks/get-compliance-requirements-for-a-compliance
https://sandbox-api.borderless.xyz/v1/api-json get /v1/identities/{identityId}/compliance-checks/{slug}/requirements
# Re-syncs an approved identity's data to the provider after an edit
Source: https://docs.borderless.xyz/api-reference/compliance-checks/re-syncs-an-approved-identitys-data-to-the-provider-after-an-edit
https://sandbox-api.borderless.xyz/v1/api-json post /v1/identities/{identityId}/compliance-checks/{slug}/resync
# Retrieves a list of possible compliance checks together with their coverage
Source: https://docs.borderless.xyz/api-reference/compliance-checks/retrieves-a-list-of-possible-compliance-checks-together-with-their-coverage
https://sandbox-api.borderless.xyz/v1/api-json get /v1/compliance-checks/coverage
# Idempotency
Source: https://docs.borderless.xyz/api-reference/idempotency
Some requests require an `Idempotency-Key` to ensure that operations are not accidentally executed multiple times. The key should be unique for each request, preventing duplicate processing and maintaining data integrity.
## How It Works
When you make a request that requires `Idempotency-Key`, you must include a header with a unique value, such as a UUID (Universally Unique Identifier).
```bash bash theme={null}
curl -X 'POST' 'https://sandbox-api.borderless.xyz/v1/withdrawals' \
-H "Idempotency-Key: 8f14e45f-e6c3-4f7e-bd56-1b9a2e46f1d6"
```
## Generating a Unique Idempotancy Key
You can generate a unique UUID for your key using various programming libraries or online tools or using the online tool: [Generate UUID](https://www.uuidgenerator.net/)
If you have any questions, please don't hesitate to reach out to us via [email](mailto:support@borderless.xyz) or slack.
# Create a new Business Identity
Source: https://docs.borderless.xyz/api-reference/identities/create-a-new-business-identity
https://sandbox-api.borderless.xyz/v1/api-json post /v1/identities/business
Create a new Business Identity using the data provided in the request body.
# Create a new Personal Identity
Source: https://docs.borderless.xyz/api-reference/identities/create-a-new-personal-identity
https://sandbox-api.borderless.xyz/v1/api-json post /v1/identities/personal
Create a new Personal Identity using the data provided in the request body.
# Delete a Document
Source: https://docs.borderless.xyz/api-reference/identities/delete-a-document
https://sandbox-api.borderless.xyz/v1/api-json delete /v1/identities/{id}/documents/{documentId}
Delete a document by id from the specified identity.
# Delete an Identity by id
Source: https://docs.borderless.xyz/api-reference/identities/delete-an-identity-by-id
https://sandbox-api.borderless.xyz/v1/api-json delete /v1/identities/{id}
Delete the specified an Identity by its id. This action is irreversible. Returns 404 if the entity is not found.
# Get a Document URL
Source: https://docs.borderless.xyz/api-reference/identities/get-a-document-url
https://sandbox-api.borderless.xyz/v1/api-json get /v1/identities/{id}/documents/{documentId}/url
Get a short-lived presigned URL to view or download a document side.
# Get an Identity by id
Source: https://docs.borderless.xyz/api-reference/identities/get-an-identity-by-id
https://sandbox-api.borderless.xyz/v1/api-json get /v1/identities/{id}
Retrieve an Identity by its unique identification. Returns 404 if the Identity does not exist.
# Get Identities
Source: https://docs.borderless.xyz/api-reference/identities/get-identities
https://sandbox-api.borderless.xyz/v1/api-json get /v1/identities
Retrieve a list of Identities with pagination support. Use query parameters `startingAfter` and `limit` to navigate results.
# Update a Business Identity
Source: https://docs.borderless.xyz/api-reference/identities/update-a-business-identity
https://sandbox-api.borderless.xyz/v1/api-json patch /v1/identities/business/{id}
Update a Business Identity using the data provided in the request body.
# Update a Personal Identity
Source: https://docs.borderless.xyz/api-reference/identities/update-a-personal-identity
https://sandbox-api.borderless.xyz/v1/api-json patch /v1/identities/personal/{id}
Update a Personal Identity using the data provided in the request body.
# Upload a Document
Source: https://docs.borderless.xyz/api-reference/identities/upload-a-document
https://sandbox-api.borderless.xyz/v1/api-json put /v1/identities/{id}/documents
Upload a new Document, and attach it to Identity by id.
# Delete v1importsidentitiescsv
Source: https://docs.borderless.xyz/api-reference/identity-imports/delete-v1importsidentitiescsv
https://sandbox-api.borderless.xyz/v1/api-json delete /v1/imports/identities/csv
# Get Imported identities
Source: https://docs.borderless.xyz/api-reference/identity-imports/get-imported-identities
https://sandbox-api.borderless.xyz/v1/api-json get /v1/imports/identities
Retrieve a list of Imported identities with pagination support. Use query parameters `startingAfter` and `limit` to navigate results.
# Get v1importsidentities
Source: https://docs.borderless.xyz/api-reference/identity-imports/get-v1importsidentities
https://sandbox-api.borderless.xyz/v1/api-json get /v1/imports/identities/{id}
# Post v1importsidentitiescsv
Source: https://docs.borderless.xyz/api-reference/identity-imports/post-v1importsidentitiescsv
https://sandbox-api.borderless.xyz/v1/api-json post /v1/imports/identities/csv
# Delete integration configuration for a PFI.
Source: https://docs.borderless.xyz/api-reference/integrations-config/delete-integration-configuration-for-a-pfi
https://sandbox-api.borderless.xyz/v1/api-json delete /v1/organizations/integrations
Removes the stored integration configuration for the given PFI name and organization.
# Get a provider's configured credential sets
Source: https://docs.borderless.xyz/api-reference/integrations-config/get-a-providers-configured-credential-sets
https://sandbox-api.borderless.xyz/v1/api-json get /v1/organizations/integrations/credentials
Returns whether the organization-level default credentials are set for the provider and the list of business-identity IDs that have their own credential set. Never returns secrets. Providers without per-identity credentials return an empty `identityIds` list.
# Get integration configuration info
Source: https://docs.borderless.xyz/api-reference/integrations-config/get-integration-configuration-info
https://sandbox-api.borderless.xyz/v1/api-json get /v1/organizations/integrations/config-info
Returns an array of integration providers with a boolean indicating whether each provider is configured (API keys or provider-specific credentials are set).
# Remove a business identity's credential set for a provider
Source: https://docs.borderless.xyz/api-reference/integrations-config/remove-a-business-identitys-credential-set-for-a-provider
https://sandbox-api.borderless.xyz/v1/api-json delete /v1/organizations/integrations/credentials/{identityId}
Removes the per-identity credential set for the given business identity and provider. The organization-level default and other identities' credentials are left intact. Fails if the provider does not support per-identity credentials.
# Setup Alfred integration.
Source: https://docs.borderless.xyz/api-reference/integrations-config/setup-alfred-integration
https://sandbox-api.borderless.xyz/v1/api-json put /v1/organizations/integrations/alfred
Create Alfred integration to configure the connection with the Alfred account.
# Setup Bitso integration.
Source: https://docs.borderless.xyz/api-reference/integrations-config/setup-bitso-integration
https://sandbox-api.borderless.xyz/v1/api-json put /v1/organizations/integrations/bitso
Create Bitso integration to configure the connection with the Bitso Wallet.
# Setup Bivo integration.
Source: https://docs.borderless.xyz/api-reference/integrations-config/setup-bivo-integration
https://sandbox-api.borderless.xyz/v1/api-json put /v1/organizations/integrations/bivo
Create Bivo partner username and password.
# Setup Brale integration.
Source: https://docs.borderless.xyz/api-reference/integrations-config/setup-brale-integration
https://sandbox-api.borderless.xyz/v1/api-json put /v1/organizations/integrations/brale
Create Brale partner api key and secret.
# Setup Bridge integration.
Source: https://docs.borderless.xyz/api-reference/integrations-config/setup-bridge-integration
https://sandbox-api.borderless.xyz/v1/api-json put /v1/organizations/integrations/bridge
Create Bridge partner api key.
# Setup Capa integration.
Source: https://docs.borderless.xyz/api-reference/integrations-config/setup-capa-integration
https://sandbox-api.borderless.xyz/v1/api-json put /v1/organizations/integrations/capa
Create Capa partner api key.
# Setup Cobre integration.
Source: https://docs.borderless.xyz/api-reference/integrations-config/setup-cobre-integration
https://sandbox-api.borderless.xyz/v1/api-json put /v1/organizations/integrations/cobre
Create Cobre partner user ID and secret.
# Setup CrissCross integration.
Source: https://docs.borderless.xyz/api-reference/integrations-config/setup-crisscross-integration
https://sandbox-api.borderless.xyz/v1/api-json put /v1/organizations/integrations/crisscross
Create CrissCross OAuth client credentials and merchant configuration.
# Setup Dfns integration.
Source: https://docs.borderless.xyz/api-reference/integrations-config/setup-dfns-integration
https://sandbox-api.borderless.xyz/v1/api-json put /v1/organizations/integrations/dfns
Create Dfns integration to configure the connection with the Dfns workspace.
# Setup Finity integration.
Source: https://docs.borderless.xyz/api-reference/integrations-config/setup-finity-integration
https://sandbox-api.borderless.xyz/v1/api-json put /v1/organizations/integrations/finity
Create Finity integration to configure the connection with the Finity account.
# Setup Hercle integration.
Source: https://docs.borderless.xyz/api-reference/integrations-config/setup-hercle-integration
https://sandbox-api.borderless.xyz/v1/api-json put /v1/organizations/integrations/hercle
Create Hercle integration to configure connectivity and credentials for the Hercle PFI.
# Setup HoneyCoin integration.
Source: https://docs.borderless.xyz/api-reference/integrations-config/setup-honeycoin-integration
https://sandbox-api.borderless.xyz/v1/api-json put /v1/organizations/integrations/honeycoin
Create HoneyCoin integration to configure the connection with the HoneyCoin account.
# Setup Infinia integration.
Source: https://docs.borderless.xyz/api-reference/integrations-config/setup-infinia-integration
https://sandbox-api.borderless.xyz/v1/api-json put /v1/organizations/integrations/infinia
Create Infinia integration to configure the connection of Identity with the Infinia company.
# Setup integration credentials (consolidated)
Source: https://docs.borderless.xyz/api-reference/integrations-config/setup-integration-credentials-consolidated
https://sandbox-api.borderless.xyz/v1/api-json put /v1/organizations/integrations
Single endpoint for configuring credentials for any supported integration provider. The `credentials` payload is validated server-side against the provider-specific DTO. Replaces the 22 per-provider PUT endpoints (which remain available but are deprecated).
# Setup Kotanipay integration.
Source: https://docs.borderless.xyz/api-reference/integrations-config/setup-kotanipay-integration
https://sandbox-api.borderless.xyz/v1/api-json put /v1/organizations/integrations/kotanipay
Create Kotanipay integration to configure the connection with the Kotanipay account.
# Setup Koywe integration.
Source: https://docs.borderless.xyz/api-reference/integrations-config/setup-koywe-integration
https://sandbox-api.borderless.xyz/v1/api-json put /v1/organizations/integrations/koywe
Create Koywe integration to configure the connection with the Koywe account.
# Setup Onmeta integration.
Source: https://docs.borderless.xyz/api-reference/integrations-config/setup-onmeta-integration
https://sandbox-api.borderless.xyz/v1/api-json put /v1/organizations/integrations/onmeta
Create Onmeta integration to configure the connection with the Onmeta account.
# Setup PFI client credentials.
Source: https://docs.borderless.xyz/api-reference/integrations-config/setup-pfi-client-credentials
https://sandbox-api.borderless.xyz/v1/api-json put /v1/organizations/integrations/yativo
Create PFI integration to configure the connection with the PFI account via client credentials.
# Setup Trace Finance integration.
Source: https://docs.borderless.xyz/api-reference/integrations-config/setup-trace-finance-integration
https://sandbox-api.borderless.xyz/v1/api-json put /v1/organizations/integrations/trace-finance
Create Trace Finance integration to configure the connection with the Trace Finance account.
# Setup Utila integration.
Source: https://docs.borderless.xyz/api-reference/integrations-config/setup-utila-integration
https://sandbox-api.borderless.xyz/v1/api-json put /v1/organizations/integrations/utila
Create Utila integration to configure the connection with the Utila workspace.
# Setup Walapay integration.
Source: https://docs.borderless.xyz/api-reference/integrations-config/setup-walapay-integration
https://sandbox-api.borderless.xyz/v1/api-json put /v1/organizations/integrations/walapay
Create Walapay partner api key.
# Setup Yellowcard integration.
Source: https://docs.borderless.xyz/api-reference/integrations-config/setup-yellowcard-integration
https://sandbox-api.borderless.xyz/v1/api-json put /v1/organizations/integrations/yellowcard
Create Yellowcard integration to configure the connection of Identity with the Yellowcard Wallet.
# Create a new Liquidation Address
Source: https://docs.borderless.xyz/api-reference/liquidation-addresses/create-a-new-liquidation-address
https://sandbox-api.borderless.xyz/v1/api-json post /v1/liquidation-addresses
Create a new Liquidation Address using the data provided in the request body.
# Delete a Liquidation Address by id
Source: https://docs.borderless.xyz/api-reference/liquidation-addresses/delete-a-liquidation-address-by-id
https://sandbox-api.borderless.xyz/v1/api-json delete /v1/liquidation-addresses/{liquidationAddressId}
Delete the specified a Liquidation Address by its id. This action is irreversible. Returns 404 if the entity is not found.
# Get a Liquidation Address by id
Source: https://docs.borderless.xyz/api-reference/liquidation-addresses/get-a-liquidation-address-by-id
https://sandbox-api.borderless.xyz/v1/api-json get /v1/liquidation-addresses/{liquidationAddressId}
Retrieve a Liquidation Address by its unique identification. Returns 404 if the Liquidation Address does not exist.
# Get Liquidation Addresses
Source: https://docs.borderless.xyz/api-reference/liquidation-addresses/get-liquidation-addresses
https://sandbox-api.borderless.xyz/v1/api-json get /v1/liquidation-addresses
Retrieve a list of Liquidation Addresses with pagination support. Use query parameters `startingAfter` and `limit` to navigate results.
# Create a Crypto Credential account
Source: https://docs.borderless.xyz/api-reference/mastercard-crypto-credential/create-a-crypto-credential-account
https://sandbox-api.borderless.xyz/v1/api-json post /v1/mastercard/crypto-credential/accounts
Registers an alias with Mastercard Crypto Credential so it can receive crypto. Only accountAlias is required. Mastercard derives a domain name alias from it and returns it under additionalAccountAliases — that derived alias, not the one you submitted, is what other participants resolve. Registering an alias that already exists fails.
# Decommission a registered blockchain address
Source: https://docs.borderless.xyz/api-reference/mastercard-crypto-credential/decommission-a-registered-blockchain-address
https://sandbox-api.borderless.xyz/v1/api-json delete /v1/mastercard/crypto-credential/crypto-addresses/{cryptoAddressId}
Permanently retires a registered address so the alias no longer resolves to it. This cannot be undone — to stop an address temporarily, suspend it through the update endpoint instead.
# Get a registered blockchain address
Source: https://docs.borderless.xyz/api-reference/mastercard-crypto-credential/get-a-registered-blockchain-address
https://sandbox-api.borderless.xyz/v1/api-json get /v1/mastercard/crypto-credential/crypto-addresses/{cryptoAddressId}
Returns a single registered address by its id. Obtain the id from the response of the register endpoint or from an account search.
# Look up a Crypto Credential alias
Source: https://docs.borderless.xyz/api-reference/mastercard-crypto-credential/look-up-a-crypto-credential-alias
https://sandbox-api.borderless.xyz/v1/api-json get /v1/mastercard/crypto-credential/alias-lookup
Resolves an alias across the Crypto Credential network and returns its status, the country it is registered in, and the assets it can receive. The alias may belong to any participant, which makes this the check to run before sending funds to one. vasps is present only when your organization is entitled to that data.
# Receive Mastercard Crypto Credential event notifications
Source: https://docs.borderless.xyz/api-reference/mastercard-crypto-credential/receive-mastercard-crypto-credential-event-notifications
https://sandbox-api.borderless.xyz/v1/api-json post /v1/webhooks/mastercard
# Register a blockchain address
Source: https://docs.borderless.xyz/api-reference/mastercard-crypto-credential/register-a-blockchain-address
https://sandbox-api.borderless.xyz/v1/api-json post /v1/mastercard/crypto-credential/crypto-addresses
Attaches a blockchain address to an existing account alias, so that resolving the alias for that asset returns this address. An account can hold several addresses, one per asset. The response is the only place the new address id is returned — keep it, or find it later through the account search endpoint.
# Search for a Crypto Credential account
Source: https://docs.borderless.xyz/api-reference/mastercard-crypto-credential/search-for-a-crypto-credential-account
https://sandbox-api.borderless.xyz/v1/api-json get /v1/mastercard/crypto-credential/accounts/search
Returns the accounts registered under an alias, together with their blockchain addresses. This is the only way to discover the id of a registered address, since there is no endpoint that lists them.
# Update a Crypto Credential account
Source: https://docs.borderless.xyz/api-reference/mastercard-crypto-credential/update-a-crypto-credential-account
https://sandbox-api.borderless.xyz/v1/api-json put /v1/mastercard/crypto-credential/accounts
Updates an account addressed by its accountAlias. Send only the fields you want to change; omitted fields are left as they are. Use it to suspend or reactivate an alias, optionally stating why through statusReasonInformation.
# Update a registered blockchain address
Source: https://docs.borderless.xyz/api-reference/mastercard-crypto-credential/update-a-registered-blockchain-address
https://sandbox-api.borderless.xyz/v1/api-json put /v1/mastercard/crypto-credential/crypto-addresses/{cryptoAddressId}
Changes a registered address, addressed by its id. Use it either to change the status, or to replace the address, its asset, or the account alias it belongs to. Send only the fields you want to change.
# Delete v1organizationsnetworkdefaults
Source: https://docs.borderless.xyz/api-reference/network-defaults/delete-v1organizationsnetworkdefaults
https://sandbox-api.borderless.xyz/v1/api-json delete /v1/organizations/network/defaults
# List default PFIs
Source: https://docs.borderless.xyz/api-reference/network-defaults/list-default-pfis
https://sandbox-api.borderless.xyz/v1/api-json get /v1/organizations/network/defaults
Retrieve default PFI assignments per (country, operationType) for the organization.
# Post v1organizationsnetworkdefaults
Source: https://docs.borderless.xyz/api-reference/network-defaults/post-v1organizationsnetworkdefaults
https://sandbox-api.borderless.xyz/v1/api-json post /v1/organizations/network/defaults
# Post v1organizationsnetworkdefaultsbulk
Source: https://docs.borderless.xyz/api-reference/network-defaults/post-v1organizationsnetworkdefaultsbulk
https://sandbox-api.borderless.xyz/v1/api-json post /v1/organizations/network/defaults/bulk
# Get namespace detail
Source: https://docs.borderless.xyz/api-reference/network-health/get-namespace-detail
https://sandbox-api.borderless.xyz/v1/api-json get /v1/network-health/{namespace}
Returns full detail for a namespace: components with statuses, active incidents, and scheduled maintenances.
# Get network health summary
Source: https://docs.borderless.xyz/api-reference/network-health/get-network-health-summary
https://sandbox-api.borderless.xyz/v1/api-json get /v1/network-health
Returns all monitored namespaces with their overall status (worst-status-wins), component counts, and last event timestamp.
# Get network providers
Source: https://docs.borderless.xyz/api-reference/network/get-network-providers
https://sandbox-api.borderless.xyz/v1/api-json get /v1/organizations/network
Retrieve all network providers with their capabilities for the organization.
# Get Organization Audit Events
Source: https://docs.borderless.xyz/api-reference/organizations/get-organization-audit-events
https://sandbox-api.borderless.xyz/v1/api-json get /v1/organizations/audit-events
Retrieve a list of Organization Audit Events with pagination support. Use query parameters `startingAfter` and `limit` to navigate results.
# Create a new Payment Instruction
Source: https://docs.borderless.xyz/api-reference/payment-instructions/create-a-new-payment-instruction
https://sandbox-api.borderless.xyz/v1/api-json post /v1/identities/{identityId}/payment-instructions
Create a new Payment Instruction using the data provided in the request body.
# Delete a Payment Instruction by id
Source: https://docs.borderless.xyz/api-reference/payment-instructions/delete-a-payment-instruction-by-id
https://sandbox-api.borderless.xyz/v1/api-json delete /v1/identities/{identityId}/payment-instructions/{paymentInstructionId}
Delete the specified a Payment Instruction by its id. This action is irreversible. Returns 404 if the entity is not found.
# Get a Payment Instruction by id
Source: https://docs.borderless.xyz/api-reference/payment-instructions/get-a-payment-instruction-by-id
https://sandbox-api.borderless.xyz/v1/api-json get /v1/identities/{identityId}/payment-instructions/{paymentInstructionId}
Retrieve a Payment Instruction by its unique identification. Returns 404 if the Payment Instruction does not exist.
# Get Payment Instructions
Source: https://docs.borderless.xyz/api-reference/payment-instructions/get-payment-instructions
https://sandbox-api.borderless.xyz/v1/api-json get /v1/identities/{identityId}/payment-instructions
Retrieve a list of Payment Instructions with pagination support. Use query parameters `startingAfter` and `limit` to navigate results.
# Delete v1reconciliationimportscsv
Source: https://docs.borderless.xyz/api-reference/reconciliation/delete-v1reconciliationimportscsv
https://sandbox-api.borderless.xyz/v1/api-json delete /v1/reconciliation/imports/csv
# Get v1reconciliationimportsstatus
Source: https://docs.borderless.xyz/api-reference/reconciliation/get-v1reconciliationimportsstatus
https://sandbox-api.borderless.xyz/v1/api-json get /v1/reconciliation/imports/status
# Get v1reconciliationitems
Source: https://docs.borderless.xyz/api-reference/reconciliation/get-v1reconciliationitems
https://sandbox-api.borderless.xyz/v1/api-json get /v1/reconciliation/items
# Get v1reconciliationitems 1
Source: https://docs.borderless.xyz/api-reference/reconciliation/get-v1reconciliationitems-1
https://sandbox-api.borderless.xyz/v1/api-json get /v1/reconciliation/items/{transactionId}
# Get v1reconciliationorphaned transactions
Source: https://docs.borderless.xyz/api-reference/reconciliation/get-v1reconciliationorphaned-transactions
https://sandbox-api.borderless.xyz/v1/api-json get /v1/reconciliation/orphaned-transactions
# Get v1reconciliationorphaned transactions 1
Source: https://docs.borderless.xyz/api-reference/reconciliation/get-v1reconciliationorphaned-transactions-1
https://sandbox-api.borderless.xyz/v1/api-json get /v1/reconciliation/orphaned-transactions/{id}
# Get v1reconciliationruns
Source: https://docs.borderless.xyz/api-reference/reconciliation/get-v1reconciliationruns
https://sandbox-api.borderless.xyz/v1/api-json get /v1/reconciliation/runs
# Get v1reconciliationruns 1
Source: https://docs.borderless.xyz/api-reference/reconciliation/get-v1reconciliationruns-1
https://sandbox-api.borderless.xyz/v1/api-json get /v1/reconciliation/runs/{id}
# Get v1reconciliationsummary
Source: https://docs.borderless.xyz/api-reference/reconciliation/get-v1reconciliationsummary
https://sandbox-api.borderless.xyz/v1/api-json get /v1/reconciliation/summary
# Post v1reconciliationimports
Source: https://docs.borderless.xyz/api-reference/reconciliation/post-v1reconciliationimports
https://sandbox-api.borderless.xyz/v1/api-json post /v1/reconciliation/imports
# Post v1reconciliationimportscsv
Source: https://docs.borderless.xyz/api-reference/reconciliation/post-v1reconciliationimportscsv
https://sandbox-api.borderless.xyz/v1/api-json post /v1/reconciliation/imports/csv
# Get refund capabilities
Source: https://docs.borderless.xyz/api-reference/refunds/get-refund-capabilities
https://sandbox-api.borderless.xyz/v1/api-json get /v1/refunds/capabilities
Returns supported refund paths, accepted request types, chains, and prerequisites for the given (country, fiat).
# Get the organization's default refund destination
Source: https://docs.borderless.xyz/api-reference/refunds/get-the-organizations-default-refund-destination
https://sandbox-api.borderless.xyz/v1/api-json get /v1/refunds/config
Returns the default refund destination used when a transaction has no per-transaction destination, along with its verification freshness. Returns null when none is configured.
# Manually dispatch a refund for a failed or cancelled transaction
Source: https://docs.borderless.xyz/api-reference/refunds/manually-dispatch-a-refund-for-a-failed-or-cancelled-transaction
https://sandbox-api.borderless.xyz/v1/api-json post /v1/transactions/{id}/refund
Starts the refund workflow for the transaction's existing refund plan.
Works even when the transaction was created with `autoRefund: false`, so use this endpoint to trigger refunds that were intentionally left for manual handling.
Optionally pass a `refundDestination` to replace the destination stored on the plan. The override is validated against the PFI's refund capability before dispatch.
Plans in `Created` or `Eligible` status can be dispatched. Plans in `ManualRequired` status can also be dispatched if they were parked after a failed fiat payout; dispatching such a plan records consent to return the funds in crypto, converted from fiat at the current rate.
# Re-confirm the organization's default refund destination
Source: https://docs.borderless.xyz/api-reference/refunds/re-confirm-the-organizations-default-refund-destination
https://sandbox-api.borderless.xyz/v1/api-json post /v1/refunds/config/reconfirm
Resets the verification timestamp to now without changing the destination. Use this to clear a stale warning or rejection.
# Remove the organization's default refund destination
Source: https://docs.borderless.xyz/api-reference/refunds/remove-the-organizations-default-refund-destination
https://sandbox-api.borderless.xyz/v1/api-json delete /v1/refunds/config
Removes the default. Refunds will then fall back to per-transaction destinations.
# Set the organization's default refund destination
Source: https://docs.borderless.xyz/api-reference/refunds/set-the-organizations-default-refund-destination
https://sandbox-api.borderless.xyz/v1/api-json put /v1/refunds/config
Creates or replaces the organization's default refund destination and resets its verification timestamp to now.
# Delete v1rficases references
Source: https://docs.borderless.xyz/api-reference/rfi/delete-v1rficases-references
https://sandbox-api.borderless.xyz/v1/api-json delete /v1/rfi/cases/{id}/references/{referenceId}
# Get v1rficases
Source: https://docs.borderless.xyz/api-reference/rfi/get-v1rficases
https://sandbox-api.borderless.xyz/v1/api-json get /v1/rfi/cases
# Get v1rficases 1
Source: https://docs.borderless.xyz/api-reference/rfi/get-v1rficases-1
https://sandbox-api.borderless.xyz/v1/api-json get /v1/rfi/cases/{id}
# Get v1rficases attachments
Source: https://docs.borderless.xyz/api-reference/rfi/get-v1rficases-attachments
https://sandbox-api.borderless.xyz/v1/api-json get /v1/rfi/cases/{id}/attachments/{attachmentId}
# Post v1rficases attachments
Source: https://docs.borderless.xyz/api-reference/rfi/post-v1rficases-attachments
https://sandbox-api.borderless.xyz/v1/api-json post /v1/rfi/cases/{id}/attachments
# Post v1rficases references
Source: https://docs.borderless.xyz/api-reference/rfi/post-v1rficases-references
https://sandbox-api.borderless.xyz/v1/api-json post /v1/rfi/cases/{id}/references
# Post v1rficases reply
Source: https://docs.borderless.xyz/api-reference/rfi/post-v1rficases-reply
https://sandbox-api.borderless.xyz/v1/api-json post /v1/rfi/cases/{id}/reply
# Post v1rficases resolve
Source: https://docs.borderless.xyz/api-reference/rfi/post-v1rficases-resolve
https://sandbox-api.borderless.xyz/v1/api-json post /v1/rfi/cases/{id}/resolve
# Create a new Deposit transaction
Source: https://docs.borderless.xyz/api-reference/transaction-deposits/create-a-new-deposit-transaction
https://sandbox-api.borderless.xyz/v1/api-json post /v1/deposits
Create a new Deposit transaction using the data provided in the request body.
# Create executable Deposit Quote
Source: https://docs.borderless.xyz/api-reference/transaction-deposits/create-executable-deposit-quote
https://sandbox-api.borderless.xyz/v1/api-json post /v1/deposits/quotes
Create an executable Deposit quote that can later be referenced by its `quoteId` when initiating a deposit. The quote is valid until the returned `expiresAt` timestamp.
# Deprecated. Use GET /organizations/network instead.
Source: https://docs.borderless.xyz/api-reference/transaction-deposits/deprecated-use-get-organizationsnetwork-instead
https://sandbox-api.borderless.xyz/v1/api-json get /v1/deposits/countries
Retrieve a list of all Deposit available Countries.
# Deprecated. Use GET /organizations/network instead.
Source: https://docs.borderless.xyz/api-reference/transaction-deposits/deprecated-use-get-organizationsnetwork-instead-1
https://sandbox-api.borderless.xyz/v1/api-json get /v1/deposits/options
Retrieve a list of all Deposit available Options.
# Get available finance institutions (e.g. banks, mobile money providers)
Source: https://docs.borderless.xyz/api-reference/transaction-deposits/get-available-finance-institutions-eg-banks-mobile-money-providers
https://sandbox-api.borderless.xyz/v1/api-json get /v1/deposits/institutions
Retrieve information about available finance institutions (e.g. banks, mobile money providers) in a specific country for specified currency and payment method.
# Get Deposit Quote
Source: https://docs.borderless.xyz/api-reference/transaction-deposits/get-deposit-quote
https://sandbox-api.borderless.xyz/v1/api-json get /v1/deposits/quotes
Retrieve real-time information about Deposit exchange rates and fees. Deprecated: use GET /deposits/quotes/pfis (optionally with the pfiName query param) for marketplace-aware pricing. The single-PFI shape returned here is equivalent to element [0] of the /pfis response when filtered to one provider.
# Create a new Exchange transaction
Source: https://docs.borderless.xyz/api-reference/transaction-exchanges/create-a-new-exchange-transaction
https://sandbox-api.borderless.xyz/v1/api-json post /v1/exchanges
Create a new Exchange transaction using the data provided in the request body.
# Create a new Withdrawal transaction
Source: https://docs.borderless.xyz/api-reference/transaction-withdrawals/create-a-new-withdrawal-transaction
https://sandbox-api.borderless.xyz/v1/api-json post /v1/withdrawals
Create a new Withdrawal transaction using the data provided in the request body.
# Create executable Withdrawal Quote
Source: https://docs.borderless.xyz/api-reference/transaction-withdrawals/create-executable-withdrawal-quote
https://sandbox-api.borderless.xyz/v1/api-json post /v1/withdrawals/quotes
Create an executable Withdrawal quote that can later be referenced by its `quoteId` when initiating a withdrawal. The quote is valid until the returned `expiresAt` timestamp.
# Deprecated. Use GET /organizations/network instead.
Source: https://docs.borderless.xyz/api-reference/transaction-withdrawals/deprecated-use-get-organizationsnetwork-instead
https://sandbox-api.borderless.xyz/v1/api-json get /v1/withdrawals/countries
Retrieve a list of all Withdrawal available Countries.
# Deprecated. Use GET /organizations/network instead.
Source: https://docs.borderless.xyz/api-reference/transaction-withdrawals/deprecated-use-get-organizationsnetwork-instead-1
https://sandbox-api.borderless.xyz/v1/api-json get /v1/withdrawals/options
Retrieve a list of all Withdrawal available Options.
# Get available finance institutions (e.g. banks, mobile money providers)
Source: https://docs.borderless.xyz/api-reference/transaction-withdrawals/get-available-finance-institutions-eg-banks-mobile-money-providers
https://sandbox-api.borderless.xyz/v1/api-json get /v1/withdrawals/institutions
Retrieve information about available finance institutions (e.g. banks, mobile money providers) in a specific country for specified currency and payment method.
# Get Withdrawal Quote
Source: https://docs.borderless.xyz/api-reference/transaction-withdrawals/get-withdrawal-quote
https://sandbox-api.borderless.xyz/v1/api-json get /v1/withdrawals/quotes
Retrieve real-time information about Withdrawal exchange rates and fees. Deprecated: use GET /withdrawals/quotes/pfis (optionally with the pfiName query param) for marketplace-aware pricing. The single-PFI shape returned here is equivalent to element [0] of the /pfis response when filtered to one provider.
# Attach documents to a transaction.
Source: https://docs.borderless.xyz/api-reference/transactions/attach-documents-to-a-transaction
https://sandbox-api.borderless.xyz/v1/api-json post /v1/transactions/{id}/documents
Uploads transaction documents (e.g. an invoice) for a pending or processing transaction. For payments that require a compliance document, such as SWIFT payouts from a liquidation address, the document is forwarded to the payment provider so the payment can proceed.
# Export transactions
Source: https://docs.borderless.xyz/api-reference/transactions/export-transactions
https://sandbox-api.borderless.xyz/v1/api-json get /v1/transactions/export
Exports a list of transactions that occurred between the specified fromDate and endDate.
# Get a Transaction by id
Source: https://docs.borderless.xyz/api-reference/transactions/get-a-transaction-by-id
https://sandbox-api.borderless.xyz/v1/api-json get /v1/transactions/{id}
Retrieve a Transaction by its unique identification. Returns 404 if the Transaction does not exist.
# Get Transactions
Source: https://docs.borderless.xyz/api-reference/transactions/get-transactions
https://sandbox-api.borderless.xyz/v1/api-json get /v1/transactions
Retrieve a list of Transactions with pagination support. Use query parameters `startingAfter` and `limit` to navigate results.
# Imported-transaction execution portfolio summary
Source: https://docs.borderless.xyz/api-reference/transactions/imported-transaction-execution-portfolio-summary
https://sandbox-api.borderless.xyz/v1/api-json get /v1/transactions/import-benchmark-summary
Portfolio-level vs-market opportunity across the organization's imported, classified transactions — a confidence-gated USD range, suppressed when the interval straddles zero. Powers the import benchmark portfolio card.
# Request cancellation of a transaction.
Source: https://docs.borderless.xyz/api-reference/transactions/request-cancellation-of-a-transaction
https://sandbox-api.borderless.xyz/v1/api-json post /v1/transactions/{id}/cancel
Sends a cancellation request for the specified transaction. Cancellation is not guaranteed and depends on the transaction status.
# Transaction intelligence stats
Source: https://docs.borderless.xyz/api-reference/transactions/transaction-intelligence-stats
https://sandbox-api.borderless.xyz/v1/api-json get /v1/transactions/intelligence-stats
Aggregate counts (total, all-clear, need-review, reconciliation-issues, matched ratio, USD volume) over the same filter set as the transactions list. Powers the Transaction Intelligence Strip.
# Create a new Virtual Account
Source: https://docs.borderless.xyz/api-reference/virtual-accounts/create-a-new-virtual-account
https://sandbox-api.borderless.xyz/v1/api-json post /v1/accounts/{id}/virtual-accounts
Create a new Virtual Account using the data provided in the request body.
# Delete a Virtual Account by id
Source: https://docs.borderless.xyz/api-reference/virtual-accounts/delete-a-virtual-account-by-id
https://sandbox-api.borderless.xyz/v1/api-json delete /v1/accounts/{id}/virtual-accounts/{virtualAccountId}
Delete the specified a Virtual Account by its id. This action is irreversible. Returns 404 if the entity is not found.
# Get a Virtual Account by id
Source: https://docs.borderless.xyz/api-reference/virtual-accounts/get-a-virtual-account-by-id
https://sandbox-api.borderless.xyz/v1/api-json get /v1/accounts/{id}/virtual-accounts/{virtualAccountId}
Retrieve a Virtual Account by its unique identification. Returns 404 if the Virtual Account does not exist.
# Get Virtual Accounts
Source: https://docs.borderless.xyz/api-reference/virtual-accounts/get-virtual-accounts
https://sandbox-api.borderless.xyz/v1/api-json get /v1/accounts/{id}/virtual-accounts
Retrieve a list of Virtual Accounts with pagination support. Use query parameters `startingAfter` and `limit` to navigate results.
# Create a new Webhook Settings
Source: https://docs.borderless.xyz/api-reference/webhooks/create-a-new-webhook-settings
https://sandbox-api.borderless.xyz/v1/api-json post /v1/notifications/webhooks/settings
Create a new Webhook Settings using the data provided in the request body.
# Delete a Webhook Settings by id
Source: https://docs.borderless.xyz/api-reference/webhooks/delete-a-webhook-settings-by-id
https://sandbox-api.borderless.xyz/v1/api-json delete /v1/notifications/webhooks/settings/{id}
Delete the specified a Webhook Settings by its id. This action is irreversible. Returns 404 if the entity is not found.
# Generate Webhook keys
Source: https://docs.borderless.xyz/api-reference/webhooks/generate-webhook-keys
https://sandbox-api.borderless.xyz/v1/api-json post /v1/notifications/webhooks/settings/public-key
Regenerate webhook private/public keys pair and return public key.
# Get a Webhook Settings by id
Source: https://docs.borderless.xyz/api-reference/webhooks/get-a-webhook-settings-by-id
https://sandbox-api.borderless.xyz/v1/api-json get /v1/notifications/webhooks/settings/{id}
Retrieve a Webhook Settings by its unique identification. Returns 404 if the Webhook Settings does not exist.
# Get all Registered Webhooks
Source: https://docs.borderless.xyz/api-reference/webhooks/get-all-registered-webhooks
https://sandbox-api.borderless.xyz/v1/api-json get /v1/notifications/webhooks/settings
Retrieve a list of all Registered Webhooks.
# Get Webhook Events
Source: https://docs.borderless.xyz/api-reference/webhooks/get-webhook-events
https://sandbox-api.borderless.xyz/v1/api-json get /v1/notifications/webhooks/events
Retrieve a list of Webhook Events with pagination support. Use query parameters `startingAfter` and `limit` to navigate results.
# Retrieve Webhook public key
Source: https://docs.borderless.xyz/api-reference/webhooks/retrieve-webhook-public-key
https://sandbox-api.borderless.xyz/v1/api-json get /v1/notifications/webhooks/settings/public-key
Retrieve webhook public key if present in the system.
# Update a Webhook Settings
Source: https://docs.borderless.xyz/api-reference/webhooks/update-a-webhook-settings
https://sandbox-api.borderless.xyz/v1/api-json patch /v1/notifications/webhooks/settings/{id}
Update a Webhook Settings using the data provided in the request body.
# Accounts & Wallets
Source: https://docs.borderless.xyz/docs/accounts
An `account` is a structure that is owned by an identity and has the underlying infratructure or connectivity to interact with stablecoins or fiat.
It is important to configure this correctly, including the web3 wallet provider choice. Please contact us if you have any questions during this process.
Accounts are ultimately linked to identities as a way to streamline and coalesce all places you may hold funds. This is generally a web3 wallet with stablecoins, but can also be your balance with a PFI in local fiat currency. Either way, an `account` is a flexible object to facilitate streamlined and standardized interactions with any PFI, or underlying infrastructure that suites you best.
If you're just getting started, please check out our [quick start guide](/docs/quick-start-guide).
## Account structure diagram
## Overview
Accounts help you group and organize multiple blockchain wallet addresses under a single logical entity, allowing you to operate on an account level rather than dealing with raw blockchain addresses directly. Accounts also facilitate seamless workflows between your blockchain wallets and your local fiat accounts held at some PFIs.
Structure
* Each Identity in the system is associated with: One Account and Multiple SubAccounts
* Each Account (including SubAccounts) can hold multiple Assets, but an asset cannot be duplicated within the same Account.
It is important to note, Borderless is never in the flow of funds. These accounts are either custodied with the PFI, the wallet provider, or self-custodied by the identity itsself. We do not provide any form of custody and we never initiate any movement of funds on behalf of the identity.
### SubAccounts
SubAccounts function the same way as standard Accounts but follow the configuration and rules defined by the Primary Account. The only difference lies in the creation process, which is covered in the sections below on Account Creation and SubAccount Creation.
In all other operations — including Virtual Accounts, Withdrawals, Deposits, Transfers, and Asset Deposits — there is no difference between an Account and a SubAccount.
Throughout this documentation, the term Account refers to both Accounts and SubAccounts, unless explicitly stated otherwise.
## Web3 wallet infrastructure
Web3 wallet infrastructure enables your organization to interact with web3 in a fast and convenient way. We offer several integration options depending on your infrastructure setup and needs. Please click through the tabs below to explore the different options you have available.
Best for advanced teams with custom infrastructure, or those looking for ultimate flexibility.
We support direct blockchain address usage, allowing you to connect with any web3 infrastructure you prefer. You manage all web3 interactions yourself — we provide the necessary endpoints and flexibility.
In this setup, an Account within Borderless acts only as a wrapper around your existing blockchain addresses.
Borderless can:
* Read and display on-chain data: balances, transactions
* Execute asset deposits to your addresses (Deposits, Asset-Deposits)
* We cannot execute any outbound transactions from your address.
Instead, for operations like withdrawals, we generate a transaction instructions, which includes all necessary transaction data, and a pre-built blockchain transaction payload.
You are responsible for executing this transaction on-chain using your own infrastructure.
Once the transaction is confirmed, the withdrawal flow continues as expected on the Borderless platform.
All outbound transaction signing happens on your side using your standalone wallet — Borderless does not manage key material or signing operations.
Best for Organizations already working with Utila.
We also support direct integration with Utila. If Utila is already part of your infrastructure, this option enables a smooth transition to our platform.
Utila uses non-custodial wallets, meaning you are the sole-custodian of your assets, and Borderless does not have access at any time to move the funds on your behalf. These are also using MPC technology for additional layers of security.
An MPC wallet is a multi-party computational wallet, meaning your private key, which is used to secure the wallet, is encrypted and then broken into three parts which are managed by yourself, and Utila technology separately. It's important to note, that Borderless never receives a copy of this private key, and does not gain controlling access at any point.
All outbound transaction signing happens on your side using Utila — Borderless does not manage key material or signing operations.
Best for Organizations already working with Dfns.
If you're already using Dfns as your wallet infrastructure, we offer seamless integration.\
We connect Borderless to your existing Dfns account structure with minimal configuration.
Dfns uses non-custodial wallets, meaning you are the sole-custodian of your assets, and Borderless does not have access at any time to move the funds on your behalf. These are also using MPC technology for additional layers of security.
An MPC wallet is a multi-party computational wallet, meaning your private key, which is used to secure the wallet, is encrypted and then broken into three parts which are managed by yourself, and Dfns technology separately. It's important to note, that Borderless never receives a copy of this private key, and does not gain controlling access at any point.
All outbound transaction signing happens on your side using Dfns — Borderless does not manage key material or signing operations.
Best for startups, and folks working through POCs - we recommend managing your own for enterprises who facilitate meaningful stablecoin payment volumes.
We provide and manage a complete web3 setup for you, powered by Fireblocks. You interact with stablecoins solely through our secure API — no additional setup required, you simply delegate wallet management.
Fireblocks uses non-custodial wallets, meaning you are the sole-custodian of your assets, and Borderless does not have access at any time to move the funds on your behalf. These are also using MPC technology for additional layers of security.
An MPC wallet is a multi-party computational wallet, meaning your private key, which is used to secure the wallet, is encrypted and then broken into three parts which are managed by yourself, and Fireblocks technology separately. It's important to note, that Borderless never receives a copy of this private key, and does not gain controlling access at any point.
To protect your account, we encrypt your MPC key shard with a passphrase which is required for all transactions that this wallet initiates.
In addition to the passphrase, you must also provide a passphraseId, which must be a valid UUID. This identifier is used to back up your MPC key material and is essential for recovery purposes. Even in the event of a system failure on Borderless, having your passphrase and corresponding passphraseId allows you to restore access to your account.
With this integration you can easily:
* Create different blockchain wallets
* View balances
* Track transactions
* Initiate transfers within your organization or to external blockchain addresses
* Use one unified address for all EVM-compatible chains
* Spin up separate addresses for all non-EVM chains
We do not cache or store your passphrase on our side.
If your passphrase is lost or forgotten, access to the account and its funds will be permanently lost.
Please store this passphrase securely, and do not share it. All transactions performed with a valid passphrase are considered legitimate.
If you suspect your passphrase has been compromised, we strongly recommend:
* Creating a new account immediately (in another identity)
* Transferring all assets to the new account
* Contacting our support team to block the compromised account
Currently, passphrase changes are not supported. If you need to rotate or change your passphrase, please contact our support team.
Best for power users needing maximum flexibility and managing multiple infrastructures.
This mode allows you to assign different providers on a main account basis rather than organization-wide. While powerful, it introduces complexity in account management and is not recommended for users unfamiliar with web3 wallet management.
Unlike other providers, MultiProvider does not offer its own Web3 infrastructure integration. Instead, it shifts the provider selection from the organization level to the account level.
With MultiProvider, each identity account can be created using a different Web3 provider. SubAccounts automatically inherit the Web3 provider of the main Account of Identity.
All outbound transaction signing happens on your side using your standalone wallet — Borderless does not manage key material or signing operations.
## Web3 Accounts
### Step 1: Web3 Account creation
Let's create our first account. Please use the tabs to explore specific account creation examples for the web3 infrastructure you use. After this, we will add stablecoin assets.
Please capture account `id` from the response to use it as needed later.
With this provider, Account-level configuration is not required. Blockchain addresses are linked directly to Account Assets, not the Account itself. As such, no additional fields are required for creating Accounts or SubAccounts:
Endpoint: [`POST /accounts`](/api-reference/accounts/create-a-new-account)
```bash request expandable theme={null}
curl -X POST "https://sandbox-api.borderless.xyz/v1/accounts" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-access-token" \
-H "idempotency-key: 8f14e45f-e6c3-4f7e-bd56-1b9a2e46f1d6"\
-d '{
"name": "Main Account",
"identityId": "cm34yhws000343brvezoqdqn0"
}'
```
```json response expandable theme={null}
{
"id": "cm9db4g2s2r7ro224ra6u1qvl",
"type": "web3",
"pfi": null,
"web3Provider": "Standalone",
"name": "Main Account",
"addresses": [
{
"id": "cm9db4g2s2r7ro224ra6u1qvl",
"asset": "USDC_POLYGON",
"address": "0xE79a68B87544ed42Cc5aA805bb056201e7942D3A"
}
],
"assets": [
{
"id": "cm9db4g2s2r7ro224ra6u1qvl",
"asset": "USDC_POLYGON",
"address": "0xE79a68B87544ed42Cc5aA805bb056201e7942D3A"
}
],
"fiats": [],
"identityId": "cm34yhws000343brvezoqdqn0",
"createdAt": "2025-11-19T01:10:26.466Z"
}
```
### Enable Utila as your infrastructure provider
Before using the Utila provider, you must already have access to Utila infrastructure and it must be integrated with your system. To enable Borderless-Utila integration, follow these steps:
1. Go to your Utila console and open your organization.
2. Open the Service Accounts tab.
3. Create a new Service Account.
4. Copy the Service Account Id and private RSA Key and use them to configure your Borderless integration.
Important: Ensure you grant read-only permissions only. Do not include Write, Create, Sign, or Update permissions. Borderless does not require them and assumes no responsibility if they are granted.
To configure Borderless, use the following API endpoint:
Endpoint: [`PUT /organizations/integrations/utila`](/api-reference/integrations-config/setup-utila-integration)
```bash request expandable theme={null}
curl -X POST "https://sandbox-api.borderless.xyz/v1/organizations/integrations/utila" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-access-token" \
-H "idempotency-key: 8f14e45f-e6c3-4f7e-bd56-1b9a2e46f1d6"\
-d {
"utilaServiceAccount": "sa_1234567890abcdef",
"utilaPrivateRSAKey": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADAN..."
}
```
### Create account and add assets with Utila
Once you have linked your Utila account for streamlined interoperability, you can set up an account with your Utila infrastructure similarly to how you would for standalone wallets.
The main difference is when adding an asset to a Borderless Account, you must include the corresponding utilaServiceAccount of a wallet that already exists in your Utila setup.
When using Utila, Borderless does not link the Account entity directly to a Utila wallet.\
Instead, the linkage is done at the Asset level, during asset address assignment. Therefore, no additional fields are required when creating an Account or SubAccount under Utila.
Endpoint: [`POST /accounts/`](/api-reference/accounts/create-a-new-account)
```bash request expandable theme={null}
curl -X POST "https://sandbox-api.borderless.xyz/v1/accounts/" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-access-token" \
-H "idempotency-key: 8f14e45f-e6c3-4f7e-bd56-1b9a2e46f1d6"\
-d '{
"vaultId": "Utila Vault id",
"walletId": "Utila Wallet id", // optional
"name": "Account Name",
"identityId": "Id of Identity",
"assets": [
{
"asset": AssetId
}
]
}'
```
### Enable Dfns as your infrastructure provider
Before using the Dfns provider, you must already have access to Dfns infrastructure and it must be integrated with your system. To enable Borderless-Dfns integration, follow these steps:
1. Go to your Dfns console and open your organization.
2. From the left menu, navigate to Settings.
3. Open the Service Accounts tab.
4. Create a new Service Account (e.g. named Borderless Integration) and fill in all required fields.
5. Create a new Permission set including only:\
"Wallets:Transactions:Read", "Wallets:Transfers:Read", "Wallets:ReadTransaction", "Wallets:ReadTransfer"
Important: Ensure you grant read-only permissions only. Do not include Write, Create, Sign, or Update permissions. Borderless does not require them and assumes no responsibility if they are granted.
6. After creation, open the Service Account and assign Permissions.
7. Copy the auth token and use it along with your appId to configure your Borderless integration. To configure Borderless, use the following API endpoint:
Endpoint: [`PUT /organizations/integrations/dfns`](/api-reference/integrations-config/setup-dfns-integration)
```bash request expandable theme={null}
curl -X POST "https://sandbox-api.borderless.xyz/v1/organizations/integrations/dfns" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-access-token" \
-H "idempotency-key: 8f14e45f-e6c3-4f7e-bd56-1b9a2e46f1d6"\
-d {
"dfnsAppId": "ap-66rrf-kcjqj-8ppri8f3aa4h6opn",
"dfnsAuthToken": "eyJ1eXAiOiJKV1QiLCJhbGciOiJFZERTQSJ9.eyJpc3MiOiJhdXRoLmRmbnMubmluamEiLCJhdWQiOiJkZm5zOmF1dGg6dXNlciIsInN1YiI6Im9yLTZydDRkLWJiNWgwLThkbGJqbjk5aWd1c3N1NTIiLCJqdGkiOiJ0by02Y3JjNC1qMHByNi05YTg4bDM3c3V0dWdwZHU4Iiwic2NvcGUiOiIiLCJwZXJtaXNzaW9ucyI6W10sImh0dHBzOi8vY3VzdG9tL3VzZXJuYW1lIjoiQm9yZGVybGVzczEiLCJodHRwczovL2N1c3RvbS9hcHBfbWV0YWRhdGEiOnsidXNlcklkIjoidXMtMzJwcnUtdnJmbTEtOWhpOWhuOTIzMmk1djUzciIsIm9yZ0lkIjoib3ItNnJ0NGQtYmI1aDAtOGRsYmpuGTlpZ3Vzc3U1MiIsInRva2VuS2luZCI6IlNlcnZpY2VBY2NvdW50In0sImlhdCI6MTczNjM2MzQ5MiwiZXhwIjoxNzk5NDM1NDkyfQ.DhsE-rZ-8cHudw2RklP9nFSbAEGgsVBN_bxjBMm_Rx_ohaT1VRlJRtpHvtd-OkrAvRbyayVzLC49UBQwPs1yBA"
}
```
### Create account and add assets with Dfns
Once you have linked your Dfns account for streamlined interoperability, you can set up an account with your Dfns infrastructure similarly to how you would for standalone wallets.
The main difference is when adding an asset to a Borderless Account, you must include the corresponding dfnsWalletId of a wallet that already exists in your Dfns setup.
When using Dfns, Borderless does not link the Account entity directly to a Dfns wallet.\
Instead, the linkage is done at the Asset level, during asset address assignment. Therefore, no additional fields are required when creating an Account or SubAccount under Dfns.
Endpoint: [`POST /accounts/`](/api-reference/accounts/create-a-new-account)
```bash request expandable theme={null}
curl -X POST "https://sandbox-api.borderless.xyz/v1/accounts/" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-access-token" \
-H "idempotency-key: 8f14e45f-e6c3-4f7e-bd56-1b9a2e46f1d6"\
-d '{
"name": "Account Name",
"identityId": "Id of Identity",
"assets": [
{
"asset": AssetId,
"dfnsWalletId": "wa-7jesf-pmt6i-92lbukigvpvahmki"
}
]
}'
```
If you're using the Fully Managed Web3 provider, you must supply two additional fields when creating the Main Account for an Identity. These are `passphrase` and `passphraseId` which are both established during the creation of your Fireblocks self-custodial, MPC wallet. Read more about this specific configuration just above in the web3 wallet infrastructure section.
Endpoint: [`POST /accounts/`](/api-reference/accounts/create-a-new-account)
```bash request expandable theme={null}
curl -X POST "https://sandbox-api.borderless.xyz/v1/accounts" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-access-token" \
-H "idempotency-key: 8f14e45f-e6c3-4f7e-bd56-1b9a2e46f1d6"\
-d '{
"name": "Main Account",
"identityId": "cm34yhws000343brvezoqdqn0",
"passphrase": "secret-phrase",
"passphraseId": "9849f5bc-bc32-4a48-a023-a89ad2c6d00b"
}'
```
### Step 2: Adding assets to account
With an account set up for this identity, it's necessary to add assets to the account. Specifically, these assets are the stablecoin funds that will be used to initiate off-ramp payments into local fiat currencies. These accounts will also be used to receive funds when on-ramping payments between local fiat currencies and stablecoins.
Please note that when you add new assets to your account, this is a configuration for the stablecoin wallet infrastructure to track these assets correctly. This does not mean you are sending real stablecoin funds to this account with this endpoint. Borderless is fully non-custodial, you will need to transfer your stablecoins directly to this wallet address yourself, or receive funds from an on-ramp transaction.
Please use the account `id` from the response to the previous request above.
Please double check the wallet’s blockchain matches the blockchain of the Asset you’re adding.\
If not, the operation will fail with an error, and funds may be lost.
Please check for Tron-based assets, that the generated address is activated by sending a minimum of 0.1 TRX to it.
Endpoint: [`POST /accounts/{id}/assets`](/api-reference/accounts/add-assets-to-account)
```bash request expandable theme={null}
curl -X POST "https://sandbox-api.borderless.xyz/v1/accounts/{id}/assets" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-access-token" \
-d '{
"asset": "USDC_BASE",
"address": "0xE79a68B87544ed42Cc5aA805bb056201e7942D3A"
}'
```
```json response expandable theme={null}
{
"id": "cm9db4g2s2r7ro224ra6u1qvl",
"asset": "USDC_BASE",
"address": "0xE79a68B87544ed42Cc5aA805bb056201e7942D3A"
}
```
### Step 3: Check account balances
Once you receive funds to this account, and added the stablecoin assets to be tracked on the account, you can easily check the balances at any time. Just pass the account `id` as a parameter in the request, and the balance is returned.
Endpoint: [`GET /accounts/{id}/balances`](/api-reference/accounts/get-account-balances)
```bash request expandable theme={null}
curl -X GET "https://sandbox-api.borderless.xyz/v1/accounts/{id}/balances" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-access-token" \
```
```json response expandable theme={null}
[
{
"type": "asset",
"asset": "USDC_BASE",
"fiat": null,
"total": "0"
}
]
```
## PFI Accounts
### Step 1: Account creation
Let's create our first PFI account. After this, we will add fiat currencies.
Please capture account `id` from the response to use it as needed later.
Before creating a PFI Account, you must first configure Borderless access to the specific PFI you want to use. To do this, use the Integrations API request for that PFI.
For example to configure Finity, use the following API endpoint:
Endpoint: `PUT /organizations/integrations/finity`
Once access to the PFI provider is configured, you can create a PFI Account that will operate with it. To do this, use the standard Account creation request and include the `pfi` property with the name of the PFI you want to link to this Account.
Make sure the fiat currency is supported by chosen PFI provider before adding it to the PFI Account.
Endpoint: `POST /accounts/`
```bash request expandable theme={null}
curl -X POST "https://sandbox-api.borderless.xyz/v1/accounts/" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-access-token" \
-H "idempotency-key: 8f14e45f-e6c3-4f7e-bd56-1b9a2e46f1d6"\
-d '{
"pfi": "Finity",
"name": "Finity Account Name",
"identityId": "Id of Identity",
}'
```
### Step 2: Adding fiat to account
With a PFI Account set up for this identity, it is necessary to add fiat currencies to the account (for example, COP, USD, BRL) that will be used to send payouts, perform exchanges into this PFI Account.
Please use the account `id` from the response to the previous request above.
Endpoint: `POST /accounts/{id}/assets`
```bash request expandable theme={null}
curl -X POST "https://sandbox-api.borderless.xyz/v1/accounts/{id}/assets" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-access-token" \
-d '[
{
"fiat": "USD"
},
{
"fiat": "COP"
}
]'
```
```json response expandable theme={null}
[
{
"id": "cmi7s8wgk471upg23mlc2chms",
"fiat": "USD"
},
{
"id": "cmi7s8wgk471wpg23vjl4rhvb",
"fiat": "COP"
}
]
```
### Step 3: Check account balances
Once you receive funds to this account, and added the stablecoin assets to be tracked on the account, you can easily check the balances at any time. Just pass the account `id` as a parameter in the request, and the balance is returned.
Endpoint: `GET /accounts/{id}/balances`
```bash request expandable theme={null}
curl -X GET "https://sandbox-api.borderless.xyz/v1/accounts/{id}/balances" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-access-token" \
```
```json response theme={null}
[
{
"type": "fiat",
"asset": null,
"fiat": "USD",
"total": "0"
},
{
"type": "fiat",
"asset": null,
"fiat": "COP",
"total": "1405"
}
]
```
If you have any questions, please don't hesitate to reach out to us via [email](mailto:support@borderless.xyz) or slack.
# Borderless Benchmark
Source: https://docs.borderless.xyz/docs/benchmarks-widget
The Borderless Benchmark widget displays fiat/stablecoin exchange rates for the last 30 days.
The chart renders:
* Average buy/sell prices (lines)
* Min/Max bands across Borderless providers
If you're just getting started, please check out our [quick start guide](/docs/quick-start-guide).
## Production widget URL
Please use the following URL when embedding the widget or using it in additional context:
[https://widget.borderless.xyz/rates](https://widget.borderless.xyz/rates)
## Quick start
Embed the widget via an iframe:
```bash bash theme={null}
```
## Query parameters
You can control defaults and UI visibility with URL params.
The specified local fiat currency. (e.g. ARS, USD, BRL, EUR)
The stablecoin to display and compare against. (e.g. USDC, USDT)
The metric value visualized in the widget. (e.g. average or median)
The direction the rates data is visualized. (e.g. sorting)
Hides all other elements except the chart object.
Hides the top control bar. (i.e. the fiat and stablecoin selectors)
Hides the title and subtitles.
Removes the outer padding and framing to fit tight embeds.
Remove the background. This can be useful for seamless embedding.
This parameter defines the shape of the line on the chart, and how it curves to connect between points.
The color of the buy rate line. Please use encodeURIComponent or replace `#` to `%23` to work in URL.
The color of the sell rate line. Please use encodeURIComponent or replace `#` to `%23` to work in URL.
X-axis label text. (e.g. "Date")
Y-axis label text. (e.g.)
Available additional parameters: centralMetric, base, and quote. (e.g. "centralMetric-(base/quote)" will be shown like "Average - USD/USDC")
Position of Y Label on Chart.
Boolean syntax supported: ?hideHeader=true/1/yes/on or false/0/no/off.
## Preselected fiat/asset
```bash bash theme={null}
```
## Only Chart with preselected values
```bash bash theme={null}
```
**Recommendations**
* Sizing: Set width="100%" and adjust height (600-1000px recommended).
* Background: If you pass hideBackground, also set style="background:transparent;" on the iframe to match the host page.
* Accessibility: Provide a descriptive title on the iframe, e.g., title="Exchange Rates (ARS/USDC)".
If you have any questions, please don't hesitate to reach out to us via [email](mailto:support@borderless.xyz) or slack.
# Coverage
Source: https://docs.borderless.xyz/docs/coverage
Borderless is your gateway to global stablecoin payments, powered by our network of locally licensed and regulated partner financial institutions (PFIs). Connect once to the network and get all of the following coverage and capabilities.
If you're just getting started, please check out our [quick start guide](/docs/quick-start-guide).
## Explore the Borderless network
You can explore the network in three primary ways:
* Local Fiat Currency Support
* Country Support
* Partner Finanical Institution (PFI) Support
Use the tabs below to switch how you explore coverage.
## Coverage by Country
Start here to check for your desired country support.
AED Live
United Arab Emirates Dirham
AUD Live
Australian Dollar
BDT Live
Bangladeshi Taka
BOB Live
Bolivian Boliviano
CRC Live
Costa Rican Colon
CZK Coming soon
Czech Koruna
GBP Live
British Pound Sterling
GTQ Live
Guatemalan Quetzal
HKD Live
Hong Kong Dollar
HNL Live
Honduran Lempira
HUF Live
Hungarian Forint
IDR Live
Indonesian Rupiah
ILS Live
Israeli New Shekel
KRW Live
South Korean Won
LKR Live
Sri Lankan Rupee
MYR Live
Malaysian Ringgit
PAB Coming soon
Panamanian Balboa
PYG Live
Paraguayan Guarani
RON Coming soon
Romanian Leu
SGD Live
Singapore Dollar
TZS Live
Tanzanian Shilling
UGX Live
Ugandan Shilling
USD Live
United States Dollar
UYU Coming soon
Uruguayan Peso
XAF Live
Central African CFA Franc
XOF Live
West African CFA Franc
ZAR Live
South African Rand
ARE Live
United Arab Emirates
COD Live
Democratic Republic of the Congo
COG Live
Republic of the Congo
DOM Live
Dominican Republic
Stillman Digital Coming soon
## Key concepts
The three views above share the same primitives. This section defines them so you can interpret coverage consistently.
**Deposits (on-ramps)**\
Local fiat currency moves **from you or your user to a Borderless PFI**, who then converts the local fiat currency into stablecoins and sends it to you, your user, or another approved party.
Examples:
* USD local bank transfer → USDC
* BRL Pix transfer → USDT
**Withdrawals (off-ramps)**\
Stablecoins move **from you or your user to a Borderless PFI**, who then converts the stablecoins into local fiat currency and sends it to you, your user, or another approved party.
Examples:
* USDC → MXN local bank transfer
* USDT → ARS local bank transfer
**First-party payments**
* Funds move between **accounts you control** (corporate accounts, your own wallets, internal balances).
* Common for:
* Treasury operations
* Internal rebalancing (stablecoin ⇄ fiat)
* Funding local payout accounts
**Third-party payments**
* Funds move **to or from your end users, merchants, or suppliers**.
* Common for:
* Merchant payouts
* Supplier payments
* Marketplace disbursements
For each route in the network, we track:
* **Asset in** – e.g. `USDC`, `USDT`, `USD`
* **Fiat out** – e.g. `MXN`, `EUR`, `KES`
* **Network** (for stablecoins) – e.g. `Ethereum`, `Polygon`, `Base`, `Tron`
* **Rails** – e.g. local bank schemes (SPEI, SEPA, FPS), card rails, SWIFT
If you have any questions, please don't hesitate to reach out to us via [email](mailto:support@borderless.xyz) or slack.
# Mastercard Crypto Credential
Source: https://docs.borderless.xyz/docs/crypto-credential
Issue verifiable Crypto Credential usernames for your KYC-verified users, and check counterparties across the Mastercard network, through the Borderless API.
This document is a technical guide for integrating with Mastercard Crypto Credential through the Borderless platform.
Crypto Credential provides a common usable credential for ID-verified consumers from verified Virtual Asset Service Providers (VASPs). Participating VASPs can issue a Crypto Credential username to users who have been properly verified through their KYC process. Any other participating VASP can then verify that credential, helping reduce the risk and friction of duplicative KYC while saving time and cost for both the VASP and the end user.
Borderless acts as the gateway between VASPs and the Mastercard Crypto Credential network. All Mastercard API calls are handled by Borderless on behalf of VASPs using securely stored credential keys. VASPs never communicate with Mastercard directly.
***
## Roles & Terminology
This guide covers two integration roles. Your role determines which flows are relevant to your integration.
| **Role** | **Description** |
| :------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Originator VASP** | A VASP that uses the Borderless API to onboard its own users and wants Crypto Credential created for them so they can be verified when sending transactions. |
| **Beneficiary VASP** | A VASP (PFI) that receives user verification requests from Borderless and needs to use Crypto Credential to validate eligibility before accepting a transaction. |
| **Term** | **Definition** |
| :-------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **User** | The end user — the individual whose identity is verified and for whom a Crypto Credential is created and issued. Corresponds to an **identity** in the Borderless system or a **customer** at your platform (PFI). |
| **Alias** | Any identifier that resolves to a Crypto Credential account. An account has an email alias and a Mastercard-generated domain name alias. |
| **Domain name alias** | The Crypto Credential username Mastercard derives at registration, in the form `user.customer.mastercard`. This is the identifier other participants resolve when sending funds. |
| **ICA** | Interbank Card Association identifier. Mastercard issues one per participant; it scopes every account you create. |
**Which role am I?** If you use the Borderless API to create identities and accounts for your users — you are an **Originator VASP**. If you receive users from Borderless — you are a **Beneficiary VASP**. Some organizations act as both.
***
## Prerequisites
Before integrating with Mastercard Crypto Credential, ensure the following:
1. Your organization is registered on the Borderless platform with active API or Dashboard credentials. Please contact the Borderless team.
2. You have received your Mastercard Crypto Credential keys from Mastercard. Please see the links below for details on how to generate each prerequisite:
* **ICA** — created and shared after onboarding
* **Client ID** — [How to generate](https://developer.mastercard.com/crypto-solutions-api/documentation/mtid/)
* **Encryption Key** — [How to generate an RSA key pair](https://developer.mastercard.com/crypto-solutions-api/documentation/tutorials-and-guides/tutorials/generate-rsa-key-pair/)
3. Your Mastercard keys are stored in Borderless via [`PUT /organizations/integrations`](/api-reference/integrations-config/setup-integration-credentials-consolidated) or through the Borderless Dashboard, and your organization is flagged as a Mastercard partner. These are two separate switches and both must be set — otherwise no Crypto Credential is created and the proxy endpoints report a configuration error.
4. Proxy endpoint access is enabled for your organization, if you intend to call Mastercard directly through Borderless. Contact the Borderless team to turn it on. The passive flows described below do not require it.
Mastercard responses are encrypted. Alongside Mastercard's public encryption key you also provide **your own** RSA private key, which Borderless uses to decrypt them. Generate the pair with the tutorial linked above and share the public certificate with Mastercard during onboarding.
***
## Originator VASP
You use the Borderless API to onboard users and manage their accounts. By storing your Mastercard keys in Borderless, your users automatically receive a Crypto Credential — making them verifiable across the Mastercard Crypto Credential network.
### Creating Crypto Credential
#### Option A: Automatic Creation (Passive)
**How it works:**
This flow uses the standard Borderless API for creating identities and managing compliance. If you are not yet integrated with the Borderless API, see the [Quick Start Guide](/docs/quick-start-guide) to get started.
Once your Mastercard keys are stored in Borderless, a Crypto Credential is created automatically for each identity you create — personal or business. No additional API calls or integration work is needed. The response to [`POST /identities/personal`](/api-reference/identities/create-a-new-personal-identity) and [`POST /identities/business`](/api-reference/identities/create-a-new-business-identity) includes the resulting `cryptoCredential`.
**When to use:**
This is the recommended default for Originator VASPs. Your existing Borderless integration handles everything — creation happens transparently in the background.
**What to implement:**
Nothing. Store your Mastercard keys in Borderless and continue using your existing flow.
If the alias is already registered by another participant, Mastercard rejects the registration. We record the identity as verified and keep serving its status, but the credential itself remains under the participant that registered it first — so `aliases.domainName` is not returned and the Crypto Credential endpoints will not accept it.
An email address is required. Since the alias is the identity's email, an identity created without one gets `cryptoCredential.errors` instead of a credential. This mostly affects business identities, where email is optional in the standard flow.
#### Option B: Create via Proxy Endpoint (Active)
**How it works:**
If you need to create a Crypto Credential at a specific point in your flow — for example for a user who was onboarded outside of Borderless, or when you want explicit control over timing — call the proxy endpoint directly.
**When to use:**
When you need granular control over when and for whom a credential is created, or when the user was not onboarded through the standard Borderless identity flow.
**Example:**
```bash theme={null}
curl -X POST "https://sandbox-api.borderless.xyz/v1/mastercard/crypto-credential/accounts" \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"accountAlias": "user@example.com",
"aliasType": "Email",
"country": "US"
}'
```
**Request body:**
| **Field** | **Type** | **Required** | **Description** |
| :------------------------ | :------- | :----------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `accountAlias` | string | Yes | The alias to register — typically the user's email address. Up to 255 characters. |
| `aliasType` | enum | No | `Email`, `PhoneNumber` or `DomainName`. There is no default — if you omit it, no alias type is sent to Mastercard. |
| `status` | enum | No | `Active`, `Suspended` or `Decommissioned`. Mastercard registers new accounts as `Active`. |
| `country` | enum | No | ISO 3166-1 alpha-2 country code. |
| `statusReasonInformation` | array | No | Up to 10 `{ reasonCode, description }` entries explaining a non-default status. Within each entry `reasonCode` is **required** and must be one of Mastercard's accepted codes; `description` is optional free text, up to 255 characters. |
Full endpoint documentation: [Create a Crypto Credential account](/api-reference/mastercard-crypto-credential/create-a-crypto-credential-account)
Credentials created this way are not linked to a Borderless identity, so they do not appear in `GET /identities/{id}`. Use [Search for a Crypto Credential account](/api-reference/mastercard-crypto-credential/search-for-a-crypto-credential-account) to read them back.
### Crypto Credential Lifecycle
#### Option A: Update via Identity Endpoint (Passive)
**How it works:**
To change an identity's Crypto Credential state — for example to suspend it during an investigation — include a `cryptoCredential` object in the standard identity update request: [`PATCH /identities/personal/{id}`](/api-reference/identities/update-a-personal-identity) or [`PATCH /identities/business/{id}`](/api-reference/identities/update-a-business-identity). Borderless maps your status to the corresponding Mastercard status and handles the API call.
For an identity that already has a credential, omitting `cryptoCredential` leaves it untouched.
For an identity that has none, any update creates one as `Active` — including an update that omits `cryptoCredential` entirely. Note the asymmetry: sending `status: "Suspended"` or `"Decommissioned"` for an identity with no credential creates nothing and returns none. Create the credential first, then change its status in a second call.
**When to use:**
When you manage credential lifecycle through the standard Borderless identity flow. This is the recommended default.
**Example:**
```bash theme={null}
curl -X PATCH "https://sandbox-api.borderless.xyz/v1/identities/personal/{id}" \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"cryptoCredential": {
"status": "Suspended",
"reasonCode": "ALIAS_UNDER_INVESTIGATION",
"reasonDescription": "Account flagged for compliance review"
}
}'
```
**Request body (`cryptoCredential`):**
| **Field** | **Type** | **Required** | **Description** |
| :------------------ | :------- | :----------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `status` | enum | Yes | `Active`, `Suspended` or `Decommissioned`. |
| `reasonCode` | enum | No | Machine readable code explaining the change. A closed set defined by Mastercard — any other value is rejected with `400`. For status changes you will most often need `ALIAS_UNDER_INVESTIGATION` or `OTHER`; the endpoint reference lists every accepted value. |
| `reasonDescription` | string | No | Free-text explanation, up to 255 characters. Only forwarded to Mastercard when `reasonCode` is also set — on its own it is silently dropped. |
`Decommissioned` is permanent and irreversible. Mastercard keeps the alias reserved afterwards, so the same email cannot be registered again — by you or by any other participant.
You can only change a credential your organization issued. If it was issued by another participant the credential is left untouched, but the request still returns `200` — the reason arrives in `cryptoCredential.errors`, not as an error status code. Check that field rather than relying on the HTTP status.
#### Option B: Update via Proxy Endpoint (Active)
**How it works:**
If you need full control over Mastercard-specific fields, or want to update a credential that is not tied to a Borderless identity, call the proxy endpoint directly.
**Example:**
```bash theme={null}
curl -X PUT "https://sandbox-api.borderless.xyz/v1/mastercard/crypto-credential/accounts" \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"accountAlias": "user@example.com",
"status": "Suspended",
"statusReasonInformation": [{
"reasonCode": "ALIAS_UNDER_INVESTIGATION",
"description": "Account flagged for compliance review"
}]
}'
```
Returns `204 No Content` on success.
Full endpoint documentation: [Update a Crypto Credential account](/api-reference/mastercard-crypto-credential/update-a-crypto-credential-account)
### Credential Lookup
As an Originator VASP, you may need to check a Crypto Credential before initiating a transaction.
#### Option A: Standard Identity Endpoint (Passive)
Use [`GET /identities/{id}`](/api-reference/identities/get-an-identity-by-id). The response includes the identity's `cryptoCredential`, with state read live from Mastercard.
```bash theme={null}
curl -X GET "https://sandbox-api.borderless.xyz/v1/identities/{id}" \
-H "Authorization: Bearer {token}"
```
**Response — `cryptoCredential`:**
```json theme={null}
{
"cryptoCredential": {
"aliases": {
"email": "user@example.com",
"domainName": "user.yourcompany.mastercard"
},
"status": "Active",
"country": "US",
"vasps": null,
"assets": [],
"errors": null
}
}
```
| **Field** | **Description** |
| :------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `aliases.email` | The alias the credential is registered under. May differ from `identity.email` if the user has since changed their address — the credential stays bound to the alias it was created with. |
| `aliases.domainName` | The Crypto Credential username. `null` unless your organization issued the credential. |
| `status` | `Active`, `Suspended` or `Decommissioned`, as currently reported by Mastercard. `null` when `errors` is set. |
| `country` | The country the credential is registered in, ISO 3166-1 alpha-2. |
| `assets` | The assets the alias can receive, populated once blockchain addresses are registered. Always an array — `[]` when it can receive none. |
| `assets[].asset` | An `AssetId` such as `USDC_ETHEREUM`, combining the token and the network it resolves on. |
| `assets[].vasps` | Participants that can route **that asset** to the alias. `null` unless Mastercard entitles your ICA to VASP data. |
| `vasps` | Participants that can route funds to the alias at all. `null` unless Mastercard entitles your ICA to VASP data. |
| `errors` | Non-`null` when the operation did not complete — Mastercard unreachable, no email on the identity, a rejected registration, or an attempt to change a credential issued elsewhere. Each entry carries a `message` and an optional `reasonCode`. |
`cryptoCredential` is present when a VASP in the Borderless network has verified this identity — either your own organization, or a PFI you routed compliance to. It is scoped to **that identity**, not to the email address: verification happens once per identity, and if the same person later appears as a separate identity — a different customer record, at your platform or another — that record starts without a credential until it completes compliance in its own right. We do not treat two identities as the same person because they share an alias.
Every field inside `cryptoCredential` is always present in the response, holding `null` — or `[]` for `assets` — where there is no value. Nothing is dropped from the object. Only `cryptoCredential` itself is omitted, and only when your organization is not set up for Mastercard. Test for `=== null`, not for a missing key.
`errors` and `status` never both carry a value: when `errors` is set, `status`, `country` and `vasps` are `null` and `assets` is `[]`. `aliases` stays populated in most error cases, so it remains the one field you can still read. Treat the state as unknown and retry — do not treat it as an absent credential.
`cryptoCredential: null` does **not** mean the user has no Crypto Credential. It means we hold no record for this identity — the same alias may be registered by a participant outside the Borderless network. To ask the network directly, call [`GET /mastercard/crypto-credential/alias-lookup`](/api-reference/mastercard-crypto-credential/look-up-a-crypto-credential-alias).
A Crypto Credential identifies a **verified alias**, not the person currently in front of you. `status: "Active"` confirms that the holder of that alias completed verification with a network participant. It does not confirm that whoever is contacting you now controls that alias. Establish alias ownership by your own means before relying on it.
#### Option B: Proxy Endpoints (Active)
**Cross-network lookup** — query the entire Mastercard network to check an alias at any participant:
```bash theme={null}
curl -X GET "https://sandbox-api.borderless.xyz/v1/mastercard/crypto-credential/alias-lookup?accountAlias=recipient@example.com" \
-H "Authorization: Bearer {token}"
```
Optional query parameters: `asset` to narrow the result to one asset and network pair, plus `offset` (default `0`) and `limit` (default `25`, maximum `100`) to page through the alias's assets.
Full endpoint documentation: [Look up a Crypto Credential alias](/api-reference/mastercard-crypto-credential/look-up-a-crypto-credential-alias)
**Account search** — read the accounts your own organization registered:
```bash theme={null}
curl -X GET "https://sandbox-api.borderless.xyz/v1/mastercard/crypto-credential/accounts/search?accountAlias=user@example.com" \
-H "Authorization: Bearer {token}"
```
Full endpoint documentation: [Search for a Crypto Credential account](/api-reference/mastercard-crypto-credential/search-for-a-crypto-credential-account)
**alias-lookup vs accounts/search:** `alias-lookup` queries the **entire Mastercard network** and returns status, country and supported assets — but never a blockchain address or an alias list. `accounts/search` is scoped to **your own ICA** and returns the full account, including every alias and registered address. Use `alias-lookup` to check a counterparty; use `accounts/search` to inspect your own records.
### Crypto Address
Registering a blockchain address links it to a Crypto Credential and declares which asset and network it supports. This is what allows other participants to send funds to your user by alias, and lets Mastercard confirm the recipient can actually receive a given asset on a given chain before a transaction starts.
#### Option A: Automatic via Borderless Account (Passive)
This flow is planned for an upcoming release. Until it ships, register addresses with the proxy endpoints below.
Once available, adding blockchain addresses to a Borderless Account will register them against the user's Crypto Credential automatically, and changes to those addresses will propagate to Mastercard.
#### Option B: Manage via Proxy Endpoints (Active)
**How it works:**
Register, update and decommission blockchain addresses directly.
**Example:**
```bash theme={null}
curl -X POST "https://sandbox-api.borderless.xyz/v1/mastercard/crypto-credential/crypto-addresses" \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"accountAlias": "user@example.com",
"address": "0x1234567890abcdef1234567890abcdef12345678",
"asset": "USDC_ETHEREUM"
}'
```
**Request body:**
| **Field** | **Type** | **Required** | **Description** |
| :------------- | :------- | :----------- | :------------------------------------------------------------------------------------------------------------------------------- |
| `accountAlias` | string | Yes | The alias the address belongs to. Up to 255 characters. |
| `address` | string | Yes | The blockchain wallet address. Between 10 and 255 characters. |
| `asset` | enum | No | An `AssetId` such as `USDC_ETHEREUM` or `USDT_POLYGON`. Borderless splits it into the asset and network pair Mastercard expects. |
The response carries the address `id`. Keep it — the update, get and decommission endpoints address the record by that identifier, and it is otherwise only recoverable through `accounts/search`.
**Additional address endpoints:**
* [`PUT /mastercard/crypto-credential/crypto-addresses/{cryptoAddressId}`](/api-reference/mastercard-crypto-credential/update-a-registered-blockchain-address) — change the `accountAlias`, `address`, `asset` or `status`. All four are optional; returns `204 No Content`
* [`DELETE /mastercard/crypto-credential/crypto-addresses/{cryptoAddressId}`](/api-reference/mastercard-crypto-credential/decommission-a-registered-blockchain-address) — decommission permanently; returns `204 No Content`
* [`GET /mastercard/crypto-credential/crypto-addresses/{cryptoAddressId}`](/api-reference/mastercard-crypto-credential/get-a-registered-blockchain-address) — read a single address
Full endpoint documentation: [Register a blockchain address](/api-reference/mastercard-crypto-credential/register-a-blockchain-address)
A registered address makes your user discoverable as a recipient across the Crypto Credential network. Completing an inbound transfer additionally requires responding to Mastercard alias resolution requests, which Borderless does not currently handle on your behalf.
***
## Beneficiary VASP
As a Beneficiary VASP, you receive users from Borderless. When an identity already carries a Crypto Credential, Borderless passes it to your platform — enabling a simplified compliance process. If the identity has none, Borderless creates a Crypto Credential on your behalf after the user passes compliance at your platform.
The integration requires **minimal changes on your side**. All existing flows remain unchanged — the integration is entirely additive. VASPs that are not participating in the program are not affected in any way.
### Creating Crypto Credential
#### Option A: Automatic Creation (Passive)
When a user is sent to your platform by Borderless, they go through your standard compliance and KYC process. Borderless monitors the outcome — either via long polling or by receiving a webhook from your system — and waits for your decision.
Once you approve the user, Borderless automatically creates a Crypto Credential record in the Mastercard network on your behalf, using your stored keys. If you reject the user, Borderless suspends the credential instead and passes your rejection reasons along as the explanation.
This is the default behaviour and **requires no changes to your existing flow**.
It is recommended that a blockchain address be linked to a user's Crypto Credential username, so the crypto address can be used for both sending and receiving from other participants in the global Crypto Credential network.
#### Option B: Create via Proxy Endpoint (Active)
If you need to create a Crypto Credential independently — for a user who was not onboarded through Borderless, or at a specific point in your own flow — use the proxy endpoint directly:
```bash theme={null}
curl -X POST "https://sandbox-api.borderless.xyz/v1/mastercard/crypto-credential/accounts" \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"accountAlias": "user@example.com",
"aliasType": "Email",
"country": "US"
}'
```
Full endpoint documentation: [Create a Crypto Credential account](/api-reference/mastercard-crypto-credential/create-a-crypto-credential-account)
Once a Crypto Credential username has been created and linked to a blockchain address, the VASP is responsible for telling their user that they can receive from other Crypto Credential network participants using that username. The username is the Mastercard-generated domain name alias. The proxy response returns it in `additionalAccountAliases`, as the entry whose `aliasType` is `DomainName`; in the passive identity flow the same value appears as `aliases.domainName`.
### Crypto Credential Lifecycle
#### Option A: Automatic via Compliance Status (Passive)
**How it works:**
When you update a user's status at your platform — for example when a user fails re-verification or is flagged for investigation — Borderless receives that update through your existing reporting mechanism and maps it to the corresponding Mastercard status. Your rejection reasons are passed through as the explanation.
**What to implement:**
Nothing. Continue using your existing status reporting flow.
#### Option B: Update via Proxy Endpoint (Active)
If you need direct control over credential status, call the proxy endpoint with the same payload as described for Originator VASPs:
Full endpoint documentation: [Update a Crypto Credential account](/api-reference/mastercard-crypto-credential/update-a-crypto-credential-account)
### Retrieving Crypto Credential
#### Option A: Receive Credential Data (Passive)
**How it works:**
Once enabled, the user payload sent to your platform includes a `cryptoCredential` object alongside the standard user data you already receive. No additional API calls are needed.
This is not turned on by default. Borderless enables it after you confirm your system accepts the new field — an unrecognised field can otherwise fail schema validation on your side.
**What to implement:**
* Update your user creation endpoint to accept the `cryptoCredential` field.
* If `status` is `Active`, consider a reduced review based on your internal compliance policy.
**Example payload from Borderless:**
```json theme={null}
{
"firstName": "John",
"lastName": "Doe",
"email": "john@example.com",
"...": "your standard user fields",
"cryptoCredential": {
"aliases": { "email": "john@example.com", "domainName": null },
"status": "Active",
"country": "US",
"assets": [
{ "asset": "USDC_ETHEREUM", "vasps": ["VASP_A"] }
]
}
}
```
If no VASP in the Borderless network has verified the identity yet, `cryptoCredential` is `null`. Proceed with your standard KYC flow.
`aliases.domainName` is `null` unless your organization issued the credential itself, because only the issuing participant can act on it.
Not all participants choose to display assets and networks during onboarding to Crypto Credential, so not every user on the network has them associated with their username. If there are associated assets and networks they will be returned; if not, `assets` is empty.
#### Option B: Query the Network (Active)
**How it works:**
Borderless sends user data to your system as it does today. When you want to check an alias against the Mastercard network, call the proxy endpoint yourself. This gives you full control over when and how you retrieve credential data.
**What to implement:**
* Call [`GET /mastercard/crypto-credential/alias-lookup`](/api-reference/mastercard-crypto-credential/look-up-a-crypto-credential-alias) with the user's alias.
* Use the status returned to make a compliance decision: reduced review, or full KYC.
```bash theme={null}
curl -X GET "https://sandbox-api.borderless.xyz/v1/mastercard/crypto-credential/alias-lookup?accountAlias=john@example.com" \
-H "Authorization: Bearer {token}"
```
A network lookup tells you that the alias has been verified by some participant. It is not a record held by Borderless, and it carries no information about which participant verified the user or when. Your compliance team decides what that is worth.
***
## Comparison: Passive vs Active
| **Flow** | **Passive (Automatic)** | **Active (Manual)** |
| :-------------------------------------- | :---------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------- |
| **Scope** ⚠️ | **The Borderless network** — bound to a Borderless identity, so verification counts per identity, not per email address | **The Mastercard network** — bound to an alias, with no Borderless record. Invisible to the identity endpoints |
| **Creating Credential** | Created automatically with the identity, or after the PFI approves the user | Call `POST /mastercard/crypto-credential/accounts` |
| **Credential Lifecycle** | Send `cryptoCredential` on `PATCH /identities/personal/{id}` (Originator), or report a status change (Beneficiary) | Call `PUT /mastercard/crypto-credential/accounts` |
| **Credential Lookup** | `GET /identities/{id}` returns `cryptoCredential` | Call `GET /mastercard/crypto-credential/alias-lookup` or `/accounts/search` |
| **Crypto Address** | Planned for an upcoming release | Call `POST`, `PUT`, `DELETE` and `GET` on `/mastercard/crypto-credential/crypto-addresses` |
| **Retrieving Credential** (Beneficiary) | `cryptoCredential` included in the user payload | Call `GET /mastercard/crypto-credential/alias-lookup` |
| **Integration effort** | No additional API calls needed | Requires implementing proxy endpoint calls |
**Scope is the one row that changes your architecture.** Everything else in this table is a choice about effort; that row is a choice about where the credential lives. Anything created actively exists only in Mastercard's ledger and will never appear on a Borderless identity — if you use both flows, reconciling the two views is on you.
***
## API Reference
All endpoints require a Bearer token. See [Authentication](/api-reference/authentication).
### Borderless API Endpoints
These standard Borderless endpoints participate in the Crypto Credential flow:
| **Method** | **Endpoint** | **Description** | **Docs** |
| :--------- | :----------------------------- | :---------------------------------------------------------------------------- | :-------------------------------------------------------------------- |
| POST | `/v1/identities/personal` | Create a personal identity — creates a Crypto Credential automatically | [View docs](/api-reference/identities/create-a-new-personal-identity) |
| POST | `/v1/identities/business` | Create a business identity — creates a Crypto Credential automatically | [View docs](/api-reference/identities/create-a-new-business-identity) |
| GET | `/v1/identities/{id}` | Get identity by ID — includes `cryptoCredential` | [View docs](/api-reference/identities/get-an-identity-by-id) |
| PATCH | `/v1/identities/personal/{id}` | Update a personal identity — accepts `cryptoCredential` for lifecycle changes | [View docs](/api-reference/identities/update-a-personal-identity) |
| PATCH | `/v1/identities/business/{id}` | Update a business identity — accepts `cryptoCredential` for lifecycle changes | [View docs](/api-reference/identities/update-a-business-identity) |
### Configuration
| **Method** | **Endpoint** | **Description** | **Docs** |
| :--------- | :------------------------------- | :----------------------------------------------------------------------------------------------- | :----------------------------------------------------------------------------------------- |
| PUT | `/v1/organizations/integrations` | Provide Mastercard Crypto Credential keys (also available via Dashboard). Returns `202 Accepted` | [View docs](/api-reference/integrations-config/setup-integration-credentials-consolidated) |
### Proxy Endpoints
Proxy endpoints require proxy access to be enabled for your organization. Without it every call below returns `403 Forbidden` with `Mastercard Proxy access is not enabled for your organization`. Contact the Borderless team to enable it.
| **Method** | **Endpoint** | **Description** | **Docs** |
| :--------- | :-------------------------------------------------------------------- | :--------------------------------------------- | :---------------------------------------------------------------------------------------------------- |
| POST | `/v1/mastercard/crypto-credential/accounts` | Register an alias with Crypto Credential | [View docs](/api-reference/mastercard-crypto-credential/create-a-crypto-credential-account) |
| PUT | `/v1/mastercard/crypto-credential/accounts` | Change an account's status | [View docs](/api-reference/mastercard-crypto-credential/update-a-crypto-credential-account) |
| GET | `/v1/mastercard/crypto-credential/accounts/search` | Read accounts registered under your ICA | [View docs](/api-reference/mastercard-crypto-credential/search-for-a-crypto-credential-account) |
| GET | `/v1/mastercard/crypto-credential/alias-lookup` | Look up an alias across the Mastercard network | [View docs](/api-reference/mastercard-crypto-credential/look-up-a-crypto-credential-alias) |
| POST | `/v1/mastercard/crypto-credential/crypto-addresses` | Register a blockchain address | [View docs](/api-reference/mastercard-crypto-credential/register-a-blockchain-address) |
| PUT | `/v1/mastercard/crypto-credential/crypto-addresses/{cryptoAddressId}` | Update a registered address | [View docs](/api-reference/mastercard-crypto-credential/update-a-registered-blockchain-address) |
| DELETE | `/v1/mastercard/crypto-credential/crypto-addresses/{cryptoAddressId}` | Decommission an address | [View docs](/api-reference/mastercard-crypto-credential/decommission-a-registered-blockchain-address) |
| GET | `/v1/mastercard/crypto-credential/crypto-addresses/{cryptoAddressId}` | Read a registered address | [View docs](/api-reference/mastercard-crypto-credential/get-a-registered-blockchain-address) |
### Webhook
Forwarding Mastercard event notifications to your webhook endpoint is planned for an upcoming release.
Mastercard sends event notifications to Borderless, which holds the single webhook registration for your ICA. Once forwarding ships, those events will be delivered through the [Borderless webhook mechanism](/docs/webhooks) you already use, with the Mastercard payload passed through unchanged for event types Borderless does not model itself.
***
## Frequently Asked Questions
**Do I need to register with Mastercard separately?**
Yes. Your organization must have an active contract with Mastercard and receive credential keys (ICA, Client ID and Encryption Key). You also generate your own RSA key pair for decrypting responses. You never communicate with Mastercard directly — Borderless handles all API calls on your behalf using your stored keys.
**What happens if an identity has no Crypto Credential?**
For Beneficiary VASPs: `cryptoCredential` is `null` in the user payload. Proceed with your standard KYC process. Once you approve the user, Borderless creates a Crypto Credential for them.
For Originator VASPs: a Crypto Credential is created automatically with the identity. If `cryptoCredential` is missing entirely, your organization is not set up — either it is not flagged as a Mastercard partner, or one of the required keys is absent. An alias already registered by another participant is a different case: `cryptoCredential` is still returned, just without `aliases.domainName`.
**Does `null` mean the user has no Crypto Credential at all?**
No. It means we hold no verification record for that identity. The same alias may be registered by a participant outside the Borderless network. Use `alias-lookup` to ask the network.
**Can Beneficiary VASPs auto-approve users based on a Crypto Credential?**
`status: "Active"` means the alias holder was verified by a participant in the network. A Crypto Credential indicates that a user has been verified by an eligible VASP and may be eligible for the requested activity — it does not eliminate the need for the receiving or sending VASP to meet all relevant regulatory and compliance obligations, including establishing that the person contacting you controls the alias. Your compliance team defines the policy.
**Why is `aliases.domainName` missing?**
Because the credential was issued by another participant — either a PFI you routed compliance to, or a VASP outside Borderless. Only the issuing participant can surface the username or act on the credential.
**Why does `aliases.email` differ from `identity.email`?**
The credential stays bound to the alias it was registered with. If the user later changes their email address on your platform, the credential does not follow. Other participants will continue to resolve the original alias.
**What is the difference between alias-lookup and accounts/search?**
`alias-lookup` queries the entire Mastercard network and returns status, country and supported assets. `accounts/search` is scoped to your own ICA and returns full account detail, including aliases and registered addresses.
**Can my organization be both an Originator and Beneficiary VASP?**
Yes. Some organizations act as both — onboarding their own users (Originator) while also receiving users from other VASPs through Borderless (Beneficiary). Implement the flows for both roles as needed.
**What is the sandbox base URL?**
`https://sandbox-api.borderless.xyz`. Use this for all integration testing. Contact Borderless for production credentials and base URL.
The Mastercard sandbox returns mock responses and validates only the length and data type of request parameters. It is suitable for verifying your integration wiring, not for exercising complete credential lifecycles.
***
## Support
For questions or integration support, reach out to the Borderless team:
* **Email:** [support@borderless.xyz](mailto:support@borderless.xyz)
* **Slack:** your dedicated partner channel
* **API Docs:** [docs.borderless.xyz](https://docs.borderless.xyz)
# Deposit Webhooks
Source: https://docs.borderless.xyz/docs/deposit-webhooks
If you're just getting started, please check out our [quick start guide](/docs/quick-start-guide).
## Transaction creation
When a deposit request is submitted to the borderless, a webhook notification will be sent to the configured webhook URL. This notification will contain the relevant transaction details for further processing or integration with your system. Webhook payload is below:
```bash bash theme={null}
{
"type": "Transaction_Created",
"organizationId": "clxt0xrqp0000gokerkq2mpdl",
"data": {
"id": "cmbz26gn6000eyn24nq2hgutw",
"type": "Deposit",
"status": "Submitted",
"source": {
"asset": null,
"amount": "1000",
"fiatCurrency": "USD",
"paymentMethod": "ACH",
"accountId": null,
"accountName": null,
"sender": null
},
"destination": {
"asset": "USDC_ETHEREUM",
"amount": null,
"fiatCurrency": null,
"imad": null,
"reference": null,
"omad": null,
"traceNumber": null,
"externalAddress": null,
"accountId": "cmbhs3xxa000nynt7lqwbyjsw",
"accountName": "Main Account",
"paymentInstructionId": null
},
"instructions": null,
"createdAt": "2025-06-16T12:16:32.706Z",
"txHash": [],
"feeAmount": "0",
"failureReason": null,
"counterPartyIdentityId": "cmbhs3xxa000nynt7abc12345",
"virtualAccountId": null
},
"timestamp": 1750076192717
}
```
## Transaction state changes
Subsequent transaction processing updates and state changes will be communicated via webhook notifications to the configured webhook URL. Webhook payload remains as previous, please note its status change:
### Verifying
```bash bash theme={null}
{
"type": "Transaction_Updated",
"organizationId": "clxt0xrqp0000gokerkq2mpdl",
"data": {
"id": "cmbz26gn6000eyn24nq2hgutw",
"type": "Deposit",
"status": "Verifying",
"source": {
"asset": null,
"amount": "1000",
"fiatCurrency": "USD",
"paymentMethod": "ACH",
"accountId": null,
"accountName": null,
"sender": null
},
"destination": {
"asset": "USDC_ETHEREUM",
"amount": null,
"fiatCurrency": null,
"imad": null,
"reference": null,
"omad": null,
"traceNumber": null,
"externalAddress": null,
"accountId": "cmbhs3xxa000nynt7lqwbyjsw",
"accountName": "Main Account",
"paymentInstructionId": null
},
"instructions": null,
"createdAt": "2025-06-16T12:16:32.706Z",
"txHash": [],
"feeAmount": "0",
"failureReason": null,
"counterPartyIdentityId": "cmbhs3xxa000nynt7abc12345",
"virtualAccountId": null
},
"timestamp": 1750076193367
}
```
### Orchestrating
```bash bash theme={null}
{
"type": "Transaction_Updated",
"organizationId": "clxt0xrqp0000gokerkq2mpdl",
"data": {
"id": "cmbz26gn6000eyn24nq2hgutw",
"type": "Deposit",
"status": "Orchestrating",
"source": {
"asset": null,
"amount": "1000",
"fiatCurrency": "USD",
"paymentMethod": "ACH",
"accountId": null,
"accountName": null,
"sender": null
},
"destination": {
"asset": "USDC_ETHEREUM",
"amount": null,
"fiatCurrency": null,
"imad": null,
"reference": null,
"omad": null,
"traceNumber": null,
"externalAddress": null,
"accountId": "cmbhs3xxa000nynt7lqwbyjsw",
"accountName": "Main Account",
"paymentInstructionId": null
},
"instructions": null,
"createdAt": "2025-06-16T12:16:32.706Z",
"txHash": [],
"feeAmount": "0",
"failureReason": null,
"counterPartyIdentityId": "cmbhs3xxa000nynt7abc12345",
"virtualAccountId": null
},
"timestamp": 1750076193658
}
```
### Pending
```bash bash theme={null}
{
"type": "Transaction_Updated",
"organizationId": "clxt0xrqp0000gokerkq2mpdl",
"data": {
"id": "cmbz26gn6000eyn24nq2hgutw",
"type": "Deposit",
"status": "Pending",
"source": {
"asset": null,
"amount": "1000",
"fiatCurrency": "USD",
"paymentMethod": "ACH",
"accountId": null,
"accountName": null,
"sender": null
},
"destination": {
"asset": "USDC_ETHEREUM",
"amount": "1000",
"fiatCurrency": null,
"imad": null,
"reference": null,
"omad": null,
"traceNumber": null,
"externalAddress": null,
"accountId": "cmbhs3xxa000nynt7lqwbyjsw",
"accountName": "Main Account",
"paymentInstructionId": null
},
"instructions": {
"amount": "1000.0",
"currency": "usd",
"bank_name": "Bank of Nowhere",
"bank_address": "1800 North Pole St., Orlando, FL 32801",
"payment_rail": "wire",
"deposit_message": "BRGZHDZ83UK2884Y6G3U",
"bank_account_number": "11223344556677",
"bank_routing_number": "123456789",
"bank_beneficiary_name": "Bridge Ventures Inc",
"bank_beneficiary_address": "1234 Elm St, Springfield, IL 12345"
},
"createdAt": "2025-06-16T12:16:32.706Z",
"txHash": [],
"feeAmount": "0",
"failureReason": null,
"counterPartyIdentityId": "cmbhs3xxa000nynt7abc12345",
"virtualAccountId": null
},
"timestamp": 1750076194846
}
```
### Completed
```bash bash theme={null}
{
"type": "Transaction_Updated",
"organizationId": "clxt0xrqp0000gokerkq2mpdl",
"data": {
"id": "cmbz26gn6000eyn24nq2hgutw",
"type": "Deposit",
"status": "Completed",
"source": {
"asset": null,
"amount": "1000",
"fiatCurrency": "USD",
"paymentMethod": "ACH",
"accountId": null,
"accountName": null,
"sender": null
},
"destination": {
"asset": "USDC_ETHEREUM",
"amount": "1000",
"fiatCurrency": null,
"imad": null,
"reference": null,
"omad": null,
"traceNumber": null,
"externalAddress": null,
"accountId": "cmbhs3xxa000nynt7lqwbyjsw",
"accountName": "Main Account",
"paymentInstructionId": null
},
"instructions": {
"amount": "1000.0",
"currency": "usd",
"bank_name": "Bank of Nowhere",
"bank_address": "1800 North Pole St., Orlando, FL 32801",
"payment_rail": "wire",
"deposit_message": "BRGZHDZ83UK2884Y6G3U",
"bank_account_number": "11223344556677",
"bank_routing_number": "123456789",
"bank_beneficiary_name": "Bridge Ventures Inc",
"bank_beneficiary_address": "1234 Elm St, Springfield, IL 12345"
},
"createdAt": "2025-06-16T12:16:32.706Z",
"txHash": [
"0xabc123..."
],
"feeAmount": "0",
"failureReason": null,
"counterPartyIdentityId": "cmbhs3xxa000nynt7abc12345",
"virtualAccountId": null
},
"timestamp": 1750076495740
}
```
## Transaction failure
In the case of a transaction failure, a webhook notification is sent to the configured webhook URL. This notification contains detailed information about the transaction and the reason for its failure.
```bash bash theme={null}
{
"type": "Transaction_Updated",
"organizationId": "clxt0xrqp0000gokerkq2mpdl",
"data": {
"id": "cmbz5vfzr0001ynfeqby1yypt",
"type": "Deposit",
"status": "Failed",
"source": {
"asset": null,
"amount": "1000",
"fiatCurrency": "USD",
"paymentMethod": "ACH",
"accountId": null,
"accountName": null,
"sender": null
},
"destination": {
"asset": "USDC_SOLANA",
"amount": null,
"fiatCurrency": null,
"imad": null,
"reference": null,
"omad": null,
"traceNumber": null,
"externalAddress": null,
"accountId": "cmbz2dgni000tyn241ip38gwj",
"accountName": "Main Account",
"paymentInstructionId": null
},
"instructions": null,
"createdAt": "2025-06-16T13:59:57.111Z",
"txHash": [],
"feeAmount": "0",
"failureReason": "Couldn't find asset USDC_SOLANA in account: cmbz2dgni000tyn241ip38gwj, add this asset to account before using it",
"counterPartyIdentityId": "cmbhs3xxa000nynt7abc12345",
"virtualAccountId": null
},
"timestamp": 1750082398433
}
```
If you have any questions, please don't hesitate to reach out to us via [email](mailto:support@borderless.xyz) or slack.
# On-ramp (Deposit)
Source: https://docs.borderless.xyz/docs/deposits
On-ramping is converting `fiat currencies` into `stablecoins` such as USDT or USDC. This conversion is facilitated by the PFIs on the Borderless network and can be part of either a payin or payout flow simply depending on if you are sending or receiving the payments. In this scenario you are ultimately sending or receiving stablecoins, after the local fiat currencies are converted at the PFI.
On-ramps are a simple 3 step process.
Optionally, you can also request a quote before initiating the on-ramp to have a transparent view of the estimated fees and exchange rates.
Quotes are returned directly from the PFIs, and are regularly changing. Quotes are not firm, and they do not guarantee any final received amount. They are estimates only, and Borderless is not responsible for incorrect quotes provided to us by PFIs.
Endpoint: [`GET /deposits/quotes`](/api-reference/transaction-deposits/get-deposit-quote)
```bash request expandable theme={null}
curl -X GET 'https://sandbox-api.borderless.xyz/v1/deposits/quotes' \
-H 'Authorization: Bearer your-access-token' \
-H 'Content-Type: application/json' \
-d '{
"country": "US",
"fiat": "USD",
"asset": "USDC_POLYGON",
"paymentMethod": "ACH",
"fromAmount": "10"
}'
```
```json response expandable theme={null}
{
"limits": {
"transaction": {
"minAmount": "1",
"maxAmount": "100",
"fiat": "USD"
}
},
"fiat": "USD",
"country": "US",
"asset": "USDC_POLYGON",
"paymentMethod": "ACH",
"fromAmount": "10",
"toAmount": "8.99",
"exchangeRate": "0.999",
"totalFee": "1",
"orchestrationFee": "1"
}
```
## Create an on-ramp order
First, you will create an order for an on-ramp. This will return the payment instructions from the PFI, for the payment originator to send the local fiat currency. This alerts the PFI to expect the payment, and allows them to attribute the funds to your account when they arrive.
Please use account `id` in the on-ramp creation request from an account created above in the Accounts section.
Please note: if KYB or KYC are in progress, you'll see `"instructions":null` in the response. To fetch the payment instructions after order creation, you can subscribe to a Webhook or use `GET /transactions/{id}`using the on-ramp `id` from the response.
Endpoint: [`POST /deposits`](/api-reference/transaction-deposits/create-a-new-deposit-transaction)
```bash request expandable theme={null}
curl -X POST 'https://sandbox-api.borderless.xyz/v1/deposits' \
-H 'Authorization: Bearer your-access-token' \
-H 'Content-Type: application/json' \
-H 'idempotency-key: 8f14e45f-e6c3-4f7e-bd56-1b9a2e46f1d6'\
-d '{
"fiat": "USD",
"amount": 1000.00,
"asset": "USDC_POLYGON",
"accountId": "account_id_from_prevous_step",
"paymentMethod": "ACH",
"country": "US"
}'
```
```json response expandable theme={null}
{
"id": "cmi7scamc471ypg23idn5epg6",
"type": "Deposit",
"status": "Submitted",
"pfiName": "Bridge",
"source": {
"asset": null,
"amount": "1000",
"fiatCurrency": "USD",
"paymentMethod": "ACH",
"accountId": null,
"accountName": null,
"sender": null
},
"destination": {
"asset": "USDC_POLYGON",
"amount": null,
"fiatCurrency": null,
"imad": null,
"reference": null,
"omad": null,
"traceNumber": null,
"externalAddress": null,
"accountId": "cmgjc1jvv00qlny23fx79oga0",
"accountName": "Main Account",
"paymentInstructionId": null
},
"instructions": null,
"createdAt": "2025-11-19T16:56:10.169Z",
"updatedAt": "2025-11-19T16:56:10.169Z",
"txHash": [],
"feeAmount": "0",
"failureReason": null,
"depositInstruction": null,
"destinationPaymentInstruction": null,
"withdrawalOnchainInstruction": null,
"counterPartyIdentityId": "cmgjbx4ab00qhny23bt333en5",
"virtualAccountId": null
}
```
## Send local fiat direct to PFI
Second, the payment originator follows the payment instructions that were returned in the first step, and sends the local fiat to the PFI directly. This step takes place directly with the PFI, over traditional local rails such as ACH, Wire, or PIX depending on region.
The PFI will be expecting the inbound fiat transfer to match the order created via the `/deposits` endpoint, please ensure you are following the payment instructions exactly.
Borderless cannot be held responsible for transfers that originate outside the Borderless network to incorrect addresses. It is your responsibility to review the payment instructions exactly as they are returned from our partner financial institutions (PFIs).
## Release stablecoins to beneficiary
Third, the PFI will issue the stablecoins to the specified stablecoin wallet, as defined in your account set up above in the Accounts section. Once the stablecoins are received, this completes the on-ramp or deposit flow.
You can easily track the status of transactions, request cancellation of transactions, and export transactions with the following endpoints.
Please ensure you are using the transaction `id `value which you will receive from the request to create a transaction such as the first step in this sequence on the `/deposits` endpoint.
To track the status of your deposit transactions and other types of transactions:
We recommend listening to the statuses via Webhook.
Endpoint: [`GET /transactions/{id}`](/api-reference/transactions/get-a-transaction-by-id)
To request a cancellation of your deposit transaction and other types of transactions:
Endpoint: [`POST /transactions/{id}/cancel`](/api-reference/transactions/request-cancellation-of-a-transaction)
To export your transactions:
Endpoint: [`GET /transactions/export`](/api-reference/transactions/export-transactions)
**Congratulations! You've now completed your first stablecoin payment!**
If you have any questions, please don't hesitate to reach out to us via [email](mailto:support@borderless.xyz) or slack.
# Exchange
Source: https://docs.borderless.xyz/docs/exchanges
Exchanges allow you to convert one `fiat currency balance` into another within the same PFI Account. We covered PFI Accounts in more detail in the Accounts section, but at a high level they represent local fiat balances that your organization holds with a specific partner financial institution (PFI). For example, you can convert COP held on a PFI Account into USD on that same PFI Account.
It’s important to understand that the funds remain on your PFI Account at all times and are only converted from one fiat currency to another. If you want to move these funds out to an external bank account, you should use one of the Withdrawals flows described in this section.
Borderless is not in the flow of funds, and does not take custody of any client funds at any point throughout this exchange transaction.
An Exchange is a simple transaction that consists of a single step: you request a conversion from one fiat currency to another, and once the PFI executes it, your PFI Account balances are updated accordingly.
## Create a exchange order
You will create an order for an exchange. This will send the exchange request to the PFI, instructing them to convert one fiat currency balance into another within the same PFI Account. Once the exchange is executed, the original fiat balance is debited and the new fiat balance is credited on that PFI Account.
It’s important to note that there is no on-chain leg or external bank transfer involved in this flow. All funds remain on your PFI Account at all times - only the fiat currency in which they are denominated changes.
Please use the account `id` from an PFI Account created above in the Accounts section.
Endpoint: `POST /exchanges`
```bash request expandable theme={null}
curl -X POST 'https://sandbox-api.borderless.xyz/v1/exchanges' \
-H 'Authorization: Bearer your-access-token' \
-H 'Content-Type: application/json' \
-H "idempotency-key: 8f14e45f-e6c3-4f7e-bd56-1b9a2e46f1d6"\
-d '
{
"accountId": "cm2c4x3cc000019stwv7um4zl",
"from": {
"type": "fiat",
"fiat": "USD"
},
"to": {
"type": "fiat",
"fiat": "COP"
},
"amount": "1000"
}
'
```
```json response expandable theme={null}
{
"id": "cmi7scamc471ypg23idn5epg6",
"type": "Exchange",
"status": "Submitted",
"pfiName": "Finity",
"source": {
"asset": null,
"amount": "1000",
"fiatCurrency": "USD",
"paymentMethod": null,
"accountId": "cm2c4x3cc000019stwv7um4zl",
"accountName": "PFI Account",
"sender": null
},
"destination": {
"asset": null,
"amount": null,
"fiatCurrency": "COP",
"imad": null,
"reference": null,
"omad": null,
"traceNumber": null,
"externalAddress": null,
"accountId": "cm2c4x3cc000019stwv7um4zl",
"accountName": "PFI Account",
"paymentInstructionId": null
},
"instructions": null,
"createdAt": "2025-11-19T19:49:46.918Z",
"updatedAt": "2025-11-19T19:49:46.918Z",
"txHash": [],
"feeAmount": "0",
"failureReason": null,
"depositInstruction": null,
"destinationPaymentInstruction": null,
"withdrawalOnchainInstruction": null,
"counterPartyIdentityId": "cmhlu3zlt002qpf246wd6vwrr",
"virtualAccountId": null
}
```
## Receiving fiat into PFI Account
Finally, the PFI will execute the exchange by converting the requested amount from the source fiat currency to the target fiat currency on your PFI Account. Once the conversion is completed and the balances are updated, this completes the exchange flow.
You can easily track the status of exchange transactions and export them using the standard transaction endpoints described in this section.
Please ensure you are using the transaction `id `value which you will receive from the request to create a transaction such as the first step in this sequence on the `/exchanges` endpoint.
To track the status of your withdrawal transactions and other types of transactions:
We recommend listening to the statuses via Webhook.
Endpoint: [`GET /transactions/{id}`](/api-reference/transactions/get-a-transaction-by-id)
To request a cancellation of your withdrawal transaction and other types of transactions:
Endpoint: [`POST /transactions/{id}/cancel`](/api-reference/transactions/request-cancellation-of-a-transaction)
To export your transactions:
Endpoint: [`GET /transactions/export`](/api-reference/transactions/export-transactions)
**Congratulations! You've now completed your first fiat exchange!**
If you have any questions, please don't hesitate to reach out to us via [email](mailto:support@borderless.xyz) or slack.
# Quotes & Transaction Limits
Source: https://docs.borderless.xyz/docs/get-a-quote
When you are executing transactions, often times you will want to fetch a quote first, to understand what the estimated cost of a transaction will be, and what the estimated final output of the transaction will be. Borderless has a series of streamlined API endpoints to help you.
If you're just getting started, please check out our [quick start guide](/docs/quick-start-guide).
## Fetching quote details
The quotes endpoints returns estimated or indicative exchange rates between stablecoins and local fiat currencies, as well as the estimated fees and spread that are applied throughout.
These quotes are generally expected to be estimates, not guaranteed. It is likely that the final output will be slightly different than the quote as rates change continuously. Borderless is not responsible for any divergence between quotes and the final executed amount. Borderless passes along the fees of our partner financial institutions (PFIs) at cost.
Fees are calculated in stablecoin currency for withdrawals and fiat currency for deposits, but in future versions will be calculated in USD only.
### Endpoints
The quotes endpoint for deposits.
Endpoint: `GET /deposits/quotes`
```bash request expandable theme={null}
curl --location 'https://sandbox-api.borderless.xyz/v1/deposits/quotes?fiat=USD&country=US&asset=USDC_POLYGON&fromAmount=1000&paymentMethod=Wire' \
--header 'Authorization: Bearer your-access-token
```
The quotes endpoint for withdrawals.
Endpoint: `GET /withdrawals/quotes`
```bash request expandable theme={null}
curl --location 'https://sandbox-api.borderless.xyz/v1/withdrawals/quotes?fiat=USD&country=US&asset=USDC_POLYGON&fromAmount=1000&paymentMethod=Wire' \
--header 'Authorization: Bearer your-access-token'
```
Please read more detail about the API endpoints in the API reference documentation.
## Transaction Limits
Withdrawal and Deposit transactions may be subject to limits, which define the minimum and maximum allowed fiat amounts per transaction. These limits vary depending on: Country, Currency, Payment method, and Asset.
The limits object contains:
The minimum allowed fiat amount
The maximum allowed fiat amount
The fiat currency the limites apply to
If either `minAmount` or `maxAmount` is null, it means there is no limit set for that value.
Quotes could be calculated based on `fromAmount` or `toAmount`. Only one of `fromAmount` or `toAmount` could be present at the same time. Quote by `toAmount` is available for US and EU countries only.
If `paymentMethod` is not provided, the quote will be calculated for the first available option by `fiat`, `country` and `asset`. E.g. if both ACH and Wire option is available for USD to USDC deposit in US any of them could be used and order is not guaranteed.
## Response
```bash bash theme={null}
{
"limits": {
"transaction": {
"minAmount": "21.44",
"maxAmount": null,
"fiat": "USD"
}
},
"fiat": "USD",
"asset": "USDC_POLYGON",
"country": "US",
"paymentMethod": "Wire",
"fromAmount": "1000",
"toAmount": "978.5",
"exchangeRate": "1",
"totalFee": "21.5",
"orchestrationFee": "21.5"
}
```
A quote could be requested for specific `paymentMethod` (ACH, Wire, SPEI, etc.) and fees will be calculated according to payment method. For example, ACH fee is 0.50 USD but Wire fee is \$20.00 USD, etc.
`exchangeRate` represents estimated exchange rate with up to 6 decimals precision.
`orchestrationFee` is a Borderless fee for a transaction. The collection method of orchestration fee discuss with operations team.
`totalFee` is a sum of `orchestrationFee` and PFI fee.
If you have any questions, please don't hesitate to reach out to us via [email](mailto:support@borderless.xyz) or slack.
# Identities & Compliance
Source: https://docs.borderless.xyz/docs/identities
An `identity` is a core object in our API, representing the fundamental information required for any individual or business to interact with partner financial institutions (PFIs) via the Borderless network. All transactions, payment instructions, and accounts are associated with an identity.
All identities **must** pass a compliance check before they are allowed to do any transactions in the network. The compliance check can be performed by you or the (PFI), depending on the compliance model that the PFI supports. You can find more detailed information in the compliance section below.
If you're just getting started, please check out our [quick start guide](/docs/quick-start-guide).
## Identity types
There are two types of identities in the Borderless network:
`Personal` — used to represent a person. Can usually start doing transactions on the Borderless network in minutes. You can find detailed instructions on how to create them and get them ready in the `Personal Identity` tab below.
`Business` — used to represent a business or corporation. Can usually start doing transactions on the Borderless network in three to five business days. You can find detailed instructions on how to create these identities and get them ready in the `Business Identity` tab below.
## Compliance details
Each Partner Financial Institution (PFI) on the Borderless network has its own compliance programs, and decides how to implement them. The Borderless network is a data layer that stores the information for every person or business doing transactions, and sends it on to the PFIs for their usual operations and record keeping. You only upload the necessary data to the Borderless identity once, then it is available for all the PFIs in the network.
This is is part of a process called compliance orchestration. In some cases, passing one compliance-check will automatically satisfy other checks with less strict requirements. This is handled via the `incorporates` field: `[slug-1, slug-2]`
This means that upon passing this compliance-check, the identity also gains access to the operation options covered by the checks listed in `incorporates`.
## Working with identities & compliance
Note: Borderless is never in the flow of funds, and never takes custody of client or partner funds. Borderless is a gateway connecting clients directly with regulated and licensed providers.
### Create a personal identity
Creating a `personal identity` is an important step when using the Borderless network. Every deposit or withdrawal must be tied to an identity, and this is also how we collect information for required compliance checks (KYC).
### Step 1: Initiate identity object
First, initiate an identity object, which creates a simple identity object. We will then add information to this object so that we can use it for KYC or KYB going forward. You can find a link to the endpoint reference documentation, as well as request and response examples below.
This compliance process is managed by our partner finanical institutions (PFIs) who are the locally licensed and regulated stablecoin and fiat on-ramps and off-ramps.
Some requests require an `Idempotency-Key` header to ensure that operations are not accidentally executed multiple times. Please generate and use a unique UUID for this field.
Please capture identity `id` from the response to use it during account creation later.
Endpoint: [`POST /identities/personal`](/api-reference/identities/create-a-new-personal-identity)
```bash request expandable theme={null}
curl -X POST "https://sandbox-api.borderless.xyz/v1/identities/personal" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-access-token" \
-H "idempotency-key: 8f14e45f-e6c3-4f7e-bd56-1b9a2e46f1d6"\
-d '{
"firstName": "John",
"lastName": "Doe",
"secondLastName": "Smith",
"middleName": "Michael",
"taxId": "123456789",
"dateOfBirth": "2003-01-01",
"email": "john.doe@example.com",
"phone": "+1234567890",
"activity": "Software Engineer",
"sex": "Male",
"occupationCode": "172011",
"employmentStatus": "SelfEmployed",
"sourceOfFunds": "InvestmentsLoans",
"accountPurpose": "InvestmentPurposes",
"accountPurposeOther": "string",
"monthlyAmounts": "From10KTo50K",
"actingAsIntermediary": false,
"address": {
"street1": "123 Main St",
"street2": "Apt 4B",
"city": "New York",
"state": "NY",
"country": "US",
"postalCode": "10001"
}
}
'
```
```json response expandable theme={null}
{
"id": "cm34yhws000343brvezoqdqn0",
"type": "Personal",
"deleted": false,
"hasComplianceChecks": true,
"data": {
"firstName": "string",
"lastName": "string",
"secondLastName": "string",
"middleName": "string",
"taxId": "string",
"dateOfBirth": "YYYY-MM-DD",
"email": "string",
"phone": "string",
"activity": "string",
"sex": "Male",
"address": {
"id": "string",
"street1": "string",
"street2": "string",
"city": "string",
"state": "string",
"country": "AF",
"postalCode": "string"
},
"documents": [
{
"id": "string",
"issuingCountry": "AF",
"type": "Passport",
"idNumber": "string",
"issuedDate": "YYYY-MM-DD",
"expiryDate": "YYYY-MM-DD"
}
],
"occupationCode": "132011",
"employmentStatus": "Employed",
"sourceOfFunds": "CompanyFunds",
"accountPurpose": "CharitableDonations",
"monthlyAmounts": "LessThan5K",
"actingAsIntermediary": true
}
}
```
### Step 2: Gather configured PFIs
Once an identity has been created, this identity will have limited ability to transact until they pass a KYC or KYB check with the on-ramp and off-ramp providers (PFIs) they’d like to enable. You can easily gather the configured PFIs from our API before collecting the necessary documents and initiating a compliance check.
Additionally, this endpoint provides the terms of service link, where required, which will need to be forwarded to the client. Some of our partner financial institutions (PFIs) require users to accept their terms and conditions before they can transact. Each identity must accept their own ToS link, and it cannot be reused.
Please capture compliance `slug` from the response to use it next.
Please capture terms of service `link` to deliver to end users.
Endpoint: [`GET /identities/{identityId}/compliance-checks`](/api-reference/compliance-checks/get-a-compliance-check-by-id)
```bash request expandable theme={null}
curl -X GET "https://sandbox-api.borderless.xyz/v1/identities/{identityId}/compliance-checks" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-access-token" \
-d '{
"country": "AF",
"asset": "USDC_BASE",
"fiat": "USD",
"paymentMethod": "ACH",
"type": "Deposit"
}'
```
```json response expandable theme={null}
{
"slug": "compliance-d4a0bea2",
"incorporates": [],
"coverage": [
{
"type": "Deposit",
"operationType": "Deposit",
"method": "ACH",
"fiat": "USD",
"country": "AF",
"asset": "USDC_BASE"
}
],
"id": "cm34yhws000343brvezoqdqn0",
"kycStatus": "NotStarted",
"status": "NotStarted",
"metadata": {
"tosLink": "http://localhost:4000/v1/webhooks/walapay/terms-of-service?redirect_url=http%3A%2F%2Flocalhost%3A4000%2Fv1%2Fwebhooks%2Fwalapay%2Faccept-tos%2Fcm91wowj60000vxpj2tsfwhrg%2Fcmi4vz80w00eo8o2c10el32s6",
"redirectUrl": null,
"hasAcceptedTos": false
}
}
```
### Step 3: Check required documents
With the identity `id` and compliance `slug` you can now check the list of required information and documentation needed for the configured PFIs. This allows you to dynamically build your UI such that you only ask your customers for what is required for each specific business or user.
Please use the compliance `slug` from the response above.
Endpoint: [`GET /identities/{identityId}/compliance-checks/{slug}/requirements`](/api-reference/compliance-checks/get-compliance-requirements-for-a-compliance)
```bash request expandable theme={null}
curl -X GET "https://sandbox-api.borderless.xyz/v1/identities/{identityId}/compliance-checks/{slug}/requirements" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-access-token" \
```
```json response expandable theme={null}
{
"slug": "compliance-d4a0bea2",
"schema": {
"additionalProp": {}
},
"missingFields": [
"string"
],
"requiredDocuments": [
{
"mode": "oneOf",
"documents": [
"Passport"
]
}
],
"requiredExtras": {
"acceptTermsOfService": {
"link": "string"
}
},
"type": {}
}
```
### Step 4: Attach required documents
Now that required documents have been identified, and the terms of service link, if required, has been accepted, we can submit these documents for review via our API. This information will be added to the identity object so that we can streamline and orchestrate future compliance as well.
For clarity, the `id` parameter here is the identity id of the organization or person you have created in step 1 of this process. This will submit all required information for the compliance check. You can use this endpoint at any time to add documents to the related identity object.
Please note, `imageFront` and `imageBack` should be converted in base64 format with resolution at least `200*200`pixels.
Endpoint: [`PUT /identities/{id}/documents`](/api-reference/identities/upload-a-document)
```bash request expandable theme={null}
curl -X PUT "https://sandbox-api.borderless.xyz/v1/identities/{id}/documents" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-access-token" \
-H "idempotency-key: 8f14e45f-e6c3-4f7e-bd56-1b9a2e46f1d6"\
-d '{
"issuingCountry": "US",
"type": "Passport",
"issuedDate": "2024-07-25",
"expiryDate": "2027-07-25",
"imageFront": "image/200*200;base64",
"imageBack": "image/200*200;base64"
}'
```
```json response expandable theme={null}
{
"id": "cm34yhws000343brvezoqdqn0",
"type": "Personal",
"deleted": true,
"hasComplianceChecks": true,
"data": {
"firstName": "string",
"lastName": "string",
"secondLastName": "string",
"middleName": "string",
"taxId": "string",
"dateOfBirth": "YYYY-MM-DD",
"email": "string",
"phone": "string",
"activity": "string",
"sex": "Male",
"address": {
"id": "string",
"street1": "string",
"street2": "string",
"city": "string",
"state": "string",
"country": "AF",
"postalCode": "string"
},
"documents": [
{
"id": "string",
"issuingCountry": "AF",
"type": "Passport",
"idNumber": "string",
"issuedDate": "YYYY-MM-DD",
"expiryDate": "YYYY-MM-DD"
}
]
}
}
```
### Step 5: Start compliance check
After attaching the required documents to the identity object, you are ready to submit and start the compliance check with our partner financial institutions (PFIs). You can submit this once, and we will orchestrate the data to all PFIs you have enabled, helping to streamline an otherwise repetitive process.
If all prerequisites are satisfied, the check will begin. Use the GET request above from step 2 and the API will return the current compliance status.
Endpoint: [`POST /identities/{identityId}/compliance-checks/{slug}`](/api-reference/compliance-checks/create-a-new-compliance-check)
```bash request expandable theme={null}
curl -X POST "https://sandbox-api.borderless.xyz/v1/identities/{identityId}/compliance-checks/{slug}" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-access-token" \
-H "idempotency-key: 8f14e45f-e6c3-4f7e-bd56-1b9a2e46f1d6"\
```
```json response expandable theme={null}
{
"slug": "compliance-d4a0bea2",
"status": "NotStarted",
"metadata": {}
}
```
The timeline for different levels of compliance checks varries. It can be as fast as near-instant and in some rare occasions can take a few days. We will keep you informed through the whole process via the returned compliance status in the response body of step 2.
Requests for information (RFIs) are a regular part of the compliance process. If there are follow up questions on documents, completely missing documents, or other details that need to be reviewed manually, our PFIs can send a request for additional information.
\
These requests for information will be communicated manually, and are generally expected to be resolved in 24 to 48 hours.
### Create a business identity
Creating a `business identity` is an important step when using the Borderless network. Every deposit or withdrawal must be tied to an identity, and this is also how we collect information for required compliance checks (KYB).
### Step 1: Initiate identity object
We need to collect information about the people who own, control, and can sign for the business.\
It doesn't have to be just one person, different people can cover these roles, but all roles must be represented.
For a person to be considered an owner of the business, they need to own at least 25% of it (directly or indirectly). They are called Ultimate Beneficial Owners (UBOs). Each business must list all of its UBOs. Persons that control, and can sign for the business do not have to be UBOs.
You need a personal identity for each person that is either an owner, has control, or can sign for the business. If you have not yet created one, please click on the `Personal Identity` tab at the top of this section. After creating their identity, you will obtain an `identityId` for each person. You will use the `identityId` in future steps to create a business identity.
Please capture identity `id` from the response to use it during account creation later.
Endpoint: [`POST /identities/business`](/api-reference/identities/create-a-new-business-identity)
```bash request expandable theme={null}
curl -X POST "https://sandbox-api.borderless.xyz/v1/identities/business" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-access-token" \
-H "idempotency-key: 8f14e45f-e6c3-4f7e-bd56-1b9a2e46f1d6"\
-d '{
"email": "business@example.com",
"phone": "+1234567890",
"taxId": "123456789",
"name": "Example Corp",
"dateOfIncorporation": "2003-01-01",
"address": {
"street1": "123 Main St",
"street2": "Apt 4B",
"city": "New York",
"state": "NY",
"country": "US",
"postalCode": "10001"
},
"description": "A technology solutions provider",
"sourceOfFunds": "inter_company_funds",
"businessIndustryCode": "336390",
"website": "https://example.com",
"businessType": "Llc",
"isDao": false,
"hasMaterialIntermediaryOwnership": false,
"businessTradeName": "Example Solutions",
"accountPurpose": "investment_purposes",
"accountPurposeOther": "string",
"ultimateBeneficialOwners": [
{
"hasOwnership": true,
"hasControl": true,
"controlPersonTitle": "CEO",
"ownershipPercentage": 30,
"isSigner": true,
"relationshipEstablishedAt": "2023-01-15",
"personalIdentityId": "cm9db4g2s4r7ro224ra6u1qvl"
},
{
"hasOwnership": true,
"hasControl": true,
"controlPersonTitle": "CEO",
"ownershipPercentage": 30,
"isSigner": true,
"relationshipEstablishedAt": "2023-01-15",
"personalIdentity": {
"firstName": "John",
"lastName": "Doe",
"secondLastName": "Smith",
"middleName": "Michael",
"taxId": "123456789",
"dateOfBirth": "2003-01-01",
"email": "john.doe@example.com",
"phone": "+1234567890",
"activity": "Software Engineer",
"sex": "Male",
"occupationCode": "172011",
"employmentStatus": "SelfEmployed",
"sourceOfFunds": "InvestmentsLoans",
"accountPurpose": "InvestmentPurposes",
"accountPurposeOther": "string",
"monthlyAmounts": "From10KTo50K",
"actingAsIntermediary": false,
"address": {
"street1": "123 Main St",
"street2": "Apt 4B",
"city": "New York",
"state": "NY",
"country": "US",
"postalCode": "10001"
}
}
}
]
}
'
```
```json response expandable theme={null}
{
"id": "cm34yhws000343brvezoqdqn0",
"type": "Business",
"deleted": false,
"hasComplianceChecks": true,
"data": {
"email": "business@example.com",
"phone": "+1234567890",
"taxId": "123456789",
"name": "Example Corp",
"dateOfIncorporation": "2003-01-01",
"description": "A technology solutions provider",
"sourceOfFunds": "inter_company_funds",
"website": "https://example.com",
"businessType": "Llc",
"businessIndustryCode": "336390",
"isDao": false,
"hasMaterialIntermediaryOwnership": false,
"businessTradeName": "Example Solutions",
"accountPurpose": "investment_purposes",
"ultimateBeneficialOwners": [
{
"hasOwnership": true,
"hasControl": true,
"controlPersonTitle": "CEO",
"ownershipPercentage": 30,
"isSigner": true,
"relationshipEstablishedAt": "2023-01-15",
"personalIdentityId": "cm9db4g2s4r7ro224ra6u1qvl"
}
],
"address": {
"id": "cm34yhws000343brvezoqdqn1",
"street1": "123 Main St",
"street2": "Apt 4B",
"city": "New York",
"state": "NY",
"country": "US",
"postalCode": "10001"
},
"documents": [
{
"id": "cm34yhws000343brvezoqdqn2",
"issuingCountry": "US",
"type": "Passport",
"idNumber": "A12345678",
"issuedDate": "2020-01-01",
"expiryDate": "2030-01-01"
}
]
}
}
```
### Step 2: Gather configured PFIs
Once an identity has been created, this identity will have limited ability to transact until they pass a KYC or KYB check with the on-ramp and off-ramp providers (PFIs) they’d like to enable. You can easily gather the configured PFIs from our API before collecting the necessary documents and initiating a compliance check.
Additionally, this endpoint provides the terms of service link, where required, which will need to be forwarded to the client. Some of our partner financial institutions (PFIs) require users to accept their terms and conditions before they can transact. Each identity must accept their own ToS link, and it cannot be reused.
Please capture compliance `slug` from the response to use it next.
Please capture terms of service `link` to deliver to end users.
Endpoint: [`GET /identities/{identityId}/compliance-checks`](/api-reference/compliance-checks/get-a-compliance-check-by-id)
```bash request expandable theme={null}
curl -X GET "https://sandbox-api.borderless.xyz/v1/identities/{identityId}/compliance-checks" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-access-token" \
-d '{
"country": "AF",
"asset": "USDC_BASE",
"fiat": "USD",
"paymentMethod": "ACH",
"type": "Deposit"
}'
```
```json response expandable theme={null}
{
"slug": "compliance-d4a0bea2",
"incorporates": [],
"coverage": [
{
"type": "Deposit",
"operationType": "Deposit",
"method": "ACH",
"fiat": "USD",
"country": "AF",
"asset": "USDC_BASE"
}
],
"id": "cm34yhws000343brvezoqdqn0",
"kycStatus": "NotStarted",
"status": "NotStarted",
"metadata": {
"tosLink": "http://localhost:4000/v1/webhooks/walapay/terms-of-service?redirect_url=http%3A%2F%2Flocalhost%3A4000%2Fv1%2Fwebhooks%2Fwalapay%2Faccept-tos%2Fcm91wowj60000vxpj2tsfwhrg%2Fcmi4vz80w00eo8o2c10el32s6",
"redirectUrl": null,
"hasAcceptedTos": false
}
}
```
### Step 3: Check required documents
With the identity `id` and compliance `slug` you can now check the list of required information and documentation needed for the configured PFIs. This allows you to dynamically build your UI such that you only ask your customers for what is required for each specific business or user.
Please use the compliance `slug` from the response above.
Endpoint: [`GET /identities/{identityId}/compliance-checks/{slug}/requirements`](/api-reference/compliance-checks/get-compliance-requirements-for-a-compliance)
```bash request expandable theme={null}
curl -X GET "https://sandbox-api.borderless.xyz/v1/identities/{identityId}/compliance-checks/{slug}/requirements" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-access-token" \
```
```json response expandable theme={null}
{
"slug": "compliance-d4a0bea2",
"schema": {
"additionalProp": {}
},
"missingFields": [
"string"
],
"requiredDocuments": [
{
"mode": "oneOf",
"documents": [
"Passport"
]
}
],
"requiredExtras": {
"acceptTermsOfService": {
"link": "string"
}
},
"type": {}
}
```
### Step 4: Attach required documents
Now that required documents have been identified, and the terms of service link, if required, has been accepted, we can submit these documents for review via our API. This information will be added to the identity object so that we can streamline and orchestrate future compliance as well.
For clarity, the `id` parameter here is the identity id of the organization or person you have created in step 1 of this process. This will submit all required information for the compliance check. You can use this endpoint at any time to add documents to the related identity object.
Please note, `imageFront` and `imageBack` should be converted in base64 format with resolution at least `200*200`pixels.
Endpoint: [`PUT /identities/{id}/documents`](/api-reference/identities/upload-a-document)
```bash request expandable theme={null}
curl -X PUT "https://sandbox-api.borderless.xyz/v1/identities/{id}/documents" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-access-token" \
-H "idempotency-key: 8f14e45f-e6c3-4f7e-bd56-1b9a2e46f1d6"\
-d '{
"issuingCountry": "US",
"type": "Passport",
"issuedDate": "2024-07-25",
"expiryDate": "2027-07-25",
"imageFront": "image/200*200;base64",
"imageBack": "image/200*200;base64"
}'
```
```json response expandable theme={null}
{
"id": "cm34yhws000343brvezoqdqn0",
"type": "Personal",
"deleted": true,
"hasComplianceChecks": true,
"data": {
"firstName": "string",
"lastName": "string",
"secondLastName": "string",
"middleName": "string",
"taxId": "string",
"dateOfBirth": "YYYY-MM-DD",
"email": "string",
"phone": "string",
"activity": "string",
"sex": "Male",
"address": {
"id": "string",
"street1": "string",
"street2": "string",
"city": "string",
"state": "string",
"country": "AF",
"postalCode": "string"
},
"documents": [
{
"id": "string",
"issuingCountry": "AF",
"type": "Passport",
"idNumber": "string",
"issuedDate": "YYYY-MM-DD",
"expiryDate": "YYYY-MM-DD"
}
]
}
}
```
### Step 5: Start compliance check
After attaching the required documents to the identity object, you are ready to submit and start the compliance check with our partner financial institutions (PFIs). You can submit this once, and we will orchestrate the data to all PFIs you have enabled, helping to streamline an otherwise repetitive process.
If all prerequisites are satisfied, the check will begin. Use the GET request above from step 2 and the API will return the current compliance status.
Endpoint: [`POST /identities/{identityId}/compliance-checks/{slug}`](/api-reference/compliance-checks/create-a-new-compliance-check)
```bash request expandable theme={null}
curl -X POST "https://sandbox-api.borderless.xyz/v1/identities/{identityId}/compliance-checks/{slug}" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-access-token" \
-H "idempotency-key: 8f14e45f-e6c3-4f7e-bd56-1b9a2e46f1d6"\
```
```json response expandable theme={null}
{
"slug": "compliance-d4a0bea2",
"status": "NotStarted",
"metadata": {}
}
```
The timeline for different levels of compliance checks varries. It can be as fast as near-instant and in some rare occasions can take a few days. We will keep you informed through the whole process via the returned compliance status in the response body of step 2.
Requests for information (RFIs) are a regular part of the compliance process. If there are follow up questions on documents, completely missing documents, or other details that need to be reviewed manually, our PFIs can send a request for additional information.
\
These requests for information will be communicated manually, and are generally expected to be resolved in 24 to 48 hours.
## Handle compliance rejection
The `rejectionReasons` field in the `IdentityComplianceCheck` API response provides structured information about why a compliance check was rejected by Payment Facilitator Institutions (PFIs).
### Response Structure
Each rejection reason object contains three fields:
* **`code`** (enum: `ComplianceRejectionReasonCode`): A standardized enum value categorizing the rejection reason
* **`description`** (string): A predefined, human-readable message corresponding to the code
* **`pfiMessage`** (string): The raw, original message from the underlying verification provider
### Example Response
```json theme={null}
{
"rejectionReasons": [
{
"code": "DocumentExpired",
"description": "Document has expired.",
"pfiMessage": "ID is expired."
},
{
"code": "FaceNotLive",
"description": "Liveness check failed.",
"pfiMessage": "The selfie video shows signs of presentation attack."
}
]
}
```
## Rejection Reason Codes Reference
### Document Quality & Detection
| Code | Message | Description |
| --------------------------- | ---------------------------------------------- | ------------------------------------------------------------------------------- |
| `DocumentNotFound` | Document not found. | No government-issued identity document was detected in the submission. |
| `DocumentUnrecognized` | Document could not be recognized. | The document type or format could not be identified by the verification system. |
| `DocumentUnreadable` | Document image is unreadable. | The document image quality prevents extraction of information. |
| `DocumentExpired` | Document has expired. | The expiration date on the document has passed. |
| `DocumentDamaged` | Document is damaged. | Physical damage to the document prevents proper verification. |
| `DocumentCropped` | Document image is cropped. | The document image is cut off or incomplete. |
| `DocumentIncomplete` | Document submission is incomplete. | Required document pages or sides are missing. |
| `DocumentBlurry` | Document image is blurry. | Motion blur or focus issues prevent clear reading of the document. |
| `DocumentPoorQuality` | Document image quality is too low. | Resolution or compression artifacts make the document unusable. |
| `DocumentGlareDetected` | Glare detected on document. | Light reflection obscures parts of the document. |
| `DocumentTooSmall` | Document image is too small. | The document appears too small in the frame to extract details. |
| `DocumentTooFar` | Document is too far from the camera. | Distance from camera prevents reading document details. |
| `DocumentFaceNotFound` | Face not found on document. | Photo on the identity document could not be detected. |
| `DocumentFrontMissing` | Front side of document is missing. | The front page of the document was not submitted. |
| `DocumentBackMissing` | Back side of document is missing. | The back page of the document was not submitted. |
| `DocumentFrontBackMismatch` | Front and back document details do not match. | Information on front and back pages is inconsistent. |
| `DocumentSameSideSubmitted` | Same side of the document was submitted twice. | Both submissions show the same side of the document. |
| `DocumentWrongType` | Incorrect document type submitted. | The submitted document type doesn't meet requirements. |
| `DocumentNotAccepted` | Document type is not accepted. | This specific document type is not supported. |
| `DocumentInvalidDates` | Document dates are invalid. | Issue date, expiry date, or other dates are logically invalid. |
### Document Fraud & Tampering
| Code | Message | Description |
| ---------------------------------------- | ----------------------------------------------- | ------------------------------------------------------------------------------- |
| `FraudDocumentTampered` | Document appears tampered. | Signs of physical alteration detected on the document. |
| `FraudDocumentAltered` | Document appears altered. | Document information has been modified. |
| `FraudDocumentFake` | Document appears fake. | Document does not match characteristics of genuine documents. |
| `FraudDocumentForged` | Document appears forged. | Document appears to be a counterfeit. |
| `FraudDocumentCompromised` | Document security appears compromised. | Security features of the document have been breached. |
| `FraudDocumentPhotoOfPhoto` | Document seems to be a photo of a photo. | The submission is a photograph of a physical document rather than the original. |
| `FraudDocumentScreenDetected` | Document was captured from a screen. | The document was photographed from a digital display. |
| `FraudDocumentElectronicReplica` | Document appears to be an electronic replica. | A digital copy rather than the physical document was submitted. |
| `FraudDocumentPrintout` | Document appears to be a printout. | Document is a printed copy rather than an original. |
| `FraudDocumentPaperCopy` | Document appears to be a paper copy. | Document is a photocopied or scanned reproduction. |
| `FraudDocumentBlackWhite` | Black and white document copy detected. | Document lacks color, suggesting it's a copy. |
| `FraudDocumentFoundOnline` | Document image was found online. | The submitted image matches images available on the internet. |
| `FraudDocumentArtificialImage` | Document appears AI-generated. | Image shows signs of artificial intelligence generation. |
| `FraudDocumentArtificialText` | Document contains AI-generated text. | Text on the document appears synthetically generated. |
| `FraudDocumentTextForgery` | Document text appears forged. | Text appears to be manually altered or falsified. |
| `FraudDocumentFeatureVerificationFailed` | Document security features failed verification. | Holograms, watermarks, or other security features are absent or incorrect. |
| `FraudDocumentCheckDigitFailed` | Document check digits failed validation. | Mathematical verification of document numbers failed. |
| `FraudDocumentFabrication` | Document appears fabricated. | Document appears to be completely manufactured rather than issued. |
### Document Data & MRZ
| Code | Message | Description |
| --------------------------------------------- | ------------------------------------------- | --------------------------------------------------------------- |
| `DocumentDataMissingField` | Document data is missing a required field. | A required data field could not be extracted from the document. |
| `DocumentDataMissingExpiry` | Document expiry date is missing. | The expiration date is not present or readable. |
| `DocumentDataMissingIssueDate` | Document issue date is missing. | The issuance date is not present or readable. |
| `DocumentDataMissingDateOfBirth` | Date of birth is missing on the document. | Birth date field is absent or unreadable. |
| `DocumentDataMissingNumber` | Document number is missing. | The primary document identifier is absent or unreadable. |
| `DocumentDataMissingPersonalNumber` | Personal number is missing on the document. | National ID or personal number is absent or unreadable. |
| `DocumentDataMissingName` | Name is missing on the document. | The holder's name is absent or unreadable. |
| `DocumentDataMissingAddress` | Address is missing on the document. | Address information is absent or unreadable. |
| `DocumentDataMissingDetails` | Additional document details are missing. | Other required fields could not be extracted. |
| `DocumentDataInvalidDetails` | Document details appear invalid. | Extracted information contains invalid or illogical values. |
| `DocumentDataMachineReadableZoneNotDetected` | Machine-readable zone was not detected. | The MRZ on passports or IDs could not be located. |
| `DocumentDataMachineReadableZoneMismatch` | Machine-readable zone data does not match. | MRZ data conflicts with visual inspection zone data. |
| `DocumentDataMachineReadableZoneInconsistent` | Machine-readable zone data is inconsistent. | MRZ contains internal contradictions or errors. |
| `DocumentDataBarcodeMissing` | Document barcode is missing. | Required barcode (e.g., PDF417) is absent or unreadable. |
| `DocumentDataBarcodeInconsistent` | Document barcode data is inconsistent. | Barcode data conflicts with other document information. |
### Identity Verification
| Code | Message | Description |
| ---------------------------------------- | ----------------------------------------------------- | ---------------------------------------------------------------------------- |
| `IdentityVerificationFailed` | Identity verification failed. | General failure to verify the identity against authoritative sources. |
| `IdentityCannotVerify` | Identity could not be verified. | Unable to confirm identity through available verification methods. |
| `IdentityNameMismatch` | Identity name does not match records. | Name on document doesn't match provided or database records. |
| `IdentityDateOfBirthMismatch` | Date of birth does not match records. | Birth date conflicts with provided or database information. |
| `IdentityDataMismatch` | Identity data does not match records. | General mismatch between document and records. |
| `IdentityTypeMismatch` | Identity type does not meet requirements. | The type of identity provided doesn't satisfy requirements. |
| `IdentityCountryMismatch` | Identity country does not meet requirements. | Document country differs from expected or required country. |
| `IdentityNumberInvalid` | Identity number is invalid. | The identity/document number format is incorrect or fails validation. |
| `IdentityNumberNotVerified` | Identity number could not be verified. | Unable to confirm identity number against government databases. |
| `IdentityNumberFormatInconsistent` | Identity number format is inconsistent. | The number format doesn't match the expected pattern for that document type. |
| `IdentityFormatInconsistent` | Identity format is inconsistent. | Overall document format doesn't match standard specifications. |
| `IdentityExtractionInconsistent` | Extracted identity data is inconsistent. | Extracted data contains internal contradictions. |
| `IdentityDetailsInconsistent` | Identity details are inconsistent. | Information fields contradict each other or known facts. |
| `IdentityPreviousSubmissionInconsistent` | Identity details conflict with a previous submission. | Current submission contradicts a prior verification attempt. |
| `IdentityPreviouslySeen` | Identity document was previously seen. | This exact document has been submitted before. |
| `IdentityPreviouslyAttempted` | Identity verification was previously attempted. | Prior verification attempts exist for this identity. |
| `IdentityDuplicateAccount` | Duplicate account detected for this identity. | This identity is already associated with another account. |
| `IdentityDuplicateSubmission` | Duplicate identity submission detected. | The same identity was recently submitted. |
| `IdentityNotRealId` | Submitted ID does not appear genuine. | Document fails authenticity checks. |
| `IdentityUnderAge` | Individual is under the required age. | Person doesn't meet minimum age requirements. |
| `IdentityMinor` | Individual is a minor. | Person is below the age of majority. |
| `IdentityCannotValidateAge` | Unable to validate the individual's age. | Age verification cannot be completed with available information. |
| `IdentityAgeMismatch` | Age does not match provided information. | Calculated age conflicts with stated or expected age. |
| `IdentityDeceased` | Individual appears as deceased in records. | Identity matches records of deceased individuals. |
| `IdentitySuspectedTheft` | Identity is suspected to be stolen. | Identity characteristics suggest it may be fraudulently obtained. |
### Biometric & Face
| Code | Message | Description |
| ---------------------------- | ----------------------------------------------- | -------------------------------------------------------------------- |
| `FaceNotFound` | Face not found. | No face was detected in the selfie or video submission. |
| `FaceMultipleDetected` | Multiple faces detected. | More than one face appears in the submission. |
| `FaceMismatch` | Face does not match the document. | Selfie face doesn't match the document photo. |
| `FaceLowSimilarity` | Face similarity is too low. | Biometric comparison score is below acceptance threshold. |
| `FaceIdentical` | Face matches another submission. | Face is identical to a different person's submission. |
| `FacePhotoMismatch` | Selfie does not match the document photo. | Live photo differs from document photo. |
| `FacePublicFigure` | Face matches a public figure. | The person appears to be impersonating a celebrity or public figure. |
| `FaceNotLive` | Liveness check failed. | Unable to confirm the subject is physically present. |
| `FaceLivenessFailed` | Liveness detection failed. | Signs of spoofing detected (mask, photo, video replay). |
| `FaceLivenessReviewRequired` | Liveness check requires manual review. | Automated liveness check was inconclusive. |
| `FaceLivenessTooFar` | Face is too far for liveness check. | Distance prevents accurate liveness detection. |
| `FacePhotoOfPhoto` | Detected face appears to be a photo of a photo. | Selfie shows characteristics of photographed images. |
| `FaceCovered` | Face is covered. | Mask, glasses, or other objects obscure facial features. |
| `FaceEdited` | Face image appears edited. | Digital manipulation detected in facial image. |
| `FaceBlur` | Face image is blurred. | Motion or focus blur affects facial features. |
| `FaceBlurry` | Face image is blurry. | Image quality prevents accurate facial recognition. |
| `FaceTooClose` | Face is too close to the camera. | Face fills too much of the frame for proper analysis. |
| `FaceTooFar` | Face is too far from the camera. | Face is too small in the frame for biometric matching. |
| `FaceCropped` | Face is cropped in the image. | Part of the face is cut off in the submission. |
| `FaceTooSmall` | Face is too small in the image. | Facial resolution is insufficient for matching. |
| `FaceAngleTooLarge` | Face angle is too large. | Face is at an extreme angle preventing clear biometric capture. |
| `FaceDeepfake` | Face appears to be a deepfake. | AI-generated or manipulated face detected. |
| `FaceVideoFraud` | Face appears manipulated in video. | Video liveness check shows signs of digital manipulation. |
| `FacePreviouslyOnboarded` | Face was previously onboarded. | This face biometric is already registered in the system. |
### Address Verification
| Code | Message | Description |
| --------------------------------- | -------------------------------------------- | ------------------------------------------------------ |
| `AddressMissing` | Address was not provided. | No address information was submitted. |
| `AddressIncomplete` | Address information is incomplete. | Required address fields are missing. |
| `AddressMismatch` | Address does not match records. | Provided address conflicts with verification data. |
| `AddressNotVerified` | Address could not be verified. | Unable to confirm address through available sources. |
| `AddressPoBox` | PO boxes are not accepted. | Post office boxes are not valid for this verification. |
| `AddressProofMissing` | Proof of address is missing. | Required address documentation was not provided. |
| `AddressProofInvalid` | Proof of address is invalid. | Submitted proof of address doesn't meet requirements. |
| `AddressProofExpired` | Proof of address has expired. | The proof of address document is too old. |
| `AddressProofNotRecent` | Proof of address is not recent enough. | Document date doesn't meet recency requirements. |
| `AddressDocumentUnrecognized` | Address document could not be recognized. | The type of address proof submitted is not recognized. |
| `AddressDocumentMissingAddress` | Address document is missing the address. | Address field is not present on the submitted proof. |
| `AddressDocumentMissingName` | Address document is missing the name. | Name field is not present on the address proof. |
| `AddressDocumentMissingIssueDate` | Address document is missing the issue date. | Date of issuance is absent on the address proof. |
| `AddressDocumentNameMismatch` | Name on the address document does not match. | Name on address proof differs from identity document. |
| `AddressDocumentAddressMismatch` | Address on the document does not match. | Address on proof differs from stated address. |
### Geographic Restrictions
| Code | Message | Description |
| -------------------------------- | ------------------------------------------------ | -------------------------------------------------------------- |
| `GeographicRestrictedRegion` | Region is restricted. | The geographic region is not supported for compliance reasons. |
| `GeographicDisallowedCountry` | Country is disallowed. | Services are not available in this country. |
| `GeographicUnsupportedCountry` | Country is not supported. | Country is outside the service area. |
| `GeographicProhibitedCountry` | Country is prohibited. | Country is explicitly restricted due to regulations. |
| `GeographicProhibitedState` | State or province is prohibited. | Specific state/province is restricted. |
| `GeographicUnsupportedState` | State or province is not supported. | Service not available in this state/province. |
| `GeographicUnsupportedRegion` | Region is not supported. | Geographic region is outside coverage area. |
| `GeographicLocationMismatch` | Geolocation does not match provided information. | IP or GPS location conflicts with stated location. |
| `GeographicHighRiskJurisdiction` | High-risk jurisdiction detected. | Country/region is flagged as high-risk for financial crime. |
### Compliance & AML
| Code | Message | Description |
| -------------------------------- | ------------------------------------ | ------------------------------------------------------- |
| `ComplianceAmlMatch` | Match found on AML lists. | Individual appears on Anti-Money Laundering watchlists. |
| `ComplianceAmlFailed` | AML screening failed. | Unable to pass Anti-Money Laundering checks. |
| `CompliancePepMatch` | Match found on PEP lists. | Individual identified as a Politically Exposed Person. |
| `CompliancePotentialPep` | Potential PEP match detected. | Possible match to Politically Exposed Person lists. |
| `ComplianceSanctionsMatch` | Match found on sanctions lists. | Individual appears on international sanctions lists. |
| `ComplianceWatchlistMatch` | Match found on watchlists. | Match detected on regulatory or internal watchlists. |
| `ComplianceAdverseMedia` | Adverse media detected. | Negative news coverage or media reports found. |
| `ComplianceBackgroundCheckAlert` | Background check returned alerts. | Background screening identified potential issues. |
| `ComplianceOccupationRestricted` | Occupation is restricted. | Stated occupation is not permitted. |
| `ComplianceIndustryRestricted` | Industry is restricted. | Industry sector is not supported. |
| `ComplianceSourceOfFunds` | Source of funds requires review. | Source of funds needs additional verification. |
| `ComplianceElderAbuse` | Potential elder abuse risk detected. | Indicators suggest possible financial exploitation. |
### Information Completeness
| Code | Message | Description |
| ------------------------------- | ---------------------------------------- | ------------------------------------------------------- |
| `InformationMissingField` | A required information field is missing. | Essential field was not provided in submission. |
| `InformationIncomplete` | Provided information is incomplete. | Submission lacks required information. |
| `InformationInconsistent` | Provided information is inconsistent. | Submitted information contains contradictions. |
| `InformationInvalidTaxId` | Tax ID is invalid. | Tax identification number format or value is incorrect. |
| `InformationContactInvalid` | Contact information is invalid. | Phone or email format is incorrect. |
| `InformationEmailInvalid` | Email address is invalid. | Email format is incorrect or undeliverable. |
| `InformationEmailNotFound` | Email address was not found. | Email address doesn't exist in verification databases. |
| `InformationEmailMismatch` | Email address does not match records. | Email differs from expected or previous records. |
| `InformationPhoneInvalid` | Phone number is invalid. | Phone number format or country code is incorrect. |
| `InformationPhoneNotFound` | Phone number was not found. | Phone number doesn't exist in verification databases. |
| `InformationPhoneMismatch` | Phone number does not match records. | Phone differs from expected or previous records. |
| `InformationVerificationFailed` | Information verification failed. | Unable to verify the provided information. |
### Business Specific
| Code | Message | Description |
| ------------------------------------------- | ---------------------------------------------------- | --------------------------------------------------------- |
| `BusinessMissingUltimateBeneficialOwner` | Ultimate beneficial owner information is missing. | UBO details were not provided. |
| `BusinessIncompleteUltimateBeneficialOwner` | Ultimate beneficial owner information is incomplete. | UBO information lacks required fields. |
| `BusinessAwaitingUltimateBeneficialOwner` | Awaiting ultimate beneficial owner information. | UBO documentation is pending. |
| `BusinessRegistrationFailed` | Business registration verification failed. | Cannot verify business registration status. |
| `BusinessNotRegistered` | Business is not registered. | No registration found for the business entity. |
| `BusinessStructureUnclear` | Business structure is unclear. | Legal structure of business cannot be determined. |
| `BusinessLicenseExpired` | Business license has expired. | Required business license is no longer valid. |
| `BusinessLicenseInvalid` | Business license is invalid. | Business license verification failed. |
| `BusinessFormationDocumentMissing` | Business formation document is missing. | Articles of incorporation or equivalent not provided. |
| `BusinessOwnershipDocumentMissing` | Ownership document is missing. | Proof of ownership or shareholder documents not provided. |
| `BusinessDissolved` | Business appears to be dissolved. | Records indicate business has been closed or dissolved. |
| `BusinessHighRiskIndustry` | Business operates in a high-risk industry. | Industry sector is categorized as high-risk. |
### Behavioral & Fraud Detection
| Code | Message | Description |
| --------------------------------- | ----------------------------------------- | ---------------------------------------------------- |
| `FraudMultipleAttempts` | Multiple suspicious attempts detected. | Unusual number of verification attempts detected. |
| `FraudVelocityCheck` | Velocity checks were triggered. | Activity frequency exceeds normal patterns. |
| `FraudSuspiciousBehaviour` | Suspicious behavior detected. | User actions indicate potentially fraudulent intent. |
| `FraudSuspiciousPattern` | Suspicious pattern detected. | Behavior matches known fraud patterns. |
| `FraudDeviceReputation` | Device has a poor reputation. | Device is associated with fraudulent activity. |
| `FraudIpReputation` | IP address has a poor reputation. | IP address is flagged for suspicious activity. |
| `FraudIpSuspicious` | Suspicious IP address detected. | IP characteristics indicate potential fraud. |
| `FraudTorDetected` | Tor usage detected. | Connection through Tor network identified. |
| `FraudVpnDetected` | VPN usage detected. | Connection through VPN or proxy identified. |
| `FraudBotDetected` | Bot activity detected. | Automated/non-human interaction detected. |
| `FraudSyntheticIdentity` | Synthetic identity is suspected. | Identity appears to be artificially constructed. |
| `FraudBrowserPreviouslyAttempted` | Browser was used in previous attempts. | Browser fingerprint matches previous submissions. |
| `FraudIpPreviouslyAttempted` | IP address was used in previous attempts. | IP address linked to other verification attempts. |
### Database & Lookup
| Code | Message | Description |
| ------------------------------- | ------------------------------------------ | ------------------------------------------------------------ |
| `DatabaseLookupFailed` | Database lookup failed. | Error occurred during database verification. |
| `DatabaseLookupSourceDown` | Data source is unavailable. | External verification database is unreachable. |
| `DatabaseLookupFaceNotFound` | Face not found in database. | Biometric not found in verification databases. |
| `DatabaseLookupIssue` | Issue encountered during database lookup. | Problem occurred accessing verification data. |
| `DatabaseNoCheckPerformed` | No database check was performed. | Database verification was not attempted. |
| `DatabaseCannotVerify` | Database cannot verify the information. | Information not found in authoritative databases. |
| `DatabaseCannotExtractMetadata` | Database cannot extract required metadata. | Unable to retrieve necessary data from verification sources. |
### Technical & System
| Code | Message | Description |
| --------------------------------- | ----------------------------------------------------- | -------------------------------------------------- |
| `TechnicalVerificationError` | Verification failed due to a technical error. | System error prevented completion of verification. |
| `TechnicalSystemError` | A system error occurred during verification. | Internal system failure during processing. |
| `TechnicalProcessingError` | A processing error occurred during verification. | Error in verification workflow execution. |
| `TechnicalTimeout` | Verification request timed out. | Verification took too long to complete. |
| `TechnicalApiError` | Upstream API error occurred during verification. | Third-party service error prevented verification. |
| `TechnicalCannotProcess` | The request cannot be processed. | Submission cannot be handled by the system. |
| `TechnicalPrivacyBlocked` | Verification was blocked due to privacy restrictions. | Privacy settings prevent verification completion. |
| `TechnicalDataRequirementsNotMet` | Data requirements for verification were not met. | Submission doesn't meet minimum data requirements. |
### Other & General
| Code | Message | Description |
| --------------------------- | ----------------------------------- | --------------------------------------------------------- |
| `OtherManualReviewFailed` | Manual review failed. | Human review determined submission should be rejected. |
| `OtherManualReviewRequired` | Manual review is required. | Submission requires human review before approval. |
| `OtherTermsNotAccepted` | Terms were not accepted. | User did not accept required terms and conditions. |
| `OtherUnspecified` | Unspecified compliance rejection. | Rejection reason doesn't fit standard categories. |
| `OtherCustomError` | Custom compliance rejection reason. | Provider-specific rejection not mapped to standard codes. |
### Usage Notes
1. **Multiple Reasons**: A compliance check may have multiple rejection reasons when the PFI identifies several issues.
2. **Code Consistency**: The `code` field is standardized across all PFIs, allowing for consistent handling of rejection reasons in your application logic.
3. **Provider Messages**: The `pfiMessage` field contains the original message from the verification provider and may vary in format and detail across different PFIs.
4. **Description Mapping**: The `description` field is automatically derived from the `code` enum value and provides a consistent human-readable message.
5. **Actionability**: Some rejection codes indicate user-correctable issues (e.g., `DocumentExpired`, `DocumentBlurry`) while others indicate systemic blocks (e.g., `ComplianceSanctionsMatch`, `GeographicProhibitedCountry`).
### Integration Recommendations
* **Display Strategy**: Show the `description` to end users for clarity, and log the `pfiMessage` for debugging and support purposes.
* **Retry Logic**: Implement different retry strategies based on rejection codes (e.g., allow retries for quality issues but not for compliance flags).
* **User Guidance**: Map specific codes to actionable user instructions (e.g., "Please retake photo in better lighting" for `DocumentBlurry`).
* **Analytics**: Track rejection code frequency to identify common user issues and improve the verification flow.
If you have any questions, please don't hesitate to reach out to us via [email](mailto:support@borderless.xyz) or slack.
# Identity Compliance Webhooks
Source: https://docs.borderless.xyz/docs/identity-compliance
If you're just getting started, please check out our [quick start guide](/docs/quick-start-guide).
Compliance check creation, regardless was it successful or not, results into webhooks delivered to the registered addresses.
### Completed
When identity compliance check completes, either with Approved or Rejected KYC status, system sends **IdentityComplianceCheck\_Completed** webhook.
```bash bash theme={null}
{
"type": "IdentityComplianceCheck_Completed",
"organizationId": "clwf218k000001wrwr7dvi9wp",
"timestamp": 1740071905278,
"data": {
"id": "cm7dlpeon000kp925og708phy",
"identityId": "cm7dloxy8000gp925tzej8sxk",
"status": "Approved",
"metadata": {
"hasAcceptedTos": true,
"rejectionReason": []
}
}
}
```
```bash bash theme={null}
{
"type": "IdentityComplianceCheck_Completed",
"organizationId": "clwf218k000001wrwr7dvi9wp",
"timestamp": 1740071905278,
"data": {
"id": "cm7dlpeon000kp925og708phy",
"identityId": "cm7dloxy8000gp925tzej8sxk",
"status": "Rejected",
"metadata": {
"hasAcceptedTos": true,
"rejectionReasons": [
{
"code": "DocumentExpired",
"description": "Document has expired.",
"pfiMessage": "ID is expired."
},
{
"code": "FaceNotLive",
"description": "Liveness check failed.",
"pfiMessage": "The selfie video shows signs of presentation attack."
}
]
}
}
}
```
Changes during compliance check process are reflected via **IdentityComplianceCheck\_Updated** webhooks, e.g. when a customer accepts terms of service or there is a change in KYC status.
### Updated
```bash bash theme={null}
{
"type": "IdentityComplianceCheck_Updated",
"organizationId": "clwf218k000001wrwr7dvi9wp",
"timestamp": 1740071905278,
"data": {
"id": "cm7dlpeon000kp925og708phy",
"identityId": "cm7dloxy8000gp925tzej8sxk",
"status": "UnderReview",
"metadata": {
"hasAcceptedTos": true,
"rejectionReason": []
}
}
}
```
If you have any questions, please don't hesitate to reach out to us via [email](mailto:support@borderless.xyz) or slack.
# Introduction
Source: https://docs.borderless.xyz/docs/introduction
## Welcome to Borderless
Welcome to Borderless, the leading stablecoin payments orchestration network. Borderless enables seamless payments with stablecoins and local banking rails in 50+ countries.
We know companies like yours can accelerate when built on global stablecoin rails, but liquidity, compliance, and fiat are still fragmented by local regulatory environments.
The Borderless network solves this with a global connectivity layer, providing a single API gateway to local stablecoin onramp and offramp partners all across the world.
With Borderless, you can go global as quickly as you can sign paper with your chosen providers. Keep the team focused on your core mission, and leave the heavy lifting to us.
Note: Borderless is never in the flow of funds, and never takes custody of client or partner funds. Borderless is a gateway connecting clients directly with regulated and licensed providers.
## Borderless products
Stablecoin payment infrastructure are our core products.
Make global payments between local fiat currencies and stablecoins.
Streamline the compliance burden to simplify management of many providers.
Build on the first free, public, and credibly neutral, stablecoin : local currency benchmark.
Drive decisions with a consolidated command center for analytics, reporting, and more.
## Next steps
A quick look at what comes next.
To get started, you'll need sandbox access and an API key.
Payments are associated with identities, so we first establish these identities.
Accounts structure data about client assets.
Once we have accounts to facilitate payments, and identities to participate, we can initiate our pay-ins and pay-outs.
The central command center. A consolidated transaction history lives here for streamlined reporting, alongside analytics that help to drive future decisions.
To get started with step 1, please reach out to us via email to request access.
# Organization
Source: https://docs.borderless.xyz/docs/organization-setup-and-user-invitation
An `organization` represents your company or team on the Borderless network.
The Borderless team will set up your organization for you during the onboarding process at the very beginning of your journey with us. You will be invited to join the organization via email or slack. You can read more about what comes next in our [quick start guides](/docs/quick-start-guide).
As the highest overarching level, the `organization` will be the umbrella for associated API keys, access tokens, identities, accounts, transactions, and everything else that belongs to your team.
To manage your organization and configure settings, you will have access to the Borderless dashboard as your central command center. Here you can add new members, remove members, change your passwords, configure your web3 wallet infrastructure, view key metrics, and much more.
Example of organization configuration in Borderless dashboard.
If you have any questions, please don't hesitate to reach out to us via [email](mailto:support@borderless.xyz) or slack.
# Payment Instructions
Source: https://docs.borderless.xyz/docs/payment-instructions
When withdrawing fiat funds from Borderless, you need to specify where you'd like the funds to be sent. Since Borderless supports a wide range of countries with different payout methods - such as bank transfers, PIX, Mobile Money, and others - this is done through Payment Instructions.
A Payment Instruction is created for a specific `identity`, and contains the method and destination details for where funds should be sent during a withdrawal.
If you're just getting started, please check out our [quick start guide](/docs/quick-start-guide).
## Payment Method
The core of the Payment Instruction is the payment method, which defines how the transfer will be made. Each country may support different methods. Please see a list below of local payment rails.
| Rail | Region | Currency | Type |
| -------------------------------------------- | --------------------------- | ---------------------------- | ----------------------- |
| SWIFT MT / ISO 20022 | Global | Multi-currency | Messaging / interbank |
| Card networks (Visa, Mastercard, Amex, etc.) | Global | Multi-currency | Card schemes |
| T2 (Eurosystem RTGS) | Eurozone | EUR | RTGS |
| TIPS (TARGET Instant Payment Settlement) | Europe (SEPA) | EUR, SEK, DKK | Instant |
| Buna | Arab region (selected MENA) | AED, SAR, JOD, EGP, USD, EUR | Cross-border / regional |
| CIPS | Global (RMB-focused) | CNY (RMB) | Cross-border RTGS |
Core account-based rails across North and South America.
**United States & Canada**
| Rail | Country | Currency | Type |
| -------------------- | ------- | -------- | ---------------- |
| ACH | US | USD | Batch ACH |
| Fedwire | US | USD | High-value RTGS |
| RTP | US | USD | Instant |
| FedNow | US | USD | Instant |
| Zelle | US | USD | Scheme / overlay |
| Interac e-Transfer | Canada | CAD | Instant |
| Lynx (RTGS) | Canada | CAD | High-value RTGS |
| Real-Time Rail (RTR) | Canada | CAD | Instant |
**Latin America**
| Rail | Country | Currency | Type |
| ---------------------------- | --------- | -------- | -------------- |
| Pix | Brazil | BRL | Instant |
| TED / DOC | Brazil | BRL | RTGS / batch |
| SPEI | Mexico | MXN | Instant |
| CoDi (overlay on SPEI) | Mexico | MXN | Instant / QR |
| PSE (Pagos Seguros en Línea) | Colombia | COP | Near real-time |
| Local ACH/RTGS rails | Colombia | COP | Batch / RTGS |
| Local ACH/RTGS rails | Argentina | ARS | Batch / RTGS |
| COELSA | Argentina | ARS | Batch / RTGS |
| Local ACH/RTGS rails | Chile | CLP | Batch / RTGS |
| SPAV | Chile | CLP | Batch / RTGS |
| Local ACH/RTGS rails | Peru | PEN | Batch / RTGS |
Euro-area SEPA rails plus major national systems.
**Pan-European (SEPA / Eurozone)**
| Rail | Region | Currency(ies) | Type |
| ---------------------------- | --------- | ------------- | --------------------- |
| SEPA Credit Transfer | SEPA zone | EUR | Batch credit transfer |
| SEPA Instant Credit Transfer | SEPA zone | EUR | Instant |
| SEPA Direct Debit | SEPA zone | EUR | Batch debit |
| TARGET2 | Eurozone | EUR | High-value RTGS |
| TIPS | Eurozone | EUR | Instant |
**United Kingdom & other Europe**
| Rail | Country | Currency(ies) | Type |
| ----------------------------- | ------- | ------------- | ---------------- |
| Faster Payments Service (FPS) | UK | GBP | Instant |
| Bacs | UK | GBP | Batch ACH |
| CHAPS | UK | GBP | High-value RTGS |
| Swish | Sweden | SEK | Instant / mobile |
| Rail / Scheme | Country / Region | Currency | Type |
| -------------------------------- | ------------------------- | --------- | ----------------- |
| UPI (Unified Payments Interface) | India | INR | Instant |
| IMPS / NEFT | India | INR | Faster / batch |
| New Payments Platform (NPP) | Australia | AUD | Instant |
| FAST | Singapore | SGD | Fast ACH |
| PayNow (on FAST) | Singapore | SGD | Instant overlay |
| PromptPay | Thailand | THB | Instant |
| DuitNow | Malaysia | MYR | Instant |
| BI-FAST | Indonesia | IDR | Instant |
| InstaPay | Philippines | PHP | Instant |
| PESONet | Philippines | PHP | Batch ACH |
| Faster Payment System (FPS) | Hong Kong SAR | HKD, CNY | Instant |
| CNAPS | China (domestic) | CNY | RTGS / ACH |
| CIPS | Global (RMB cross-border) | CNY (RMB) | Cross-border RTGS |
GCC and MENA rails, including instant and cross-border systems.
| Rail | Country | Currency | Type |
| ------------------------- | --------------------------------------- | ------------------------------------ | --------------------------- |
| Sarie / SARIE | Saudi Arabia | SAR | Instant + batch |
| UAEFTS / local RTGS & ACH | UAE | AED (multi-currency for some flows) | RTGS / batch |
| Buna | Arab region (cross-border) | AED, SAR, EGP, USD, EUR (and others) | Cross-border RTGS / instant |
| InstaPay (overlay) | Egypt | EGP | Instant |
| Other GCC instant rails | GCC (e.g. Qatar, Bahrain, Oman, Kuwait) | Local currencies | Instant |
Account-based rails alongside mobile money ecosystems.
| Rail | Country | Currency | Type |
| --------------------------------------------------------- | ------------------------- | ------------------------ | ------------ |
| NIBSS Instant Payment (NIP) | Nigeria | NGN | Instant |
| GhIPSS Instant Pay (GIP) | Ghana | GHS | Instant |
| PayShap | South Africa | ZAR | Instant |
| RTGS / ACH systems | Various African markets | Local currencies | RTGS / batch |
| Mobile money rails (M-Pesa, MTN MoMo, Airtel Money, etc.) | Kenya, TZ, UG, GH, others | KES, TZS, UGX, GHS, etc. | Wallet rails |
**Required Fields** The required fields for a Payment Instruction depend on the payment method and the country. Each method has its own set of required data.
## Usage
To create a payment instruction simply ensure the correct combination of country, currency, payment method, and required fields. You can submit payment instructions for an `identity` with the following endpoint:
Endpoint: [`POST /identities/{id}/payment-instructions`](/api-reference/payment-instructions/create-a-new-payment-instruction)
```json payment-instruction expandable theme={null}
{
"country": "CountryCode",
"currency": "FiatCurrencyId",
"name": "Name of Payment Instruction",
"paymentMethod": "PaymentMethod",
"details": "PaymentInstructionDetails"
}
```
**Payment Instructions**
In the United States, Payment Instructions offer two methods: **ACH** and **Wire**. The data required for both payment methods is the same:
We require a valid street address when creating US payment instructions. Address should start with a street number.\
\
Example: 99 Central Street
```json US payload theme={null}
{
"country": "US",
"currency": "USD",
"name": "Personal USD Account",
"paymentMethod": "ACH", // ACH, Wire
"details": {
"accountHolderName": "John Doe",
"bankAccountNumber": "123456789",
"bankAccountType": "Checking", // Savings
"bankName": "Bank of America",
"bankRoutingNumber": "026009593",
"address": {
"street1": "123 Main St",
"street2": "Apt 4B",
"city": "Los Angeles",
"state": "CA",
"country": "US",
"postalCode": "90001"
}
}
}
```
The SEPA (Single Euro Payments Area) payment method is available for all European countries that support payments in Euros (EUR).
```json SEPA payload theme={null}
{
"country": "NL",
"currency": "EUR",
"name": "Personal EUR Account",
"paymentMethod": "Sepa",
"details": {
"bankName": "Rabobank",
"accountHolderName": "John Doe",
"bankAccountNumber": "NL39RABO0301234567",
"swiftOrBicNumber": "RABONL2U",
"accountOwnerType": "Personal",
"firstName": "John",
"lastName": "Doe",
"address": {
"street1": "Keizersgracht 123",
"street2": "Apt 4B",
"city": "Amsterdam",
"country": "NL",
"postalCode": "1015CW"
}
}
}
```
Africa has a few different systems for payments and money transfer across the continent.
**+** is required for `phone` fields
```json mobile-money-payload expandable theme={null}
{
"country": "GH",
"currency": "GHS",
"name": "Personal GHS Account",
"paymentMethod": "MobileMoney",
"details": {
"accountHolderName": "Kwame Mensah",
"phone": "+254701234567",
"networkProvider": "MPESA" // deprecated please use networkSlug instead
}
}
```
```json EFT-payload expandable theme={null}
{
"country": "ZA",
"currency": "ZAR",
"name": "ZAR BankTransfer",
"paymentMethod": "EFT", // BankTransfer, EFT (for South Africa only)
"details": {
"bankSlug": "0fPrRVk7mkkCDKpzE2oOZXhlUjgKW7bEII2pz4crGX0",
"bankAccountNumber": "1111111111",
"address": {
"street1": "45 Sandton Drive",
"street2": "Sandhurst",
"city": "Johannesburg",
"state": "Gauteng",
"country": "ZA",
"postalCode": "2196"
}
}
}
```
SPEI is the primary payment method in **Mexico**.
```json SPEI-payload expandable theme={null}
{
"country": "MX",
"currency": "MXN",
"name": "Personal MXN Account",
"paymentMethod": "SPEI",
"details": {
"bankCode": "002",
"bankAccountNumber": "12345678901234567890123456",
"bankName": "BBVA México",
"taxId": "HEGJ8507157M9",
"businessDescription": "Software Engineer",
"address": {
"street1": "Avenida Insurgentes Sur 1234",
"street2": "Colonia del Valle",
"city": "Mexico City",
"state": "MX",
"country": "MX",
"postalCode": "03100"
}
}
}
```
PIX is the primary payment method for **Brazil.**
```json PIX-payload-CPF expandable theme={null}
{
"country": "BR",
"currency": "BRL",
"name": "Personal BRL Account",
"paymentMethod": "PIX",
"details": {
"identifierType": "CPF",
"identifierValue": "12345678901",
"address": {
"street1": "Avenida Paulista 1000",
"street2": "Bela Vista",
"city": "São Paulo",
"state": "SP",
"country": "BR",
"postalCode": "01310-100"
}
}
}
```
```json PIX-payload-phone expandable theme={null}
{
"country": "BR",
"currency": "BRL",
"name": "Personal BRL Account",
"paymentMethod": "PIX",
"details": {
"identifierType": "PhoneNumber",
"identifierValue": "1123456789",
"address": {
"street1": "Avenida Paulista 1000",
"street2": "Bela Vista",
"city": "São Paulo",
"state": "SP",
"country": "BR",
"postalCode": "01310-100"
}
}
}
```
COELSA is a primary payment method in **Argentina**.
```json COLESA-payload expandable theme={null}
{
"country": "AR",
"currency": "ARS",
"name": "Personal ARS Account",
"paymentMethod": "COELSA",
"details": {
"bankCode": "072",
"bankAccountNumber": "12345678901234567890123456",
"bankName": "Banco Nación Argentina",
"accountHolderName": "Carlos Martínez",
"bankAccountNumberType": "CVU", // CBU, ALIAS
"address": {
"street1": "Calle Ficticia 456",
"street2": "Piso 5",
"city": "Buenos Aires",
"country": "AR",
"postalCode": "C1000"
}
}
}
```
**Colombia** can use their local PSE rails for withdrawals.
```json PSE-payload expandable theme={null}
{
"country": "CO",
"currency": "COP",
"name": "Personal COP Account",
"paymentMethod": "PSE",
"details": {
"bankCode": "001",
"bankAccountNumber": "12345678901234567890123456",
"bankName": "Bancolombia",
"accountHolderName": "Carlos Martínez",
"address": {
"street1": "Carrera 7 # 123",
"street2": "Oficina 7A",
"city": "Bogotá",
"state": "DC",
"country": "CO",
"postalCode": "110010"
}
}
}
```
CCE payment method supports **Peru**.
```json CCE-payload expandable theme={null}
{
"country": "PE",
"currency": "PEN",
"name": "Personal PEN Account",
"paymentMethod": "CCE",
"details": {
"bankCode": "003",
"bankAccountNumber": "12345678901234567890123456",
"bankName": "Banco de Crédito del Perú",
"bankAccountType": "Checking",
"address": {
"street1": "Avenida Pardo y Aliaga 1234",
"street2": "Oficina 302",
"city": "Lima",
"state": "LI",
"country": "PE",
"postalCode": "15073"
}
}
}
```
SPAV supports **Chilean** withdrawals of Peso.
```json SPAV-payload expandable theme={null}
{
"country": "CL",
"currency": "CLP",
"name": "Personal CLP Account",
"paymentMethod": "SPAV",
"details": {
"bankCode": "003",
"bankAccountNumber": "12345678901234567890123456",
"bankName": "BancoEstado",
"address": {
"street1": "Avenida Apoquindo 1234",
"street2": "Oficina 404",
"city": "Santiago",
"state": "RM",
"country": "Chile",
"postalCode": "7550000"
}
}
}
```
Borderless does not validate the accuracy of the provided payment instruction details upon creation, only the format is checked.
The primary validation is performed by the PFI at the time of transaction execution. This means that if the payment instruction contains incorrect details, you may receive a failureReason during the withdrawal process.
It is responsibility of Integrator to validate the correctness of the provided data when creating payment instructions.
If you have any questions, please don't hesitate to reach out to us via [email](mailto:support@borderless.xyz) or slack.
# Quick Start
Source: https://docs.borderless.xyz/docs/quick-start-guide
We're excited to build with you! Let's jump right in and get things going.
## Set up
Let's get you set up to begin sending requests to Borderless.
Please contact us via email if you are not already in touch for onboarding. During your onboarding we will configure your selected partner finanial institutions (PFIs) who facilitate your on-ramping and off-ramping for stablecoin payments. Borderless will configure your organization in our system and invite your first user via email or Slack.
Once you receive this invitation, you can use it to set a password, and invite additional team members to the organization via your Borderless dashboard. Here you will have options to manage roles, configure organizational settings, and reset your password.
In the Borderless dashboard, you'll be able to generate your API keys to continue the integration and testing.
Look for the `Developers` section on the left hand navigation panel. Click the `Generate` button and copy your API keys.
**Please ensure you store your API keys in a safe place and do not share them.**
With your API keys from the previous step, you can generate an access token to authenticate future API requests. Authentication is enforced via OAuth 2.0. All endpoints require verified bearer tokens, and webhook communications are signed for end-to-end trust.
In your request body, include your `Client ID` and `Client Secret`, which you generated in the `Developers` section of the Borderless Dashboard.
Endpoint: [`POST /auth/m2m/token`](/api-reference/authentication/obtain-authentication-m2m-tokens)
```bash request expandable theme={null}
curl -X POST "https://sandbox-api.borderless.xyz/v1/auth/m2m/token" \
-H "Content-Type: application/json" \
-d '{
"clientId": "your-client-id",
"clientSecret": "your-client-secret"
}'
```
```json response expandable theme={null}
{
"accessToken": "your-access-token",
"tokenType": "Bearer",
"expiresIn": 3600,
"piiAccess": "all"
}
```
## Identities & compliance
Quickly establish identity objects and understand how to initiate compliance.
Every transaction on the Borderless network is associated with an `identity` and then linked to Borderless `accounts` for secure transactions.
There are two types of identities:
1. **Personal Identity** – Represents an individual (natural person). Used for account holders, directors, or ultimate beneficial owners (UBOs). Subject to know your customer (KYC) checks.
2. **Business Identity** – Represents a legal entity (company, organization, or institution). Required for clients performing business transactions or onboarding as a financial partner. Subject to know your business (KYB) checks.
This guide describes how you can create an `identity object` to represent a user in your system. An identity includes essential information (PII) about each customer, such as their name, email, and documents required for the KYC or KYB process.
This compliance process is managed by our partner financial institutions (PFIs), who serve as the the locally licensed and regulated stablecoin and fiat on-ramps and off-ramps.
Some requests require an `Idempotency-Key` header to ensure that operations are not accidentally executed multiple times. Please generate and use a unique UUID for this field. If you have additional questions about the `Idempotency-Key` you can review more in the [API Reference.](/api-reference/idempotency)
The following request will create a new `identity object`. Below is a full example showing all supported fields for a business identity.
Please replace `your-access-token `with the actual token you've received on Step 3.
Please capture identity `id` from the response to use it during account creation later.
Endpoint: [`POST /identities/personal`](/api-reference/identities/create-a-new-personal-identity)
Endpoint: [`POST /identities/business`](/api-reference/identities/create-a-new-business-identity)
```bash request expandable theme={null}
curl -X POST "https://sandbox-api.borderless.xyz/v1/identities/business" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-access-token" \
-H "idempotency-key: 8f14e45f-e6c3-4f7e-bd56-1b9a2e46f1d6"\
-d '{
"email": "business@example.com",
"phone": "+1234567890",
"taxId": "123456789",
"name": "Example Corp",
"dateOfIncorporation": "2003-01-01",
"address": {
"street1": "123 Main St",
"street2": "Apt 4B",
"city": "New York",
"state": "NY",
"country": "US",
"postalCode": "10001"
},
"description": "A technology solutions provider",
"sourceOfFunds": "inter_company_funds",
"businessIndustryCode": "336390",
"website": "https://example.com",
"businessType": "Llc",
"isDao": false,
"hasMaterialIntermediaryOwnership": false,
"businessTradeName": "Example Solutions",
"accountPurpose": "investment_purposes",
"accountPurposeOther": "string",
"ultimateBeneficialOwners": [
{
"hasOwnership": true,
"hasControl": true,
"controlPersonTitle": "CEO",
"ownershipPercentage": 30,
"isSigner": true,
"relationshipEstablishedAt": "2023-01-15",
"personalIdentityId": "cm9db4g2s4r7ro224ra6u1qvl"
},
{
"hasOwnership": true,
"hasControl": true,
"controlPersonTitle": "CEO",
"ownershipPercentage": 30,
"isSigner": true,
"relationshipEstablishedAt": "2023-01-15",
"personalIdentity": {
"firstName": "John",
"lastName": "Doe",
"secondLastName": "Smith",
"middleName": "Michael",
"taxId": "123456789",
"dateOfBirth": "2003-01-01",
"email": "john.doe@example.com",
"phone": "+1234567890",
"activity": "Software Engineer",
"sex": "Male",
"occupationCode": "172011",
"employmentStatus": "SelfEmployed",
"sourceOfFunds": "InvestmentsLoans",
"accountPurpose": "InvestmentPurposes",
"accountPurposeOther": "string",
"monthlyAmounts": "From10KTo50K",
"actingAsIntermediary": false,
"address": {
"street1": "123 Main St",
"street2": "Apt 4B",
"city": "New York",
"state": "NY",
"country": "US",
"postalCode": "10001"
}
}
}
]
}
'
```
```json response expandable theme={null}
{
"id": "cm34yhws000343brvezoqdqn0",
"type": "Business",
"deleted": false,
"hasComplianceChecks": true,
"data": {
"email": "business@example.com",
"phone": "+1234567890",
"taxId": "123456789",
"name": "Example Corp",
"dateOfIncorporation": "2003-01-01",
"description": "A technology solutions provider",
"sourceOfFunds": "inter_company_funds",
"website": "https://example.com",
"businessType": "Llc",
"businessIndustryCode": "336390",
"isDao": false,
"hasMaterialIntermediaryOwnership": false,
"businessTradeName": "Example Solutions",
"accountPurpose": "investment_purposes",
"ultimateBeneficialOwners": [
{
"hasOwnership": true,
"hasControl": true,
"controlPersonTitle": "CEO",
"ownershipPercentage": 30,
"isSigner": true,
"relationshipEstablishedAt": "2023-01-15",
"personalIdentityId": "cm9db4g2s4r7ro224ra6u1qvl"
}
],
"address": {
"id": "cm34yhws000343brvezoqdqn1",
"street1": "123 Main St",
"street2": "Apt 4B",
"city": "New York",
"state": "NY",
"country": "US",
"postalCode": "10001"
},
"documents": [
{
"id": "cm34yhws000343brvezoqdqn2",
"issuingCountry": "US",
"type": "Passport",
"idNumber": "A12345678",
"issuedDate": "2020-01-01",
"expiryDate": "2030-01-01"
}
]
}
}
```
Once an identity has been created, they will have limited ability to transact until they pass a KYC or KYB check with the on-ramp and off-ramp providers (PFIs) they'd like to enable. You can easily gather the configured PFIs from our API before collecting the necessary documents and initiating a compliance check. Additionally, this endpoint provides the terms of service link, where required, which will need to be forwarded to the client.
Some of our partner financial institutions (PFIs) require users to accept their terms and conditions before they can transact. Each identity must accept their own ToS link, and it cannot be reused.
Please use the identity `id` from the response above.
Please capture compliance `slug` from the response to use it next.
Please capture terms of service `link` to deliver to end users.
Endpoint: [`GET /identities/{identityId}/compliance-checks`](/api-reference/compliance-checks/get-a-compliance-check-by-id)
```bash request expandable theme={null}
curl -X GET "https://sandbox-api.borderless.xyz/v1/identities/{identityId}/compliance-checks?country=US&asset=USDC_BASE&fiat=USD&paymentMethod=ACH&type=Deposit" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-access-token"
```
```json response expandable theme={null}
{
"slug": "compliance-d4a0bea2",
"incorporates": [],
"coverage": [
{
"type": "Deposit",
"operationType": "Deposit",
"method": "ACH",
"fiat": "USD",
"country": "US",
"asset": "USDC_BASE"
}
],
"schema": {},
"documents": [],
"id": "cm34yhws000343brvezoqdqn0",
"kycStatus": "NotStarted",
"status": "NotStarted",
"incompleteReasons": null,
"metadata": {
"tosLink": "https://example-pfi.com/terms-of-service",
"redirectUrl": null,
"hasAcceptedTos": false
},
"rejectionReasons": null
}
```
With the identity `id` and compliance `slug` you can now check the list of required information and documentation needed for the configured PFIs. This allows you to dynamically build your UI such that you only ask your customers for what is required for each specific business or user.
It is important to remember that the compliance slug is an identifier that represents a specific combination of provider and country coverage. This allows us to dynamically get a tailored list of required documentation for the client use case.
Please use the compliance `slug` from the response above.
Endpoint: [`GET /identities/{identityId}/compliance-checks/{slug}/requirements`](/api-reference/compliance-checks/get-compliance-requirements-for-a-compliance)
```bash request expandable theme={null}
curl -X GET "https://sandbox-api.borderless.xyz/v1/identities/{identityId}/compliance-checks/{slug}/requirements" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-access-token" \
```
```json response expandable theme={null}
{
"slug": "compliance-d4a0bea2",
"schema": {
"additionalProp": {}
},
"missingFields": [
"string"
],
"requiredDocuments": [
{
"mode": "oneOf",
"documents": [
"Passport"
]
}
],
"requiredExtras": {
"acceptTermsOfService": {
"link": "string"
}
},
"type": {}
}
```
Now that required documents have been identified, and the terms of service link, if required, has been accepted, we can submit these documents for review via our API. This information will be added to the identity object so that we can streamline and orchestrate future compliance as well.
For clarity, the `id` parameter here is the identity id of the organization or person you have created in step 1 of this process. This will upload the information to be associated with the id for the compliance check. You can use this endpoint at any time to add documents to the related identity object.
Please note, `imageFront` and `imageBack` should be converted in base64 format with resolution at least `200*200`pixels.
Endpoint: [`PUT /identities/{id}/documents`](/api-reference/identities/upload-a-document)
```bash request expandable theme={null}
curl -X PUT "https://sandbox-api.borderless.xyz/v1/identities/{id}/documents" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-access-token" \
-H "idempotency-key: 8f14e45f-e6c3-4f7e-bd56-1b9a2e46f1d6"\
-d '{
"issuingCountry": "US",
"type": "Passport",
"issuedDate": "2024-07-25",
"expiryDate": "2027-07-25",
"imageFront": "image/200*200;base64",
"imageBack": "image/200*200;base64"
}'
```
```json response expandable theme={null}
{
"id": "cm34yhws000343brvezoqdqn0",
"type": "Personal",
"deleted": false,
"hasComplianceChecks": true,
"data": {
"firstName": "string",
"lastName": "string",
"secondLastName": "string",
"middleName": "string",
"taxId": "string",
"dateOfBirth": "YYYY-MM-DD",
"email": "string",
"phone": "string",
"activity": "string",
"sex": "Male",
"address": {
"id": "string",
"street1": "string",
"street2": "string",
"city": "string",
"state": "string",
"country": "AF",
"postalCode": "string"
},
"documents": [
{
"id": "string",
"issuingCountry": "AF",
"type": "Passport",
"idNumber": "string",
"issuedDate": "YYYY-MM-DD",
"expiryDate": "YYYY-MM-DD"
}
]
}
}
```
After attaching the required documents to the identity object, you are ready to submit and start the compliance check with our partner financial institutions (PFIs).
You will need to initiate compliance checks for each of the compliance slugs that the identity will want to transact via. Borderless will maintain the info/documents uploaded for identities, meaning you will not need to re-upload the same info/documents if they are required to initiate compliance checks with different compliance slugs.
If all prerequisites are satisfied, the check will begin. Use the GET request above from step 2 and the API will return the current compliance status.
Endpoint: [`POST /identities/{identityId}/compliance-checks/{slug}`](/api-reference/compliance-checks/create-a-new-compliance-check)
```bash request expandable theme={null}
curl -X POST "https://sandbox-api.borderless.xyz/v1/identities/{identityId}/compliance-checks/{slug}" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-access-token" \
-H "idempotency-key: 8f14e45f-e6c3-4f7e-bd56-1b9a2e46f1d6"\
```
```json response expandable theme={null}
{
"slug": "compliance-d4a0bea2",
"status": "NotStarted",
"metadata": {}
}
```
The timeline for different compliance checks varies by both provider and type of identity. For personal identities, providers generally provide approvals within the span of a few hours or less, with some being near instant. For business identities, providers generally provide approvals within the span of 1-4 days. We will keep you informed during the whole process via the returned compliance status in the response body of step 2.
Requests for information (RFIs) are a regular part of the compliance process. If there are follow up questions on documents, completely missing documents, or other details that need to be reviewed manually, our PFIs can send a request for additional information.
\
These requests for information will be communicated manually, and are generally expected to be resolved in 24 to 48 hours.
## Accounts
Each identity needs to be configured with accounts to interact with their funds.
At a high level, an account is a structure that is owned by an identity and has the underlying infrastructure or connectivity to interact with stablecoins or fiat. It is important to configure this correctly.
This can take a handful of shapes, but an identity will generally link a stablecoin wallet provider such as Fireblocks, Utila, Dfns, Fordefi, Metamask, or others. We have also expanded the concept of accounts to include fiat balances held with the PFIs such as Finity. You can link your Finity fiat balance as well, to initiate actions on those funds such as bulk fx conversions, ahead of fiat payments that are executed over a longer period of time.
We are using an example below for standalone wallet infrastructure, but please review additional examples with all of the different infrastructure options in the [Accounts & Wallets](/docs/accounts) section of the docs.
It's also important to know we support sub-accounts. Sub-accounts function the same way as standard accounts but follow the configuration and rules defined by the primary account. Throughout this documentation, the term Account refers to both accounts and sub-accounts, unless explicitly stated otherwise.
It is important to note, Borderless is never in the flow of funds. These accounts are either custodied with the PFI, the wallet provider, or self-custodied by the identity itself. We do not provide any form of custody and we never initiate any movement of funds on behalf of the identity.
Let's create our first account. For this example we will use a Standalone Account type, but feel free to explore the others in the Accounts & Wallets section. After this, we will need to add stablecoin assets.
Please capture account `id` from the response to use it as needed later.
Endpoint: [`POST /accounts`](/api-reference/accounts/create-a-new-account)
```bash request expandable theme={null}
curl -X POST "https://sandbox-api.borderless.xyz/v1/accounts" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-access-token" \
-H "idempotency-key: 8f14e45f-e6c3-4f7e-bd56-1b9a2e46f1d6"\
-d '{
"name": "Main Account",
"identityId": "cm34yhws000343brvezoqdqn0"
}'
```
```json response expandable theme={null}
{
"id": "cm9db4g2s2r7ro224ra6u1qvl",
"type": "web3",
"pfi": null,
"web3Provider": "Standalone",
"name": "Main Account",
"addresses": [
{
"id": "cm9db4g2s2r7ro224ra6u1qvl",
"asset": "USDC_POLYGON",
"address": "0xE79a68B87544ed42Cc5aA805bb056201e7942D3A"
}
],
"assets": [
{
"id": "cm9db4g2s2r7ro224ra6u1qvl",
"asset": "USDC_POLYGON",
"address": "0xE79a68B87544ed42Cc5aA805bb056201e7942D3A"
}
],
"fiats": [],
"identityId": "cm34yhws000343brvezoqdqn0",
"createdAt": "2025-11-19T01:10:26.466Z"
}
```
With an account set up for this identity, it's necessary to add assets to the account. Specifically, these assets are the stablecoin funds that will be used to initiate off-ramp payments into local fiat currencies, such as USDC or USDT. These accounts will also be used to receive funds when on-ramping payments between local fiat currencies and stablecoins.
Please note that when you add new assets to your account, this is a configuration for the stablecoin wallet infrastructure to track these assets correctly. This does not mean you are sending real stablecoin funds to this account with this endpoint. Borderless is fully non-custodial, you will need to transfer your stablecoins directly to this wallet address yourself, or receive funds from an on-ramp transaction.
Please use the account `id` from the response to the previous request above.
Endpoint: [`POST /accounts/{id}/assets`](/api-reference/accounts/add-assets-to-account)
```bash request expandable theme={null}
curl -X POST "https://sandbox-api.borderless.xyz/v1/accounts/{id}/assets" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-access-token" \
-d '[
{
"asset": "POL"
},
{
"asset": "USDC_POLYGON"
}
]'
```
```json response expandable theme={null}
[
{
"id": "cmi7s8wgk471upg23mlc2chms",
"asset": "POL",
"address": "0x844e374159575A44Fbe92391B9297c62e495f2a6"
},
{
"id": "cmi7s8wgk471wpg23vjl4rhvb",
"asset": "USDC_POLYGON",
"address": "0x844e374159575A44Fbe92391B9297c62e495f2a6"
}
]
```
Once you receive funds to this account, and added the stablecoin assets to be tracked on the account, you can easily check the balances at any time. Just pass the account `id` as a parameter in the request, and the balance is returned.
Endpoint: [`GET /accounts/{id}/balances`](/api-reference/accounts/get-account-assets-balances)
```bash request expandable theme={null}
curl -X GET "https://sandbox-api.borderless.xyz/v1/accounts/{id}/balances" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-access-token" \
```
```json response expandable theme={null}
[
{
"type": "asset",
"asset": "POL",
"fiat": null,
"total": "10"
},
{
"type": "asset",
"asset": "USDC_POLYGON",
"fiat": null,
"total": "10"
}
]
```
## Transactions
Let's walk through on-ramp (deposit) and off-ramp (withdrawal) payment examples.
It is important to note, Borderless is never in the flow of funds. These transactions are executed directly between the PFI, and yourself (the client). We do not provide any form of custody and we never initiate any movement of funds on behalf of the identity. Borderless is strictly a connectivity technology solution to streamline integrations.
### On-Ramp (Deposit)
On-ramping is converting `fiat currencies` into `stablecoins` such as USDT or USDC. This conversion is facilitated by the PFIs on the Borderless network and can be part of either a payin or payout flow simply depending on if you are sending or receiving the payments. In this scenario you are ultimately sending or receiving stablecoins, after the local fiat currencies are converted at the PFI.
On-ramps are a simple 3 step process.
Optionally, you can also request a quote before initiating the on-ramp to have a transparent view of the estimated fees and exchange rates.
Quotes are returned directly from the PFIs, and are regularly changing. Quotes are not firm, and they do not guarantee any final received amount. They are estimates only, and Borderless is not responsible for incorrect quotes provided to us by PFIs.
Endpoint: [`GET /deposits/quotes`](/api-reference/transaction-deposits/get-deposit-quote)
```bash request expandable theme={null}
curl -X GET 'https://sandbox-api.borderless.xyz/v1/deposits/quotes' \
-H 'Authorization: Bearer your-access-token' \
-H 'Content-Type: application/json' \
-d '{
"country": "US",
"fiat": "USD",
"asset": "USDC_POLYGON",
"paymentMethod": "ACH",
"fromAmount": "10"
}'
```
```json response expandable theme={null}
{
"limits": {
"transaction": {
"minAmount": "1",
"maxAmount": "100",
"fiat": "USD"
}
},
"fiat": "USD",
"country": "US",
"asset": "USDC_POLYGON",
"paymentMethod": "ACH",
"fromAmount": "10",
"toAmount": "8.99",
"exchangeRate": "0.999",
"totalFee": "1",
"orchestrationFee": "1"
}
```
First, you will initiate an on-ramp transaction. This will return the payment instructions from the PFI, for the payment originator to send the local fiat currency. This alerts the PFI to expect the payment, and allows them to attribute the funds to your account when they arrive.
Please use account `id` in the on-ramp creation request from an account created above in the Accounts section.
Please note: if KYB or KYC are in progress, you'll see `"instructions":null` in the response. To fetch the payment instructions after order creation, you can subscribe to a Webhook or use `GET /transactions/{id}`using the on-ramp `id` from the response.
Webhook details can be found in the [API reference here.](/docs/webhooks)
Endpoint: [`POST /deposits`](/api-reference/transaction-deposits/create-a-new-deposit-transaction)
```bash request expandable theme={null}
curl -X POST 'https://sandbox-api.borderless.xyz/v1/deposits' \
-H 'Authorization: Bearer your-access-token' \
-H 'Content-Type: application/json' \
-H 'idempotency-key: 8f14e45f-e6c3-4f7e-bd56-1b9a2e46f1d6'\
-d '{
"fiat": "USD",
"amount": 1000.00,
"asset": "USDC_POLYGON",
"accountId": "account_id_from_prevous_step",
"paymentMethod": "ACH",
"country": "US"
}'
```
```json response expandable theme={null}
{
"id": "cmi7scamc471ypg23idn5epg6",
"type": "Deposit",
"status": "Submitted",
"pfiName": "Bridge",
"source": {
"asset": null,
"amount": "1000",
"fiatCurrency": "USD",
"paymentMethod": "ACH",
"accountId": null,
"accountName": null,
"sender": null
},
"destination": {
"asset": "USDC_POLYGON",
"amount": null,
"fiatCurrency": null,
"imad": null,
"reference": null,
"omad": null,
"traceNumber": null,
"externalAddress": null,
"accountId": "cmgjc1jvv00qlny23fx79oga0",
"accountName": "Main Account",
"paymentInstructionId": null
},
"instructions": null,
"createdAt": "2025-11-20T18:49:18.276Z",
"updatedAt": "2025-11-20T18:49:18.276Z",
"txHash": [],
"feeAmount": "0",
"failureReason": null,
"depositInstruction": null,
"destinationPaymentInstruction": null,
"withdrawalOnchainInstruction": null,
"counterPartyIdentityId": "cmgjbx4ab00qhny23bt333en5",
"virtualAccountId": null
}
```
Second, the payment originator follows the payment instructions that were returned in the first step, and sends the local fiat to the PFI directly. This step takes place directly with the PFI, over traditional local rails such as ACH, Wire, or PIX depending on region.
The PFI will be expecting the inbound fiat transfer to match the order created via the `/deposits` endpoint, please ensure you are following the payment instructions exactly.
Borderless cannot be held responsible for transfers that originate outside the Borderless network to incorrect addresses. It is your responsibility to review the payment instructions exactly as they are returned from our partner financial institutions (PFIs).
Third, the PFI will issue the stablecoins to the specified stablecoin wallet, as defined in your account set up above in the Accounts section. Once the stablecoins are received, this completes the on-ramp or deposit flow.
You can easily track the status of transactions, request cancellation of transactions, and export transactions with the following endpoints.
Please ensure you are using the transaction `id `value which you will receive from the request to create a transaction such as the first step in this sequence on the `/deposits` endpoint.
To track the status of your deposit transactions and other types of transactions:
We recommend listening to the statuses via Webhook. Webhook details can be found in the [API reference here.](/docs/webhooks)
Endpoint: [`GET /transactions/{id}`](/api-reference/transactions/get-a-transaction-by-id)
To request a cancellation of your deposit transaction and other types of transactions:
Endpoint: [`POST /transactions/{id}/cancel`](/api-reference/transactions/request-cancellation-of-a-transaction)
To export your transactions:
Endpoint: [`GET /transactions/export`](/api-reference/transactions/export-transactions)
**Congratulations! You've now completed your first stablecoin payment!**
### Off-ramp (Withdrawal)
Off-ramping is converting `stablecoins` into `fiat currencies` such as USD or BRL. This conversion is facilitated by the PFIs on the Borderless network and can be part of either a payin or payout flow simply depending on if you are sending or receiving the payments. In this scenario you are ultimately sending or receiving local fiat currencies, after the stablecoins are converted at the PFI.
An important note on payment instructions below.
Withdrawals are very similar to deposits as we've already accomplished above. The key difference to highlight, is around payment instructions.
With deposits, the local fiat leg is to the PFI's bank, and they provide the payment instructions in the api response when you open an order to deposit with them.
For a withdrawal, the local fiat leg is ultimately received by you or your clients in the respective banks. This means, we need to instruct the partner financial institution (PFI) where to send the fiat leg, and you must provide these payment instructions.
With this additional step in mind, withdrawals are a simple 4 step process.
Optionally, you can also request a quote before initiating the withdrawal to have a transparent view of the estimated fees and exchange rates.
Quotes are returned directly from the PFIs, and are regularly changing. Quotes are not firm, and they do not guarantee any final received amount. They are estimates only, and Borderless is not responsible for incorrect quotes provided to us by PFIs.
Endpoint: [`GET /withdrawals/quotes`](/api-reference/transaction-withdrawals/get-withdrawal-quote)
```bash request expandable theme={null}
curl -X GET 'https://sandbox-api.borderless.xyz/v1/withdrawals/quotes' \
-H 'Authorization: Bearer your-access-token' \
-H 'Content-Type: application/json' \
-d '{
"country": "US",
"fiat": "USD",
"asset": "USDC_POLYGON",
"paymentMethod": "ACH",
"fromAmount": "10"
}'
```
```json response expandable theme={null}
{
"limits": {
"transaction": {
"minAmount": "1",
"maxAmount": "100",
"fiat": "USD"
}
},
"fiat": "USD",
"country": "US",
"asset": "USDC_POLYGON",
"paymentMethod": "ACH",
"fromAmount": "10",
"toAmount": "8.99",
"exchangeRate": "0.999",
"totalFee": "1",
"orchestrationFee": "1"
}
```
First, create payment instructions to share with the partner financial institution (PFI) who is off-ramping or processing your withdrawal. This step is critical to ensure the local fiat currency arrives in the correct account at the end.
Please use an account `id` in the Payment Instruction creation request from an account created above in the Accounts section
Please capture payment instructions `id` from the response to use it for the withdrawal request after.
The PFI will be initiating the off-ramp directly to the payment instructions you create in this step. Borderless cannot be held responsible for transfers that originate outside the Borderless network to incorrect addresses. It is your responsibility to review the payment instructions and ensure they are correct.
Endpoint: [`POST /identities/{id}/payment-instructions`](/api-reference/payment-instructions/get-payment-instructions)
```bash request expandable theme={null}
curl -X POST 'https://sandbox-api.borderless.xyz/v1/identities/{id}/payment-instructions' \
-H 'Authorization: Bearer your-access-token' \
-H 'Content-Type: application/json' \
-H "idempotency-key: 8f14e45f-e6c3-4f7e-bd56-1b9a2e46f1d6"\
-d '{
"country": "US",
"currency": "USD",
"name": "Primary Bank Account",
"paymentMethod": "ACH",
"details": {
"bankName": "Example Bank",
"accountHolderName": "John Doe",
"bankAccountNumber": "123456789012",
"bankRoutingNumber": "123456789",
"bankAccountType": "Checking",
"address": {
"street1": "123 Main St",
"street2": "Apt 4B",
"city": "New York",
"state": "NY",
"country": "US",
"postalCode": "10001"
}
}
}'
```
```json response expandable theme={null}
{
"id": "cmi7sfuf04729pg23a00yntya",
"name": "Default ACH",
"paymentMethod": "ACH",
"currency": "USD",
"country": "US",
"deleted": false,
"details": {
"bankName": "Chase",
"bankSlug": null,
"bankAccountNumberLast4": "6789",
"bankRoutingNumber": "123456789",
"bankCode": null,
"phone": null,
"taxId": null,
"accountHolderName": "John Doe",
"bankAccountType": "Checking",
"address": {
"id": "cmi7sfueh4727pg23ga5lqhi2",
"street1": "123 Main St",
"street2": "Apt 2F",
"city": "New York",
"state": "NY",
"country": "US",
"postalCode": "10001"
}
}
}
```
Second, you will create a withdrawal transaction. This will send the payment instructions to the PFI, who will send the local fiat currency upon receipt of the matching amount of stablecoins. This alerts the PFI to expect the payment, and allows them to attribute the funds to your account when they arrive.
It's important to note that in the response to this withdrawal order, the PFI will return the onchain stablecoin payment instructions (generally a deposit address) that will handle the stablecoins which are being off-ramped.
Please capture the onchain instructions from the PFI in the response field `onchainInstructionTransaction` to use it to send stablecoins in the next step.
Please use both the account `id` from an account created above in the Accounts section, and the payment instructions `id` in the withdrawal creation request from the step above where you created the payment instructions.
Endpoint: [`POST /withdrawals`](/api-reference/transaction-withdrawals/create-a-new-withdrawal-transaction)
```bash request expandable theme={null}
curl -X POST 'https://sandbox-api.borderless.xyz/v1/withdrawals' \
-H 'Authorization: Bearer your-access-token' \
-H 'Content-Type: application/json' \
-H "idempotency-key: 8f14e45f-e6c3-4f7e-bd56-1b9a2e46f1d6"\
-d '
{
"fiat": "USD",
"country": "US",
"asset": "USDC_POLYGON",
"amount": "100.00",
"accountId": "cm2c4x3cc000019stwv7um4zl",
"developerFee": "5.00",
"paymentInstructionId": "cm2c4x3cc000019stwv7um4zl",
"paymentPurpose": "delivery fees",
"purposeDescription": "Monthly delivery service payment",
"reference": "INV-2025-001"
}
'
```
```json response expandable theme={null}
{
"id": "cmi7sihwi472bpg2301ptz9gv",
"type": "Withdrawal",
"status": "Submitted",
"pfiName": "Bridge",
"source": {
"asset": "USDC_POLYGON",
"amount": "100",
"fiatCurrency": null,
"paymentMethod": null,
"accountId": "cmgjc1jvv00qlny23fx79oga0",
"accountName": "Main Account",
"sender": null
},
"destination": {
"asset": null,
"amount": null,
"fiatCurrency": "USD",
"imad": null,
"reference": null,
"omad": null,
"traceNumber": null,
"externalAddress": null,
"accountId": null,
"accountName": null,
"paymentInstructionId": "cmi7sfuf04729pg23a00yntya"
},
"instructions": null,
"createdAt": "2025-11-20T18:54:07.650Z",
"updatedAt": "2025-11-20T18:54:07.650Z",
"txHash": [],
"feeAmount": "0",
"failureReason": null,
"depositInstruction": null,
"destinationPaymentInstruction": null,
"withdrawalOnchainInstruction": null,
"counterPartyIdentityId": "cmhlu3zlt002qpf246wd6vwrr",
"virtualAccountId": null
}
```
Once the local fiat payment instructions are sent to the PFI, and the withdrawal transaction is initiated, this order will remain open until the PFI receives the stablecoins as outlined in the instructions they shared via response to the withdrawal request. At the time the stablecoins arrive, the PFI will send the local fiat transfer as defined in the payment instructions.
It is important to note that most PFIs match withdrawal orders with a combination of `amount`, `from_account` (stablecoin wallet), and `deposit_address` .
Please ensure you are sending the stablecoins to the correct deposit address, on the correct blockchain, with the correct assets (i.e. USDC, USDT, etc.).
It is also important that the stablecoins come from the same `from_address` that you shared with the PFI. If the PFI is told that stablecoins will come from and addres 0x...456 and then they arrive from 0x...987, this can result in potentially lost funds. Borderless will not provide refunds for stablecoins sent incorrectly.
Finally, when the partner financial institution (PFI) receives the stablecoins, they will then issue the local fiat payment to the bank defined in the payment instructions. Once the local fiat currency is received, this completes the off-ramp or withdrawal flow.
You can easily track the status of transactions, request cancellation of transactions, and export transactions with the following endpoints.
Please ensure you are using the transaction `id `value which you will receive from the request to create a transaction such as the first step in this sequence on the `/withdrawals` endpoint.
To track the status of your withdrawal transactions and other types of transactions:
We recommend listening to the statuses via Webhook. Webhook details can be found in the [API reference here.](/docs/webhooks)
Endpoint: [`GET /transactions/{id}`](/api-reference/transactions/get-a-transaction-by-id)
To request a cancellation of your withdrawal transaction and other types of transactions:
Endpoint: [`POST /transactions/{id}/cancel`](/api-reference/transactions/request-cancellation-of-a-transaction)
To export your transactions:
Endpoint: [`GET /transactions/export`](/api-reference/transactions/export-transactions)
**Congratulations! You've now completed your first stablecoin withdrawal!**
## Dashboard
The unified admin and operations command center.
Easily view a consolidated record of all global payments across all of your enabled partner financial institutions (PFIs). No more juggling multiple dashboards, with inconsistent data. Click into any of the transactions for more detail such as the stablecoin transaction hash, fees spent, and more.
As our clients grow, we often see expansion into new stablecoin / fiat corridors and support for more regions. You can quickly check what regions, local fiat rails, and stablecoins are supported with the PFIs you have currently enabled. With this reference, teams can identify low hanging growth opportunities to expand into regions you already have support for, that you may not actively service today.
With the Borderless Provider Marketplace\*, the Dashboard allows you to track PFI activations, connect to new PFIs easily, and see which other PFIs are available for you. This unlocks the ability to easily add redundancy to your service, reducing risk of downtime.
\**coming soon*
Identities are core to how Borderless orchestrates payments across a multitude of providers. In the Borderless dashboard, we present a streamlined view of all identities, their compliance statuses, and options to manage them.
With the ability to connect across multiple providers who service overlapping stablecoin payment corridors, Borderless is uniquely positioned to provide layers of intelligence. One simple example of this is allowing you to compare rates to drive your order routing decisions. This type of intelligence is a core focus for the team with more to come soon.
Although Borderless is an API first product. We've only scratched the surface of features and tools for organizational admins, financial operations teams, leadership, and more. You can even initiate payments directly from the dashboard for large volume, low frequency workflows that don't require an API connection.
If you have any questions, please don't hesitate to reach out to us via [email](mailto:support@borderless.xyz) or slack.
# Refunds
Source: https://docs.borderless.xyz/docs/refunds
A refund returns funds to the originator when a transaction cannot be completed after funds have already moved. This can happen for several reasons — the receiving bank returns the payment, a compliance review reverses it, the transaction expires or fails after funds left the source, or an explicit refund is requested. When a refund completes, the original transaction reaches the `Refunded` status.
If you're just getting started, please check out our [quick start guide](/docs/quick-start-guide).
Like every operation on Borderless, refunds are **asynchronous**. You can track a refund either via webhooks or by polling the transaction. For background on the transaction lifecycle and the `Refunded` status, see [Transactions](/docs/transactions).
## How refunds work
When a transaction is created, Borderless builds a **refund plan** for it. The plan records how a refund would be handled if it becomes necessary — where the funds should be returned (the refund destination) and whether the refund should be triggered automatically.
If the transaction later fails or is reversed:
* When the plan has **auto-refund enabled** (the default), Borderless dispatches the refund automatically.
* When auto-refund is **disabled**, the plan stays eligible but waits until the refund is dispatched manually through the [refund endpoint](#executing-a-refund-plan).
Whether a refund is supported, and which return paths are available, depends on the partner financial institution (PFI) handling the transaction.
## Refund destinations
A refund destination describes where returned funds should go. It is configured with the following fields:
How the refund should be handled. One of:
* `Address` — return funds to a specific crypto address.
* `Source` — return funds to the original on-chain sender.
* `ProviderBalance` — leave the funds in your account balance at the PFI.
The crypto address that should receive the refund. Required when `type` is `Address`.
Whether Borderless should automatically trigger the refund on failure. Defaults to `true`. Setting it to `false` records the plan as eligible but keeps it waiting until the refund is dispatched manually.
These are the fields for a **per-transaction** destination. The organization-wide default takes a slightly different shape — see [Organization default refund destination](#organization-default-refund-destination).
You can attach a `refundDestination` when creating a withdrawal. The examples below show each destination type:
```json Address theme={null}
{
"paymentInstructionId": "cm2c4x3cc000019stwv7um4zl",
"paymentPurpose": "delivery fees",
"refundDestination": {
"type": "Address",
"address": "0x1234567890abcdef1234567890abcdef12345678",
"autoRefund": true
}
}
```
```json Source theme={null}
{
"paymentInstructionId": "cm2c4x3cc000019stwv7um4zl",
"paymentPurpose": "delivery fees",
"refundDestination": {
"type": "Source",
"autoRefund": true
}
}
```
```json ProviderBalance theme={null}
{
"paymentInstructionId": "cm2c4x3cc000019stwv7um4zl",
"paymentPurpose": "delivery fees",
"refundDestination": {
"type": "ProviderBalance",
"autoRefund": false
}
}
```
## Where the destination comes from
The refund destination is resolved from three layers. Each layer overrides the one before it, so the most specific configuration always wins:
```mermaid theme={null}
flowchart TD
A([Refund destination needed]) --> B{Execute Plan override?
POST /transactions/:id/refund}
B -- yes --> M[/"Use override
destinationSource: Manual"/]
B -- no --> C{Withdrawal refundDestination
set at creation?}
C -- yes --> P[/"Use per-transaction value
destinationSource: PerTransaction"/]
C -- no --> D{Organization default
set?}
D -- yes --> O[/"Use org default
destinationSource: OrganizationDefault"/]
D -- no --> N[/"No destination resolved
destinationSource: None"/]
classDef win fill:#199eff,stroke:#0b6fb0,color:#fff;
class M,P,O win;
```
1. **Organization default** — an org-wide fallback applied to every transaction. Resolves to `destinationSource: OrganizationDefault`.
2. **Withdrawal** — the `refundDestination` you set on the create request. Overrides the organization default and resolves to `destinationSource: PerTransaction`.
3. **Execute Plan** — a `refundDestination` override passed to the refund endpoint, applied just before the refund is dispatched. Takes precedence over everything and resolves to `destinationSource: Manual`.
Two further `destinationSource` values can appear when the PFI, rather than your configuration, determines where the money goes: `OriginalSender` when the funds are reversed to the on-chain sender, and `ProviderLocked` when the PFI returns them to a destination you cannot influence. `None` means no destination could be resolved.
## Organization default refund destination
The organization default is the fallback applied to any transaction that has no per-transaction destination. Reading it is available to any authenticated caller; creating, replacing, re-confirming, and removing it require the **Owner** role.
| Method | Endpoint | Description |
| -------- | ------------------------------ | ------------------------------------------------------------------------ |
| `GET` | `/v1/refunds/config` | Fetch the current default. Returns `null` when none is configured. |
| `PUT` | `/v1/refunds/config` | Create or replace the default. Resets the verification timestamp to now. |
| `POST` | `/v1/refunds/config/reconfirm` | Reset the verification timestamp without changing the destination. |
| `DELETE` | `/v1/refunds/config` | Remove the default. Responds with `204 No Content`. |
Unlike a per-transaction destination, which carries a single `address`, the organization default takes an **`addresses` array with one entry per network**. At refund time the address matching the transaction's network is used. Networks with no entry have no default and fall back to per-transaction destinations.
One of `Address`, `Source`, or `ProviderBalance`, as described above.
Required when `type` is `Address`. Each entry is a `network` and the `address` that should receive refunds on it. At least one entry.
Whether Borderless automatically triggers the refund on failure. Defaults to `true`.
Whether Borderless automatically returns a failed fiat payout as crypto, by re-converting the fiat held at the PFI and paying out to the refund destination. Defaults to `false`; when disabled the plan is marked for manual handling instead. This field has no per-transaction equivalent.
```bash Request theme={null}
curl --request PUT \
--url https://api.borderless.xyz/v1/refunds/config \
--header 'Authorization: Bearer ' \
--header 'Content-Type: application/json' \
--data '{
"destination": {
"type": "Address",
"addresses": [
{
"network": "ETHEREUM",
"address": "0x1234567890abcdef1234567890abcdef12345678"
},
{
"network": "POLYGON",
"address": "0xabcdef1234567890abcdef1234567890abcdef12"
}
],
"autoRefund": true,
"autoFiatReturn": false
}
}'
```
```json Response theme={null}
{
"destination": {
"type": "Address",
"addresses": [
{
"network": "ETHEREUM",
"address": "0x1234567890abcdef1234567890abcdef12345678"
},
{
"network": "POLYGON",
"address": "0xabcdef1234567890abcdef1234567890abcdef12"
}
],
"autoRefund": true,
"autoFiatReturn": false
},
"verifiedAt": "2026-08-26T10:15:00.000Z",
"isStaleWarning": false,
"isStaleReject": false
}
```
### Keeping the default confirmed
The default carries a `verifiedAt` timestamp and two staleness flags:
True once the default is older than **30 days**. Refunds still run — treat it as a prompt to re-confirm.
True once the default is older than **90 days**. Automatic refunds to the default are **paused** until it is re-confirmed.
Call `POST /v1/refunds/config/reconfirm` to reset `verifiedAt` to now and clear both flags without changing the destination.
## Refund capabilities
Before creating a transaction, you can check which refund behavior is supported for an off-ramp corridor. The capabilities endpoint reports, per partner financial institution (PFI), the refund paths, accepted destination types, supported chains, and estimated timing for a given country and fiat currency.
Both query parameters are required:
Destination country of the withdrawal corridor, such as `MX`.
Destination fiat currency of the withdrawal corridor, such as `MXN`.
The response is an **array** with one entry per PFI that currently serves the corridor. Each entry contains:
The partner financial institution the capabilities apply to.
The refund paths the PFI supports for this corridor. One or more of `PfiAutoReversal`, `BalancePayout`, `ReturnToSender`, `PfiAutoReturn`, `ManualRequired`, or `Unsupported`.
The refund destination `type` values you may specify on a transaction. Either `["Address"]` or empty.
How the refund destination is determined: `none`, `address_optional`, `address_required`, or `provider_locked`.
The assets/chains available for refunds on this corridor, such as `USDC_POLYGON`.
The expected refund time as `minSeconds`, `maxSeconds`, and a `businessDays` flag indicating whether the range is measured in business days.
Whether the auto-refund preference can be overridden for this corridor. Currently always `false`.
Any prerequisites that must be met before a refund can be processed.
```bash Request theme={null}
curl --request GET \
--url 'https://api.borderless.xyz/v1/refunds/capabilities?country=MX&fiat=MXN' \
--header 'Authorization: Bearer '
```
```json Response theme={null}
[
{
"pfiName": "Bridge",
"supportedPaths": ["PfiAutoReversal"],
"acceptedRequestTypes": ["Address"],
"destinationModes": ["address_optional"],
"chainsSupported": ["USDC_POLYGON"],
"estimatedTimingRange": {
"minSeconds": 3600,
"maxSeconds": 172800,
"businessDays": false
},
"autoRefundOverrideSupported": false,
"prerequisites": [
"A `Source`-typed refund destination sends no explicit instruction to Bridge; it relies on Bridge's default reversal to the original sender. Only `Address`-typed destinations are forwarded as an explicit refund address."
]
}
]
```
Capabilities are scoped to the PFIs currently enabled for your organization. An empty array means no enabled PFI serves that corridor.
## Executing a refund plan
When auto-refund is disabled, or when you need to override the stored destination, you can dispatch the refund manually:
```bash Request theme={null}
curl --request POST \
--url https://api.borderless.xyz/v1/transactions/{id}/refund \
--header 'Authorization: Bearer ' \
--header 'Content-Type: application/json' \
--data '{
"refundDestination": {
"type": "Address",
"address": "0x1234567890abcdef1234567890abcdef12345678"
}
}'
```
```json Response theme={null}
{
"supported": true,
"requiresManualAction": false,
"dispatchable": false,
"path": "PfiAutoReversal",
"status": "InProgress",
"destinationSource": "Manual",
"destination": {
"type": "Address",
"address": "0x1234567890abcdef1234567890abcdef12345678",
"autoRefund": true
},
"reason": null,
"completedAt": null,
"failedAt": null
}
```
The request body is optional — call the endpoint with an empty body to dispatch using the destination already stored on the plan. The endpoint responds with `202 Accepted` and returns the current refund resolution.
The response includes a `dispatchable` flag telling you whether the plan can be dispatched through this endpoint right now, so you can check it before calling:
Whether the refund plan can be dispatched now. True for plans in `Created` or `Eligible` status, and for `ManualRequired` plans parked after a failed fiat payout.
Present when a refund attempt has failed. Contains a human-readable `message` and a `details` array of provider-level error details. `null` otherwise.
Dispatching a refund through this endpoint bypasses the `autoRefund: false` preference, so it is the way to trigger refunds for transactions created with auto-refund disabled. Any `refundDestination` override is re-validated against the PFI's refund capability before it is applied.
Plans in `ManualRequired` status can also be dispatched when they were parked after a failed fiat payout. Dispatching such a plan records your consent to return the funds **in crypto, converted from the fiat held at the PFI at the current rate** — so the returned amount may differ from the original.
If you have any questions, please don't hesitate to reach out to us via [email](mailto:support@borderless.xyz) or slack.
# Testing in Sandbox
Source: https://docs.borderless.xyz/docs/sandbox-testing
Trigger Completed, Failed, and Refunded outcomes in the Borderless sandbox by varying the transaction amount.
The Borderless sandbox lets you exercise your integration end-to-end without moving real funds. Sandbox transactions do not call real PFIs — Borderless simulates the full transaction lifecycle, including the same intermediate statuses and webhook deliveries you would observe in production.
## Choosing the final status
The **final status** of a sandbox deposit, withdrawal, or exchange is determined by the **last digit of the integer part of `source.amount`**:
| Last digit of `source.amount` | Final status |
| ------------------------------ | ------------ |
| `9` (e.g. `19`, `109`, `1009`) | `Failed` |
| `8` (e.g. `18`, `108`, `1008`) | `Refunded` |
| anything else | `Completed` |
Only the integer part is considered — `19.99` triggers `Failed`, `10.50` triggers `Completed`. The rule applies regardless of currency, so you can use the same convention for fiat-denominated deposits and stablecoin-denominated withdrawals.
## Timing
Sandbox status transitions are emitted on a short delay (a few seconds between each status). The transaction moves through the same status sequence as in production — typically `Submitted` → `Verifying` → `Orchestrating` → `Pending` → `Processing` → final — so your integration can observe and react to each intermediate webhook just as it would in production.
## Cancellation
To exercise the `Cancelled` flow, cancel the transaction yourself via the API or dashboard while it is still in `Submitted`, `Verifying`, `Preparing`, or `Pending`. The amount-based trigger does not produce `Cancelled` on its own.
## Sandbox vs production
Sandbox and production are fully separate environments. Sandbox API keys do not work against the production API. Triggering `Failed` or `Refunded` in sandbox has no effect on any production transaction.
If you have any questions, please don't hesitate to reach out to us via [email](mailto:support@borderless.xyz) or slack.
# Transactions
Source: https://docs.borderless.xyz/docs/transactions
Transactions are a core pillar of the Borderless network. These are the actions taken by users and organizations across many functions. Types of transactions include converting stablecoins to local fiat currencies via withdrawals (off-ramp), or vice versa as a deposit (on-ramp). We've also recently expanded these concepts to include fx exchange, now decoupled from a withdrawal or deposit, as well as upcoming OTC type transactions.
If you're just getting started, please check out our [quick start guide](/docs/quick-start-guide).
All transactions with Borderless are asynchronous, meaning when you initiate an operation, you receive a transaction object in an initial state. As the transaction progresses, you can track updates either via webhooks or by polling the transaction status using the API.
For full API details and request structure, please refer to the API Reference.
Transactions are primarily divided into two main categories:
* [Withdrawals (Off-ramps)](/docs/quick-start-guide#off-ramps-withdrawals)
* [Deposits (On-ramps)](/docs/quick-start-guide#on-ramps-deposits)
## Transaction Structure
A transaction in Borderless contains rich metadata. Below are some of the main fields:
Unique transaction identifier
The type of transaction such as `AssetDeposit` `Deposit` `Withdrawal` `Transfer` `TransferToExternalWallet` `Swap` `Approval` `Exchange`
The status of the transaction such as `Submitted` `Verifying` `Orchestrating` `Pending` `Processing` `Completed` `Failed` `Cancelled` `Refunded`
When a transaction is in the `Pending` status, it may include instructions which are required whenever additional action is needed from the user.
For example, in a Deposit transaction, Borderless creates a transaction with an instruction that tells the user where to send the fiat funds to complete the deposit.
Similar instruction objects are used in other types of transactions and may vary depending on the web3 infrastructure provider you're using.
Make sure to check the specific operation documentation to understand what instructions may be required and how to handle them.
The name of the partner financial institution (PFI) who is completing the transaction such as `Bridge` `Pipes` `Koywe` `Kotanipay` `LIFI` `Hercle` `Manual` `Bitso` `YellowCard` `TraceFinance` `HoneyCoin` `BlindPay` `Finity` `Ares` `Infinia` `Walapay` `Abra` `Yativo` `Capa`
An object of data that describes the source or beginning leg of the transaction. This object contains fields such as `asset` `amount` `fiatCurrency` `paymentMethod` `accountId` `accountName` `sender`
An object of data that describes the destination or end leg of the transaction. This object contains fields such as `asset` `amount` `fiatCurrency` `imad` `omad` `traceNumber` `externalAddress` `accountId` `accountName` `paymentInstructionId`
Date and time the transaction was created.
Date and time the transaction was updated.
The hash of an onchain transaction that was completed.
The developer fee amount that was charged in the transaction.
... and more.
Please see the full and current list on our API Reference [here](/api-reference/transactions/get-transactions)
## Transaction Statuses
Let's take a moment to provide a detailed explanation of the various statuses a transaction can go through during its lifecycle. Each status represents a specific stage in the process, from the moment a transaction is created to its final completion or failure. Understanding these statuses helps users track their transactions and take necessary actions when required.
Every transaction begins with the `Submitted` status and progresses through various stages depending on its type and requirements. Ultimately, a transaction concludes with one of the following final statuses: `Completed`, `Failed`, `Canceled`, `Refunded`
`Submitted` - The transaction has been received by Borderless and sent to the queue for processing. It begins to be processed in less than one second.
`Verifying` - This status applies only to transactions involving Partner Financial Institutions that require KYC reviews. If the identity has already been verified (KYC/KYB review completed successfully), the status will immediately change to the next one. Please note that a compliance check may take seconds for a personal identity or days for a business identity.
`Orchestrating` - Borderless is preparing the necessary data and selecting the optimal PFI to execute the transaction. This process takes milliseconds.
`Pending` - This status requires action from the user who initiated the transaction. For `Deposit` transactions, this status means that the PFI is waiting for the user to complete the fiat transfer (usually a bank transfer). For `Withdrawal`, `Swap`, or `Transfer` transactions, this status means that the PFI is waiting for an on-chain transaction to be completed. The execution time depends on the user, and the blockchain confirmation time.
`Processing` - Funds have been received, and the transaction is being executed by a PFI.
`Failed` - An error occurred during the transaction lifecycle. Details can be found in the failureReason via the API or on the transaction details page in the Borderless Dashboard.
`Cancelled` - The transaction was canceled by the user. A transaction can only be canceled if it is in one of the following statuses: `Submitted`, `Verifying`, `Preparing`, or `Pending`. Once the transaction moves beyond these statuses, it cannot be canceled. For additional details, please contact our support team.
`Completed` - The user has received the funds, and the transaction has been successfully completed. This status may update some time after the user has actually received the funds.
`Refunded` - The transaction was returned by the PFI after funds were initially received. This may happen due to a return from the receiving bank, a compliance reversal, or an explicit refund request. The funds are returned to the originator.
If you have any questions, please don't hesitate to reach out to us via [email](mailto:support@borderless.xyz) or slack.
# Virtual Accounts
Source: https://docs.borderless.xyz/docs/virtual-accounts
Virtual accounts create a unique bank account in the identity name (sometimes also referred to as a "named account"). These accounts can be used in a recurrent way since they keep the same deposit instructions (including routing number and account number).
Virtual accounts allow end users to make first party deposits (i.e. deposits from other accounts that are registered to the same end user). They do not generally allow deposits from third parties.
**Some benefits of Virtual accounts are:**
First-party VAs allow businesses to have more oversight and transparency. This level of control makes tracking incoming and outgoing funds, reconciling accounts, and auditing much easier.
Reconciling transactions is easier and more compliant with financial regulations, especially for companies that have complex payment requirements.
VA provide a localized banking experience. Each VA can correspond to a specific currency or region, making global expansion more straightforward.
Virtual accounts are currently only supported in the US and EU regions.
If you're just getting started, please check out our [quick start guide](/docs/quick-start-guide).
## Create a virtual account
For users who are working with PFIs that support virtual accounts, you can easily create new ones all from the Borderless API.
Creating a virtual account is an asynchronous operation. After submitting the creation request, the virtual account will initially be in a "NotActive" status and will not have any instructions.
Endpoint: `POST /accounts/{id}/virtual-accounts`
```bash request expandable theme={null}
curl -X POST "https://sandbox-api.borderless.xyz/v1/accounts/{id}/virtual-accounts" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-access-token" \
-H "idempotency-key: 8f14e45f-e6c3-4f7e-bd56-1b9a2e46f1d6"\
-d '{
"fiat": "FiatCuurencyId", // USD, ...
"country": "CountryCode", // US
"asset": "AssetId", // USDC_POLYGON
"counterPartyIdentityId": "Identity Id"
}'
```
```json response - not active expandable theme={null}
{
"id": "cm1gikfqt000e1la7x49gsywn",
"accountId": "clwf43ntm0005o8knqqht0qcr",
"counterPartyIdentityId": "cm1giduyh00051la7nrbna9xf",
"status": "NotActive",
"asset": "USDC_POLYGON",
"fiat": "USD",
"instructions": null,
"depositInstructions": null,
"createdAt": "2024-09-24T14:10:37.878Z",
"failureReason": null
}
```
```json response - active expandable theme={null}
{
"id": "cm1giy8yn000i1la7r22rw1si",
"accountId": "clwf43ntm0005o8knqqht0qcr",
"counterPartyIdentityId": null,
"status": "Active",
"asset": "USDC_POLYGON",
"fiat": "USD",
"instructions": {
"currency": "usd",
"bank_name": "Bank of Nowhere",
"bank_address": "1800 North Pole St., Orlando, FL 32801",
"payment_rail": "ach_push",
"payment_rails": [
"ach_push",
"wire"
],
"bank_account_number": "900044396474",
"bank_routing_number": "101019644",
"bank_beneficiary_name": "Mark Smith",
"bank_beneficiary_address": null
},
"depositInstructions": null,
"createdAt": "2024-09-24T14:21:22.272Z",
"failureReason": null
}
```
Once the virtual account is activated, the account object will include a field called `instructions`, which contains the bank details for depositing funds. You can send any amount of funds to this account as many times as needed.
All funds received in this bank account will be automatically credited to your Borderless `account` in the asset that was selected during the creation of the virtual account.
If you have any questions, please don't hesitate to reach out to us via [email](mailto:support@borderless.xyz) or slack.
# Virtual accounts
Source: https://docs.borderless.xyz/docs/virtual-accounts-1
If you're just getting started, please check out our [quick start guide](/docs/quick-start-guide).
There are two events regarding virtual accounts:
* VirtualAccount\_Created
* VirtualAccount\_CreationFailed
## Created
**VirtualAccount\_Created** is sent after virtual account has been created successfully and deposit instructions obtained. Below is a payload example:
```bash bash theme={null}
{
"organizationId": "clxt0xrqp0000gokerkq2mpdl",
"type": "VirtualAccount_Created",
"data": {
"id": "cmbz2ee050011yn24wqjru28f",
"accountId": "cmbz2dgni000tyn241ip38gwj",
"counterPartyIdentityId": "cmbz0v42m0002yn53zeayhilz",
"status": "Active",
"asset": "USDC_ETHEREUM",
"fiat": "USD",
"instructions": {
"currency": "usd",
"bank_name": "Bank of Nowhere",
"bank_address": "1800 North Pole St., Orlando, FL 32801",
"payment_rail": "ach_push",
"payment_rails": [
"ach_push",
"wire"
],
"bank_account_number": "900544275163",
"bank_routing_number": "101019644",
"bank_beneficiary_name": "Olaf Kling",
"bank_beneficiary_address": "123 Washington St, Apt 2F, Chicago, IL 10001, US"
},
"createdAt": "2025-06-16T12:22:42.533Z",
"failureReason": null
},
"timestamp": 1750076563854
}
```
## Failed
**VirtualAccount\_CreationFailed** is sent after virtual account failed to create.
```bash bash theme={null}
{
"organizationId": "clxt0xrqp0000gokerkq2mpdl",
"type": "VirtualAccount_CreationFailed",
"data": {
"id": "cmbz2brwb000nyn245kyyrgqw",
"accountId": "cmbhs3xxa000nynt7lqwbyjsw",
"counterPartyIdentityId": "cmbz0v42m0002yn53zeayhilz",
"status": "Rejected",
"asset": "USDC_POLYGON",
"fiat": "USD",
"instructions": null,
"createdAt": "2025-06-16T12:20:40.572Z",
"failureReason": "Couldn't find asset USDC_POLYGON in account: cmbhs3xxa000nynt7lqwbyjsw, add this asset to account before using it"
},
"timestamp": 1750076440780
}
```
If you have any questions, please don't hesitate to reach out to us via [email](mailto:support@borderless.xyz) or slack.
# Webhook Overview
Source: https://docs.borderless.xyz/docs/webhooks
Borderless allows integrators to register webhooks in the system. Webhooks enable external systems to receive notifications or updates about withdrawal and deposit events in your account
To consume the webhook, register a callback URL where the Borderless will sends a notification via an HTTP POST method with the corresponding payload, documented below.
**Note:** Currently, you cannot specify which events you would like to receive when registering the webhook. Instead, your system will receive all event notifications, and you will need to implement filtering logic on your end to process only the events relevant to your needs.
Currently, Web hooks are delivered for transaction-related events, when **Deposit**, **Withdrawal**, **Transfer**, **TransferToExternalWallet**, **Swap** or **Approval** are executed.
If you're just getting started, please check out our [quick start guide](/docs/quick-start-guide).
## Webhook registration
Use the **Endpoint**: POST `/v1/notifications/webhooks/settings` to register a new webhook to receive notifications.
Request Example:
```bash bash theme={null}
curl -X POST "https://sandbox-api.borderless.xyz/v1/notifications/webhooks/settings" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-access-token" \
-d '{
"url": "https://myapp.com/hooks"
}'
```
Response sample:
```bash bash theme={null}
{
"id": "webhook_123456",
"url": "https://myapp.com/hooks",
"enabled": true,
"createdAt": "2024-11-24T12:34:56.789Z",
"updatedAt": "2024-11-24T12:34:56.789Z"
}
```
The response contains:
`id`: A unique identifier for the webhook (e.g., `webhook_123456`). Use this id to delete or update the webhook when needed `url`: The URL where webhook notifications will be sent `enabled`: indicates if message devivery is enabled for specific web hook. `true` by default. `createdAt`: The timestamp when the webhook was created. `updatedAt`: The timestamp when the last time the webhook was updated.
\*\*Note: \*\* When a webhook is sent, a 200 OK response is expected to confirm successful delivery. If the receiving endpoint does not respond with a 200 status or raise an error, the system will automatically attempt to retry the delivery multiple times.
If all retry attempts fail, the webhook will be marked as disabled by setting `"enabled": false.` Once disabled, no further webhook events will be delivered to that endpoint. Web hook could be re-enabled using endpoint below
## Updating webhook
Use the **Endpoint**: POST `https://sandbox-api.borderless.xyz/v1/notifications/webhooks/settings/${id}` to update existing webhook `url` :
Request Example:
```bash bash theme={null}
curl -X PATCH "https://sandbox-api.borderless.xyz/v1/notifications/webhooks/settings/${id}" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-access-token" \
-d '{
"url": "https://myapp.com/newUrl"
}'
```
Please replace `${id}` with webhook id you would like to update the URL. Additionally, you could disable the web hook is needed:
Request Example:
```bash bash theme={null}
curl -X PATCH "https://sandbox-api.borderless.xyz/v1/notifications/webhooks/settings/${id}" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-access-token" \
-d '{
"url": "https://myapp.com/newUrl",
"enabled": false
}'
```
In case the web hook was disabled by Borderless due to failed previous deliveries, you could re-enable it by updating web hook). In case URL should not be changed, just pass it in `url` field:
Request Example:
```bash bash theme={null}
curl -X PATCH "https://sandbox-api.borderless.xyz/v1/notifications/webhooks/settings/${id}" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-access-token" \
-d '{
"url": "https://myapp.com/newUrl"
}'
```
## Get webhook by id
Use the **Endpoint**: GET `/v1/notifications/webhooks/settings/${id}` to receive all webhooks registered for your organization.
Request Example:
```bash bash theme={null}
curl -X GET "https://sandbox-api.borderless.xyz/v1/notifications/webhooks/settings/${id}" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-access-token"
```
Please replace `${id}` with webhook id youʼre interested in.
## Get all registered webhooks
Use the **Endpoint**: GET `/v1/notifications/webhooks/settings` to receive all webhooks registered for your organization.
Request Example:
```bash bash theme={null}
curl -X GET "https://sandbox-api.borderless.xyz/v1/notifications/webhooks/settings" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-access-token"
```
## Webhook deletion
Finally, use the **Endpoint**: DELETE `/v1/notifications/webhooks/settings/${id}` to delete the webhook by id.
Request Example:
```bash bash theme={null}
curl -X DELETE "https://sandbox-api.borderless.xyz/v1/notifications/webhooks/settings/${id}" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-access-token"
```
## Signing payload using public and private keys
Borderless supports webhooks payload authenticity verification using private and public key pair at organization level.
A private key is generated with RSA-SHA256 when first web hook address is registered in the system. The verification process on the caller side could use the corresponding public key along with the payload to validate the signature.
To regenerate private and public key, send a request to this API:
```bash bash theme={null}
curl -X POST "https://sandbox-api.borderless.xyz/v1/notifications/webhooks/settings/public-key' \
-H 'accept: application/json' \
-H "Authorization: Bearer your-access-token"
```
This call will generate new private & public keys pair and return public key to the caller. Private key is stored securely in Borderless and is not shared under any circumstances with the client
To verify the payload extract the payload and the signature from the webhook message's ***x-signature*** header and use previously stored public key for signature validation.
In case you didn't store public key in your application, it could be retrieved using this API call:
```bash bash theme={null}
curl -X GET "https://sandbox-api.borderless.xyz/v1/notifications/webhooks/settings/public-key' \
-H 'accept: application/json' \
-H "Authorization: Bearer your-access-token"
```
## Supported event types
Following event\_types are supported:
* Transaction\_Created
* Transaction\_Updated
* VirtualAccount\_Created
* VirtualAccount\_CreationFailed
* IdentityComplianceCheck\_Updated
* IdentityComplianceCheck\_Completed
## Supported operation types
Web hooks are triggered when one of operation from the list below is executed in the system:
* Deposit
* Withdrawal
* Transfer
* TransferToExternalWallet
* Swap
* Approval
If you have any questions, please don't hesitate to reach out to us via [email](mailto:support@borderless.xyz) or slack.
# Withdrawal Webhooks
Source: https://docs.borderless.xyz/docs/withdrawal-webhooks
If you're just getting started, please check out our [quick start guide](/docs/quick-start-guide).
## Transaction Creation
When a withdrawal transaction is created, a webhook notification will be sent to the configured webhook URL. This notification will contain the relevant transaction details for further processing or integration with your system. Webhook payload is below:
```bash bash theme={null}
{
"type": "Transaction_Created",
"organizationId": "clxt0xrqp0000gokerkq2mpdl",
"timestamp": 1733495693232,
"data": {
"id": "cm4cuktc0000c5453lwolag7t",
"type": "Withdrawal",
"status": "Submitted",
"source": {
"asset": "USDT_ETHEREUM",
"amount": "1",
"fiatCurrency": null,
"paymentMethod": null,
"accountId": "cm46w78c40006ts9gkrx6r6jw",
"accountName": "Main Account",
"sender": null
},
"destination": {
"asset": null,
"amount": null,
"fiatCurrency": "USD",
"imad": null,
"reference": null,
"omad": null,
"traceNumber": null,
"externalAddress": null,
"accountId": null,
"accountName": null,
"paymentInstructionId": "cm46w78c40006ts9gkrx6abcd"
},
"instructions": null,
"createdAt": "2024-12-06T14:34:53.184Z",
"txHash": [],
"feeAmount": "0",
"failureReason": null,
"counterPartyIdentityId": "cm46w78c40006ts9gkrx6efgh",
"virtualAccountId": null
}
}
```
## Transaction state changes
Subsequent transaction processing updates and state changes will be communicated via webhook notifications to the configured webhook URL. Webhook payload remains as previous, please note its status change:
```bash bash theme={null}
{
"type": "Transaction_Updated",
"organizationId": "clxt0xrqp0000gokerkq2mpdl",
"timestamp": 1733495695125,
"data": {
"id": "cm4cuktc0000c5453lwolag7t",
"type": "Withdrawal",
"status": "Verifying",
"source": {
"asset": "USDT_ETHEREUM",
"amount": "1",
"fiatCurrency": null,
"paymentMethod": null,
"accountId": "cm46w78c40006ts9gkrx6r6jw",
"accountName": "Main Account",
"sender": null
},
"destination": {
"asset": null,
"amount": null,
"fiatCurrency": "USD",
"imad": null,
"reference": null,
"omad": null,
"traceNumber": null,
"externalAddress": null,
"accountId": null,
"accountName": null,
"paymentInstructionId": "cm46w78c40006ts9gkrx6abcd"
},
"instructions": null,
"createdAt": "2024-12-06T14:34:53.184Z",
"txHash": [],
"feeAmount": "0",
"failureReason": null,
"counterPartyIdentityId": "cm46w78c40006ts9gkrx6efgh",
"virtualAccountId": null
}
}
```
The **txHash** field remains null until the transaction is executed on the underlying blockchain network. Once the transaction is processed, this field will be updated with the corresponding transaction hash.
## Transaction failure
In the case of a transaction failure, a webhook notification is sent to the configured webhook URL This notification contains detailed information about the transaction and the reason for its failure in .
```bash bash theme={null}
{
"type": "Transaction_Updated",
"organizationId": "clxt0xrqp0000gokerkq2mpdl",
"timestamp": 1733495699167,
"data": {
"id": "cm4cuktc0000c5453lwolag7t",
"type": "Withdrawal",
"status": "Failed",
"source": {
"asset": "USDT_ETHEREUM",
"amount": "1",
"fiatCurrency": null,
"paymentMethod": null,
"accountId": "cm46w78c40006ts9gkrx6r6jw",
"accountName": "Main Account",
"sender": null
},
"destination": {
"asset": null,
"amount": null,
"fiatCurrency": "USD",
"imad": null,
"reference": null,
"omad": null,
"traceNumber": null,
"externalAddress": null,
"accountId": null,
"accountName": null,
"paymentInstructionId": "cm46w78c40006ts9gkrx6abcd"
},
"instructions": null,
"createdAt": "2024-12-06T14:34:53.184Z",
"txHash": [],
"feeAmount": "0",
"failureReason": {
"accountOwnerType": "is required"
},
"counterPartyIdentityId": "cm46w78c40006ts9gkrx6efgh",
"virtualAccountId": null
}
}
```
Please note: **failureReason** in the response above is sample only
## Payment instructions for an unsigned on-chain transaction to be executed using your own infrastructure
Webhook will contains payment instructions with two parts:
1. General Information: Details about the token, amount, and source/destination addresses:
```bash bash theme={null}
"instructions": {
"fromAddress": "0x123123",
"toAddress": "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",
"asset": "USDC_POLYGON",
"amount": "12",
"transaction": "SEE BELOW"
```
2. Prepared Blockchain Transaction:
The transaction field depends on the blockchain. For **EVM-compatible blockchains** (non-native token):
```bash bash theme={null}
"instructions": {
// General information. SEE ABOVE
"transaction": {
"to": "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",
"data": "0xa9059cbb0000000000000000000000007d369e60b9dd8903006d09955d636630392e571800000000000000000000000000000000000000000000000000000000002dc6c0",
"nonce": 19,
"value": "0x00",
"chainId": 137,
"gasLimit": "0xf600",
"gasPrice": "0x0689010ed9"
}
}
```
This section for EVM-compatible blockchains (native token) will look like sample below:
```bash bash theme={null}
"instructions": {
// General information. SEE ABOVE
"transaction": {
"to": "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",
"nonce": 19,
"value": "0x12",
"chainId": 137,
"gasLimit": "0xf600",
"gasPrice": "0x0689010ed9"
}
}
```
So you have two options:
1. Execute the already prepared raw transaction directly instructions.transaction
2. Use the provided data (fromAddress, toAddress, asset, and amount) to generate and execute your own transaction on the blockchain
If you have any questions, please don't hesitate to reach out to us via [email](mailto:support@borderless.xyz) or slack.
# Off-ramp (Withdrawal)
Source: https://docs.borderless.xyz/docs/withdrawals-1
Off-ramping is converting `stablecoins` into `fiat currencies` such as USD or BRL. This conversion is facilitated by the PFIs on the Borderless network and can be part of either a payin or payout flow simply depending on if you are sending or receiving the payments. In this scenario you are ultimately sending or receiving local fiat currencies, after the stablecoins are converted at the PFI.
An important note on payment instructions below.
Withdrawals are very similar to deposits as we've already accomplished above. The key difference to highlight, is around payment instructions.
With deposits, the local fiat leg is to the PFI's bank, and they provide the payment instructions in the api response when you open an order to deposit with them.
For a withdrawal, the local fiat leg is ultimately received by you or your clients in the respective banks. This means, we need to instruct the partner financial institution (PFI) where to send the fiat leg, and you must provide these payment instructions.
With this additional step in mind, withdrawals are a simple 4 step process.
Optionally, you can also request a quote before initiating the withdrawal to have a transparent view of the estimated fees and exchange rates.
Quotes are returned directly from the PFIs, and are regularly changing. Quotes are not firm, and they do not guarantee any final received amount. They are estimates only, and Borderless is not responsible for incorrect quotes provided to us by PFIs.
Endpoint: [`GET /withdrawals/quotes`](/api-reference/transaction-withdrawals/get-withdrawal-quote)
```bash request expandable theme={null}
curl -X GET 'https://sandbox-api.borderless.xyz/v1/withdrawals/quotes' \
-H 'Authorization: Bearer your-access-token' \
-H 'Content-Type: application/json' \
-d '{
"country": "US",
"fiat": "USD",
"asset": "USDC_POLYGON",
"paymentMethod": "ACH",
"fromAmount": "10"
}'
```
```json response expandable theme={null}
{
"limits": {
"transaction": {
"minAmount": "1",
"maxAmount": "100",
"fiat": "USD"
}
},
"fiat": "USD",
"country": "US",
"asset": "USDC_POLYGON",
"paymentMethod": "ACH",
"fromAmount": "10",
"toAmount": "8.99",
"exchangeRate": "0.999",
"totalFee": "1",
"orchestrationFee": "1"
}
```
## Create payment instruction
First, create payment instructions to share with the partner financial institution (PFI) who is off-ramping or processing your withdrawal. This step is critical to ensure the local fiat currency arrives in the correct account at the end.
Please use account `id` in the deposit creation request from an account created above in the Accounts section.
Please capture payment instructions `id` from the response to use it for the withdrawal request after.
The PFI will be initiating the off-ramp directly to the payment instructions you create in this step. Borderless cannot be held responsible for transfers that originate outside the Borderless network to incorrect addresses. It is your responsibility to review the payment instructions and ensure they are correct.
Endpoint: [`POST /identities/{id}/payment-instructions`](/api-reference/payment-instructions/get-payment-instructions)
```bash request expandable theme={null}
curl -X POST 'https://sandbox-api.borderless.xyz/v1/identities/{id}/payment-instructions' \
-H 'Authorization: Bearer your-access-token' \
-H 'Content-Type: application/json' \
-H "idempotency-key: 8f14e45f-e6c3-4f7e-bd56-1b9a2e46f1d6"\
-d '{
"country": "US",
"currency": "USD",
"name": "Primary Bank Account",
"paymentMethod": "ACH",
"details": {
"bankName": "Example Bank",
"accountHolderName": "John Doe",
"bankAccountNumber": "123456789012",
"bankRoutingNumber": "123456789",
"bankAccountType": "Checking",
"address": {
"street1": "123 Main St",
"street2": "Apt 4B",
"city": "New York",
"state": "NY",
"country": "US",
"postalCode": "10001"
}
}
}'
```
```json response expandable theme={null}
{
"id": "cmi7sfuf04729pg23a00yntya",
"name": "Primary Bank Account",
"paymentMethod": "ACH",
"currency": "USD",
"country": "US",
"deleted": false,
"details": {
"bankName": "Example Bank",
"bankSlug": null,
"bankAccountNumberLast4": "9012",
"bankRoutingNumber": "123456789",
"bankCode": null,
"phone": null,
"taxId": null,
"accountHolderName": "John Doe",
"bankAccountType": "Checking",
"recipientRelationship": null,
"address": {
"id": "cmi7sfueh4727pg23ga5lqhi2",
"street1": "123 Main St",
"street2": "Apt 4B",
"city": "New York",
"state": "NY",
"country": "US",
"postalCode": "10001"
}
}
}
```
## Create a withdrawal order
Second, you will create an order for a withdrawal. This will send the payment instructions to the PFI, who will send the local fiat currency upon receipt of the matching amount of stablecoins. This alerts the PFI to expect the payment, and allows them to attribute the funds to your account when they arrive.
It's important to note that in the response to this withdrawal order, the PFI will return the onchain stablecoin payment instructions (generally a deposit address) that will handle the stablecoins which are being off-ramped.
Please capture the onchain instructions from the PFI in the response field `onchainInstructionTransaction` to use it to send stablecoins in the next step.
Please use both the account `id` from an account created above in the Accounts section, and the payment instructions `id` in the withdrawal creation request from the step above where you created the payment instructions.
Endpoint: [`POST /withdrawals `](/api-reference/transaction-withdrawals/create-a-new-withdrawal-transaction)
```bash request expandable theme={null}
curl -X POST 'https://sandbox-api.borderless.xyz/v1/withdrawals' \
-H 'Authorization: Bearer your-access-token' \
-H 'Content-Type: application/json' \
-H "idempotency-key: 8f14e45f-e6c3-4f7e-bd56-1b9a2e46f1d6"\
-d '
{
"fiat": "USD",
"country": "US",
"asset": "USDC_POLYGON",
"amount": "100.00",
"accountId": "cm2c4x3cc000019stwv7um4zl",
"developerFee": "5.00",
"paymentInstructionId": "cm2c4x3cc000019stwv7um4zl",
"paymentPurpose": "delivery fees",
"purposeDescription": "Monthly delivery service payment",
"reference": "INV-2025-001"
}
'
```
```json response expandable theme={null}
{
"id": "cmi7sihwi472bpg2301ptz9gv",
"type": "Withdrawal",
"status": "Submitted",
"pfiName": "Bridge",
"source": {
"asset": "USDC_POLYGON",
"amount": "100",
"fiatCurrency": null,
"paymentMethod": null,
"accountId": "cm2c4x3cc000019stwv7um4zl",
"accountName": "Main Account",
"sender": null
},
"destination": {
"asset": null,
"amount": null,
"fiatCurrency": "USD",
"imad": null,
"reference": null,
"omad": null,
"traceNumber": null,
"externalAddress": null,
"accountId": null,
"accountName": null,
"paymentInstructionId": "cmi7sfuf04729pg23a00yntya"
},
"instructions": null,
"createdAt": "2025-11-19T19:49:46.918Z",
"updatedAt": "2025-11-19T19:49:46.918Z",
"txHash": [],
"feeAmount": "0",
"failureReason": null,
"depositInstruction": null,
"destinationPaymentInstruction": null,
"withdrawalOnchainInstruction": null,
"counterPartyIdentityId": "cmhlu3zlt002qpf246wd6vwrr",
"virtualAccountId": null
}
```
## Send stablecoins direct to PFI
Once the local fiat payment instructions are sent to the PFI, and the withdrawal request is made, this order will remain open until the PFI receives the stablecoins as outlined in the instructions they shared via response to the withdrawal request. At the time the stablecoins arrive, the PFI will send the local fiat transfer as defined in the payment instructions.
It is important to note that most PFIs match withdrawal orders with a combination of `amount`, `from_account` (stablecoin wallet), and `deposit_address` .
Please ensure you are sending the stablecoins to the correct deposit address, on the correct blockchain, with the correct assets (i.e. USDC, USDT, etc.).
It is also important that the stablecoins come from the same `from_address` that you shared with the PFI. If the PFI is told that stablecoins will come from and addres 0x...456 and then they arrive from 0x...987, this can result in potentially lost funds. Borderless will not provide refunds for stablecoins sent incorrectly.
## Release local fiat to beneficiary
Finally, when the partner financial institution (PFI) receives the stablecoins, they will then issue the local fiat payment to the bank defined in the payment instructions. Once the local fiat currency is received, this completes the off-ramp or withdrawal flow.
You can easily track the status of transactions, request cancellation of transactions, and export transactions with the following endpoints.
Please ensure you are using the transaction `id `value which you will receive from the request to create a transaction such as the first step in this sequence on the `/withdrawals` endpoint.
To track the status of your withdrawal transactions and other types of transactions:
We recommend listening to the statuses via Webhook.
Endpoint: [`GET /transactions/{id}`](/api-reference/transactions/get-a-transaction-by-id)
To request a cancellation of your withdrawal transaction and other types of transactions:
Endpoint: [`POST /transactions/{id}/cancel`](/api-reference/transactions/request-cancellation-of-a-transaction)
To export your transactions:
Endpoint: [`GET /transactions/export`](/api-reference/transactions/export-transactions)
**Congratulations! You've now completed your first stablecoin withdrawal!**
If you have any questions, please don't hesitate to reach out to us via [email](mailto:support@borderless.xyz) or slack.
# Balance (Withdrawal)
Source: https://docs.borderless.xyz/docs/withdrawals-payouts
Withdrawals (Balances) all you to move `local fiat balances` out of a PFI Account to an external bank account of your beneficiary. PFI Accounts were described in detail in the Accounts section above, but at a high level they represent local fiat balances that your organization holds with a specific partner financial institution (PFI).
Withdrawals (Balances) are very similar to Withdrawals (Off-ramps), described above, but with a few important differences. Withdrawals (Off-ramps) convert `stablecoins` held on your Web3 account into local `fiat currencies` (for example, USDC\_POLYGON to BRL in a Brazilian bank account) through one of our off-ramp PFIs. In this flow, you first create a withdrawal order, receive on-chain payment instructions, and then send `stablecoins` on-chain to the PFI.
Withdrawals (Balances), on the other hand, do not involve any on-chain transfer. Instead, they use the existing fiat balance that you already have on a PFI Account. For example, you can withdraw COP from a PFI Account and send it directly to a beneficiary’s COP bank account. In this case, the PFI simply debits your PFI Account and initiates a local payout to the payment instructions that you provide. And it has just 3 simple steps.
## Create payment instruction
First, create payment instructions to share with the partner financial institution (PFI) who is off-ramping or processing your withdrawal. This step is critical to ensure the local fiat currency arrives in the correct account at the end.
Please use account `id` in the deposit creation request from an account created above in the Accounts section.
Please capture payment instructions `id` from the response to use it for the withdrawal request after.
The PFI will be initiating the off-ramp directly to the payment instructions you create in this step. Borderless cannot be held responsible for transfers that originate outside the Borderless network to incorrect addresses. It is your responsibility to review the payment instructions and ensure they are correct.
Endpoint: [`POST /identities/{id}/payment-instructions`](/api-reference/payment-instructions/get-payment-instructions)
```bash request expandable theme={null}
curl -X POST 'https://sandbox-api.borderless.xyz/v1/identities/{id}/payment-instructions' \
-H 'Authorization: Bearer your-access-token' \
-H 'Content-Type: application/json' \
-H "idempotency-key: 8f14e45f-e6c3-4f7e-bd56-1b9a2e46f1d6"\
-d '{
"country": "US",
"currency": "USD",
"name": "Primary Bank Account",
"paymentMethod": "ACH",
"details": {
"bankName": "Example Bank",
"accountHolderName": "John Doe",
"bankAccountNumber": "123456789012",
"bankRoutingNumber": "123456789",
"bankAccountType": "Checking",
"address": {
"street1": "123 Main St",
"street2": "Apt 4B",
"city": "New York",
"state": "NY",
"country": "US",
"postalCode": "10001"
}
}
}'
```
```json response expandable theme={null}
{
"id": "string",
"name": "string",
"paymentMethod": "ACH",
"currency": "USD",
"country": "US",
"deleted": false,
"details": {
"bankName": "Chase",
"bankSlug": "Chase",
"bankAccountNumberLast4": "7890",
"bankRoutingNumber": "021000021",
"bankCode": "40006",
"phone": "string",
"taxId": "string",
"accountHolderName": "John Doe",
"bankAccountType": "Checking",
"address": {
"id": "string",
"street1": "string",
"street2": "string",
"city": "string",
"state": "string",
"country": "AF",
"postalCode": "string"
}
}
}
```
## Create a withdrawal order
Second, you will create an order for a withdrawal. This will send the payment instructions to the PFI, who will send the local fiat currency upon receipt. This alerts the PFI to expect the payment, and allows them to attribute the funds to your bank account when they arrive.
It's important to note that in the response to this withdrawal order, the PFI will return the onchain stablecoin payment instructions (generally a deposit address) that will handle the stablecoins which are being off-ramped.
Please use both the account `id` from an PFI Account created above in the Accounts section, and the payment instructions `id` in the withdrawal creation request from the step above where you created the payment instructions.
Endpoint: [`POST /withdrawals `](/api-reference/transaction-withdrawals/create-a-new-withdrawal-transaction)
```bash request expandable theme={null}
curl -X POST 'https://sandbox-api.borderless.xyz/v1/withdrawals' \
-H 'Authorization: Bearer your-access-token' \
-H 'Content-Type: application/json' \
-H "idempotency-key: 8f14e45f-e6c3-4f7e-bd56-1b9a2e46f1d6"\
-d '
{
"fiat": "COP",
"country": "CO",
"amount": "100.00",
"accountId": "cm2c4x3cc000019stwv7um4zl",
"paymentInstructionId": "cm2c4x3cc000019stwv7um4zl",
"paymentPurpose": "delivery fees",
"purposeDescription": "string",
"memo": "string"
}
'
```
```json response expandable theme={null}
{
"id": "string",
"type": "AssetDeposit",
"status": "Submitted",
"pfiName": "Bridge",
"source": {
"asset": "POL",
"amount": "string",
"fiatCurrency": "string",
"paymentMethod": "ACH",
"accountId": "string",
"accountName": "string",
"sender": {
"name": "string",
"legalName": "string",
"description": "string"
}
},
"createdAt": "2025-11-19T19:49:46.918Z",
"updatedAt": "2025-11-19T19:49:46.918Z",
"txHash": [
"string"
],
"withdrawalOnchainInstruction": {
"id": "string",
"amount": "100.00",
"asset": "BTC",
"fromAddress": "string",
"toAddress": "string",
"spenderAddress": "string",
"type": "Transfer",
"onchainInstructionTransaction": {
"id": "string",
"to": "string",
"from": "string",
"data": "string",
"nonce": "string",
"value": "string",
"chainId": 0,
"gasLimit": "string",
"gasPrice": "string",
"fee": "string",
"unsignedTx": "string",
"psbt": "string",
"inputs": {},
"outputs": {},
"walletId": "string",
"body": {},
"visible": true,
"txID": "string",
"rawData": {},
"rawDataHex": "string",
"spender": "string",
"mint": "string"
}
},
"counterPartyIdentityId": "string",
"developerFeeAmount": {}
}
```
## Release local fiat to beneficiary
Finally, PFI provider will issue the local fiat payment to the bank defined in the payment instructions. Once the local fiat currency is received, this completes the off-ramp or withdrawal flow.
You can easily track the status of transactions, request cancellation of transactions, and export transactions with the following endpoints.
Please ensure you are using the transaction `id `value which you will receive from the request to create a transaction such as the first step in this sequence on the `/withdrawals` endpoint.
To track the status of your withdrawal transactions and other types of transactions:
We recommend listening to the statuses via Webhook.
Endpoint: [`GET /transactions/{id}`](/api-reference/transactions/get-a-transaction-by-id)
To request a cancellation of your withdrawal transaction and other types of transactions:
Endpoint: [`POST /transactions/{id}/cancel`](/api-reference/transactions/request-cancellation-of-a-transaction)
To export your transactions:
Endpoint: [`GET /transactions/export`](/api-reference/transactions/export-transactions)
**Congratulations! You've now completed your first fiat withdrawal!**
If you have any questions, please don't hesitate to reach out to us via [email](mailto:support@borderless.xyz) or slack.
# Build with Borderless
Source: https://docs.borderless.xyz/index
One API integration, and Borderless connects you directly to regulated on-ramp and off-ramp providers, local rails, and stablecoins around the world. Build global payments solutions with transparency, predictable FX, and faster settlement. It's time to make your payments Borderless.
## Start making global stablecoin payments
Jump right into integrating Borderless.
Walk through our quick start guides.
## Choose your path
Accelerate your journey through our docs.
Everything to know about our API products.
Run your payments operation from the Borderless platform.
Test our endpoints, and get familiar today.
## Take Action
Common actions right at your fingertips.
You need to create identity objects before you can begin with payments.
Take stablecoin and fiat exchange pricing anywhere you need it.
Put it all together and turn stablecoin deposits into local fiat payouts.
Say hello! We'd love to hear what you think, and how we can help.
# Creating Transactions
Source: https://docs.borderless.xyz/platform-guides/creating-transactions
Create deposits, withdrawals, and exchanges, and track them to completion.
Most transactions start from an account: depending on the account, you'll see a **Deposit**, **Withdrawal**, or **Exchange** button — each opens a short form, a review screen, and a confirmation. The **Home** page also has its own **Deposit** and **Withdrawal** shortcuts that open the same forms without an account pre-selected. This guide covers all three flows, plus how to track, cancel, and export what you create.
## Money in, money out
Borderless is stablecoin-centric, and the platform uses two words for moving money:
* A **Deposit** brings money in: fiat is onramped into stablecoins. Depending on where you work, you may know this as an onramp, a pay-in, or a collection.
* A **Withdrawal** sends money out: stablecoins are offramped into local fiat. Also known as an offramp or a payout.
Whatever your team calls it, those two buttons are where it happens. A third operation, **Exchange**, converts one asset to another without moving money in or out — covered below.
## Accounts link your wallets — they don't replace them
Transactions start from accounts, so it's worth being clear about what an account is. Creating an account doesn't create a wallet, and you never hold funds in Borderless. You've already chosen, configured, and secured your wallet infrastructure — an account links it to Borderless, connecting the compliance information that lives in the platform (the identity) with the wallets you already run, whether that's Utila, Dfns, Fireblocks, Privy, Turnkey, or anything else on the market.
Accounts come in two types:
* **Wallet accounts** — linked to your own wallet infrastructure. [Wallets](/platform-guides/wallets) covers the linking options.
* **Provider balance accounts** — balances you hold with your providers.
Borderless holds neither. It links, orchestrates, and visualizes: your wallet infrastructure and its balances, and your provider balances, side by side in one place.
## Before you start
You need the **Create Transaction** permission to see the Deposit, Withdrawal, or Exchange buttons on an account (or the Home page shortcuts). If you don't see them, ask your administrator — you may also need a connected web3 provider, which gates transaction buttons on every account type, fiat or crypto.
For deposits, the account needs a linked blockchain address for the asset you want to receive. If it doesn't have one, add it first: on the account page, click **Add Asset** (or **Add Asset / Fiat**) in the Assets section.
## Finding the right button
Open **Accounts** from the nav and click into the account you want to transact on. The buttons next to the account name depend on the account type:
* An account holding a **provider balance** (fiat) shows **Exchange**.
* A **Web3/crypto account** shows **Deposit**.
* **Withdrawal** appears on both.
* Infinia accounts show no Deposit, Withdrawal, or Exchange button at all.
The button is fixed by account type — you can't choose Deposit on a balance account, and a plain crypto-to-crypto move isn't available on one either.
Before you commit to a route, you can preview pricing without creating anything. **Quotes**, in the nav, compares provider rates for a deposit or withdrawal. **Rates** shows a market-rate comparison table. Neither creates a transaction — use them to check pricing, then go to the account to submit.
## Depositing funds
A deposit brings fiat in and converts it to a stablecoin or other asset in a Web3 account.
1. On the account page, click **Deposit**.
2. Fill in the form:
* **Account** — pre-filled if you have only one.
* **Originator** — the identity initiating the transaction. It must have passed compliance checks in the country you select.
* **Country** and **Fiat** — the source of funds.
* **Payment Method** — how you're sending the fiat.
* **Asset** — the stablecoin or asset you'll receive. If this shows "No available blockchain addresses," go back and add one via **Add Asset** on the account page.
* **Provider (optional)** — pick a provider explicitly to route this transaction through it, or leave **Use default routing** to follow the defaults you've configured in the [routing table](/platform-guides/routing). Appears as soon as your organization has at least one active provider.
* Amount — turn on **Receive Exact Amount** if you'd rather enter what you want to receive than what you're sending.
* Optional: expand **Optional Details** to attach a supporting document.
3. Click **Review**. This stays disabled until Borderless has a live quote for your inputs — if it won't activate, check the form for a routing warning.
4. Check the review screen: the source amount, what it **Routes through**, the fee, and the total. A notice here warns that the amount credited may differ slightly, since exchange rates move between quote and settlement.
5. Click **Submit**.
6. You'll land on a **Thank You** confirmation. Click **Check status** to open the transaction's detail page.
## Withdrawing funds
A withdrawal moves funds out — onchain to a wallet, or offramp to a bank account, depending on the payment instruction you pick.
1. On the account page, click **Withdrawal**.
2. Fill in the form:
* **Account**, **Originator** — same as Deposit.
* **Beneficiary** — who receives the funds. It auto-fills to match Originator whenever you change Originator — including if you'd already edited Beneficiary by hand, so re-check it after changing Originator.
* **Payment Instructions** — where the funds go. Picking one back-fills country, fiat, and payment method. "No available payment instructions" means you need to add one first.
* **Payment Purpose** — required (for example, salary payment, rent payment, or property purchase).
* **Asset** — shown only for Web3 accounts; hidden on balance accounts, which pay out directly in fiat.
* **Provider (optional)** — same as Deposit.
* Amount — same **Receive Exact Amount** toggle as Deposit.
* Optional: expand **Optional Details** for a **Reference** message (length depends on the rail — 1–256 characters for wire, 1–10 for ACH, 6–140 for SEPA, 1–190 for SWIFT) and to attach a document.
3. Click **Review** — disabled until a quote loads.
4. Check the review screen: amount, provider, fee, total, payment purpose, and your reference if you added one. The same FX-fluctuation notice as Deposit applies.
5. Click **Submit**, then **Check status** on the confirmation screen.
If you're sending stablecoins onchain, confirm the destination address and network before submitting. Borderless can't refund stablecoins sent to the wrong address or network.
## Exchanging funds
Exchange converts one asset to another inside a balance you hold with a provider — without a deposit or a withdrawal. No money comes in and none goes out, so you can manage conversions separately from money movement.
1. On the account page, click **Exchange**.
2. Fill in **Amount** and choose the **From** and **To** sides. Each side is either a fiat currency or an asset — what's available to select depends on your providers and their configuration.
3. Click **Review**.
4. Check the total and the account the exchange happens within.
5. Click **Submit**, then **Check status**.
## Checking transaction status
Go to **Transactions** to see every transaction, or view them embedded on an account's page. The **All / Orchestrated / Imported** tabs filter between transactions Borderless routed and ones imported from a connected provider without Borderless routing.
The table shows date, type, source and destination accounts and amounts, status, provider, and transaction ID. Click a row to open its detail page, or use the copy icon in the table header to copy every visible transaction ID at once.
A transaction moves through **Submitted**, **Verifying**, **Orchestrating**, **Pending**, **Processing**, then **Completed**. Orchestrating has its own chip and color in the table and its own option in the status filter — it isn't folded into Verifying anywhere except the status timeline on the detail page, which groups it with Verifying as a single step. Two statuses need attention:
* **Pending** means the transaction needs action from you — the detail page shows what to do.
* **Failed**, **Cancelled**, and **Refunded** are end states; a failed transaction shows the reason on its detail page.
## Cancelling a transaction
You can cancel only while a transaction is **Submitted**, **Verifying**, **Orchestrating**, or **Pending**. Once it reaches Processing, there's no cancel option.
1. Open the transaction's detail page.
2. Click **Cancel**.
3. Read the confirmation dialog: cancellation isn't guaranteed — it depends on the stage the provider has reached.
4. Click **Confirm**.
You need the **Cancel Transaction** permission to see this button.
## Exporting and filtering transactions
From the **Transactions** list, click **Filters** to narrow the table by date, type, provider, status, currency, asset, country, or account ID, then **Apply**. Click **Export** to download a CSV — you need the **Export Transactions** permission to see this button. Export opens its own blank filter form (date range, type, provider, status, source/destination account ID); it isn't pre-populated from the Filters panel, so set your criteria there separately rather than assuming it exports whatever the table currently shows. Export is only available from the standalone Transactions page, not on the embedded Transactions view on an account's page.
This section covers the quick path; for everything about getting data out — filter details, filename conventions, reconciliation run exports, and size limits — see [Exporting Reports](/platform-guides/exporting-reports).
## Troubleshooting
**The Review button won't activate.** Deposit and Withdrawal need a live quote first, which depends on country, fiat, payment method, and asset resolving to a route a provider supports. A warning nearby usually says why — no active provider for that combination, or no default routing set up for the country.
**"No available blockchain addresses."** The account has no linked address for the asset, country, fiat, and payment method you chose. Go to the account page and click **Add Asset** to link one.
**Quote error.** The form tells you why a quote failed — an unsupported country, an amount outside limits, missing provider credentials, or a generic message asking you to adjust your inputs and try again.
**The final amount doesn't match the quote.** Small differences are normal — rates move between the quote and when the provider executes the transaction.
**A deposit, withdrawal, or exchange won't submit.** You'll see an error toast if the request fails. Try again, and if it keeps failing, check back shortly or contact support.
**Cancel didn't stop the transaction.** Cancellation isn't guaranteed. If the provider already moved past a cancellable stage, the transaction continues processing.
# Execution Benchmarking
Source: https://docs.borderless.xyz/platform-guides/execution-benchmarking
Grade every transfer's all-in landed cost against the Borderless network.
There are a lot of providers to choose from, their coverage overlaps, and each prices a little differently — which makes one simple question surprisingly hard to answer: am I getting a good price? Execution benchmarking answers it with numbers. Every transfer is graded against reference rates built from all the activity across the Borderless network on that corridor and direction, so you can see how competitive your provider mix actually is — and quantify it.
And it grades what you actually care about: the all-in landed cost of the payment, not just the FX rate. Fees, spread, everything that separates what you spent from what arrived.
Execution benchmarking is enabled per organization — talk to your Borderless representative if you don't see the surfaces described here.
## How grading works
Every eligible transfer is classified into one of three grades, based on how its executed rate compares to the weighted network average for that corridor and direction:
* **Competitive** — better than the network average.
* **In Line** — within one standard deviation of the network average.
* **Off Market** — materially worse than the network average.
Differences are expressed in bps, and the comparison is on all-in landed cost. Figures carry an **INDICATIVE** tag throughout — the benchmark is directional guidance. Exchanges aren't graded; benchmarking applies to money moving in and out.
Some transfers can't be classified yet, and the platform says so rather than guessing: **Calibrating** means the corridor doesn't have enough recent observations, **Syncing** means the execution rate hasn't been captured yet, and **Stale benchmark** means the corridor's data may not reflect current rates.
## See grades on the transactions list
With benchmarking enabled, the **Transactions** table gains an **Execution** column showing each transfer's grade as a chip — hover it for the explanation. Use **Filters → Execution** to narrow the list to a grade or state, for example everything **Off Market** this month.
## Read a transaction's execution quality
Open any completed transfer and look for the **Execution quality** card. It shows:
* The corridor and direction (for example "USDC → BRL · Off-ramp") with the verdict.
* A **network quote distribution** strip — where your execution landed on the network's distribution for this corridor, with the mean, the zones, and a marker for you (and the best quote, when available).
* **vs market** — your signed distance from the weighted network average, in bps.
* **opportunity vs best** — what was left on the table versus the single best network quote, in bps.
* **Your landed cost** — what you spent, what was received, and the **all-in landed rate**, so the benchmark always sits next to the real economics of the transfer.
The card appears once a transfer reaches a final state. If the corridor is still calibrating, syncing, or stale, the card says exactly that in plain language instead of showing numbers.
## How transactions get benchmarked
Every transaction orchestrated by Borderless is benchmarked automatically — nothing to set up. If you also transact with providers directly through their APIs, outside the platform, you can have those transfers benchmarked too by importing them.
## Importing transactions
There are two ways to import, both from the provider's page in **Network** (Owner or integration permission required):
* **Link your provider — the way to go.** Connect your credentials for the provider and Borderless imports your transactions in the background automatically, as an ongoing feed. Once linked, new activity flows in and gets benchmarked without you doing anything; **Sync Now** on the provider's page triggers a pull on demand.
* **Upload a CSV.** **Import Transactions from CSV** takes a file of off-platform transactions and validates it row by row before importing. It works, but it's manual — every new batch means another upload. If a file has more than 100 valid rows, Borderless surfaces your top 100 by benchmark fit; linking the provider benchmarks everything, continuously.
While an import runs you'll see a banner — "Importing your transactions" — while Borderless fetches the data and computes benchmarking metrics; this usually takes up to 5 minutes. Imported transfers appear under the **Imported** tab on the Transactions page, get graded like any other transfer, and open to the same execution quality card. For imported transfers, the comparison excludes your own execution, so you're measured purely against the rest of the network.
## Your portfolio versus the market
Once imported transfers are benchmarked, the Transactions page shows an **Execution vs market** summary card: whether you're **Ahead of market** or **Behind market** in dollar terms across all benchmarked transfers, with a range and the sample size behind it. Until there's enough data for a confident comparison, the card says so plainly.
## The stats strip
With benchmarking enabled, a strip of stats appears above the transactions list: the total dollar impact of your routing, and how many payments fall into each grade — Competitive, In Line, and Off Market. It's the portfolio-level read at a glance, before you drill into any single transfer.
## Troubleshooting
**I don't see an Execution column or execution quality card at all.** Benchmarking is enabled per organization — contact your Borderless representative.
**A transaction shows no chip in the Execution column.** Exchanges aren't graded, and neither are transfers that ended before an execution rate was produced.
**The card says "Calibrating."** The corridor doesn't have enough recent transfers for a reliable classification yet. Grades appear as network activity on that corridor accumulates.
**The card says "Syncing."** The execution rate for this transfer hasn't been captured yet — backfill is in progress. Check back.
**"Stale benchmark."** The corridor's benchmark data isn't fresh; the card shows the last known grade and when it was current. Treat it as historical context, not a current verdict.
**My CSV import shows row errors.** Each bad row is listed as "Row \{n}: …" with what's wrong. Fix the file and choose it again — only clean rows import.
**The portfolio card says there's no confident comparison.** You have benchmarked transfers, but not yet enough signal for a market comparison. It fills in as more transfers are benchmarked.
# Exporting Reports
Source: https://docs.borderless.xyz/platform-guides/exporting-reports
Get transaction data out of the platform as CSV.
You can export transaction data from the platform in two places: the **Transactions** page and a reconciliation run's detail page. Both produce a CSV file. This guide covers where to find each export, what you can filter by, and what to do if an export fails.
## Before you start
Whether you see the **Export** button on **Transactions** depends on your role. Owners always see it. Custom-role users need the **Export Transactions** permission assigned — without it, the button won't appear, and your organization's admin can grant it from the Permissions screen. Viewer-role users never see the button, even if the permission were somehow assigned to them; that requires a role change, not a permission grant. Exporting from a reconciliation run's detail page has no permission requirement.
## Export transactions
1. Go to **Transactions** under **Operations** in the left nav.
2. Click **Export** in the page header, next to **Filters**.
3. In the **Export transactions** modal, set any filters you want. All of them are optional:
| Field | What it does |
| --------------------------- | ---------------------------------------------------------------------------------------------------- |
| **From Date** / **To Date** | Limits the export to a date range. You can't pick a future date. |
| **Transaction Type** | Deposit, Withdrawal, or Exchange. |
| **PFI name** | Filters to one provider. Type to search the list. |
| **Status** | Submitted, Verifying, Orchestrating, Pending, Processing, Completed, Failed, Cancelled, or Refunded. |
| **Source Account Id** | The exact account ID, 25 characters. |
| **Destination Account Id** | The exact account ID, 25 characters. |
These are the only filters the export modal offers. The on-page **Filters** drawer also supports benchmark status, reconciliation status, country, currency, and asset filters (depending on your organization's settings), but none of those carry over to export — there's no way to export, say, only unreconciled transactions or only flagged transactions directly. Use the export modal's date range, type, provider, status, and account filters to narrow things as far as they'll go.
4. Click **Export**.
The button shows a spinner while the file generates, then downloads automatically and closes the modal. You'll see "Transactions are successfully exported."
Leaving every field blank exports your full transaction history as `transactions.csv`. Filters change the filename too — for example, a date range alone produces `transactions_2026-06-01_2026-07-17.csv`, and adding a provider and status filter appends those to the name (lowercased), so you can tell what's in a file without opening it.
The **Export** button only appears on the main Transactions page — it's not available if you've drilled into a single account's transaction list.
## Export a reconciliation run
Each reconciliation run has its own export, separate from the Transactions export above, and it isn't filtered the same way.
1. Go to **Reconciliation** under **Operations** in the left nav.
2. In the **Runs** tab, click a row to open that run's detail page.
3. Click **Export** at the top of the **Run detail** page.
This downloads a CSV named `{runId}-transactions.csv` containing every transaction in that run. It always exports the **Transactions** tab's data, even if you have the **Exceptions** or **Orphaned** tab open when you click — there's no way to export exceptions or orphaned rows separately.
For a large run, this can take a while: the export gathers the full result set (up to 20,000 transactions) before building the file, and the only feedback while it works is a loading spinner on the button. If a run has more than 20,000 transactions, the export stops there with no warning — the file downloads normally and looks complete, but the rows beyond 20,000 are silently missing.
## Troubleshooting
**My Transactions export failed.**
You'll usually see "Failed to export transactions. Please check back shortly." If the API rejected the request for a specific reason — an invalid filter combination, for example — you may see that message instead. Either way, check your filters and try again.
**A reconciliation run export capped out below the run's actual size.**
Runs over 20,000 transactions export silently truncated — see the note in "Export a reconciliation run" above. There's no in-app warning when this happens, so for a run that size, check the run's total transaction count against the row count in the downloaded file before treating it as complete.
**I got "An error occurred during file conversion process".**
This means the file downloaded but couldn't be assembled into a CSV on your device. Retry the export.
**A reconciliation run export seems stuck or never downloaded, with no error message.**
This tab doesn't show an error toast if the export fails partway through — only the spinner clearing. If nothing downloads after a wait, try the export again.
**My account ID filter won't validate.**
Source and destination account IDs must be exactly 25 characters. A pasted ID with extra whitespace or a partial ID will fail with "Id must be 25 characters long" — check for stray spaces and re-paste.
**I don't see an Export button on Transactions.**
If you're on a Custom role, you need the **Export Transactions** permission — ask your admin to grant it from the Permissions screen. If you're on a Viewer role, a permission grant won't help; that role never gets the button, so you'd need a role change instead. Or use the reconciliation run export if you're trying to pull transactions tied to a specific run.
**I'm looking for an export on the Activity page.**
Activity doesn't have one. It's a table you can scroll, with no download option.
**I need a PDF, not a CSV.**
Transactions and reconciliation runs only export as CSV — there's no format choice. If you need a payment or withdrawal instructions PDF for a single transaction, look for the download icon on that transaction's instructions view instead; it's a separate, single-record download.
# Getting Started
Source: https://docs.borderless.xyz/platform-guides/getting-started
Your first steps in the Borderless platform: logging in, MFA, inviting your team, and what you need before your first transaction.
The Borderless platform is your payments hub — where your operational tools, your data, and your intelligence live. This guide covers your first steps in it: logging in, reading the Home page, securing your account with MFA, inviting your team, and what you need in place before your first transaction. Deeper setup — managing permission groups, refund destinations, wallet integrations — lives in [Organization Administration](/platform-guides/org-administration) and [Wallets](/platform-guides/wallets).
## Before you start
* You need an invitation from someone at your organization who already has platform access. There's no public sign-up — an **Owner** or a user with the right permission invites you.
* Some actions in this guide — inviting users, enabling organization-wide MFA, managing permission groups — require the **Owner** role or a **Custom** role with the matching permission. Where a step is restricted, this guide says so.
* Your workspace is connected to one environment, either sandbox or production. There's no in-app switch to move between them — each environment has its own URL. Check the colored chip near your org name in the header: green means production, amber means sandbox or another non-production environment.
## Log in
Borderless uses a hosted login screen, so the sign-in page itself may look different from the rest of the platform. Go to your platform URL and sign in with the credentials your organization gave you.
After you log in, you land on **Home**.
## Read the Home page
Home is a summary of your account: a welcome header with your name, a row of key metrics, a transaction activity chart, a network health panel, an exchange rates chart, a **Needs Attention** panel, and a list of recent transactions.
**Needs Attention** flags anything that needs action from you. When nothing does, it shows an empty-state message instead — you don't need to check further.
If you have permission to invite users, the **More** menu on Home also has a shortcut: **Invite user**. It opens the same modal as adding a user from the Team page (below).
## Notifications
Click the bell icon in the header to slide in the notifications panel from the right. It holds your notification history: mark them all as read, delete them, or click one to jump to whatever it's notifying you about.
## Find Team and Developer settings
There's no separate **Settings** page — clicking **Settings** takes you straight to **Team**. That's where org-wide settings, users, and permission groups live. Developer-facing settings — API keys, webhooks — live on their own **Developer Settings** page.
## Set up multi-factor authentication
On the **Team** page, under **Organization Settings**, you'll find a **Multi-Factor Authentication** card. It shows whether MFA is on for your organization and, if you have permission, an **Enable MFA** button.
1. Click **Enable MFA**.
2. A confirmation modal titled **Enable Organization MFA** appears, warning that this updates MFA for every user in the organization.
3. Confirm to enable it.
This applies to everyone at once — there's no per-user opt-out once it's on. Enabling MFA can also force a re-login: the platform checks your session against the server's MFA setting, and if they're out of sync it logs you out automatically. Expect to sign in again shortly after you (or an admin) turns MFA on.
You can also enable MFA for one person at a time from their row in the **Team Members** table — click **Enable** in the MFA column and confirm in the modal that appears.
## Invite a user
1. On the **Team** page, under **Team Members**, click **Add User** (or use **Invite user** from the Home page's **More** menu).
2. Fill in **First Name**, **Last Name**, **Email**, and **Business Title** — all required.
3. Choose a **Role**: **Owner** (full control), **Viewer** (view only), or **Custom** (permissions you assign through a permission group).
4. Click **Save**.
The platform copies an invitation link to your clipboard and shows a toast confirming it. Save and send that link right away — it's shown only once and can't be retrieved again afterward.
## Create a permission group
Use permission groups to give Custom-role users a defined set of actions — everything else stays denied to them, aside from viewing.
1. From **Team** or the **Permission Groups** page, click **Create Group**.
2. Enter a **Name** (3–100 characters) and, optionally, a **Description**.
3. Flip on the permissions to grant, organized by section.
4. Click **Create Group**.
Only users whose role is already **Custom** can be added to a permission group. Managing groups after that — adding and removing members, editing permissions, deleting a group — is covered in [Organization Administration](/platform-guides/org-administration).
## Find developer settings
Go to **Developer Settings** for API keys and webhooks.
* **API Keys** shows your **Client ID** and **Client Secret**, masked until you reveal them, with a copy button for each. Click **Generate Keys** the first time, or **Regenerate Keys** later. Regenerating asks you to confirm first — doing so logs out every device currently using that client ID.
* **Webhooks** lists your configured webhook URLs. Click **New Webhook** to add one.
* **Webhook Authentication** holds the public key used to verify webhook signatures, with its own **Generate Keys** / **Regenerate Keys** button.
If your organization hasn't been enabled for API access, the API Keys card shows a message to contact Borderless support instead of the usual fields — that's a prerequisite your team can't turn on from the platform.
## Connect your providers
Borderless is the orchestration platform for a network of payment providers, and enabling your providers is the first step toward moving money. Go to **Network** to browse the provider marketplace — you can search and filter by capability, country, currency, and rail to explore which providers offer the services you need.
If you're already onboarded with a provider, link your account: click **Add API keys** on the provider's card and drop in your credentials. [Provider Marketplace](/platform-guides/provider-marketplace) covers the full flow, including providers whose connection Borderless manages for you.
If you'd like to explore new providers, or want an introduction to a specific one, reach out to the Borderless team. We work with these providers across many clients and are happy to share that experience, help you choose, and introduce you to the expedited onboarding processes providers offer Borderless customers. You complete onboarding directly with the provider; once they approve you, add your credentials and the provider is live in your network.
## Your first transaction
Before you can move money, three things need to be in place — in this order:
1. **An enabled provider.** Borderless orchestrates approvals with your providers, so the provider comes first — see "Connect your providers" above and [Provider Marketplace](/platform-guides/provider-marketplace).
2. **An approved identity.** Create the identity and take it through compliance — see [Identities & Compliance](/platform-guides/identities-compliance). The identity must be approved with the provider you'll transact through, or covered by a reliance agreement with that provider.
3. **A linked wallet.** Link a wallet so Borderless knows the source of funds for your transactions — see [Wallets](/platform-guides/wallets).
With those in place, add a payment method and create the transaction — [Creating Transactions](/platform-guides/creating-transactions) walks through each flow. Onramps and offramps work the same way apart from the destination: an onramp delivers to a wallet address, an offramp delivers to a bank account.
## Troubleshooting
**I can't find Settings.** There isn't a separate Settings page — it redirects to **Team**. Bookmark or link to Team instead.
**I don't see the invite link anymore.** Invite links are shown once, right after you create the user. If you didn't save it, delete the user and re-invite them to get a new link.
**I got logged out right after enabling MFA.** Expected. The platform syncs your session with the new MFA setting and logs you out if they don't match yet — log back in.
**A user I want to add to a permission group isn't in the list.** Only users with the **Custom** role are selectable. Change their role first (through your identity provider or admin process), then add them to the group.
**I can't find the button to invite users, enable MFA, or manage permission groups.** These actions require the **Owner** role, or a **Custom** role with the matching permission. Ask an Owner at your organization to grant it or perform the action.
**I see an error like "Users went on a coffee break" or "Permission groups are playing hide and seek."** These are the platform's informal error messages for a failed load. Refresh the page; if it persists, contact your Borderless representative.
# Identities & Compliance
Source: https://docs.borderless.xyz/platform-guides/identities-compliance
Create personal and business identities and take them through compliance with every provider you use.
An identity is the person or business money is moved on behalf of. Every identity carries the underlying data Borderless passes to your providers — for compliance checks, audits, regulatory inquiries, and travel rule compliance.
Providers handle compliance in one of two models, and the difference shows up in the identity's lifecycle. Some providers run their own checks on each identity: the check moves through **Under Review** to **Approved** (or **Rejected**, which you can usually fix — see below). Others rely on your organization's own compliance program: there's no provider-side review, and the identity moves straight to **Pre Approved**. In both models the identity's data is on file with the provider from then on.
One identity in Borderless maps to every provider you use and each provider's compliance model. The platform shows you exactly where that identity stands across the network — approved with one provider, ready to onboard into another, two documents short of a third — and walks you through closing each gap. This guide covers creating an identity (KYC for individuals, KYB for businesses), onboarding it into your providers, reading its compliance status, and fixing a rejected or incomplete check.
## Before you start
Some actions on this page are role-gated and simply won't appear if you lack permission: creating an identity, editing one, deleting one, uploading documents, viewing uploaded documents, starting or restarting a compliance check, and adding a payment instruction each require a specific permission. If you don't see a button described below, ask an admin on your account to grant it.
## Create an identity
1. Go to **Identities** in the navigation and click **Create Identity**.
2. On the first step, choose an **Identity Purpose**:
* **Originator** — for full financial use: holding an account, sending, and receiving funds. Requires a compliance check after creation.
* **Beneficiary** — a payment recipient only. Needs minimal information and skips compliance checks entirely. You can upgrade a beneficiary to an originator later.
3. Choose an **Identity Type**: **Personal** (an individual) or **Business** (a company or organization).
4. Click **Next**.
*\[Screenshot: Create Identity type step with Originator/Beneficiary and Personal/Business options]*
What you fill in next depends on that choice.
### Personal details
Enter **First Name**, **Last Name**, **Email**, and **Birthday Date** (the person must be 18 or older). **Tax ID** is required if the person's country is the US. **Phone** is optional.
Fill in the address block: **Country**, **City**, **Street Address**, and optionally **Additional Address**. **State Code or Region** is required for US addresses (note: New York and Alaska aren't supported for any US identity, regardless of which compliance provider you use). **Postal Code** is required where the country has one.
If the person is from a restricted country or is 60 or older, the form asks for additional identification details — some providers need this to process their transactions. An **Optional Details** section lets you add middle name, second last name, occupation, and sex, none of which are required.
If the person's address country is in the EEA, the form adds a few more fields: **Country of Birth** and **Nationalities** (both required), **City of Birth** (optional, becomes mandatory under EU law in 2027), and a **Has Foreign Tax Registration** checkbox (check it if they hold tax registrations outside their country of residence — required from 2026-12-31).
For a beneficiary, the form only requires first name, last name, email, and address (country, city, street).
### Business details
Enter contact information (**Email**, **Phone**) and the same address block as above, then move to business details: **Legal Name** is required. The rest — **Trade Name**, **Business Type**, **Website**, **Description**, **Date of Incorporation**, **Tax ID**, **Industry Code** (NAICS 2022), **Source of Funds**, and **Account Purpose** — are flagged but won't block you from saving. **Business Registration Number** becomes required if the business is incorporated in the EEA.
**Has Foreign Tax Registration** only appears for businesses incorporated in the EEA (check it if the business holds tax registrations outside its incorporation country). **Has Material Intermediary Ownership** appears for every business regardless of where it's incorporated — check it if another legal entity holds 25% or more of the business. An **Optional Details** section covers source-of-funds detail, high-risk activities, whether the business **Operates in Prohibited Countries**, and money-services questions: if you check **Conducts Money Services**, you'll need to describe it and explain your compliance screening; a sub-checkbox, **Conducts Money Services Using Bridge**, appears underneath and requires a flow-of-funds document if checked.
Note that for a business originator, this form comes after the beneficial owners step described below, not before it — the on-screen order is beneficial owners first, then this form. Business beneficiaries go straight to this form.
*\[Screenshot: Business Details form with Legal Name and Source of Funds fields]*
### Beneficial owners (business originators only)
If you're creating a business originator, you'll add beneficial owners first — this step appears before the business details form covered above, not after it. Select owners from your existing personal identities — you can't add a new one inline here, so create the person as a personal identity first if they don't exist yet.
For each owner, check any of **Has Ownership**, **Has Control**, **Is Signer**, **Is Director** that apply. **Relationship Establishment Date** is always required, regardless of which boxes are checked. Checking **Has Control** unlocks **Control Person Role** (required) and reveals **Ownership percentage** as a preferred (not required) field, plus an **Attested Ownership Structure Date**. Checking **Has Ownership** makes **Ownership percentage** required instead of just preferred.
The validation across all the owners you add works in two independent parts. First, some owner needs **Has Control** and some owner needs **Is Signer** — it doesn't have to be the same person. Second, either some owner needs **Has Ownership**, or — if no one does — some owner needs both **Has Control** and an **Attested Ownership Structure Date** filled in. In other words, you can satisfy the ownership half of the rule without designating anyone as a 25%+ owner, as long as a control person attests to the ownership structure instead.
If the business is incorporated in the EEA, every beneficial owner effectively needs **Is Director** checked too — Bridge's MiCA/EMI regime requires it as of 2026-06-15.
If someone is a signer but not a director, owner, or control person, you'll need to upload a Letter of Authority for them afterward — you can only do this once the owner record is saved.
### Finish
Click **Save**. Beneficiary identities go straight to a success screen. Originators move to the **Compliance Check** step next.
## Onboard an identity into a provider
This step appears right after creating an originator, and any time you click **Compliance** on an identity's details page. Each provider's card lists that provider's exact requirements and whether the identity currently meets them — Borderless knows every provider's compliance model, so instead of digging through provider documentation you see the precise gap and a button to close it.
1. If a provider isn't already selected, choose one from the **Provider** list.
2. Review the provider's card: requirements show as either "All requirements must be met before starting" or "All requirements are met. You can proceed with compliance check."
3. If anything's missing, each unmet requirement has its own action next to it — **Edit Identity**, **Upload Documents**, **Copy ToS Link**, or **Provide API Keys**. Resolve them one by one; the card re-checks against the provider's requirements as you go.
4. Once everything's met, click **Start Check**.
*\[Screenshot: Compliance Check step with a provider card and Start Check button]*
Once a check starts, you'll see a confirmation that it's been kicked off — reviews take time, and you can close the window and track progress from the identity's details page. Click **Go to identity details** to head there now, or **Skip for now** to leave without starting a check (this becomes **Close** specifically when the provider you currently have selected is already approved).
If every provider for this identity is already approved or in progress, you'll see a separate message that there's nothing left to start here — this is independent of the Skip/Close button label, which only tracks the currently selected provider.
## Read an identity's compliance status
Open the identity from the **Identities** list and scroll to **Compliance Status**. This is the identity's map across your whole provider network: where it's approved, what's in review, and what it would take to onboard it anywhere else. A summary line tallies things like "2 escalations · 1 action needed · 3 in review." Providers are grouped into five sections, in priority order:
1. **Escalations required** — a rejection that needs your compliance team, not a self-service fix (fraud, geographic restrictions, and similar). There's no retry button here — only a way to copy the details for a ticket and acknowledge that you've seen it.
2. **Actions needed** — a rejection or incomplete check you can fix yourself (missing document, wrong detail).
3. **In review** — the provider is actively processing the check.
4. **Approved providers** — you can transact through this provider. The status reads **Approved** when the provider ran its own check, or **Pre Approved** when the provider relies on your compliance program.
5. **Available providers** — not started yet.
*\[Screenshot: Compliance Status section showing the five grouped provider buckets]*
Search providers or countries using the field at the top of the section. Groups with nothing in them don't appear at all.
An identity shows a green **Verified** badge on the list and details page once it has an approved compliance check.
## Fix a rejected or incomplete check
Open the provider's row in **Actions needed**. Each listed reason has a specific action attached — **Upload Document**, **Upload Selfie**, **Upload Address Proof**, **Edit Identity**, **Edit Address Details**, **Edit Business Details**, **Upload Business Document** (for a rejected business license, formation document, or ownership document), or **Retry Check** — based on what caused the rejection. Click it, resolve the issue, and the check re-runs.
If the provider is in **Escalations required** instead, there's no fix button. Click the copy icon to copy the reason details for your compliance team, and use the acknowledge toggle once you've reviewed it. Acknowledging is stored in your browser only — it isn't shared with teammates or synced to the backend, so someone else looking at the same identity on a different machine will still see it as unacknowledged.
Providers can also raise a request for information (RFI) while reviewing an identity — identity compliance is where most RFIs come from, with the rest tied to specific transactions. These arrive as cases you reply to in the platform; see [RFI Case Management](/platform-guides/rfi-case-management).
## Sync changes to an approved provider
If you edit an identity's details after it's already been approved, click **Sync changes** on that provider's row in the **Approved providers** group. This pushes your edits to the provider without re-running the full check. Use **Restart Check** instead only for a provider in **Actions needed** — that re-runs the check from scratch.
## Upload documents
1. From an identity's details page, click **Upload Docs** (or, from the Compliance Check step, use the **Upload Document(s)** action on a requirement).
2. Choose a document type. Types already on file are marked **Uploaded**.
3. Enter the document's details — issuing country, ID number, issued and expiration dates — whichever apply to that type. For a **Proof of Address** document, a **Document Sub-Type** dropdown also appears: Utility Bill, Bank Statement, Rental Agreement, Tax Document, or Government Correspondence.
4. Click **Continue**.
5. Upload the file for **Front of document** (or **Document**, if only one side is needed) and **Back of document** if the type requires both sides. Supported formats are PDF, JPEG, PNG, HEIC, and TIF.
6. Click **Submit**.
*\[Screenshot: Upload Documents step showing front and back file inputs]*
Personal identities can upload: passport, ID card, driver's license, residence permit, proof of address, source of funds, individual holding, bank verification number, selfie, letter of authority, and tax ID. Business identities can upload: formation, ownership, proof of address, source of funds, evidence of good standing, proof of nature of business, and tax ID.
## Edit an identity
Click **Edit** on the identity's details page. For a personal identity, this reopens the same form you filled in at creation. For a business identity, it's a three-step wizard: **Edit Contact Information**, **Edit Business Details**, **Edit Beneficial Owners**. Click **Continue** between steps and **Update** to save. Note this order puts business details before beneficial owners — the opposite of the order you see when creating a business originator (beneficial owners first).
If the identity already has an approved compliance check, remember to use **Sync changes** afterward so the provider sees your edits.
## Delete an identity, a document, or a provider record
* **Delete an identity** from the list or its details page. You'll be asked to confirm — this can't be undone.
* **Delete a document** from its menu on the details page. Also permanent.
* **Delete a provider record**, from a provider's row in Compliance Status, removes that provider's customer record for this identity entirely — not just the check status. You'll see a warning that this is permanent before you confirm. Use this only if you need to start over with that provider from scratch. This button appears in **Actions needed**, **In review**, and **Approved providers**, but not in **Escalations required** or **Available providers**.
## Troubleshooting
**A beneficiary identity never shows a compliance step.** That's expected — beneficiaries skip compliance checks by design, so their "Verified" badge won't populate either.
**I can't tell why Save fails on beneficial owners.** The validation applies across the whole group of owners, not to one row. Check that some owner (any owner) has Has Control and some owner (any owner, can be a different person) has Is Signer. Then check that either some owner has Has Ownership, or — if not — some owner has both Has Control and an Attested Ownership Structure Date filled in.
**A Letter of Authority is required but I can't upload it yet.** Save the beneficial owner first, then upload the document from the identity's details page.
**Extra fields appeared that I didn't expect.** Businesses incorporated in the EEA get additional required fields — Business Registration Number, Has Foreign Tax Registration, and director information. This is tied to the business's country, not a bug.
**Uploading a document fails with a generic error.** Try again; if it keeps failing, check the file size and format (PDF, JPEG, PNG, HEIC, or TIF). A message mentioning content size means the file is too large — try a smaller file or a different format.
**A provider shows "Not Started" even though I thought I fixed everything.** An incomplete check with no listed reasons is treated as never actually submitted. Open the provider's requirements and confirm everything shows as met, then click **Start Check**.
**I need to hand off an escalation to a teammate.** Acknowledging a reason only affects your own browser. Use **Copy reason details** and share it directly — don't rely on the acknowledge toggle to notify anyone else.
# Organization Administration
Source: https://docs.borderless.xyz/platform-guides/org-administration
Manage team members, permission groups, and your default refund destination.
Day-to-day administration of your organization: managing team members, maintaining permission groups, and keeping your default refund destination current. Everything here lives on the **Team** page (and the **Permission Groups** pages it links to), and most of it requires the **Owner** role. For first-time setup — inviting your first users, enabling MFA, creating your first permission group — start with [Getting Started](/platform-guides/getting-started) instead.
## Review and remove team members
The **Team Members** table on the **Team** page lists everyone in your organization: name, ID, email, business title, role, and MFA status.
If you have permission, a delete icon on each row removes that person — a confirmation modal asks you to confirm, and the action can't be undone. To bring someone back, re-invite them as a new user.
## Edit a permission group
Click the edit icon on a group's row in the **Permission Groups** table. The **Edit Permission Group** form mirrors the create form: adjust the **Name** or **Description**, flip permissions on or off by section, and click **Update Group** to save. Changes apply to every member of the group.
## Add users to a group
Only users whose role is already **Custom** can belong to a permission group — Owners and Viewers can't be added.
1. Open the group's details page from the **Permission Groups** table.
2. Click **Add Users**.
3. Select from the list of Custom-role users and confirm.
If someone you expect isn't in the list, their role isn't **Custom** — change their role first, then add them.
## Remove users from a group
Removing members is a deliberate three-click flow:
1. Click **Delete Users** to enter selection mode.
2. Check the people to remove, then click **Confirm Deletion**.
3. Click **Remove** in the confirmation modal that opens.
**Cancel deletion** exits selection mode without removing anyone. Removed users keep their Custom role but lose the group's permissions immediately.
## Delete a permission group
Deleting a group removes every member's access to those permissions immediately. You'll be asked to confirm first. If members still need a subset of those permissions, create or assign a replacement group before deleting.
## Set a default refund destination
Under **Organization Settings** on the **Team** page, the refund destination card controls where refunds go when a transaction doesn't specify one. If nothing is set, click **Set default** to configure it. If one is already set, you can **Edit**, **Re-confirm**, or **Remove** it.
Re-confirm the destination at least every 90 days. Left unconfirmed, its status badge moves from a "re-confirm recommended" warning to an expired state, and automatic refunds stop working until you re-confirm. Only Owners can manage this — it's not something you can grant through a Custom permission.
## Troubleshooting
**The refund destination badge shows a warning or error.** It needs re-confirming — the badge moves from a soft warning to an expired state after 90 days without re-confirmation, and automatic refunds stop working until you re-confirm.
**A user I want to add to a permission group isn't in the list.** Only users with the **Custom** role are selectable. Change their role first, then add them to the group.
**I removed the wrong user from a group.** Re-add them through **Add Users** on the group's details page — their Custom role is unaffected by removal, only their group membership.
**I see an error like "Permission groups are playing hide and seek."** That's the platform's informal message for a failed load. Refresh the page; if it persists, contact your Borderless representative.
# Provider Health
Source: https://docs.borderless.xyz/platform-guides/provider-health
Provider status, incidents, and upcoming maintenance, all in one place.
Is a provider having issues right now? Was it down last week? Is maintenance coming that could affect your payouts? The platform answers these in the places you already work — the **Network** page, each provider's drawer, and the transactions an incident might affect — so you don't need to watch each provider's own status page.
## Where the health data comes from
Two sources feed everything on this page. The first is the providers' own status pages: Borderless aggregates them all, so instead of checking each provider's page one by one, you monitor every provider from a single place.
The second is the Borderless network itself. Status page data is augmented with real-world transaction data for each provider across the entire network. If a provider's status page shows all-clear but transactions through that provider start failing across the network, Borderless notifies you — often before the provider has posted anything. That early signal is something only network-wide data can produce, and it's the difference between failing over as an issue develops and waiting for a status page to catch up.
## Check a provider's current status
Every provider card on the **Network** page carries a health indicator when health data is available. Open the provider's drawer for the detail: the header shows a status badge reading one of **Operational**, **Degraded**, **Partial Outage**, **Major Outage**, or **Maintenance**, along with how many of its services are operational.
Where health data exists, the header also shows an **uptime bar** — a day-by-day strip of color blocks covering recent history. Hover any day for its date, status, and (if not operational) the affected components. Green end to end means everything's been operational.
Not every provider reports health data — if the badge, uptime bar, and tabs described below are missing, that provider doesn't have live health reporting yet.
## Review incidents
If the provider has live health data, the drawer shows tabs with live counts in their labels — for example **Services (3)**, **Incidents (1)**, **Maintenance (0)**:
* **Services** — one row per service, each with its own status, so you can see exactly which capability is affected.
* **Incidents** — active and past incidents.
* **Maintenance** — scheduled and completed maintenance windows.
An active incident also shows as a banner on the provider's **Overview** tab, so you'll see it even without opening the Incidents tab.
Each incident card shows chips for the affected services, a Start/Duration row, and a **View on Status Page** link out to the Borderless status page. If the incident has updates, a collapsible "N updates" toggle expands into the timeline — each update carries a status (**Investigating**, **Identified**, **Monitoring**, or **Resolved**) with its timestamp and message, so you can follow an incident from first report to resolution.
## Check upcoming maintenance
The **Maintenance** tab lists scheduled and completed maintenance windows, with the same card layout as incidents — affected services, start and duration. Scheduled maintenance also appears as a banner on the provider's **Overview** tab. Check it before planning large payout batches through a provider.
## See health where it matters: on transactions
If a provider has an active incident, transactions routed through it warn you directly — the transaction's detail page shows "This provider has an active incident — it may affect this transaction." If a transaction seems slow, this is the first thing to check.
## At a glance, from anywhere
You don't have to open the Network page to know where things stand:
* **In the nav:** the **Network** item carries a real-time status indicator — a single green dot when every provider is healthy, green plus orange when some are degraded, and red when a provider is fully down. One dot appears per status present in your network, so a mixed picture is visible as mixed colors. Hover it for a summary of which providers have issues. It's on screen wherever you are in the platform.
* **On Home:** the network health panel summarizes provider status across your network, so a developing issue is visible the moment you log in.
## Troubleshooting
**A provider shows no health information at all.** Not every provider reports live health data. No badge or tabs means no reporting for that provider yet — not that the provider is down.
**A transaction is delayed and I don't see an incident.** Check the provider's drawer on **Network** for its Services tab — a single degraded service may not take the whole provider out of **Operational**. Reach out to your Borderless representative if the delay persists with no visible cause.
**An incident is resolved but my transaction still hasn't moved.** Providers work through backlogs after incidents. If a transaction stays stuck well after resolution, contact your Borderless representative with the transaction ID.
# Provider Marketplace
Source: https://docs.borderless.xyz/platform-guides/provider-marketplace
Explore providers by capability, country, and currency, and connect your credentials.
The Network page shows every payment provider available to your organization, whether it's live, ready to activate, or still coming. This guide covers browsing and filtering providers, reading a provider's coverage and health, connecting your own credentials, and importing transactions that happened outside Borderless.
## Before you start
Only users with the **Owner** role — or a **Custom** role explicitly granted the **Enable Integrations** permission — can configure credentials or import transactions. Everyone else can browse providers, view coverage, and check health status, but won't see the action buttons described below.
## Find the Network page
Click **Network** in the left navigation. The page opens with the header **"Provider Network"** and a subtitle telling you how many providers you have across how many countries.
Three tiles at the top summarize your network:
* **Active** — providers ready to transact
* **Available** — providers you can enable yourself
* **Coverage** — number of distinct countries covered
Below the tiles, providers are grouped into three sections, each shown only if it has matching providers:
* **Active** — "Ready to transact"
* **Available to Enable** — "Drop in your API keys to activate"
* **Coming Soon** — "New providers joining the network"
## Explore providers by capability, country, and currency
The marketplace is how you explore the network: search and filter to see which providers offer the rails and services you need — who covers a country, who supports a currency or rail, who can do deposits versus withdrawals, who offers virtual accounts. Use the filter bar above the provider list:
* **Search** — matches provider names, countries, rails, currencies, and more
* **Country**, **Currency**, and **Rail** — multi-select filters
* **Direction** — **Any**, **Deposit**, or **Withdrawal**
* **Asset** — filter by stablecoin
* **Status** — **All**, **Active**, **Available**, or **Coming Soon**
Toggle **By Provider** or **By Country** to change how results are grouped. By Country groups providers under each country they cover; if any provider serving that country is Active, the country card shows as Active even if other providers there are only Available or Coming Soon — open the country to see the real breakdown provider by provider.
If a filter is active, click **Clear** in the filter bar (or **Clear all filters** in an empty results state) to reset.
Each provider card shows the provider's logo and name, a health indicator (if available), how many countries, rails, and stablecoins it supports, and up to six country flags. Four capability icons — **Deposit**, **Withdrawal**, **Virtual Account**, **Exchange** — show which operations that provider supports.
## Open a provider's details
Click any provider card to open its drawer from the right side of the screen. The drawer header shows the provider name, its current health at a glance, and how many of its services are operational; where health data exists, tabs for **Services**, **Incidents**, and **Maintenance** appear alongside **Overview**. Health, incidents, and maintenance have their own guide — see [Monitoring Provider Health](/platform-guides/provider-health).
The **Overview** tab always appears first, and can include, in order: a short description of the provider, an active-incidents banner, a scheduled-maintenance banner, a link to the provider's website, a link to the Borderless status page, your credentials status, and buttons to import transactions.
Scroll down on the Overview tab to see **Capabilities** — which of Deposit, Withdrawal, Virtual Account, Exchange, and Custodial balance the provider supports — and **Coverage**, a country-by-country breakdown of rails, currencies, and stablecoins. Coverage has its own search box to filter by country, rail, or currency; if the provider has no coverage to show, or your search matches nothing, you'll see a message saying so instead of a list. Click any country row in Coverage to open that country's drawer, which lists every provider serving it — this drawer has its own search box too (by rail, currency, or provider) with matching empty states when nothing matches or no corridors are configured.
## Connect your own credentials
Providers in the **Available to Enable** section fall into two groups: some let you connect your own credentials, others are managed by Borderless.
1. On the provider's card, click **Add API keys** if the button is present. If it isn't, click **Contact us to enable** instead — this opens an email to Borderless support and there's no self-serve option for that provider.
2. In the **Configure \{Provider} Credentials** window, fill in the required fields (marked with **\***). Fields vary by provider — for example, some ask for just an **API Key**, others for an **API Key** and **API Secret**, and others for a **Client ID** and **Client Secret**.
3. Click **Save credentials**.
Saving replaces any credentials that were already there for that provider. Existing transactions aren't affected, but there's no way to preview the change first or undo it afterward — check the values before you save.
If a provider has no self-serve setup at all, the window instead tells you to reach out to support, with no fields to fill in.
## Update or switch credentials on an already-connected provider
Open the provider's drawer and look at the credentials card on the Overview tab. The card's status label is one of three things: **Connected** (with a sub-label of either "Customer-owned credentials" or "Borderless-managed credentials"), **Not configured**, or **Managed by Borderless**. Which button sits next to it follows from that status:
* If you're already using your own credentials, click **Update credentials** to replace them.
* If Borderless is currently managing the connection for you but self-serve is available, click **Use your own credentials** to take it over.
* If the provider isn't configured yet and self-serve is available, click **Configure credentials**.
* If the provider is fully Borderless-managed with no self-serve option, no button appears — the card shows **Managed by Borderless** with a "Contact us to enable" note underneath.
If a provider is still marked **Coming Soon**, its drawer shows a placeholder card instead of the credentials section, saying "Coming soon" — "We're working on bringing this PFI online. You'll be able to add your credentials once it's available."
## Import transactions that happened outside Borderless
If you process a transaction directly with a provider instead of through Borderless, bring it into your records from the provider's Overview tab:
* **Import Transactions via API** — only appears if you're using your own credentials and the provider supports it. Click it to start a sync; you'll see a toast confirming the sync started, or a note if one's already running.
* **Import Transactions from CSV** — available on any connected provider. Click it to open the import window.
To import from CSV:
1. Click **Download template** if you need the column layout: `externalId, type, status, asset, network, fiat, assetAmount, fiatAmount, exchangeRate, date`.
2. Click **Choose CSV file** and pick your file. Borderless checks it automatically and shows either "*\{N} row(s) ready to import*" or a list of row-level errors.
3. Fix any errors in your file and re-select it, or click **Import** once the check comes back clean.
**Import** stays greyed out until your file has zero errors and at least one valid row — you can't force through a file with bad rows, and an empty or header-only file won't pass either.
## Troubleshooting
**"Unable to load providers. Please try again."**
The Network page failed to load. Refresh the page; if it keeps happening, contact support.
**"No providers available yet."**
Your organization has no providers configured. Contact support to get connected.
**"No providers match your filters." / "No countries match your filters."**
Your filter combination has no results. Click **Clear all filters** to start over.
**"Unable to save credentials. Please try again."**
The credentials didn't save. Double-check the values and retry; if the provider's API rejected a specific field, the error message will say so.
**"Unable to load credentials. Please check back shortly."**
The credentials status couldn't load for a provider. This usually resolves on its own — refresh after a moment.
**Row errors during CSV import**
Each bad row shows as "Row \{n}: \{message}" — and a single row can list more than one message if it fails several checks at once, separated by semicolons. Fix the listed rows in your CSV and re-upload; the exact validation rules per column aren't shown in the platform, so match the error message as closely as possible.
**"Unable to start the sync. Please try again." / "A sync is already in progress for this provider."**
The first means the API import failed to start — retry. The second means a previous sync hasn't finished yet — wait for it before starting another.
# Reconciliation
Source: https://docs.borderless.xyz/platform-guides/reconciliation
Automated verification of your transaction history against every provider.
Reconciliation is what lets a network of providers run as simply as a single provider. Without it, verifying your transaction history means logging in to each provider, exporting its transactions, pulling them into your own tools, and comparing them line by line against your records — for every provider, every time. Borderless is connected to your providers' APIs, so it automates that whole loop: it pulls each provider's own transaction history, compares it against the history in Borderless, and flags anything that needs your attention — discrepancies, missing transactions, and, most commonly, transactions that changed state after reaching a terminal state (a payout that bounces two days later because the receiving account was closed, for example).
Runs happen on overlapping schedules built to catch exactly those asynchronous changes: each day Borderless re-checks the past 7 days, each week the past 30, and each month the past 90. Something that flips state days or weeks after it settled still gets caught by a later, wider pass.
The result is trust-but-verify in one place. You're not taking Borderless's transaction history on faith — reconciliation surfaces the underlying provider data that backs it, across every provider at once. That's what keeps adding providers (for coverage, redundancy, or pricing) from adding operational overhead. This guide covers the Reconciliation Hub, run detail, exceptions, orphaned transactions, and importing transactions from a provider.
## Before you start
Anyone who can see the **Reconciliation** nav item can use everything in the Hub — no separate permission is needed. Importing transaction files is different: that lives on a provider's page in **Network**, and only an organization Owner (or a user with integration permissions) can see or use it. If you don't see the import option described below, that's likely why.
## Open the Reconciliation Hub
1. Click **Reconciliation** in the left nav.
The **Reconciliation** page opens with six stats at the top: **Reconciled**, **Match rate**, **Open exceptions**, **Errors**, **Orphaned**, and **Regressions**. Two are easy to confuse. **Errors** means a provider or infrastructure call failed temporarily — it retries automatically and isn't a real discrepancy. **Exceptions** means an actual mismatch that needs your attention. Don't read a rising error count as a rising problem count.
**Regressions** counts items a slower check (weekly or monthly) later found had gone bad again, after a faster check had already marked them fine.
Below the stats are three tabs: **Runs**, **Exceptions**, and **Orphaned**.
## Review runs
The **Runs** tab is the default view. It lists every run's cadence, status, completion time, and counts for checked, matched, exceptions, errors, and orphans.
Filter by **Cadence** and **From**/**To** date — there's no PFI filter here, since a single run checks transactions across every provider at once. With no filters applied, a highlighted row at the top shows the next scheduled run, labeled **Scheduled** with its expected date. Apply any filter and that row disappears — it doesn't mean nothing else is scheduled, just that it doesn't match your filter.
1. Click any row in the runs table to open that run's detail.
If no runs exist yet, the table reads "No reconciliation runs yet." If your filters return nothing, it reads "No runs match these filters."
There's no button to start a run on demand here — runs happen on their scheduled cadence (Daily, Weekly, Monthly). A "Manual" cadence also appears as a filter option, but this guide doesn't cover how one gets triggered; check with your account team if you need an on-demand run.
## Open a run's detail
A run's detail page shows its provider, start and completion time, and its own six-stat strip — but the labels aren't identical to the Hub's. You'll see **Checked**, **Matched**, **Match rate**, **Exceptions**, **Errors**, and **Orphans**. The Hub's single **Reconciled** tile splits into **Checked** and **Matched** here, and there's no **Regressions** tile on a run's detail page at all.
1. From the run header, click **Export** to download every transaction in the run as a CSV (named `{run-id}-transactions.csv`), with columns for Transaction ID, Type, Status, PFI, source and destination amount/currency, Reconciliation status, and Updated at. A spinner shows on the button while it works — this can take a moment on large runs.
2. Use the three tabs below the header — **Transactions**, **Exceptions**, **Orphaned** — for the run's detail lists. Each loads more rows automatically as you scroll.
3. Click **Back to runs** to return to the Runs tab.
The Exceptions sub-tab reads "No exceptions in this run — everything matched" when the run is clean.
Note: export pulls the full run, but it stops at 20,000 transactions. A run larger than that will export a truncated file with no warning on screen.
## Work the Exceptions tab
The **Exceptions** tab lists every open discrepancy — a transaction whose amount or status doesn't match between Borderless and the provider, or one that only exists on one side.
At the top, four tiles group open exceptions by age: **0–7 days** (tagged Recent), **8–30 days** (Watch), **31–90 days** (Aging), and **90+ days** (Critical). Older items carry more risk — clear those first.
1. Click an age tile to filter the list below to just that bucket. Click it again, or click **Clear age filter**, to remove the filter.
2. Use the filters row — **Cadence**, **From**, **To**, **PFI**, **Status** — to narrow further. **Status** only appears on this tab, with options **Mismatched** and **Missing** (a **PFI Error** option is also listed, but provider errors are tracked under **Errors** rather than as exceptions, so the list always shows Mismatched and Missing items).
Each row shows the transaction, provider (the column is labeled **PFI**), cadence, a plain description of the discrepancy (for example "Amount mismatch" or "Not found in Borderless"), and when it was last checked. Click the transaction ID to jump to that transaction's own record — its detail page also shows the transaction's full reconciliation history, every check that has touched it. A history icon next to an item's status means it regressed — it had previously reconciled cleanly and a later check found it had gone bad again.
If nothing matches your filters, the table reads "No open exceptions match these filters."
There's no manual resolve or dismiss action here — an exception clears on its own once a later reconciliation check finds the two sides now match. There's nothing to click to mark one done.
## Check the Orphaned tab
**Orphaned** lists transactions your provider reported that have no matching record on the Borderless side. Filter by **Cadence**, **From**, **To**, and **PFI** (there's no status filter here).
1. Click any row to open that transaction's own detail page — a summary of the amount flow, the provider's status for it, and the raw data the provider reported it with.
If the list is empty, it shows a generic placeholder message rather than orphan-specific text — an empty tab just means nothing's orphaned right now.
A row here isn't always a true orphan. Transactions you bring in yourself — via CSV import or API sync, described below — land in this same list tagged **Imported** instead of **Orphaned**, with its own tooltip explaining it was brought in from a connected provider rather than found unmatched. Note that CSV-imported transactions aren't reconciled at all (see the import section below). Genuine orphans clear on their own once Borderless later creates a matching record; there's no manual action to take on this tab either.
## Import transactions from a provider
If a provider processed transactions off-platform, you can bring them into Borderless to complete your history and include them in execution benchmarking. This isn't on the Reconciliation page — it's on the provider's own page. There are two paths: syncing via the provider's API (where supported, using your own credentials) or uploading a CSV.
One important distinction: **transactions imported via CSV are not reconciled.** Reconciliation works by re-checking a transaction against the provider's API, and a CSV row has no live counterpart to check — Borderless has no way to fetch its current state. CSV import is for completing your records and benchmarking, not for verification. Where the API sync option exists, prefer it.
1. Go to **Network**, open the provider's drawer, and go to its **Overview** tab.
2. Click **Import Transactions from CSV**. If you don't see this option, you likely need Owner access or integration permissions — see "Before you start" above.
3. In the **Import transactions** modal, click **Download template** if you need the CSV format: a header row (`externalId,type,status,asset,network,fiat,assetAmount,fiatAmount,exchangeRate,date`) with one example row.
4. Click **Choose CSV file** and select your file.
As soon as you pick a file, Borderless validates it automatically — you don't click a separate "validate" button.
* If every row is clean, you'll see "*\{n}* rows ready to import."
* If any row has a problem, you'll see how many rows have errors, followed by a line for each ("Row *\{n}*: ..."). Fix the file and choose it again to re-validate.
5. Once validation passes, click **Import**.
**Import** stays disabled until the most recent validation came back with zero errors and at least one valid row — if it's greyed out, check the validation results above it. A successful import shows a confirmation toast and closes the modal.
Some providers also support importing transactions via API sync instead of a CSV — that option only appears if your organization has configured its own credentials for that provider and the provider supports it. If it's not there, use the CSV path.
## Troubleshooting
**A stats or table section won't load.** Each section fails independently, and a toast such as "Unable to load the reconciliation overview" or "Unable to load reconciliation runs" appears briefly (it auto-dismisses after a few seconds, so you may miss it if you're not looking). If you missed the toast, the section itself won't tell you it failed — the stats strip just keeps spinning, and a failed Runs tab looks identical to "no reconciliation runs yet." If a section seems stuck, refresh the page rather than waiting it out.
**Import says some rows have errors.** The per-row messages under the file picker explain what's wrong with each one. Fix the source file and choose it again; a new file selection re-runs validation.
**Import won't finish importing.** If the import call itself fails after validation passed, you'll see "Unable to import transactions. Please try again." Retry the import.
**API sync won't start.** "Unable to start the sync. Please try again" means the sync call failed — retry it. If you instead see "A sync is already in progress for this provider," wait for the running sync to finish before starting another.
**The Next run row disappeared from the Runs tab.** That's expected once you apply any filter — the forecast row only shows with no filters active. Clear your filters to see it again.
# Refunds
Source: https://docs.borderless.xyz/platform-guides/refunds
How refunds are handled, where returned funds go, and what to keep configured.
When a transaction fails after funds have already moved — a receiving bank rejects the payment, a compliance reversal, an expired transaction — the money comes back. This guide covers how refunds are handled, where the returned funds go, and what to configure so refunds happen without you touching anything.
## How refunds work
Every transaction gets a refund plan when it's created. By default, auto-refund is enabled: if the transaction fails after funds moved, Borderless dispatches the refund automatically and the transaction ends in the **Refunded** status. Refunds are asynchronous — the status updates when the refund completes, and you can follow it on the transaction's detail page like any other state change.
Refund plans can also be dispatched manually — from the transaction's detail page, or through the API if your team wants programmatic control over when refunds go out.
## Where the money goes
A refund plan resolves its destination by hierarchy — the most specific setting wins:
1. A destination set on the refund itself when it's dispatched.
2. A destination set on the individual transaction.
3. Your organization's default refund destination.
Depending on what the provider supports, returned funds can go to a wallet address you specify, back to the original onchain sender, or stay in your balance with the provider. When you nominate addresses, you set one per network — a refund uses the address matching the transaction's network, so a network you haven't given an address for has no default to fall back on.
## Set your default refund destination
The organization default is the safety net — it catches every refund that doesn't specify its own destination. Configure it on the **Team** page under **Organization Settings**: [Organization Administration](/platform-guides/org-administration) covers the steps.
One thing to keep current: the destination needs re-confirming periodically. After **30 days** its badge flags that it's due — refunds still run normally at this point. After **90 days** it lapses, the badge moves to an expired state, and **automatic refunds to the default stop working** until you re-confirm — a two-click task that's worth a recurring reminder for whoever owns it. Only Owners can manage this setting.
## Refund a transaction yourself
Some refunds wait for you rather than going out automatically — a plan created with automatic refunds turned off, or one parked because a fiat payout failed. When a transaction is in that state, a **Refund** button appears on its detail page.
The button only shows when all three of these hold:
* The transaction has **Failed**.
* Its refund plan is ready to be dispatched.
* Your role includes the refund permission for transactions. Owners have it; other roles need it granted.
Confirming sends the refund to the destination already resolved for that transaction — the modal names the address when there is one. The action can't be undone.
The returned amount may differ from the original. Where a failed fiat payout is being returned as crypto, the funds are re-converted at the current rate, so currency movement between the original transaction and the refund is reflected in what arrives.
## See refunds on your transactions
Refunded transactions show the **Refunded** status in the **Transactions** list — filter by status to see them all. Open one for the full picture: the original failure reason and the state timeline.
## Troubleshooting
**A failed transaction hasn't refunded.** Check your default refund destination on the **Team** page first — if its badge shows expired, re-confirm it; automatic refunds don't run while it's lapsed. Then open the transaction: if a **Refund** button is showing, the refund is waiting on you and confirming it will send the funds. If the destination is healthy and no button is offered, contact your Borderless representative with the transaction ID — refunds are asynchronous and some rails take longer than others.
**I don't know where a refund went.** The destination hierarchy above tells you where to look: a transaction-specific destination first, then the organization default. The transaction's detail page shows its state history.
**I want refunds to go somewhere else for one transaction.** Destinations can be set per transaction (and per dispatched refund) through the API — see the Developer Guides. In the platform, the organization default applies.
# RFI Case Management
Source: https://docs.borderless.xyz/platform-guides/rfi-case-management
Manage every provider's requests for information from a single queue.
Providers sometimes need more information about an identity or a transaction before they can act — a request for information, or RFI — and they send those requests by email. Use more than a couple of providers and the requests scatter: different senders, different threads, different inboxes, each needing its own follow-up.
RFI case management collapses all of that into one place. Point every provider at your organization's dedicated RFI inbox address, and each request becomes a case in a single queue — one source of truth across all your providers, with a workflow to respond, attach documents, link the identity or transaction the request is about, and resolve. Like reconciliation, it makes the whole network as easy to operate as a single provider: you stop chasing threads across inboxes.
It's also a place your team works together. Instead of requests buried in individual inboxes, or a separate portal per provider showing only that provider's requests, everyone you invite to the platform sees the same cases, threads, and statuses.
This guide covers pointing your providers at the inbox, replying and attaching files, linking records, and resolving cases.
## Before you start
Cases appear automatically once a provider emails your organization's dedicated RFI inbox address — there's no manual "create case" step. You'll set that up in the first section below. No specific role or permission is required to view, reply to, resolve, or link cases; any authenticated platform user can take these actions.
## Connect a provider
Before a provider's RFI emails will show up in the platform, you need to share your organization's inbox address with them.
1. Go to **Cases** under **RFIS** in the left nav.
2. On the **RFI Cases** page, find the **Connect a provider** card. It reads: "Share this address with your providers so their RFI emails appear here automatically."
3. Click the copy icon next to the address to copy it to your clipboard, then send it to your provider contact.
Once a provider emails that address, a case appears in your list automatically — you don't need to do anything else to create it.
The inbox address's domain reflects the environment you're in — production addresses end in `@rfi.borderless.xyz`, sandbox addresses end in `@sandbox-rfi.borderless.xyz`. If you're comparing addresses across a production and a sandbox organization, expect the domain to differ.
## Find and review cases
The **RFI Cases** page lists every case, provider and Borderless team messages included, with four summary stats at the top: **Total Open**, **Action Required**, **Avg Time to Resolution**, and **Resolved This Week**.
The case table below the stats shows: **CASE ID**, **SUBJECT**, **PROVIDER**, **STATUS**, **MESSAGES**, **CREATED**, and **AGE**. Click anywhere in a row to open that case — there's no separate "view" button.
Each case carries one of four statuses:
| Status | What it means |
| ------------------- | --------------------------------------------------- |
| **New** | The case just came in and hasn't been reviewed yet. |
| **Action Required** | The provider is waiting on your team to respond. |
| **Submitted** | You've replied and it's back with the provider. |
| **Resolved** | The case is closed. |
If there are no cases at all — whether because no provider has emailed the inbox yet or for any other reason — the table reads "No RFI cases yet."
## Case details
Open a case and look at the **Case details** card on the right for a quick reference summary: **Status**, **Case ID** (click to copy it), **Type**, **Provider**, **Created** timestamp, **Age**, **Resolved** timestamp (blank until the case is resolved), and counts for **Messages** and **Attachments**.
**Type** shows one of three values — **Compliance**, **Transaction**, or **Unknown** — reflecting what kind of request the provider sent.
## Reply to a case
1. Open the case from the list. (Use the back arrow in the header to return to **Cases** at any point.)
2. In the **Conversation** card, review the message thread. Each message carries an origin chip — the provider's name with "Team" appended (for example, "Acme Corp Team"), or plain "Provider" if no provider name is on file; "Your team" for your own replies; "Borderless Team" for messages from Borderless staff. Next to the chip you'll also see the actual sender — their email address for provider messages, their name for your team's messages. If a message includes quoted email history, click **Show quoted history** to expand it (or **Hide quoted history** to collapse it again).
3. To open a file a provider or teammate attached, click its chip — this opens the file in a new tab.
4. Under **Reply**, write your response in the text box (placeholder: "Write your reply…"). This field is required.
5. To attach a file, click **Attach**, then choose one or more files. Each one uploads as soon as you select it and shows a spinner while it's uploading.
6. Click **Send reply**.
**Send reply** stays disabled until you've written something and every attached file has finished uploading. If a file fails to upload, its chip turns red and you'll see "Unable to upload this file. Please try again." — remove it (click the "x" on the chip) and try again, or send without it.
A successful reply shows "Reply sent."
## Mark a case as resolved
Click **Mark as resolved** in the case header. The button relabels to **Resolved** and stays disabled once the case is closed.
Resolving isn't permanent: if the provider sends a new message on a resolved case, it reopens automatically. The case detail page notes this directly: "This case is resolved. It will reopen automatically if the provider sends a new message." The **Reply** section stays visible (just disabled) while a case is resolved, rather than disappearing.
A successful resolve shows "Case marked as resolved."
## Link a record to a case
Linking connects a case to the identity or transaction it's about, so your team has full context when replying.
1. On the case detail page, find the **Linked records** card on the right.
2. Click **Link a record**.
3. In the **Record type** field, choose **Identity** or **Transaction**.
4. In the field below it — labeled **Search identities** or **Select a transaction**, depending on your choice in step 3 — search for and select the record. Identity search matches by name as you type.
5. Click **Link record**.
**Link record** stays disabled until you've selected something. A successful link shows "Record linked."
Changing **Record type** clears whatever you'd already selected, so pick the type first.
To remove a link, click the unlink icon on that row in **Linked records**. This removes it immediately — there's no confirmation step. A successful unlink shows "Record unlinked."
If no records are linked yet, the card reads: "No records are linked to this case yet. Link an identity or transaction so your team has full context."
**Linked records** only shows records once they're fully matched — a reference tied to a record that's still ambiguous or unmatched stays invisible in this card, even though it exists behind the scenes. If you expect a link to appear and don't see it, that's the likely reason.
## Troubleshooting
**The case list won't load.**
You'll see "Unable to load RFI cases. Please check back shortly." Refresh the page after a moment. If it persists, contact your Borderless representative.
**A case won't open.**
"Unable to load this RFI case. Please check back shortly." means the same as above — retry shortly.
**"RFI case not found."**
The case may have been removed or the link is wrong. Go back to **Cases** and find it from the list.
**My reply won't send.**
Check that the message body isn't empty and that every attached file has finished uploading (no spinner showing on any chip). If you still get "Unable to send reply. Please check back shortly.", wait and try again.
**An attachment won't download.**
"Unable to download this attachment. Please check back shortly." — retry the click after a moment.
**Resolving or linking a record failed.**
Each of these actions has its own retry-shortly message ("Unable to resolve this case…", "Unable to link this record…", "Unable to unlink this record…"). These are typically transient — try again in a moment.
**The copy button didn't work.**
If copying the inbox address fails, you'll see "Unable to copy the address." — copy it manually by selecting the text instead.
**An inline image, like a logo in an email signature, isn't showing up as an attachment.**
That's expected — inline images render directly in the message body rather than as a separate downloadable file.
# Routing
Source: https://docs.borderless.xyz/platform-guides/routing
Update provider routing without code: defaults, rail overrides, and bulk setup.
Every transaction needs a provider, and there are two ways to pick one. You can name the provider explicitly when creating the transaction — in the UI or through the API — and that choice always wins. Or you can leave it to **default routing**: the rules on this page, which decide the provider for every transaction that doesn't name one.
Default routing is what makes provider changes a configuration edit instead of a code change. If a provider is having downtime and you want to fail over, you don't ship a hotfix renaming the provider in your API requests — you update the routing configuration from provider A to provider B, and every new transaction follows it. No deploy, no engineering involved.
Routing changes apply to newly created transactions; transactions already in flight keep the provider they started with.
This guide covers reading the **Routing** page, setting routes in bulk — the most common workflow, especially right after enabling a new provider — and managing rules one at a time.
## Before you start
Only users with the **Owner** role can add, edit, remove, or bulk-apply routing rules. Other roles can view the Routing page — the country list, drawer, stats, and filters — but won't see any of the buttons described below.
## Find the Routing page
Click **Routing** in the left navigation, under **Network**. The page opens with the header **"Routing"** and the subtitle **"Choose your provider defaults for each corridor."**
Three tiles at the top summarize your setup:
* **Rules** — total number of routing rules configured
* **Countries** — how many countries have at least one rule
* **Providers** — how many distinct providers are used as a default
Below that, countries are grouped by region. Click a region's header row to collapse or expand it.
If you haven't configured anything yet, you'll see **"No routes configured yet."** with the warning **"Every corridor needs a configured route or its transactions will error."** Any corridor without a rule will fail when a transaction tries to use it, so this page isn't just informational — it controls what actually processes.
## Read a country's status at a glance
Each country appears as a card with a colored bar on the left:
* **Orange** — at least one operation your active providers support has no default rule yet. Transactions for that operation will error.
* **Blue** — every operation has a default, but at least one rail-level override is layered on top.
* **Green** — every operation has a default and there are no overrides.
The card also shows the country's flag, name, and ISO code; a rule count (plus an override count, if any); three small icons for Deposit, Withdrawal, and Virtual Account (colored if that operation has a rule, greyed out if not); and up to three provider logos, with a **+N** indicator if more providers are used.
Click a country card to open its drawer and see the full rule list.
## Open a country's rule list
Click any country card. A panel slides in from the right showing the country name, ISO code, and rule count, with an **X** button to close it.
Each row is one operation — Deposit, Withdrawal, or Virtual Account — plus any rail-specific overrides for that operation:
* If a rule exists, you'll see an arrow, then the provider's logo or name, followed by edit and remove icon buttons.
* If a row is a rail-level override (for example, a rule that only applies to SEPA), it shows the rail name and an **OVERRIDE** tag. The rail-level rule takes precedence over the country/operation default for transactions on that rail.
* If no default exists yet for that operation, you'll see an orange shield icon and **"No default set"**.
## Set routes in bulk
Use this to turn a provider on across many countries in one pass, rather than adding rules country by country. This is the usual workflow when you've just enabled a provider: it likely covers more than one country, and a single bulk pass routes everything it supports.
1. On the Routing home page, click **Set routes in bulk**.
2. Choose a **Provider**. Only providers with active status appear. Until you pick one, the modal shows **"Select a provider to see the routes you can configure."**
3. A chip list of countries the provider supports appears, all selected by default. Use **Select all** or **Clear** to adjust, or click individual chips.
4. Under **Apply to**, choose **"New routes only"** to skip corridors already routed to a different provider, or **"All — replace existing"** to include and overwrite them.
5. Under **Direction**, filter the corridor list by **All**, Deposit, Withdrawal, or Virtual Account.
6. Check the boxes for the corridors you want this provider to handle. Each row shows a status:
* **"No route configured"** — nothing is set yet.
* **"Replaces \{ProviderName}"** — a different provider currently handles this corridor. Only selectable in **"All — replace existing"** mode.
* **"Already routed here"** — this provider is already the default. It's checked by default. If the row is backed by a rail-specific override, unchecking it removes that override. If it's backed by the country-level default and the operation has more than one rail row, unchecking just one of them leaves the country-level rule in place — you need to uncheck every row for that operation to remove it, and nothing tells you a partial uncheck didn't take effect.
7. Check the summary banner — it reads **"Apply \{n} change(s) for \{Provider} — …"** with the route and country-default counts.
8. Click **Apply \{n} change(s)**.
The button stays disabled until you've staged at least one change. On success, you'll see **"Routing rules updated."**
In **"New routes only"** mode, corridors already routed to another provider show their **"Replaces X"** badge but aren't selectable — double-check that mode if you expect full coverage across a region and some corridors are still on another provider.
## Add a routing rule
You can start this from two places: the **Add Rule** button on the Routing home page, or **Add rule for \{Country}** inside a country's drawer (the second option pre-fills the country for you).
1. Click **Add Rule** (or **Add rule for \{Country}**).
2. If the country field is empty, choose a country. Only countries your active providers actually support appear in this list — you can't create a rule for a country/provider combination that isn't live.
3. Under **Operations**, select one or more of Deposit, Withdrawal, or Virtual Account.
4. Optionally set **Rail** to narrow the rule to a specific rail (for example SEPA). Leave it on **"Any rail"** to set the country-level default. If you selected Virtual Account, the rail field is disabled and shows **"Not used for Virtual Account"** — virtual accounts don't have a rail.
5. Choose a **Provider**. Only providers that can handle every operation you selected, for that country and rail, appear here. If none qualify, the field shows **"No active provider supports this"** — try removing an operation or rail to widen the options.
6. Click **Add rule**.
If you selected more than one operation, this creates one separate rule per operation, all pointing to the same provider and rail — not a single combined rule. A success toast reads **"Routing rule saved."**
## Edit a routing rule
Click the edit icon on any rule row in the country drawer. The modal opens with the title **"Edit Routing Rule"**.
You can only change the provider. Country, operations, and rail are locked — to change what a rule applies to, delete it and add a new one instead. Click **Save changes** to confirm. You'll see **"Routing rule saved."** on success.
## Remove a routing rule
Click the remove icon on a rule row. A confirmation modal titled **"Remove Routing Rule"** asks you to confirm, naming the country, operation, and rail (if any). Click **Remove** to delete it.
You'll see **"Routing rule removed."** on success. This can't be undone — there's no restore option. Once removed, that operation reverts to having no default (or falls back to the country-level default, if the deleted rule was a rail-specific override).
## Search and filter
A search box above the country grid lets you type to match rules, countries, rails, currencies, or providers directly — its placeholder reads **"Search rules, countries, rails, currencies, providers…"**. Below it, six controls narrow the list further:
* **Country**, **Currency**, **Rail**, **Asset**, and **Provider** — each a multi-select; pick as many values as you need in any of them.
* **Direction** — a tab group with **Any**, **Deposit**, **Withdrawal**, and **Virtual Account**; select one to narrow the grid to countries with routing coverage for that operation.
All of these combine — searching text while filters are set narrows to countries matching every condition at once. If no countries match, you'll see **"No countries match your filters."** with a **Clear all filters** link. A **Clear** button also appears next to the search box whenever any filter is active.
## Troubleshooting
**"No default set" next to an operation.** That operation has no rule yet for this country. Add one with **Add rule for \{Country}** or through **Set routes in bulk**.
**Orange bar on a country card.** Same issue, shown at the country level — at least one supported operation has no default. Add a rule to fix it before transactions on that operation error.
**"No active provider supports this" in the Provider field.** No active provider can handle every operation and rail you selected together. Try selecting fewer operations, or leave the rail on **"Any rail"**.
**"No corridors match the current selection" in the bulk modal.** Adjust the Direction filter or the countries you've selected — there's nothing left to show for the current combination.
**Unable to load, save, or apply changes.** You will see a toast: **"Unable to load routing defaults. Please check back shortly."**, **"Unable to save routing rule. Please try again."**, **"Unable to update routing rules. Please try again."**, or **"Unable to remove routing rule. Please try again."** depending on which action failed. Retry the action; if it keeps failing, contact your Borderless representative.
**I removed the wrong rule.** There's no undo. Add the rule again with the same country, operation, rail, and provider.
**I need to change what a rule applies to, not just its provider.** Editing only changes the provider. Delete the rule and create a new one with the country, operations, and rail you want.
# Wallets
Source: https://docs.borderless.xyz/platform-guides/wallets
Bring your own wallet infrastructure: link addresses, connect Utila or Dfns, and find settlement instructions.
Borderless works with any wallet — you bring your own wallet infrastructure, and Borderless never holds your funds or signs transactions on your behalf. The only wallets in any flow are yours. This guide covers how to link your wallets to Borderless accounts, how to connect an integrated wallet platform (Utila or Dfns), and where to find the address or instructions when it's time to move funds.
## The two ways to connect a wallet
**Bring any wallet.** In the standard setup, you link a public chain wallet address to each asset on your account. When a transaction needs funds from you, Borderless shows you the destination — a settlement address from the provider — and you send from your own wallet. Any wallet works: an exchange account, a custodian, a self-hosted wallet, MPC infrastructure. It doesn't matter what you use.
**Integrate your wallet platform.** If you run your wallet infrastructure on **Utila** or **Dfns**, you can connect it to Borderless directly. Instead of copying a settlement address out of Borderless and pasting it into your wallet platform, Borderless tees the transaction up in your wallet infrastructure for you: you create the transaction in Borderless, then see it waiting in your wallet platform for signing and approval. Borderless connects with credentials that can only initiate — it never has the ability to sign transactions or send funds. The integration removes the copy-paste step (and the human error that comes with it), and lets you reference your platform's vault and wallet IDs instead of raw chain addresses.
## Link a wallet address to an account
How you link depends on your organization's wallet setup:
* **Standard (any wallet):** on the account page, click **Add Asset**, pick the asset, and fill in **Blockchain address** — the public chain address for that asset. Each asset on the account gets its own linked address.
* **Utila:** the linkage happens at account creation. In the **Create Account** modal, enter your Utila **Vault ID**; **Wallet ID (optional)** links an existing Utila wallet, or leave it blank and Borderless creates a new Utila wallet in that vault and connects it automatically. Adding assets afterward needs no address at all — they resolve through the vault.
* **Dfns:** on the account page, click **Add Asset**, pick the asset, and enter the **DFNS wallet ID** for it.
## Connect Utila or Dfns
The integration lives on the **Developer Settings** page and requires the **Enable Integrations** permission (Owners have it by default). A status indicator on the card shows **Enabled** or **Disabled**.
* **Utila Integration** — fill in **Utila Service Account**, **Utila Private RSA Key**, and optionally **Utila EVM Gas Wallet**, then click **Setup Integration** (or **Update Configuration** if it's already connected). A **View setup guide** link on the card walks through generating these in Utila.
* **Dfns Integration** — fill in **Dfns App ID** and **Dfns Auth Token**, then **Setup Integration** / **Update Configuration**. Its **View setup guide** link covers the Dfns side.
These credentials let Borderless initiate transactions into your wallet platform — signing and approval always stay in your platform, under your own policies.
## Send funds for a transaction
When a transaction is waiting on funds from you, its detail page shows an instructions card while the transaction is **Pending**.
* **Onchain (withdrawals):** the card lists **Amount**, **Asset**, **From Address**, and **To Address** — the settlement address from the provider. Click any row to copy its value, use the copy icon to copy all instructions at once, or download them as a PDF. Send the exact amount to the **To Address** from your linked wallet. If your organization is on the standard setup, a **Connect Wallet** option may also appear on supported networks — connect the linked wallet and send directly from the platform instead of copying the address.
* **Fiat (deposits):** the card lists bank details — account holder, IBAN or account number, bank name and address, and a **Deposit Message** code. Include the deposit message in your payment's memo; without it, the payment can't be matched to your transaction.
If your organization uses the Utila or Dfns integration, there's nothing to copy: the transaction appears in your wallet platform's queue for approval, and once it's signed and sent there, the Borderless transaction moves forward on its own.
After the pending stage, the same details remain available on the transaction's detail page under **Settlement Instructions**.
## Troubleshooting
**"The connected wallet address does not match the account address."** The wallet you connected isn't the one linked to this account's asset. Switch your wallet to the linked address, or connect the right wallet.
**"Wallet transfers are not supported in the Sandbox environment..."** Expected — in sandbox, you don't need to actually move funds for a transaction to process.
**Deposit, Withdrawal, or Create Account buttons are missing entirely.** Transaction actions only appear once your organization's wallet setup is configured. If none of these buttons show anywhere, contact your Borderless representative to check your organization's wallet provider configuration.
**"Unable to setup Utila integration..." / "Unable to setup Dfns integration..."** The credentials didn't save. Re-check each value against your wallet platform (the setup guide linked on the card shows where each one comes from) and try again.
**A fiat deposit isn't matching.** Confirm the payment included the **Deposit Message** code in its memo and that the amount sent matches the instructions exactly.