Skip to content
Merxian

Integration guides

Accept a payment with hosted checkout

Your server creates a checkout session. The buyer pays on a page that Merxian hosts. Your webhook endpoint receives the result.

On this page

Before you start#

You need these items:

  • A sandbox API key with the scopes checkout:write and checkout:read. See Get an API key.
  • At least one price in your catalog. Each line of a checkout session names a price ID, such as price_4Wm9TqLz2Xb7KdN8r. See Products and prices.
  • A webhook endpoint that receives payment.*, checkout.*, and transaction.* events. See Configure an endpoint.

How the flow works#

Your server creates a checkout session with Merxian and redirects the buyer to its URL. The buyer pays on the hosted page and returns to your success URL. Merxian sends payment.succeeded to your webhook endpoint, and your server fulfils.Your serverBuyerMerxianYour webhook endpoint1. Create checkout sessionSession with url2. Redirect to url3. Pay on the hosted pageRedirect to successUrl4. payment.succeeded5. Fulfil
The hosted checkout flow. A dashed line is a response or a later message.
  1. Your server creates a checkout session. Merxian returns the session with its url.
  2. Your server sends the buyer to the url.
  3. The buyer pays on the hosted page. Merxian calculates the tax, when it applies, and collects the payment. Then it sends the buyer to your successUrl.
  4. Merxian sends the result to your webhook endpoint.
  5. Your server fulfils when the result is a success.

The return to successUrl and the webhook event are independent. Either one can arrive first.

1. Create the checkout session#

Give exactly one of these two fields:

  • transactionDraft: a currency and catalog prices with quantities. Merxian creates a draft transaction for the session.
  • transactionId: a draft or ready transaction that you created before. Use this when you build the transaction yourself. See Build a transaction.

Set successUrl and cancelUrl. Both must use https. Set clientReferenceId to your own reference, so you can match the session to your records.

curl -X POST https://api.merxian.com/v1/checkout-sessions \
-H "Authorization: Bearer $MERXIAN_API_KEY" \
-H "Idempotency-Key: 9b3f6c1e-2a47-4d8b-b5e0-7c1d2e3f4a5b" \
-H "Content-Type: application/json" \
-d '{
  "transactionDraft": {
    "currency": "EUR",
    "lineItems": [{ "priceId": "price_4Wm9TqLz2Xb7KdN8r", "quantity": 1 }]
  },
  "successUrl": "https://shop.example.com/checkout/success",
  "cancelUrl": "https://shop.example.com/checkout/cancel",
  "clientReferenceId": "A-1042",
  "customerEmail": "ada@example.com",
  "customerCountry": "DE"
}'

The response has status: "open", the transactionId, and the url. The summary in transaction shows the amounts in minor units. For example, total { "amountMinor": 14280, "currency": "EUR" } is €142.80.

The session expires 24 hours after creation by default. To change this, set expiresAt in epoch milliseconds, from 30 minutes to 7 days in the future.

2. Send the buyer to the hosted page#

Redirect the buyer to url, for example with an HTTP 303 response from your server.

If a retry of the create request replays the first result, the url of the replayed response does not include the token. In that case, expire the session and create a new one with a new Idempotency-Key. See Idempotency.

3. Handle the return#

After a successful payment, Merxian sends the buyer to successUrl. When the buyer cancels, Merxian sends the buyer to cancelUrl.

A return to successUrl is not proof of payment. Anyone can open that URL. Show a page that says the payment is in progress or complete, based on the state that your server knows. Do not fulfil in the request handler of successUrl.

4. Fulfil on the webhook event#

Fulfil when your webhook endpoint receives one of these events:

Event Use it when
payment.succeeded One payment pays the transaction, which is the case for hosted checkout.
transaction.completed You want one signal that the full amount of the transaction is collected.
checkout.completed You want to update the buyer interface. Do not use it alone to release goods.

Match the event to your records with data.object.transaction_id, or with client_reference_id on the checkout event. Before you act, verify the signature and check that you did not process the event id before. See Verify signatures and Process events.

5. Read the state as a fallback#

If an event does not arrive, read the resources from the API:

A session with status: "complete" and a transaction with status: "completed" are paid.

Handle failures#

Event What it means What to do
payment.failed The payment was refused. The session returns to open. Nothing is required. The buyer can try again on the same page until the session expires.
checkout.expired The session ended without a payment. status is expired, or cancelled when the buyer cancelled. Release reservations. Create a new session if the buyer still wants to pay.
payment.canceled The open payment of an ended session was canceled. Stop waiting for that payment.

When a session created its own draft transaction and ends without a payment in progress, Merxian also cancels that transaction. You receive transaction.canceled.

Expire a session early#

To stop a buyer from paying, for example when stock runs out, call POST/v1/checkout-sessions/{sessionId}/expire. It closes an open or payment_pending session and cancels a payment that the session started. A complete or cancelled session returns 409.

Expire a session
curl -X POST https://api.merxian.com/v1/checkout-sessions/cs_6HvB2nQx9LmT4kWpR/expire \
  -H "Authorization: Bearer $MERXIAN_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)"

Try refund, payment.succeeded,POST /v1/transactions, orIdempotency-Key.