Checkout Session
Use Moosyl hosted checkout: create a checkout session on your server and redirect customers to a Moosyl payment page where they pay with their bank app.
A checkout session is a Moosyl-hosted payment page. Your server creates the session with your secret key, gets back a checkoutUrl, and redirects the customer there. The customer picks their bank app and pays; Moosyl then sends them to your successUrl or cancelUrl.
Use it when you don't want to build any payment UI yourself.
Create a session
You can create a session in two ways.
From an order ID
Pass your own transactionId and the amount in MRU. Moosyl creates the payment request for you. If a payment request with that transactionId already exists, Moosyl uses it and ignores amount.
import { Moosyl } from "moosyl-sdk";
const moosyl = new Moosyl(process.env.MOOSYL_SECRET_KEY!);
const { checkoutUrl } = await moosyl.createCheckoutSession({
transactionId: "order_1043",
amount: 2500,
phoneNumber: "22222222",
successUrl: "https://example.com/orders/1043/paid",
cancelUrl: "https://example.com/orders/1043",
expiresInMinutes: 30,
});curl https://api.moosyl.com/checkout-session \
-H "Authorization: $MOOSYL_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"transactionId": "order_1043",
"amount": 2500,
"successUrl": "https://example.com/orders/1043/paid",
"cancelUrl": "https://example.com/orders/1043"
}'From an existing payment request
If you already created a payment request (with POST /payment-request), pass its id as paymentRequestId. The other payment fields are then ignored.
const { checkoutUrl } = await moosyl.createCheckoutSession({
paymentRequestId: "b7a4e0f2-5c3d-4a8e-9f10-6d2e8c7b1a53",
successUrl: "https://example.com/orders/1043/paid",
cancelUrl: "https://example.com/orders/1043",
expiresInMinutes: 30,
});Parameters
| Field | Required | Notes |
|---|---|---|
paymentRequestId | One of these two | Use an existing payment request. |
transactionId | One of these two | Your own order ID, unique per environment. |
amount | With a new transactionId | Whole MRU, greater than 0. |
phoneNumber | No | Customer's 8-digit phone number, e.g. 22222222. |
successUrl | No | Where the customer goes after paying. |
cancelUrl | No | Where the customer goes if they cancel. |
expiresInMinutes | No | 5 to 1440. Defaults to 30. |
moosyl-sdk requires more fields
The TypeScript SDK's types require successUrl, cancelUrl and expiresInMinutes, and phoneNumber when you pass transactionId. The HTTP API treats them as optional.
Response
{
"data": {
"id": "c4f8e2a1-6b3d-4e9f-a7c5-1d8b3e6f2a90",
"paymentRequestId": "b7a4e0f2-5c3d-4a8e-9f10-6d2e8c7b1a53",
"status": "open",
"successUrl": "https://example.com/orders/1043/paid",
"cancelUrl": "https://example.com/orders/1043",
"expiresAt": "2026-09-25T10:44:02.000Z"
},
"checkoutUrl": "https://payments.moosyl.com/checkout/c4f8e2a1-6b3d-4e9f-a7c5-1d8b3e6f2a90"
}A session's status is open, completed, expired or cancelled. If an open session already exists for the same payment request, Moosyl returns that session instead of creating a new one. A payment request that's already paid can't get a new session.
Redirect the customer
Send the customer to checkoutUrl, from your server with a redirect or from your frontend:
window.location.href = checkoutUrl;Confirm the payment
Reaching your successUrl is not proof of payment: anyone can open that URL. Fulfil the order when you receive a webhook for the payment with status: "completed", matching it to your order by transactionId.
Next steps
- Webhooks: get notified when the payment completes
- Testing: try the flow with test phone numbers
- TypeScript SDK: the full server SDK