Skip to main content
The server-side TypeScript SDK. It holds your secret key, so it runs on your backend only, never in a browser. Method signatures, required fields, and webhook event shapes match the API reference exactly.

Install

Install @ionicfi/sdk with npm, which is included with Node.js:
Requires Node 18 or later. This is an ES module package; CommonJS projects can require() it on Node 20.19+ / 22.12+, or use dynamic import() on older runtimes.

Quickstart

Construct a client with a secret key and create a checkout session:

Connect requests

Pass the connected account’s ID as the account request option. The SDK sends Ionic-Account for that request. The merchant ID comes from your own records.
PaymentIntents, SetupIntents, customers, payment methods, refunds, Checkout Sessions, test clocks, products, prices, subscriptions, invoices, invoice items, and credit notes accept the option. Products, prices, subscriptions, invoices, invoice items, and credit notes need 0.4.4 or later. The platform key and the merchant’s connection both need the operation’s permission. See How Connect works, Accept payments for connected accounts, and Save cards for connected accounts. API keys are managed in the dashboard. See SDK upgrades when moving from 0.3.x.

Webhooks

For a payment page built with Ionic Blocks, the server SDK creates or retrieves the PaymentIntent. Your browser uses Ionic.js to mount the Block and call confirmPayment. Your application owns payment handling and fulfillment. The direct merchant and Connect guides describe the server and browser contracts. Verify inbound deliveries with webhooks.unwrap(). It checks the signature and replay window, then returns a typed event. Pass the raw request body exactly as received; a body that’s been parsed and re-serialized by framework middleware will not verify:
rawBody is the unmodified string or Buffer received by your backend. requestHeaders contains the incoming webhook-id, webhook-timestamp, and webhook-signature headers. The return value is a typed event; event.type identifies the shape of event.data.object. An unverifiable delivery throws WebhookVerificationError (bad signature, missing headers, or stale timestamp) or WebhookParseError (authenticated body that is not a webhook envelope). A 2xx acknowledges acceptance of a delivery. See the delivery contract. A verified event must still match the intended merchant, mode, and resource. Browser redirects do not prove that a payment completed. Your application owns persistence, reconciliation, and fulfillment decisions. The signing secret is shown once, in the response from webhookEndpoints.create. Store it immediately; it isn’t retrievable afterward.

Typed imports

Every resource shape is exported alongside the client:

Error handling

HTTP API failures expose statusCode, the parsed error envelope, and a requestId when available. Your application decides how each failure affects its payment lifecycle. Transport and local configuration failures can also occur outside an HTTP error response. A missing result is not proof that another payment should be created. The hierarchy is CardError, InvalidRequestError, AuthenticationError, PermissionError, NotFoundError, ConflictError, RateLimitError, GatewayError and ApiError, all extending IonicApiError. There is exactly one of each in the package: the per-resource names the API reference uses (BadRequestError, UnauthorizedError, …) are aliases of these, so IonicApi.checkout.BadRequestError and InvalidRequestError are the same class and instanceof cannot pick a wrong one. HTTP API errors expose statusCode, a requestId when available, and detail: the typed error body (code, message, decline_code, decline_type, retryable, doc_url), or undefined when the response had no parsable envelope, as with some 502 responses. errorDetail(err) reads the same value from an unknown. The specific class comes from the statuses an endpoint documents. InvalidRequestError, AuthenticationError, PermissionError, RateLimitError and ApiError are documented on every endpoint, so those always arrive as their class. CardError, NotFoundError, ConflictError and GatewayError are documented only where the endpoint can produce them: a list call cannot 404, and a customer lookup cannot raise a card decline. Anything undocumented arrives as IonicApiError with the correct statusCode and detail, so it is still catchable. GatewayError (502, code GATEWAY_ERROR) comes from confirming a payment intent (including create with confirmation) and creating a refund: Ionic could not complete the request and no money moved. The same idempotency key only replays that answer, so send the request with a new key to try again. A 502 without an Ionic error body comes from the network edge, where the request may have been processed: the SDK retries it with the same key, and if retries run out it surfaces as ApiError, never GatewayError.

Reliability

  • Idempotency keys are automatic. Every mutating request (POST, PUT, PATCH, DELETE) carries an Idempotency-Key; the SDK generates one per call when you don’t supply your own, so the automatic retries below replay the original operation instead of repeating it (a second charge, a second refund). To also make your own application-level retries safe, pass the same "Idempotency-Key" field with the same request body: the original response is replayed instead of the operation running twice.
  • Retries. Requests that fail with 408, 429, 502, 503, or 504 are retried automatically with backoff. A bare 500 is never retried: on a mutating endpoint it can mean the operation already committed. A 502 carrying GATEWAY_ERROR is not retried either: on confirmation and refunds no money moved and the same key would only replay it; on capture and cancel, retrieve the payment intent before retrying.
  • Auto-pagination. List calls on paymentIntents, charges, refunds, customers, invoices, subscriptions, creditNotes, paymentMethods, setupIntents, catalog.products, catalog.prices, paymentLinks, checkout.sessions, and webhookEndpoints return a Page that exposes hasNextPage() / getNextPage() and is directly for await-able. Iteration advances with starting_after cursors. The result is not a snapshot of concurrent writes:
    If the first request carried an offset, continuation requests drop it; iteration advances by cursor alone. Webhook-endpoint lists preserve their legacy full-result behavior when limit is omitted; the returned Page is terminal in that case.

Security

  • The secret key (sk_v1_test_… / sk_v1_live_…) authenticates every request in this SDK. Keep it server-side only, read from an environment variable. Never ship it to a browser or commit it to source control.
  • The webhook signing secret (whsec_…) is returned once, at endpoint creation. If you lose it, call webhookEndpoints.rotateSecret() for a new one; the previous secret is revoked immediately, and it isn’t recoverable otherwise.
  • Test keys (_test_) return livemode: false objects and never move real money. Live keys (_live_) do. Keep the two separate in your environment configuration and never charge a live key from a test script.

What’s next

Handle webhook events

Verify each event’s signature and fulfill orders from it.

Use the browser SDK

Collect payment details in the browser with Ionic Blocks.

Run the quickstart

Create a checkout session with the server SDK and take a test payment.