Create an Intent
Your backend creates the intent when the customer reaches checkout, using the amount you calculated from the cart. This is the step that authorizes the charge.
Endpoint: POST /v1/payment_intents
Authentication: Secret key
- JSON
- cURL
{
"amount": 10000,
"currency": "SAR",
"description": "Order #1234",
"callback_url": "https://example.com/checkout/payer-return"
}
curl -X POST https://api.moyasar.com/v1/payment_intents \
-u sk_test_YOUR_SECRET_KEY: \
-H "Content-Type: application/json" \
-d '{
"amount": 10000,
"currency": "SAR",
"description": "Order #1234",
"callback_url": "https://example.com/checkout/payer-return"
}'
The response includes the client_secret and the expiry:
{
"id": "8f4d1c3e-6a52-4f0b-9a1e-2c7b5d8e0f31",
"amount": 10000,
"currency": "SAR",
"description": "Order #1234",
"callback_url": "https://example.com/checkout/payer-return",
"status": "created",
"client_secret": "pi_secret_7Kq2mXbN9vT4wPzR1sYcHdLjF6aGuE8oQ3iK5nB0xVtZrWyM",
"expires_at": "2026-08-19T13:20:44.000Z",
"fulfilled_at": null,
"created_at": "2026-08-19T12:20:44.000Z"
}
Fields
| Field | Required | Notes |
|---|---|---|
amount | Yes | Integer, in the currency's smallest unit. Locked. |
currency | No | ISO-4217 code. Defaults to SAR. Locked. |
description | No | Shown to you, never to the payer. Up to 8000 characters. Locked. |
callback_url | No | Where the payer returns after the payment. Locked. Required for card and token payments — see below. |
All four are fixed at creation. The fulfillment request cannot override them.
callback_url here, not at fulfillmentCard and saved-token payments require a callback_url, and because the field is locked
to the intent, it has to be set when you create the intent. An intent created without one
cannot be fulfilled with a creditcard or token source — the fulfillment fails
validation, and no payment is created.
Handing the secret to your frontend
Return only what the browser needs — the intent id and the client_secret — from your
own checkout endpoint:
{
"intent_id": "8f4d1c3e-6a52-4f0b-9a1e-2c7b5d8e0f31",
"client_secret": "pi_secret_7Kq2mXbN9vT4wPzR1sYcHdLjF6aGuE8oQ3iK5nB0xVtZrWyM"
}
Treat the client_secret as a credential for that one payment. It is all a browser needs,
alongside your publishable key, to charge the approved amount — so send it only to the
customer whose checkout it belongs to, over HTTPS, and never log it or put it in a URL.
Errors
The secret key is required. A request made with the publishable key, or from a dashboard
session, is rejected with 403.
Validation failures return 400 with "type": "validation_error" and the offending
fields in errors — for example an amount below the minimum, a non-integer amount,
or an unsupported currency.
Next
Fulfill the intent from the browser.