Skip to main content
PayHubDeveloper docs
简体中文

Create hosted checkout session

API contract v1.0.0

createCheckoutSession
POST/v1/checkout/sessions
Required scopespayments:writeIdempotency key required

Creates a hosted checkout session linked to the order's Payment. Identify the order in one of two ways: pass payment_id, or pass merchant_order_no + amount + currency and the platform creates or reuses a Payment. Sending both groups of identity parameters, or neither, returns 400. When you reuse an existing order, a mismatched amount or currency returns 422. If the linked Payment has already succeeded, the API returns 200 and a read-only session with status=completed, and doesn't create a new entry point for charging. Any other state in which the order can't be paid returns 409. The request contains no card data, return_url and cancel_url must match a registered redirect URL rule, and the amount, currency and receiving merchant can't be changed through URL parameters. If you use a new idempotency key with the same order ID, amount and currency, the platform creates a new checkout session for the same Payment and doesn't create a second Payment.

Request headers

Request headersRequiredFormatDescription
AuthorizationYesBearer <API_KEY>

Server-side key, to be used only on the merchant's server. The merchant and environment are derived from the key. A missing, invalid, revoked or expired key returns 401.

Content-TypeYesapplication/json

The request body is UTF-8 encoded JSON.

Idempotency-KeyYes1–255 visible ASCII characters

Idempotency key, 1–255 visible ASCII characters. The scope is merchant, environment, method and path: with the same key and matching core business parameters, the original business object is reused, and conflicting parameters return 409 idempotency_conflict. Use one key per submission, and reuse the same key when you retry after a network error; use a new key for a new submission, such as a card change. For concurrent requests with the same key, only one request gets to run, and the others wait for its transaction to commit and then return the same object (200). If the wait times out, the API returns 409 operation_in_progress (retryable=true); retry later with the original key. A request rejected with 400, 401, 403 or 422 doesn't consume the idempotency key; fix it and submit with a new key.

Request body

JSON object CreateCheckoutSessionRequest

NameTypeRequiredDescription
payment_id
string
Condition: Send either this or (merchant_order_no + amount + currency), not both

An existing Payment. When you pass it, don't also pass merchant_order_no, amount or currency.

Constraints: Length 1–64

Example: pay_demo_002

merchant_order_no
string
Condition: Required together with amount and currency when payment_id isn't sent

Merchant order ID. When submitted together with amount and currency, the platform creates or reuses the Payment for this order.

Constraints: Format ^[A-Za-z0-9._:-]{1,64}$

Example: ORDER-DEMO-002

amount
integer(int64)
Condition: Required together with merchant_order_no and currency when payment_id isn't sent

Order amount, in the smallest currency unit. When you reuse an existing order, it must match the original order.

Constraints: ≥ 1

Example: 10000

currency
string
Condition: Required together with merchant_order_no and amount when payment_id isn't sent

Currency. When you reuse an existing order, it must match the original order.

Constraints: Format ^[A-Z]{3}$

Example: USD

description
stringNo

The order summary shown on the checkout page.

Constraints: Max length 256

Example: Example hosted checkout order

return_url
string(uri)Required

The merchant's return URL after the payment ends. It must match a redirect URL rule registered for the current environment: the match covers the scheme, host (exact or one-level wildcard), port and path prefix (by path segment), and the query string and fragment aren't part of the match. When the platform redirects the payer back, it uses this URL exactly as provided and appends no parameters.

Constraints: Max length 2048

Example: https://merchant.example/payment/return

cancel_url
string(uri)No

The "Return to merchant" URL. It must match a redirect URL rule registered for the current environment: the match covers the scheme, host (exact or one-level wildcard), port and path prefix (by path segment), and the query string and fragment aren't part of the match. Clicking "Return to merchant" doesn't cancel the charge.

Constraints: Max length 2048

Example: https://merchant.example/payment/cancel

locale
stringNo

Checkout page language (BCP 47): a value starting with zh shows Chinese and one starting with en shows English; for any other value, or if you don't pass one, the merchant's default language is used.

Constraints: Format ^[A-Za-z]{2,3}(-[A-Za-z0-9]{2,8})*$

Example: zh-CN

Request example

Create a checkout session for an existing Payment

curl
curl -X POST 'https://api.fluxan.co/v1/checkout/sessions' \
  -H 'Authorization: Bearer <TEST_SERVER_API_KEY>' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <UNIQUE_OPERATION_KEY>' \
  -d '{
  "payment_id": "pay_demo_008",
  "return_url": "https://merchant.example/payment/return",
  "cancel_url": "https://merchant.example/payment/cancel",
  "locale": "zh-CN"
}'

Placeholders to replace

  • <TEST_SERVER_API_KEY>: Test-environment server API key, created on the "API Key" page of the merchant portal
  • <UNIQUE_OPERATION_KEY>: The idempotency key you generate for this request (for example, a UUID); reuse the same key when you retry after a network error

Create from order info (the platform creates or reuses a Payment)

curl
curl -X POST 'https://api.fluxan.co/v1/checkout/sessions' \
  -H 'Authorization: Bearer <TEST_SERVER_API_KEY>' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <UNIQUE_OPERATION_KEY>' \
  -d '{
  "merchant_order_no": "ORDER-DEMO-008",
  "amount": 10000,
  "currency": "USD",
  "description": "Example hosted checkout order",
  "return_url": "https://merchant.example/payment/return",
  "cancel_url": "https://merchant.example/payment/cancel",
  "locale": "zh-CN"
}'

Placeholders to replace

  • <TEST_SERVER_API_KEY>: Test-environment server API key, created on the "API Key" page of the merchant portal
  • <UNIQUE_OPERATION_KEY>: The idempotency key you generate for this request (for example, a UUID); reuse the same key when you retry after a network error

Note

Server API keys must only be used on your own server, so the docs site doesn't offer interactive API testing. Get a test key: API Key page in the merchant portal (opens the merchant portal in a new tab) (Test environment; Requires Owner, Admin or Developer)

Responses

An idempotent replay with the same key, or the read-only session returned when the linked Payment has already succeeded.

The related payment succeeded: a read-only session is returned, and no new entry point for charging is created
{
  "id": "cs_demo_002",
  "payment_id": "pay_demo_008",
  "status": "completed",
  "checkout_url": "https://pay.payhub.example/checkout/<SHORT_LIVED_TOKEN>",
  "expires_at": "2026-09-23T09:30:00Z",
  "return_url": "https://merchant.example/payment/return",
  "cancel_url": "https://merchant.example/payment/cancel",
  "locale": "zh-CN",
  "created_at": "2026-09-23T09:20:00Z",
  "request_id": "req_demo_019"
}

Placeholders to replace

  • <SHORT_LIVED_TOKEN>: Short-lived credential returned by the platform; use it as is and don't log it

Response fields

Returns an object. See the object section for field descriptions.

NameTypeRequiredDescription
id
stringRequired

Checkout session ID.

Example: cs_demo_002

payment_id
stringRequired

The related Payment.

Example: pay_demo_002

status
stringRequired

Checkout session status.

  • open: payment can be submitted
  • completed: appears only after the related Payment succeeds
  • expired: new submissions are no longer allowed; this doesn't mean the related payment failed
  • open: Payment can be submitted
  • completed: Appears only after the related Payment succeeds
  • expired: New submissions are no longer allowed; this doesn't mean the related payment failed
  • More values may be added in the future. Don't treat a status you don't recognize as success.

Example: open

checkout_url
string(uri)Required

The checkout page URL. It carries a short-lived credential bound to this session only, and contains no merchant server-side key. Use it only for a full-page redirect of the payer's browser: don't write it to logs, analytics tools or error reporting, and don't share it with anyone.

Example: https://pay.payhub.example/checkout/<SHORT_LIVED_TOKEN>

expires_at
string(date-time)Required

The time the session expires, fixed at creation. A session lasts at most 30 minutes (the platform can shorten this) and never longer than the time the order has left to be paid. During the read-only period after expiry (fixed at creation; 24 hours by default, which is also the maximum), the payer can still use the original link to view the session and the payment result (read-only, no submissions). After that, the link stops working.

Example: 2026-09-23T09:30:00Z

return_url
string(uri)Required

The merchant's return URL after the payment ends.

Example: https://merchant.example/payment/return

cancel_url
string(uri)NullableRequired

The URL the payer goes to when they click "Return to merchant". Clicking it doesn't cancel a charge that was already submitted. It's null if not provided.

Example: https://merchant.example/payment/cancel

locale
stringRequired

Checkout page language.

Example: zh-CN

created_at
string(date-time)Required

Creation time.

Example: 2026-09-23T09:00:00Z

request_id
stringRequired

Unique identifier of this request, used for troubleshooting and support.

Example: req_demo_001

Possible error codes

HTTPError codeWhen it occursHow to handle
400invalid_requestIdempotency-Key is missing; the order ID contains invalid characters; payment_method_data and payment_method_id are submitted together; confirm=false carries card details; confirm=true has no return_url; a checkout session request sends both groups of identity parameters, or neither; a browser_info / billing_details field the provider requires is missing; the cursor, time format or limit is invalidFix the request according to error.field and resubmit it; don't charge again automatically
400sensitive_data_rejectedDigits that look like a card number, or similar data, appear in description or metadataRemove the sensitive content and resubmit; check why your system wrote card data into these fields
403capability_disabledDirect card isn't enabled; the payment or refund request capability has been turned off; the currency isn't enabledUse hosted checkout instead, or contact platform Operations
403merchant_not_activeThe merchant has been suspended or closed; callbacks, queries and notifications for business that was already accepted aren't affectedContact platform Operations
404not_foundAn incorrect ID; using a test key to look up a live object; looking up a platform exception refund (not returned by the open API)Check the ID and the environment of the key you used; the platform doesn't reveal whether another merchant's object exists
409idempotency_conflictThe key was reused but the amount, currency, order ID or similar parameters differThis is an integration bug: check your idempotency key generation logic; don't change the parameters and replay the original key; use a new key for a new operation
409operation_in_progressRequests with the same key were sent concurrentlyRetry later with the same key, or retrieve related_resource_id; don't switch to a new key
409invalid_stateCanceling a payment that is processing / succeeded; calling confirm on an order that has expired, been canceled or already succeeded; creating a checkout session for an order that can't be paidRetrieve the object's latest state, then decide what to do
409attempt_limit_reachedThe default maximum is 3 attempts, and the platform can lower itThis order can't be charged again; once you've confirmed the original payment is closed, use a new order ID
422order_amount_mismatchThe amount or currency of the same order ID changed when creating a checkout sessionThe amount can't be changed: close the original payment, then create a new one with a new order ID
422currency_not_supportedThe currency isn't in the overlap between the merchant's configuration and the provider's capabilitiesUse an enabled currency or contact platform Operations
422amount_out_of_rangeBelow the minimum or above the maximum amount per payment, or over the daily cumulative limit; the error doesn't return the specific thresholdsAdjust the amount or contact the platform
422url_not_allowedreturn_url / cancel_url doesn't match a registered redirect URL ruleRegister it on the redirect URL allowlist page in the merchant portal, then resubmit
503temporarily_unavailableThe platform has paused new transactions on this channel; the response doesn't give the internal reasonRetry later with the original idempotency key; this request created no Payment or charge; if it keeps happening, contact platform Operations
401unauthenticatedCommonNo Authorization header was sent; the key was copied incompletely; the old key expired after a rotation; the key was revokedCheck your credentials: on the API Key page in the merchant portal, verify the key's status and environment
403forbiddenCommonCreating a refund with a read-only key; calling getEvent without the read scope for the event's business area; if the request's source IP isn't on the key's allowlist, the more specific ip_not_allowed is returnedUse a key that has the required scope; don't work around the restriction
429rate_limitedCommonA rate limit per merchant and per key; switching keys doesn't get around the merchant's overall limitWait for Retry-After seconds, then retry with the original idempotency key
500internal_errorCommon—Retry with the original idempotency key, or query by merchant order ID / refund ID; never charge again with a new key
502 / 503upstream_unavailableCommonA provider or platform dependency failed, and the platform can't confirm whether this request took effectSame as above

Notes

  • Identify the order in one of two ways: payment_id, or merchant_order_no + amount + currency. Sending both or neither returns 400.
  • When you reuse an existing order, a mismatched amount or currency returns 422 order_amount_mismatch. If the linked payment has already succeeded, the API returns 200 and a read-only session with status=completed, and doesn't create a new entry point for charging. Any other state in which the order can't be paid returns 409.
  • If you use a new idempotency key with the same order details, the platform creates a new checkout session for the same payment and doesn't create a second payment.
  • return_url and cancel_url must match a registered redirect URL rule: Register redirect URLs (opens the merchant portal in a new tab) (Test environment; Requires Owner, Admin or Developer).
  • Changing URL parameters can't change the amount, the currency or the merchant that receives the payment.

Warning

checkout_url contains a checkout token. Use it only for a full-page redirect of the payer's browser. Don't write it to logs, analytics tools or error reporting, and don't share it with anyone.

Was this page helpful?