SDK reference
@arcora/sdk and @arcora/sdk-react — installation, types, and method-by-method walkthrough.
Packages
| Package | Use it for | Version |
|---|---|---|
@arcora/sdk | Browser or server-side invoice creation, hosted-checkout redirect, escrow listing, webhook verification | 1.4.0 |
@arcora/sdk-react | React hook and one-click button that wrap the SDK for embedded checkout | 1.4.1 |
Webhook verification ships in the SDK since 1.3.0: import { verifyWebhook } from "@arcora/sdk/webhook" enforces the replay window and compares in constant time, and is fail-closed — a missing or mismatched signature returns false. Runtimes without the SDK can reproduce the same HMAC in a few lines of node:crypto; see /docs/webhooks for both.
Two key types — publishable vs secret
| Key | Prefix | Where it goes | Capability |
|---|---|---|---|
| Publishable | pk_live_… | Browser / client code — safe to embed | Create a checkout from one of your allowlisted origins |
| Secret | ak_live_… | Server-side only — never ship to the browser | Everything: create invoices, list escrows, read private invoice data |
Anyone who loads your page can read a key embedded in it. Embed only the publishable key in browser code; keep the secretkey on your server. Privileged reads like escrows() require the secret key and only work server-side. Both keys are shown in /m/settings; set your allowed origins there so publishable-key checkouts are accepted.
@arcora/sdk
new Arcora(options)
import { Arcora } from '@arcora/sdk';
const arcora = new Arcora({
apiKey: string, // required — publishable pk_live_… in the browser, secret ak_live_… on a server
environment?: 'testnet' | 'mainnet', // default 'testnet'; selects the base URL
baseUrl?: string, // override for self-hosted deployments
timeoutMs?: number, // per-request timeout; default 30000 — a hung server rejects with code 'TIMEOUT'
});The legacy Arcora.init(...) / Arcora.createInvoice(...) singleton API is still exported for the CDN bundle but tagged @deprecated — use the instance API for any new code so multiple merchants in one process can't cross-contaminate state.
arcora.createInvoice(params)
const invoice = await arcora.createInvoice({
amount: string, // amount in major units as a DECIMAL STRING, e.g. '49.99' (no floats)
currency?: 'USDC' | 'EURC' | 'USDT', // merchant payout currency; default 'USDC'
idempotencyKey?: string, // sent as the Idempotency-Key header; a retried create never duplicates
successUrl: string, // required — http(s) where to send the customer after payment
cancelUrl?: string, // http(s) — same allowlist + SSRF guard
metadata?: Record<string, string>, // attached to invoice + webhook payloads
// Deprecated v1 amount form — prefer amount/currency above. The buyer always locks USDC.
amountUsdc?: number, // @deprecated — gross amount as a number (1 = $1.00)
payInToken?: 'USDC' | 'EURC', // @deprecated — ignored on the v2 path
});
// Returns:
// { invoiceId: '0x…',
// url: 'https://arcorapay.xyz/i/0x…',
// claimableAt?: '2026-05-20T…' } // custody escrow — populated once the invoice is paidSupply exactly one amount form — the SDK sends the v2 request when amount is present, otherwise the legacy v1 request. Throws ArcoraError with a typed code on validation, network, server, or auth failures. An amount that isn't a positive decimal string (and a legacy amountUsdc that's non-finite or ≤0) is rejected client-side before the request fires; a missing or non-http(s) successUrl is likewise rejected client-side with INVALID_URL.
Note: the SDK requires successUrl. Standalone invoices (no redirect — the invoice page just shows the paid status) are possible only by calling the raw REST endpoint POST /api/invoices directly, where successUrl is optional.
arcora.openCheckout(invoice)
arcora.openCheckout(invoice);
// equivalent to window.location.href = invoice.url
// browser-only; throws in Nodearcora.escrows()
const { pending, matured, claimed } = await arcora.escrows();
// pending: paid invoices still within the 7-day refund window
// matured: paid, window elapsed, ready to claim()
// claimed: already withdrawn to the merchant payout walletServer-side only — requires your secret ak_live_ key. Calling escrows() with a publishable key throws PUBLISHABLE_KEY_FORBIDDEN without making a request. Authenticated against the merchant whose apiKey the instance was constructed with. Three buckets cap at 200 rows each; a truncated flag tells the caller when to narrow filters.
Errors
import { Arcora, ArcoraError } from '@arcora/sdk';
try {
await arcora.createInvoice({ amount: '49.99', currency: 'EURC', successUrl: '...' });
} catch (e) {
if (e instanceof ArcoraError) {
// e.code is one of: 'INVALID_API_KEY' | 'NETWORK' | 'SERVER_ERROR'
// | 'INVALID_URL' | 'TIMEOUT' | 'NO_SECURE_RANDOM'
// | 'PUBLISHABLE_KEY_FORBIDDEN' | 'SECRET_KEY_IN_BROWSER'
// | 'UNKNOWN'
// e.retryAfter (seconds) is set on SERVER_ERROR when the server returned Retry-After
}
}@arcora/sdk-react
useCheckout(options)
import { useCheckout } from '@arcora/sdk-react';
function PayButton() {
const { checkout, loading, error, refundEndsAt } = useCheckout({
apiKey: process.env.NEXT_PUBLIC_ARCORA_PUBLISHABLE_KEY!, // pk_live_… — safe to inline in the browser
environment: 'testnet',
});
return (
<button onClick={() => checkout({
amount: '4.50',
currency: 'EURC',
successUrl: window.location.origin + '/orders/done',
})} disabled={loading}>
{loading ? 'Loading…' : 'Pay €4.50'}
</button>
);
}checkout(params) creates the invoice and immediately redirects via window.location.href.refundEndsAt is null after checkout — the created invoice is still unpaid — so read the merchant claim deadline from escrows() once the invoice is paid.
<CheckoutButton />
import { CheckoutButton } from '@arcora/sdk-react';
<CheckoutButton
apiKey={process.env.NEXT_PUBLIC_ARCORA_PUBLISHABLE_KEY!}
environment="testnet"
invoice={{ amount: '49.99', currency: 'EURC', successUrl: '...' }}
className="btn-primary"
>
Pay $49.99
</CheckoutButton>Thin wrapper around useCheckout. Renders a native <button>; bring your own styling. The button auto-disables while the invoice is being created.
Types
Full type definitions ship in the package's dist/index.d.ts: Arcora,ArcoraError, CreateInvoiceParams, Invoice, EscrowSummary,InitOptions, Environment, Currency, PayInToken. The contract ABI is also re-exported as gatewayAbi / GATEWAY_ABI for callers building their own viem clients.