Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.nuvion.co/llms.txt

Use this file to discover all available pages before exploring further.

Nuvion supports three ways to accept payments from your users: directly into provisioned account details shared with the payer, a hosted bank transfer checkout that handles the full authentication flow, and a direct card payment API for platforms that want to collect card details themselves.

Accept via account details

Entities can receive funds directly into their Nuvion account using provisioned banking coordinates — no hosted checkout or payment session required. Share the account details with your payer and Nuvion notifies you via webhook when funds arrive.
Provision account details for an entity’s account using POST /account-details. Use asset_type: fiat for banking coordinates or asset_type: stablecoin for a wallet address. See Account Details for the full guide.

How it works

  1. Provision account details for the entity (POST /account-details, asset_type: fiat or stablecoin).
  2. Share the returned banking coordinates — account number, sort code or routing number, BIC/SWIFT — with the payer.
  3. The payer initiates a bank transfer from their own bank to those coordinates.
  4. Nuvion credits the entity’s account and fires inflows.completed.

Webhook: inflows.completed

Listen for inflows.completed to be notified when funds arrive. This is the authoritative signal that the account has been credited.
{
  "event": "inflows.completed",
  "data": {
    "id": "01K6ZXCNMVA04GM3WQRCKQNCMB",
    "amount": 10000,
    "currency": "USD",
    "unique_reference": "01K6ZX7360026KPNA2SQ6NPNZY-1759504425996",
    "counterparty_id": "acct-01K6ZX7360026KPNA2SQ6NPNZY",
    "account_id": "acc_01HXYZ5678EFGH",
    "entity_id": "ent_01HXYZ1234ABCD",
    "status": "successful",
    "status_reason": "Successful.",
    "narration": "Invoice payment received",
    "type": "inflow",
    "applicable_fee": 0,
    "meta": {},
    "created": 1759860119195,
    "updated": 1759860119195
  }
}
id
string
Unique identifier for the inflow transaction.
amount
number
Amount received in the smallest currency unit. e.g. 10000 = $100.00 USD.
currency
string
ISO 4217 currency code of the received funds.
unique_reference
string
Idempotency reference for the transaction. Use this to deduplicate webhook deliveries.
counterparty_id
string
Identifier for the sender’s account.
account_id
string
The ID of the Nuvion account that was credited.
entity_id
string
The ID of the entity whose account was credited.
status
string
Always successful for this event.
narration
string
Payment reference provided by the sender.
applicable_fee
number
Fee applied to the inflow in the smallest currency unit.
type
string
Always inflow.

Open Banking

Nuvion hosts the bank transfer checkout page. Your server creates a funding session, redirects the user to the hosted URL, and receives a webhook when funds settle. Supported currencies: GBP, EUR

Create a funding session

curl -X POST https://api.nuvion.dev/v1/funding-sessions \
  -H "Authorization: Bearer $NUVION_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 10000,
    "currency": "GBP",
    "account_id": "acc_01HXYZ5678EFGH",
    "redirect_url": "https://yourplatform.com/checkout/complete",
    "unique_reference": "order-2025-001",
    "narration": "Payment for Order #1042"
  }'
amount
number
required
Amount in the smallest currency unit. 10000 = £100.00 GBP. Minimum: 1.
currency
string
required
ISO 4217 currency code. One of GBP, EUR.
account_id
string
required
The ID of the account to credit when the payment settles.
redirect_url
string
required
HTTPS URL to redirect the user to after they complete or abandon the checkout. Must use HTTPS.
unique_reference
string
required
A unique idempotency key for this session. 1–255 characters. Submitting a duplicate reference returns a 409 with the original session’s payment_id.
narration
string
Display text shown to the user on the checkout page. Max 255 characters.
country_code
string
ISO 3166-1 alpha-2 country code of the payer. e.g. GB, DE. Used to tailor the checkout experience to the payer’s country.
meta
object
Optional key-value metadata to attach to the session.
{
  "payment_id": "fps_01HXYZ9012MNOP",
  "checkout_url": "https://checkout.nuvion.co/pay/fps_01HXYZ9012MNOP",
  "amount": 10000,
  "currency": "GBP",
  "account_id": "acc_01HXYZ5678EFGH",
  "status": "awaiting_user",
  "unique_reference": "order-2025-001",
  "expires_at": 1735729200000,
  "created": 1735725600000,
  "updated": 1735725600000
}

Redirect the user

Redirect your user to the checkout_url returned in the response. Nuvion handles bank authentication, authorisation, and error states on the hosted page.
Checkout URLs expire. Check expires_at and regenerate the session if the user returns after expiry.

Handle the return

When the user completes or abandons the checkout, they are redirected to your redirect_url. Do not treat the redirect as confirmation of payment — always verify status via webhook or API.
Never fulfil an order based on the redirect alone. Always confirm status via the funding_session.updated webhook or by fetching the session.

Check session status

curl https://api.nuvion.dev/v1/funding-sessions/fps_01HXYZ9012MNOP \
  -H "Authorization: Bearer $NUVION_API_KEY"

Funding session statuses

StatusTerminalDescription
awaiting_userNoSession created, user has not started
processingNoUser has initiated the bank transfer
pending_settlementNoTransfer accepted by the bank, awaiting settlement
settledYesFunds credited to the account
failedYesTransfer rejected by the bank
expiredYesSession expired before the user completed payment
cancelledYesSession was cancelled
When failed, the response includes a failure_code:
CodeRetryableReason
insufficient_fundsYesPayer account has insufficient funds
bank_rejectedYesBank rejected the transfer
account_closedNoPayer account is closed
authorization_revokedNoAuthorisation was revoked
provider_errorYesInternal provider error

Webhook

Listen for funding_session.updated to receive real-time status changes. Nuvion retries webhook delivery for 72 hours with exponential backoff.

Accept via card

Nuvion’s card payment flow uses a Payment Intent and an Intent Action. Create a Payment Intent to declare the charge, then submit an Intent Action to confirm the payment.

Step 1: Create a payment intent

A Payment Intent represents your intent to charge a card. No funds are moved at this stage.
curl -X POST https://api.nuvion.dev/payment-intents \
  -H "Authorization: Bearer $NUVION_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "currency": "USD",
    "amount": 5000,
    "account_id": "acc_01HXYZ5678EFGH",
    "reference": "order_abc123",
    "description": "Order #1042"
  }'
currency
string
required
ISO 4217 currency code. e.g. USD.
amount
number
required
Amount in the smallest currency unit. 5000 = $50.00 USD.
account_id
string
required
The ID of the account to credit on successful charge.
reference
string
required
Your unique internal order or transaction reference.
description
string
A human-readable payment description. Maximum 250 characters.
intent_action
object
Optional confirmation details. Include this when you want to create the Payment Intent and submit the card payment in the same request.
{
  "id": "01HXYZ7K3M9PQRST4UVWXY2Z6",
  "currency": "USD",
  "amount": 5000,
  "reference": "order_abc123",
  "description": "Order #1042",
  "status": "requires_action",
  "entity_id": "ent_01HXYZ1234ABCD",
  "account_id": "acc_01HXYZ5678EFGH",
  "created": 1735725600000
}
The intent is created with status: requires_action. No charge happens until you submit an Intent Action.

Create and confirm in one request

If your server already has the encrypted card payload, you can include intent_action when creating the Payment Intent.
curl -X POST https://api.nuvion.dev/payment-intents \
  -H "Authorization: Bearer $NUVION_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "currency": "USD",
    "amount": 5000,
    "account_id": "acc_01HXYZ5678EFGH",
    "reference": "order_abc124",
    "description": "Order #1043",
    "intent_action": {
      "action": "confirm",
      "category": "collections",
      "payment_type": "card-acq",
      "payment_type_data": {
        "data": "<base64_encrypted_card_data>",
        "billing_address": {
          "address_line_one": "350 Fifth Avenue",
          "city": "New York",
          "state": "NY",
          "country": "US"
        },
        "auth_model": "3ds_disabled"
      },
      "customer": {
        "first_name": "Ada",
        "last_name": "Lovelace",
        "email": "ada@example.com"
      }
    }
  }'
{
  "id": "01HXYZ7K3M9PQRST4UVWXY2Z7",
  "currency": "USD",
  "amount": 5000,
  "reference": "order_abc124",
  "description": "Order #1043",
  "status": "completed",
  "entity_id": "ent_01HXYZ1234ABCD",
  "account_id": "acc_01HXYZ5678EFGH",
  "created": 1735725600000,
  "intent_action": {
    "id": "01HACT9012EFGI",
    "currency": "USD",
    "amount": 5000,
    "applicable_fee": 75,
    "charge_amount": 5000,
    "refunded_amount": 0,
    "reference": "order_abc124",
    "action": "confirm",
    "category": "collections",
    "payment_type": "card-acq",
    "payment_type_data": {
      "auth_model": "3ds_disabled",
      "payment_country": "US",
      "last_four_digits": "1111",
      "card_brand": "visa",
      "card_type": "credit"
    },
    "status": "completed",
    "entity_id": "ent_01HXYZ1234ABCD",
    "account_id": "acc_01HXYZ5678EFGH",
    "payment_intent_id": "01HXYZ7K3M9PQRST4UVWXY2Z7",
    "created": 1735725600000
  }
}

Step 2: Submit an intent action

Submit the card payment using POST /intent-actions with payment_type set to card-acq and the encrypted card payload in payment_type_data.data. See Card data encryption for how to create this value.
payment_intent_id
string
required
The ID of the Payment Intent to charge against. The intent must still have status: requires_action.
intent_action.action
string
required
Always confirm.
intent_action.category
string
required
Always collections.
intent_action.payment_type
string
required
The payment method. Use card-acq for card payments.
intent_action.payment_type_data.data
string
required
Base64-encoded RSA-OAEP SHA-256 encrypted card object.
intent_action.payment_type_data.billing_address
object
required
Cardholder billing address.
intent_action.payment_type_data.auth_model
string
Card authentication model. One of 3ds_required or 3ds_disabled. Defaults to 3ds_required.
intent_action.payment_type_data.browser_info
object
Browser data used for 3DS authentication. Required unless auth_model is 3ds_disabled.
intent_action.customer
object
required
Cardholder identity details.
intent_action.return_url
string
URL to redirect the cardholder to after 3DS completes. Required unless auth_model is 3ds_disabled.

Without 3DS

Use this path when the card does not require strong customer authentication.
curl -X POST https://api.nuvion.dev/intent-actions \
  -H "Authorization: Bearer $NUVION_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "payment_intent_id": "01HXYZ7K3M9PQRST4UVWXY2Z6",
    "intent_action": {
      "action": "confirm",
      "category": "collections",
      "payment_type": "card-acq",
      "payment_type_data": {
        "data": "<base64_encrypted_card_data>",
        "billing_address": {
          "address_line_one": "350 Fifth Avenue",
          "city": "New York",
          "state": "NY",
          "country": "US",
          "zip": "10001"
        },
        "auth_model": "3ds_disabled"
      },
      "customer": {
        "first_name": "Ada",
        "last_name": "Lovelace",
        "email": "ada@example.com"
      }
    }
  }'
{
  "id": "01HACT9012EFGH",
  "currency": "USD",
  "amount": 5000,
  "applicable_fee": 75,
  "charge_amount": 5000,
  "refunded_amount": 0,
  "reference": "order_abc123",
  "action": "confirm",
  "category": "collections",
  "payment_type": "card-acq",
  "payment_type_data": {
    "auth_model": "3ds_disabled",
    "payment_country": "US",
    "last_four_digits": "1111",
    "card_brand": "visa",
    "card_type": "credit"
  },
  "status": "completed",
  "entity_id": "ent_01HXYZ1234ABCD",
  "account_id": "acc_01HXYZ5678EFGH",
  "payment_intent_id": "01HXYZ7K3M9PQRST4UVWXY2Z6",
  "created": 1735725600000
}

With 3DS

3DS is the default card authentication model. If you omit auth_model, Nuvion treats the payment as 3ds_required, and browser_info becomes required. If the issuer requires customer interaction, the response returns status: pending_user_action, requires_action: true, and a next_action.url to redirect the cardholder to.
curl -X POST https://api.nuvion.dev/intent-actions \
  -H "Authorization: Bearer $NUVION_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "payment_intent_id": "01HXYZ7K3M9PQRST4UVWXY2Z6",
    "intent_action": {
      "action": "confirm",
      "category": "collections",
      "payment_type": "card-acq",
      "payment_type_data": {
        "data": "<base64_encrypted_card_data>",
        "billing_address": {
          "address_line_one": "350 Fifth Avenue",
          "city": "New York",
          "state": "NY",
          "country": "US"
        },
        "browser_info": {
          "accept_header": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
          "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)",
          "java_enabled": false,
          "javascript_enabled": true,
          "language": "en-US",
          "color_depth": "24",
          "screen_height": "900",
          "screen_width": "1440",
          "timezone_offset": "-300"
        }
      },
      "customer": {
        "first_name": "Ada",
        "last_name": "Lovelace",
        "email": "ada@example.com"
      },
      "return_url": "https://yourplatform.com/checkout/complete"
    }
  }'
{
  "id": "01HACT9012EFGH",
  "currency": "USD",
  "amount": 5000,
  "applicable_fee": 75,
  "charge_amount": 5000,
  "refunded_amount": 0,
  "reference": "order_abc123",
  "action": "confirm",
  "category": "collections",
  "payment_type": "card-acq",
  "payment_type_data": {
    "auth_model": "3ds_required",
    "payment_country": "US",
    "last_four_digits": "1111",
    "card_brand": "visa",
    "card_type": "credit"
  },
  "status": "pending_user_action",
  "entity_id": "ent_01HXYZ1234ABCD",
  "account_id": "acc_01HXYZ5678EFGH",
  "payment_intent_id": "01HXYZ7K3M9PQRST4UVWXY2Z6",
  "return_url": "https://yourplatform.com/checkout/complete",
  "requires_action": true,
  "next_action": {
    "type": "redirect_to_url",
    "url": "https://checkout.nuvion.co/card/01HACT9012EFGH"
  },
  "created": 1735725600000
}
Redirect the cardholder to next_action.url. After authentication, Nuvion redirects the cardholder to return_url. Do not treat the redirect as proof of payment; confirm completion from the payment intent status or webhook.

Step 3: Check payment status

Use GET /payment-intents/{id} to check the latest status after redirect or while waiting for a webhook.
curl https://api.nuvion.dev/payment-intents/01HXYZ7K3M9PQRST4UVWXY2Z6 \
  -H "Authorization: Bearer $NUVION_API_KEY"
{
  "id": "01HXYZ7K3M9PQRST4UVWXY2Z6",
  "currency": "USD",
  "amount": 5000,
  "reference": "order_abc123",
  "description": "Order #1042",
  "status": "completed",
  "entity_id": "ent_01HXYZ1234ABCD",
  "account_id": "acc_01HXYZ5678EFGH",
  "created": 1735725600000
}

Apple Pay

For Apple Pay, set intent_action.payment_type to applepay-acq. Apple Pay does not use payment_type_data.data, full billing address fields, or card encryption in this request. The only required billing field is payment_type_data.billing_address.country.
curl -X POST https://api.nuvion.dev/intent-actions \
  -H "Authorization: Bearer $NUVION_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "payment_intent_id": "01HXYZ7K3M9PQRST4UVWXY2Z6",
    "intent_action": {
      "action": "confirm",
      "category": "collections",
      "payment_type": "applepay-acq",
      "payment_type_data": {
        "billing_address": {
          "country": "US"
        }
      },
      "customer": {
        "first_name": "Ada",
        "last_name": "Lovelace",
        "email": "ada@example.com"
      },
      "return_url": "https://yourplatform.com/checkout/complete"
    }
  }'

Payment intent statuses

StatusDescription
requires_actionIntent created — no action submitted yet
processingIntent action is being processed
completedCharge successful
cancelledIntent cancelled before completion
failedPayment could not be completed — check status_reason

Intent action statuses

StatusDescription
pendingAction created and being processed
pending_user_actionAwaiting 3DS completion from the cardholder
completedCharge successful
failedCharge declined or failed

Webhooks

Use Payment Intent webhooks as the final confirmation that a card payment succeeded, failed, or was cancelled. This is especially important after a 3DS redirect, because the redirect only tells you the customer returned to your site.
EventTrigger
payment_intent.completedCharge successful — funds credited to the account
payment_intent.failedCharge declined or failed
payment_intent.cancelledPayment Intent cancelled before confirmation
Webhook payloads use Nuvion’s standard webhook envelope:
{
  "event": "payment_intent.completed",
  "data": {
    "id": "01HXYZ7K3M9PQRST4UVWXY2Z6",
    "currency": "USD",
    "amount": 5000,
    "reference": "order_abc123",
    "description": "Order #1042",
    "status": "completed",
    "entity_id": "ent_01HXYZ1234ABCD",
    "account_id": "acc_01HXYZ5678EFGH",
    "created": 1735725600000
  }
}
Return a 2xx response after receiving the webhook. If delivery fails, Nuvion retries with exponential backoff. See Webhooks for delivery and retry details.

What’s next

Send a payout

Send funds from an account to any bank account globally.

Stablecoins

Accept USDC and USDT via a provisioned wallet address.

Payment Intents API reference

Full endpoint documentation for payment intents and intent actions.