Skip to main content
SouthPay.js renders SouthPay’s hosted checkout inside your page, inline or as a modal. All payment UI (QR code, wallet connect, network picker, status, countdown) lives in an iframe served from the checkout origin, so the script itself is a thin DOM shell with no framework and no dependencies. It does two things: create a payment intent from the browser with a publishable key, and mount the checkout for a reference you already have.

Load the script

The script defines a global SouthPay. Read the version it loaded from SouthPay.VERSION.
There is no npm package. SouthPay.js ships only as this hosted bundle. Load it with a <script> tag rather than a bundler import.

Create a client

SouthPay is a factory, not a namespace. Call it with a publishable key to get a client.
The key must match sp_pk_live_... or sp_pk_test_.... Anything else, in particular a secret sp_ key, throws invalid_publishable_key immediately. Publishable keys can only create checkouts, which is what makes them safe to ship to a browser. A second argument overrides the endpoints:
string
default:"https://api.southpay.io"
Where paymentIntents.create posts. Must be a valid http(s) URL; trailing slashes are stripped.
string
default:"https://pay.southpay.io"
Origin the checkout iframe is loaded from, and the only origin whose messages the SDK accepts.
string
CSP nonce applied to the <style> element the SDK injects. Set this if your policy has no style-src 'unsafe-inline'.

Create a payment intent in the browser

string
required
A positive decimal string in major units: "49.99", not 4999. See Amount format.
string
required
Fiat currency code. Omitting it throws missing_currency.
string
Your own order identifier, stored on the intent as order_id.
string
Line title shown on the checkout page.
string
Longer description shown under the title.
string
Product image shown on the checkout page.
string
Where the buyer lands after a completed payment.
string
Where the buyer lands after a failed or canceled payment.
object
Arbitrary key/value pairs echoed back on the intent and on webhooks.
string
Sent as the Idempotency-Key header. If you omit it the SDK generates a UUID per call, so a retry you did not write is a new intent. Supply your own to make retries safe. See Idempotency.
number
default:"20000"
Aborts the create request and throws timeout.
AbortSignal
Cancel the request yourself. Aborting throws network_error.
The call returns only { reference }. To read the full intent, including addresses, amounts and status, fetch it server-side with a secret key; a publishable key cannot.

Mount the checkout

string
required
The 16-character reference. Missing throws missing_reference.
string | Element
A CSS selector or element to render into. Omit it and the checkout opens as a centered modal with its own overlay and close button.
number
default:"560"
Starting iframe height in pixels, before the checkout reports its own. The SDK caps subsequent resizes at 5000px.
Passing a container that matches nothing throws container_not_found. It does not silently fall back to a modal. Only omitting container gives you a modal.
mount returns a handle:
unmount() removes the iframe, tears down the modal if there is one, and detaches the message listener. Call it when your component unmounts, or the listener outlives the page.

Inline

Mounting a checkout your server created

The common production shape: create the intent server-side with a secret key so you control pricing, then hand the reference to the browser purely to render.

Events

Pass callbacks to mount.
If you do not pass onCompleted, the SDK navigates the buyer to successUrl itself. Pass onCompleted whenever you want to stay on the page. Providing it suppresses the automatic redirect entirely.
onError covers loading failures only: the iframe erroring, or no handshake within 20 seconds. Errors from paymentIntents.create are thrown, not routed here, so wrap that call in try/catch. Statuses are the six in the payment lifecycle. SouthPay derives status from the chain; you read it, you never set it.
Never fulfill an order on a browser callback alone. Any page can invoke onCompleted without a real payment. The only source of truth is the intent reaching completed server-side. Confirm with a webhook or by fetching the payment with a secret key.

Amount format

amount is a decimal string in major units, and the SDK validates precision against the currency before sending anything. Too many decimal places throws invalid_amount, as does a zero amount, a negative sign, or a number rather than a string. The SDK pads to the currency’s precision, so "10" in USD is sent as "10.00".

Errors

Every SDK failure is a SouthpayError carrying a machine-readable code.
SouthPay.isSouthpayError is safer than instanceof because it also matches errors thrown by a differently-bundled copy of the SDK on the same page. On request_failed the SDK unwraps the API’s error body for you, handling both the plain-string and structured shapes described in Errors, so err.message is the API’s message rather than a status code.

Content Security Policy

The SDK injects one <style> element. If your policy omits 'unsafe-inline' for styles, pass nonce when you construct the client and the same nonce is applied to that element.

Legacy embed script

An older, smaller script is still served from the checkout origin:
It defines window.Southpay (note the lowercase p, unlike the SouthPay global above) with a single method:
It also auto-mounts on page load: any element carrying data-southpay-checkout="<reference>" is mounted automatically, with data-southpay-min-height as an optional companion, and is marked data-southpay-mounted once done. Southpay.checkoutOrigin exposes the origin it talks to. It cannot create payment intents, takes no key, and uses different callback names. Prefer SouthPay.js for new integrations; this exists for pages already built on it.
Last modified on August 21, 2026