Create Checkout Session API
API used by a partner to create a Checkout Session for Pay with Pyng.
After a successful response, the partner receives a launchUrl which should be opened when the user clicks the Pay with Pyng button. The customer completes sign-in, agreement creation (if needed), and payment inside the Pyng-hosted experience. Pyng then redirects the customer back to returnTarget.url for UX purposes — the partner must confirm payment outcome via the Get Checkout Session Status API, never via the redirect. See Return URL below for the query parameters Pyng appends to the redirect.
URL path - /checkout/{siteId}/session
Method - POST
Request Headers
| Header Name | Header Value | Notes |
|---|---|---|
| Content-Type | application/json | |
| Authorization | Bearer access_token | Access token must have an appropriate scope to access resource |
| X-Pyng-Request-Id | string (1–255) | Required. Unique per logical create-session request — UUIDv4 recommended. Same id + identical body → original session returned. Same id + different body → 409. |
Path Parameters
| Parameter Key | Parameter Data Type | Notes |
|---|---|---|
| siteId | string | Unique site id assigned to the partner's site |
Body Parameters
| Parameter Key | Parameter Data Type | Required | Notes |
|---|---|---|---|
| orderId | string (1–256) | Y | Unique partner order identifier |
| amount | integer ≥ 1 | Y | Amount in cents (AUD) |
| returnTarget | object | Y | URL Pyng redirects the customer to after the session ends (any outcome — settled, declined, expired). |
| metadata | object (string values) | N | Optional partner key/value metadata stored against the session and echoed back by the Get Checkout Session Status API; no inspection by Pyng. A flat object of string values — see Metadata for the supported shape and limits. Do not include PII, payment instrument details, credentials, or secrets — partner-side identifiers only. |
ReturnTarget
| Parameter Key | Parameter Data Type | Required | Notes |
|---|---|---|---|
| url | string (≤ 2048) | Y | https:// URL whose origin must be in the site's allowlist. Configure the allowlist with your Pyng account contact before going live. |
Metadata
metadata is a single-level (flat) JSON object whose values must be strings. It is stored verbatim against the session and echoed back by the Get Checkout Session Status API; Pyng never inspects or interprets it.
| Constraint | Rule |
|---|---|
| Number of keys | ≤ 20 |
| Key format | 1–40 characters matching [A-Za-z0-9_-] |
| Value type | string only |
| Value length | 0–500 characters per value |
| Total serialised size | ≤ 4 KiB (UTF-8 bytes of the JSON-serialised object) |
Anything outside these rules is rejected with 400 and no session is created. In particular, nested objects, arrays, numbers, booleans, and null values are not supported — serialise such data to a string on the partner side before sending (for example, a basket reference rather than the basket itself). Sending metadata: null or omitting the field entirely are both treated as "no metadata".
Accepted example:
{
"metadata": {
"orderRef": "ABC-123",
"channel": "web",
"tier_2": "gold"
}
}
Response
Status Code - 201 Created
| Parameter Key | Parameter Data Type | Required | Notes |
|---|---|---|---|
| data | object | Y | Checkout Session data |
| traceId | string | Y | Request correlation id (echoed) |
| timestamp | integer | Y | Server-emitted epoch ms |
Checkout Session Response
| Parameter Key | Parameter Data Type | Required | Notes |
|---|---|---|---|
| checkoutSessionId | string | Y | Unique Checkout Session id |
| launchUrl | string | Y | Opaque URL the partner opens in the customer's browser to begin Hosted Checkout. Treat as opaque — do not parse, modify, or reconstruct. Valid until expiresAt. |
| status | string | Y | Always Created from this endpoint |
| expiresAt | integer | Y | Session expiry, epoch milliseconds |
| orderId | string | Y | Echo of partner order id |
| siteId | string | Y | Echo of partner site id |
Status Codes
| Status | Meaning |
|---|---|
| 201 | New session created, or idempotent replay of an earlier identical request |
| 400 | Malformed body, validation failure, return-target not allowlisted, missing X-Pyng-Request-Id, or site not configured for Pay with Pyng |
| 401 | Missing or invalid bearer token |
| 403 | Partner not authorised for siteId |
| 409 | X-Pyng-Request-Id reused with a different request body |
| 500 | Internal failure (no session persisted) |
Idempotency
Send a unique X-Pyng-Request-Id on every create-session call (UUIDv4 or equivalent entropy recommended). Retrying the same request with the same id and identical body returns the original checkoutSessionId. Reusing the same id with a different body returns 409.
Return URL
When Pyng redirects the customer back to the partner at the end of a session, it appends the following query parameters to returnTarget.url. If the URL already contains a query string, the parameters are appended with &.
| Parameter Key | Parameter Data Type | Notes |
|---|---|---|
| checkoutSessionId | string | The session id, so the partner can correlate the redirect to its order. |
| transactionStatus | string | One of Settled, Declined, Expired. Presentational only — see below. Matches the terminal subset of the Get Checkout Session Status API transactionStatus. |
| signature | string | Base64url (no padding) HMAC-SHA256 over the other parameters, letting you verify the redirect was issued by Pyng. Present only when your site has a signing secret (see below). |
Do not trust transactionStatus as the authoritative payment outcome. Confirm the real outcome via the Get Checkout Session Status API or the transaction-status webhook before fulfilling the order — the redirect stays a non-authoritative convenience signal even when signed.
Verifying the signature
If your site is provisioned with a return-redirect signing secret (arranged at onboarding with your Pyng account contact — distinct from your webhook secret), Pyng appends a signature. Until your site has a secret, the redirect arrives without signature; if you ignore the parameter entirely, nothing changes.
To verify:
- URL-decode the received
checkoutSessionIdandtransactionStatusvalues. - Rebuild the canonical string, in this exact order:
checkoutSessionId=<checkoutSessionId>&transactionStatus=<transactionStatus>
- Compute
HMAC-SHA256(secret, canonical)and encode it as base64url without padding. - Compare it to the received
signatureusing a constant-time comparison.
The signature proves the parameters were issued by Pyng and not tampered with.
Worked example (use it to check your implementation):
| Input | Value |
|---|---|
| secret | return-redirect-secret-sample |
| checkoutSessionId | 11111111-1111-4111-8111-111111111111 |
| transactionStatus | Settled |
| canonical string | checkoutSessionId=11111111-1111-4111-8111-111111111111&transactionStatus=Settled |
| signature | XflWR0N8kPRnRLkJSGTMSLbDFrFyS6vKr5892WCLbYg |
Notes
currencyis implicit AUD.