Install
Install@ionicfi/sdk with npm,
which is included with Node.js:
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 theaccount request option. The SDK sends
Ionic-Account for that request. The merchant ID comes from your own records.
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 callconfirmPayment. 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 exposestatusCode, 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, or504are retried automatically with backoff. A bare500is never retried: on a mutating endpoint it can mean the operation already committed. A502carryingGATEWAY_ERRORis 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, andwebhookEndpointsreturn aPagethat exposeshasNextPage()/getNextPage()and is directlyfor await-able. Iteration advances withstarting_aftercursors. The result is not a snapshot of concurrent writes:If the first request carried anoffset, continuation requests drop it; iteration advances by cursor alone. Webhook-endpoint lists preserve their legacy full-result behavior whenlimitis omitted; the returnedPageis 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, callwebhookEndpoints.rotateSecret()for a new one; the previous secret is revoked immediately, and it isn’t recoverable otherwise. - Test keys (
_test_) returnlivemode: falseobjects 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.

