1. Home
KuvarPay API
  • Overview
  • SDK Integration Guide
  • Webhooks Integration Guide
  • Subscriptions Guide
  • Split Payment Guide
  • Pay KuvarSend Users (Account Linking)
  • Transactions
    • Calculate Payment Amount
      POST
    • Create Transaction
      POST
    • Get Transactions Details
      GET
    • Get Transactions
      GET
    • Get Transaction Status by Reference
      GET
    • Simulate payment for sandbox transactions
      POST
    • Get detailed payment status for a transaction
      GET
    • Manually trigger refund for excess payment
      POST
    • Get list of expired transactions
      GET
  • Checkout Sessions
    • Payment Status Webhook
      POST
    • Create Checkout Session
      POST
    • Get Checkout Session
      GET
  • Transfer Fees
    • Get Optimal Transfer Fee
      GET
    • Get Transfer Fee
      GET
    • Get currencies supported for transfers
      GET
  • Sandbox Simulator
    • Start the sandbox transaction simulator
      POST
    • Stop the sandbox transaction simulator
      POST
    • Force Simulator Scenario
      POST
    • Get Simulator Status
      GET
    • Force Transaction Status
      POST
    • Update simulator configuration
      PUT
    • Get Pending Transactions
      GET
    • Reset Sandbox Transactions
      POST
  • Invoices
    • Create a new invoice
    • Send invoice email to customer
  • Payment Links
    • Create a new payment link
  • Server-Sent Events (SSE)
    • Get Transaction Details
    • Get Session Details
    • Get Health
  • Subscriptions
    • Create Plans
    • Get Plans
    • Get Plans Details
    • Update Plans Details
    • Create Prices
    • Get Prices
    • Update Prices Details
    • Create Checkout Sessions
    • Get Checkout Sessions Details
    • Confirm Subscription Checkout
    • Create Subscriptions
    • Get Subscriptions
    • Get Subscriptions Details
    • Update Subscriptions Details
    • Delete Subscriptions Details
    • Confirm Subscription Cancellation
    • Renew Subscription
    • Upgrade Subscription
    • Downgrade Subscription
    • Renew Subscription Authorization
    • Create Subscription Invoices
    • Get Subscription Invoices
    • Create Metered Invoices
    • Get Subscription Invoices Details
    • Get Charge Attempts
    • Charge Subscription Invoice
    • Create Authorizations
    • Revoke Relay Authorization
    • Get Relay Authorization Status
  • Currencies
    • Get Subscription Currencies
    • Get networks supported for subscription payments
    • Get Currencies
    • Get all supported networks
    • Get Item Details
    • Get Supported Currencies
    • Get currency statistics
  • Subaccounts
    • Create Subaccount
    • List Subaccounts
    • Get Subaccount Details
    • Update Subaccount
    • Delete Subaccount
  • Banks
    • List supported banks
    • Resolve bank account
    • List banks by currency
  • Payment Fiat Rates
    • Get Item Details
    • Create Batch
    • Get Item Details
    • Get Currencies
    • Get Item Details
    • Get Fiat Rate Details
    • Get Fiat Rates
    • Create Update Ngn
    • Create Update All
    • Get Item Details
  • Split Payments
    • Create Split Group
    • List Split Groups
    • Get Split Group Details
    • Update Split Group
    • Delete Split Group
  • Fiat
    • List fiat payment methods
    • Resolve a payout recipient
    • Preview a fiat collection price
    • Create a fiat payout
    • Get payout status
  • KuvarSend Payouts
    • Create a KuvarSend account-link request
    • Exchange an approved authorization for a linked account
    • List linked KuvarSend accounts
    • Get a linked KuvarSend account
    • Revoke a linked KuvarSend account
    • Quote a KuvarSend payout
    • Pay a linked KuvarSend wallet
    • List KuvarSend payouts
    • Get a KuvarSend payout
    • Read the branding of an account-link request
  • Schemas
    • ErrorResponse
    • KuvarSendError
    • CreateInvoiceRequest
    • CreatePaymentLinkRequest
    • KuvarSendLinkedAccount
    • InvoiceResponse
    • PaymentLinkResponse
    • KuvarSendPayout
    • CreateInvoiceResponse
    • CreatePaymentLinkResponse
    • SendInvoiceEmailRequest
    • SendInvoiceEmailResponse
    • SubscriptionInvoice
Home
Home
  1. Home

Pay KuvarSend Users (Account Linking)

Pay a KuvarSend user directly — account linking and linked payouts#

Audience: merchant developers integrating KuvarPay.
Base URL: https://payment.kuvarpay.com
Status: LIVE mode only. There is no sandbox for this product (see Environments).

1. What this is, in plain English#

Normally, paying someone means collecting their bank or mobile-money details, then sending money over a payout rail and waiting for it to settle.
This product removes that. If your user has a KuvarSend account, they can authorize your business once — the same way they'd connect an account with "Sign in with…" — and from then on your backend can credit their KuvarSend wallet with a single API call. No account numbers, no rail, no waiting.
Two things happen in that authorization:
1.
You never learn who they are on KuvarSend. You get back an opaque id such as kal_9f2c…. That is your payout destination. You never receive their KuvarSend user id, phone number, or balance.
2.
They control it. The user approves in the KuvarSend app with their PIN, and can revoke you at any time from the app. So can you, from your backend.
When you send a payout:
Your KuvarPay balance is debited, in its own currency (for example NGN if your business balance is in NGN).
The user is credited in the currency you named (for example NGN), in their KuvarSend wallet.
It is instant and final. A 201 response means the money has already moved. There is no "pending" state to poll and no reversal API.
The name of the thing: the authorization is an account link (kal_…). The money movement is a linked payout (kwp_…).

2. Do you need approval before you can use this?#

Yes — an admin must approve your business first, and one commercial setting is admin-only. Here is exactly what is gated and by whom:
RequirementWho controls itHow you get it
Business verification approvedKuvarPay admin — a human reviews your business documentsSubmit your business documents in the dashboard, then wait for review. This is the approval gate.
KYC verifiedYou — completed in the dashboardComplete KYC in the dashboard
"Merchant-initiated payouts" switched onYou — self-serve, but the button only unlocks after the two rows above are greenDashboard → Settings → Developers → Account Linking → Enable payouts
A registered HTTPS callback URIYou — self-serveDashboard → Settings → Developers → Account Linking → Registered callbacks
A LIVE secret key with the four payout scopesYou — self-serveDashboard → Settings → Developers → API Keys → tick "KuvarSend account linking and payouts"
Your server IPs on the payout allowlistYou — self-serveDashboard → Settings → Developers → Whitelisted Domains/IP → Payout IP allowlist
Please contact support (support@kuvarpay.com, or the Support section of your dashboard) if:
your business verification is still pending and you want to start integrating;
the destination currency you need is rejected with PAYOUT_CURRENCY_UNAVAILABLE;
you need help with the go-live checklist below.
If something is missing, every endpoint in this guide answers 403: ACCOUNT_LINK_NOT_ALLOWED — "Account linking is not enabled." — while the account is not yet eligible, ACCOUNT_LINK_LIVE_ONLY if you used a sandbox key, and an AUTH_004 "Insufficient permissions" error if your IP is not on the payout allowlist. ACCOUNT_LINK_NOT_ALLOWED does not say which requirement is outstanding, so work through the checklist below.

3. Setup checklist#

Work top to bottom. Steps 1–2 are gated on the admin approval above. The Developers settings are visible to team members with the Owner, Admin or Developer role; ask your dashboard owner if you cannot see them.
1.
Business verified and KYC approved. Dashboard → Settings. Business verification is reviewed by a KuvarPay admin.
2.
Enable merchant-initiated payouts. Dashboard → Settings → Developers → Account Linking → Linked-wallet payout access → Enable payouts.
3.
Register your callback URI. Same page, Registered callbacks. The URI must be:
https:// — no http, no localhost, no IP address;
an exact URL — no wildcards, no query string, no fragment, no username/password;
matched byte for byte at request time. https://app.example.com/kuvarsend/callback and https://app.example.com/kuvarsend/callback/ are different URIs.
4.
Create a LIVE secret key with the four scopes: account_links:read, account_links:write, payouts:read, payouts:write. Dashboard → Settings → Developers → API Keys → tick "KuvarSend account linking and payouts". The scopes are granted to the secret key only (rsp_secret_…); your publishable/client key can never move money.
5.
Whitelist your server IPs. Dashboard → Settings → Developers → Whitelisted Domains/IP → Payout IP allowlist. This fails closed: with no IPs configured at all, every call in this guide is refused with 403. Add the public egress IP of each server that will call the API.
6.
Fund your balance. Payouts are funded from your KuvarPay balance — route your settlements to it, or top it up in the dashboard. Check the balance before your first payout.
7.
Subscribe to webhooks. Dashboard → Settings → Developers → Webhooks. Subscribe to kuvarsend.payout.completed and account_link.revoked.

Authentication#

Every merchant call sends your live secret key:
X-API-Key: rsp_secret_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Content-Type: application/json
X-Business-ID is optional; if you send it, it must match the key's business.

Environments#

Account linking and linked payouts run in LIVE mode only. A sandbox key is rejected with 403 ACCOUNT_LINK_LIVE_ONLY — "Account linking runs in live mode only; use a live secret API key."
Plan your first integration test as a small real payout to a KuvarSend account you control.

4. How the flow works#

  YOUR BACKEND                    KUVARPAY                       KUVARSEND APP (your user)
       |                              |                                   |
  1.   |--- POST account-link-request-->|                                 |
       |<-- alr_… + authorization_url --|                                 |
  2.   |--- send user to that URL ------------------------------------->  |
       |                              |                        3. consent screen + PIN
       |                              |<--- approve --------------------  |
  4.   |<-- redirect to your callback: ?code=kpal_…&state=… ------------  |
  5.   |--- POST exchange (code + verifier) -->|                          |
       |<-- kal_… (linked_account_id) ---------|                          |
       |                              |                                   |
  6.   |--- POST payouts/kuvarsend ---->| debit your balance, credit their wallet
       |<-- 201 kwp_… (COMPLETED) -----| ---- push notification --------> |
       |<-- webhook kuvarsend.payout.completed                            |
Security model. The handshake is OAuth-style with PKCE and a state parameter:
state — a random value you generate, store server-side, and compare when the user comes back. It stops someone else's callback being replayed at your endpoint.
code_verifier / code_challenge — you generate a high-entropy verifier, send only its SHA-256 (code_challenge), and reveal the verifier only when you exchange. It stops a stolen authorization code from being useful to anyone but you.
The authorization code is single-use and lives 2 minutes. The request itself lives 10 minutes.
What the user actually agrees to. The consent screen shows your business name and logo and this text:
"Allow this business to identify this KuvarSend account as a payout destination and send payouts to it. The business cannot view your balance or history, log in, withdraw, or debit your account."
That is the full extent of the permission (scope: payouts:receive). The link is credit-only in your favour: you can pay in, and you can never pull out.

5. Step by step#

The examples below show the raw HTTP call first — that is the contract, and it works from any language. Alongside it are the helpers from the official Node SDK, @kuvarpay/sdk, which generate PKCE and state and parse the callback for you.
SDK version: use @kuvarpay/sdk 1.9.2 or newer. Earlier versions have the same helpers, but their TypeScript types describe the payout debit as USD only. The raw HTTP endpoints are the contract either way.

Step 1 — Create an account-link request#

201 Created
{
  "data": {
    "id": "alr_4b7c2f1e9a0d4c6b8e3f5a7c9d1b2e4f",
    "authorization_url": "https://pay.kuvarpay.com/account-link/alr_4b7c2f1e9a0d4c6b8e3f5a7c9d1b2e4f",
    "expires_at": "2026-08-26T12:41:07.000Z"
  }
}
external_user_reference is your user id. We store only a keyed hash of it, never the raw value.
state must be at least 22 characters. Generate it randomly and keep it in the user's server-side session next to the code verifier.
Idempotency-Key is required. Retrying with the same key and the same body returns the same request; the same key with a different body is 409 IDEMPOTENCY_CONFLICT.
The request expires after 10 minutes.

Step 2 — Send the user to authorization_url#

Open it in the browser or as a link in your app. It is a verified HTTPS universal/app link: if KuvarSend is installed it opens the native consent screen; otherwise it opens a landing page that prompts the user to install KuvarSend.
For a desktop checkout, render the URL as a QR code — see the cross-device path in Step 4.

Step 3 — The user approves#

In the KuvarSend app the user sees your name and logo, the consent text above, and confirms with their 4-digit PIN. Approving redirects them back to your registered callback with ?code=…&state=…. Denying redirects to the same URI with ?error=access_denied&state=….

Step 4 — Exchange the code for a linked account#

Same-device (the normal case). Your callback handler receives code and state. Compare state against the session, then exchange:
200 OK
{
  "data": {
    "linked_account_id": "kal_9f2c8a1d3e5b7c9a0d2f4e6b8c1a3d5f",
    "status": "ACTIVE",
    "scope": "payouts:receive",
    "display_name": null,
    "kuvar_tag": "ada",
    "linked_at": "2026-08-26T12:33:41.000Z"
  }
}
Cross-device (desktop QR). The code lands on the user's phone and never reaches your server. Send request_id instead of code and poll — the PKCE verifier is your proof:
{
  "request_id": "alr_4b7c2f1e9a0d4c6b8e3f5a7c9d1b2e4f",
  "redirect_uri": "https://app.example.com/kuvarsend/callback",
  "code_verifier": "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk"
}
While the user has not approved yet you get 409 AUTHORIZATION_NOT_READY — keep polling every few seconds. Stop at the expires_at you got in Step 1 and start a new request: an unapproved request keeps answering AUTHORIZATION_NOT_READY, so it is your own timer that ends the wait.
Send exactly one of code or request_id; sending both or neither is 400 INVALID_REQUEST.

Step 5 — Store linked_account_id#

Save it against your user. It is the only handle you need, it does not expire, and it is safe to log.
kuvar_tag is the recipient's KuvarSend tag as it stood at link time, useful for showing the user who they connected. display_name is reserved and is currently always null — do not build UI that depends on it.
One active link per user, per direction: if the same KuvarSend account (or the same external_user_reference) already has an ACTIVE link with you, a second exchange returns 409 ACCOUNT_LINK_CONFLICT. Revoke the old one first.

Step 6 — Quote (recommended)#

Show the user what they will receive before they commit.
200 OK
{
  "data": {
    "quote_id": "kwq_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
    "linked_account_id": "kal_9f2c…",
    "amount": "10000.00",
    "currency": "NGN",
    "source_currency": "NGN",
    "source_amount": "10000.00",
    "rate": "1533.5",
    "fee_percent": "2",
    "fee_amount": "200.00",
    "recipient_amount": "9800.00",
    "expires_at": "2026-08-26T12:35:41.000Z"
  }
}
source_currency is your balance's currency and source_amount is exactly what it will be debited. Here the business balance is in NGN, so paying NGN debits the same 10,000. A business with a USD balance would see "source_currency": "USD" and a USD cost such as "6.53".
Nothing is reserved and no money moves. The quote is indicative for 2 minutes; the payout re-prices at execution with the same maths.

Step 7 — Send the payout#

201 Created
{
  "data": {
    "payout_id": "kwp_7c3e1a9b5d2f4e6a8c0b1d3f5a7e9c2b",
    "status": "COMPLETED",
    "linked_account_id": "kal_9f2c…",
    "amount": "10000.00",
    "currency": "NGN",
    "external_reference": "invoice_55213",
    "source_currency": "NGN",
    "source_amount": "10000.00",
    "source_amount_usd": "6.53",
    "created_at": "2026-08-26T12:34:02.000Z"
  }
}
201 means done — your balance is debited and the user's wallet is credited atomically. There is no pending state.
Idempotency-Key is required. Repeat the identical request and you get 200 with the same payout_id and no second debit. The same key with different content is 409 IDEMPOTENCY_CONFLICT.
amount is a string in destination-currency major units. Use a string, not a float, so 0.1 + 0.2 never becomes your payout. It may not carry more decimal places than the currency supports (400 INVALID_PAYOUT_AMOUNT if it does).
source_currency and source_amount are what your balance was actually debited; source_amount_usd is the same charge valued in USD. All three are returned only here, on create. GET /api/v1/payouts/kuvarsend/{payoutId} does not repeat them — store them if you need them for your books.

Step 8 — Read back#

GET /api/v1/payouts/kuvarsend/{payoutId} — one receipt.
GET /api/v1/payouts/kuvarsend?linked_account_id=…&limit=50&cursor=… — newest first, keyset pagination. Follow next_cursor until it is null.
GET /api/v1/payouts/account-links?status=ACTIVE — your links, same pagination.
GET /api/v1/payouts/account-links/{linkId} — one link.

Step 9 — Revocation#

You: DELETE /api/v1/payouts/account-links/{linkId}, or await kv.revokeKuvarSendAccountLink('kal_9f2c…') with the SDK. Idempotent — revoking twice returns the link unchanged.
The user: from the KuvarSend app, at any time, without telling you first.
Either way an account_link.revoked webhook is sent, and the next payout to that link fails with 410 LINKED_ACCOUNT_REVOKED before any money moves. Treat that code as "ask the user to re-link", not as a retryable error.

6. Money: what you pay, what they get#

TermMeaning
amountWhat you send, in the destination currency. This is the figure you name.
fee_amountThe recipient fee, deducted from amount. The quote returns it, with fee_percent, before you commit.
recipient_amountamount − fee_amount — what actually lands in the user's wallet.
source_currencyYour balance's currency — the one this payout debits.
source_amountWhat your balance is debited for this payout, in source_currency.
source_amount_usdThe same charge valued in USD (create response only).
Reading the quote above: you send 10,000 NGN, the quoted fee is deducted from it, the user is credited recipient_amount, and your balance is debited source_amount. The fee comes out of the amount you name, never on top of your debit — so the quote tells you your exact cost before you commit. The figures in these examples are illustrative; use the ones your own quote returns.
Other things worth knowing:
What you are debited depends on your balance's currency. If it matches the payout currency, you are debited exactly amount. If your balance is in USD, you are debited the USD cost at the quote's rate (destination units per USD). If it is another currency, that USD cost is converted into your balance's currency. Either way the quote's source_amount is the exact debit, so quote before you charge and you always know your cost up front.
Fee terms are set per business. Read fee_percent and fee_amount from the quote rather than hard-coding a number, and contact support if you need different terms.
Which currencies work: any active KuvarSend wallet currency that can hold a balance and receive peer transfers. Anything else is 422 PAYOUT_CURRENCY_UNAVAILABLE. Probe with the quote endpoint — it runs exactly the same validation as the payout — or ask support for the current list.
Very small amounts are refused with 422 PAYOUT_AMOUNT_TOO_SMALL when the amount is too small to price.
Payouts are final. There is no reversal endpoint. If you need a correction, contact support; do not "reverse" by paying yourself back through the same link.

7. Webhooks#

Subscribe in Dashboard → Settings → Developers → Webhooks. Two events matter here.
kuvarsend.payout.completed — sent as soon as the payout completes, and retried until it is acknowledged.
{
  "event": "kuvarsend.payout.completed",
  "timestamp": "2026-08-26T12:34:02.512Z",
  "webhook_id": "…",
  "data": {
    "data": {
      "schema_version": 1,
      "event_id": "…",
      "event_type": "kuvarsend.payout.completed",
      "created_at": "2026-08-26T12:34:02.000Z",
      "business_id": "…",
      "environment": "LIVE",
      "payout_id": "kwp_7c3e…",
      "status": "COMPLETED",
      "linked_account_id": "kal_9f2c…",
      "amount": "10000.00",
      "currency": "NGN",
      "external_reference": "invoice_55213"
    }
  }
}
Note the nesting. The event body is at body.data.data — the outer data is the standard KuvarPay webhook envelope, the inner one is this event's payload. Read body.data.data.payout_id, not body.data.payout_id.
account_link.revoked — same envelope; the inner payload carries linked_account_id and status: "REVOKED" instead of the payout fields.
Verifying the signature. Every delivery carries:
HeaderValue
X-KuvarPay-Signaturesha256=<hex> — HMAC-SHA256 of the raw request body using your webhook's secret
X-KuvarPay-Eventthe event name
X-KuvarPay-Webhook-Idthe webhook subscription id
X-KuvarPay-TimestampISO-8601 send time
Without the SDK:
Delivery rules. Reply 2xx to acknowledge. Anything else is retried with exponential backoff until it succeeds, so make your handler idempotent — deduplicate on event_id. Your endpoint must be reachable from the public internet and answer promptly. The webhook is a notification, not the source of truth: the payout was already complete when your API call returned.

8. Endpoint reference#

Machine-readable schemas for these endpoints are published in our OpenAPI description under the KuvarSend Payouts tag.
MethodPathScopeNotes
POST/api/v1/payouts/account-link-requestsaccount_links:writeIdempotency-Key required · 30/min
POST/api/v1/payouts/account-links/exchangeaccount_links:writecode xor request_id · 30/min
GET/api/v1/payouts/account-linksaccount_links:readstatus, limit, cursor
GET/api/v1/payouts/account-links/{linkId}account_links:read
DELETE/api/v1/payouts/account-links/{linkId}account_links:writeidempotent
POST/api/v1/payouts/kuvarsend/quotepayouts:writeno money moves · 120/min
POST/api/v1/payouts/kuvarsendpayouts:writeIdempotency-Key required · 60/min
GET/api/v1/payouts/kuvarsendpayouts:readlinked_account_id, limit, cursor
GET/api/v1/payouts/kuvarsend/{payoutId}payouts:read
Endpoints without a stated limit fall under the global API rate limit (100 requests/minute by default). Rate-limited calls return 429.

9. Errors#

All errors from these endpoints share one shape:
{ "success": false, "code": "LINKED_ACCOUNT_REVOKED", "error": "Linked account has been revoked." }
Always branch on code, never on the message text.
HTTPcodeWhat it means / what to do
400INVALID_REQUESTBody failed validation, or Idempotency-Key is missing where required.
400INVALID_STATEstate is shorter than 22 characters or contains control characters.
400INVALID_EXTERNAL_REFERENCEEmpty or longer than 255 characters.
400INVALID_IDEMPOTENCY_KEYEmpty or longer than 255 characters.
400INVALID_AUTHORIZATION_REQUESTcode_challenge_method is not S256, or scope is not payouts:receive.
400REDIRECT_URI_NOT_REGISTEREDThe URI is not registered, is revoked, or does not match byte for byte.
400INVALID_PAYOUT_AMOUNTMore decimal places than the currency allows, or not positive.
400INVALID_CURSORPagination cursor is not a kwp_… id.
401INVALID_AUTHORIZATION_CODEUnknown/reused code, wrong business, wrong redirect URI, or the PKCE verifier does not match. Start over.
403ACCOUNT_LINK_LIVE_ONLYYou used a sandbox key. Use the live secret key.
403ACCOUNT_LINK_NOT_ALLOWEDA setup gate is missing (verification, KYC, payouts toggle, scope, key status) — or the KuvarSend account cannot be linked. Work through §3, then contact support.
403PAYOUT_RECIPIENT_UNAVAILABLEThe KuvarSend account is not in a state to receive. No money moved.
403(auth error, different shape)Secret key missing/wrong type, or your IP is not on the payout allowlist. These come back as {"success": false, "error": {"code": "AUTH_004", …}}.
404LINKED_ACCOUNT_NOT_FOUNDUnknown link, or it belongs to another business.
404PAYOUT_NOT_FOUNDUnknown payout, or it belongs to another business.
409IDEMPOTENCY_CONFLICTThat key was already used with different content. Use a new key.
409AUTHORIZATION_NOT_READYCross-device polling: the user has not approved yet. Keep polling.
409ACCOUNT_LINK_CONFLICTAn ACTIVE link already exists for this user. Revoke it first.
410AUTHORIZATION_CODE_EXPIREDOlder than 2 minutes, or already exchanged. Start over.
410LINKED_ACCOUNT_REVOKEDThe link is dead. No money moved. Ask the user to re-link.
422INSUFFICIENT_MERCHANT_BALANCEYour balance is too low. Top up.
422PAYOUT_CURRENCY_UNAVAILABLEThat currency cannot receive linked payouts.
422PAYOUT_RATE_UNAVAILABLENo usable rate for that currency right now. Retry shortly.
422PAYOUT_AMOUNT_TOO_SMALLBelow the smallest amount we can price.
429—Rate limited. Back off and retry.
Retry policy. 409 IDEMPOTENCY_CONFLICT, 410, 403 and 404 are terminal — fix the cause, do not retry blindly. 422 PAYOUT_RATE_UNAVAILABLE, 429 and network timeouts are safe to retry with the same Idempotency-Key: that is exactly what it is for.

10. Go-live checklist#

Business verification approved by a KuvarPay admin, KYC verified.
Merchant-initiated payouts enabled in the dashboard.
Exact HTTPS callback URI registered (and it matches what your code sends, byte for byte).
LIVE secret key created with the four scopes, stored server-side only, never in a browser or mobile app.
Every calling server's public IP on the payout allowlist.
state and code_verifier stored server-side per user session and compared on the way back.
A durable Idempotency-Key per payout — derived from your own order/invoice id, and persisted before the call so a crash-and-retry reuses it.
Webhook endpoint live, signature verified, subscribed to kuvarsend.payout.completed and account_link.revoked — and reading body.data.data.
410 LINKED_ACCOUNT_REVOKED handled as "re-link", not as a failure to retry.
Balance funded, with an alert before it runs low.
First real payout small, to a KuvarSend account you control.

11. Support#

Email: support@kuvarpay.com
Dashboard: the Support section of your merchant dashboard.
Contact us for: business verification, fee terms, currency availability, or anything in this guide that does not behave as described. When you write in, include your business id, the alr_… / kal_… / kwp_… id involved, and the error code — never your API key.
Modified at 2026-09-29 15:14:07
Previous
Split Payment Guide
Next
Calculate Payment Amount
Built with