External API — Partner Integration Guide
Create invoices, query status, share payment links, and receive signed webhooks.
| Environment | Base URL |
|---|---|
| Production | https://integration.rsompay.com/api/external/v1 |
| Sandbox | https://demo-integration.rsompay.com/api/external/v1 |
| Environment | Payment URL pattern |
|---|---|
| Production | https://payment.rsompay.com/pay/invoice/{token} |
| Sandbox | https://demo-payment.rsompay.com/pay/invoice/{token} |
| Item | Description |
|---|---|
| External client account | Provisioned by RsomPay for B2B integration |
| Integration API token | Bearer token named client-external-api |
| Webhook signing secret | Provided by RsomPay IT on onboarding — used with header X-Rsom-Signature (see §7.5) |
flowchart TB
subgraph partner [Partner system]
ERP[ERP backend]
WH[Webhook endpoint]
RET[return_url handler]
end
subgraph rsom [RsomPay]
INT[integration.rsompay.com]
PAY[payment.rsompay.com]
end
ERP -->|POST /invoices| INT
INT -->|payment_url| ERP
ERP -->|share link| PAY
PAY -->|browser redirect first| RET
RET -->|GET by-reference| INT
INT -.->|webhook later async| WH
Send the integration token on every request:
Authorization: Bearer YOUR_CLIENT_EXTERNAL_API_TOKEN Content-Type: application/json Accept: application/json
client-external-api.403.client_invoices.create, client_invoices.view.curl -X POST "https://integration.rsompay.com/api/external/v1/invoices" \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d @invoice.json
Successful responses:
{
"status": true,
"message": "Mission completed successfully",
"data": { }
}
Paginated GET /transactions adds meta: total, per_page, current_page, last_page.
POST /invoices
| Field | Required | Type | Description |
|---|---|---|---|
external_id | Yes | string | Partner idempotency key. Max 255. Unique per client; duplicates return the same invoice. |
notification_url | Yes | URL | HTTPS webhook endpoint. Publicly reachable; no localhost/private IPs. Max 2048. |
return_url | Yes | URL | HTTPS customer redirect after checkout. Max 2048. |
customer | Yes | object | Customer block — see table below. |
items | Yes | array | Line items — min 1 object; see table below. |
currency_code | No | string | Currency code. Max 8. Default SAR. |
due_date | No | date | Due date YYYY-MM-DD. |
issued_date | No | date | Issue date YYYY-MM-DD. |
payment_method | No | string | Preferred payment method: mada, credit_card (Visa/Mastercard), apple_pay, or tamara. When set, the hosted checkout page skips its own payment-method screen and opens directly into that method's form. Requesting tamara for an account without Tamara enabled returns 422. mada/credit_card/apple_pay requested for a disabled method fall back to showing the picker instead. |
notes | No | string | Invoice notes. Max 2000. |
customer)| Field | Required | Type | Description |
|---|---|---|---|
customer.fullname | Yes | string | Full name on payment page. Max 255. |
customer.id | Yes | string | Your stable customer reference (e.g. CUST-9). Max 255. |
customer.email | No | string | Valid email. Max 255. |
customer.phone | No | string | Phone (e.g. +966501234567). Max 32. |
items[])Each array element is one line item. At least one item is required.
| Field | Required | Type | Description |
|---|---|---|---|
items[].description | Yes | string | Line description. Max 255. |
items[].quantity | No | number | Qty. Min 0.001. Default 1. |
items[].unit_price | Yes | number | Unit price before discount and tax. Min 0.01. Invoice total is computed from all lines. |
items[].discount_amount | No | number | Line discount amount. Min 0. |
items[].tax_rate | No | number | Tax % (e.g. 15 = 15% VAT). |
items[].item_type | No | string | Category label (e.g. service). Max 32. |
items[].reference_id | No | string | Your line reference. Max 128. |
external_id → 201, same invoice, no duplicate.issued.amount field — each line requires unit_price. data.amount and data.totals.grand_total are computed from lines (must be > 0).One line: qty 1, unit 100, discount 10, tax 15% → grand_total: 103.5
{
"external_id": "INV-PARTNER-001",
"notification_url": "https://partner.example.com/webhooks/rsom",
"return_url": "https://partner.example.com/payment/return",
"currency_code": "SAR",
"due_date": "2026-12-31",
"issued_date": "2026-05-18",
"payment_method": "credit_card",
"notes": "Optional invoice note",
"customer": {
"id": "CUST-9",
"fullname": "Ahmed Ali",
"email": "customer@example.com",
"phone": "+966501234567"
},
"items": [
{
"description": "Service fee",
"item_type": "service",
"quantity": 1,
"unit_price": 100,
"discount_amount": 10,
"tax_rate": 15,
"reference_id": "LINE-1"
}
]
}
{
"status": true,
"message": "Mission completed successfully",
"data": {
"external_id": "INV-PARTNER-001",
"reference_number": "INV-42-001",
"status": "issued",
"amount": 103.5,
"payment_url": "https://payment.rsompay.com/pay/invoice/...",
"customer": {
"id": "CUST-9",
"fullname": "Ahmed Ali",
"email": "customer@example.com",
"phone": "+966501234567"
},
"totals": {
"subtotal": 100,
"discount_total": 10,
"tax_total": 13.5,
"grand_total": 103.5
},
"items": [
{
"description": "Service fee",
"item_type": "service",
"quantity": 1,
"unit_price": 100,
"discount_amount": 10,
"tax_rate": 15,
"tax_amount": 13.5,
"total_amount": 103.5,
"reference_id": "LINE-1"
}
]
}
}
GET /invoices/by-reference?{parameter}={value}
Look up an invoice by your reference. Use this after webhooks or before fulfilling an order.
Provide exactly one query parameter:
| Parameter | Description |
|---|---|
external_id | Your idempotency key (recommended) |
reference_number | RsomPay invoice number (e.g. INV-42-001) |
GET /invoices/by-reference?external_id=INV-PARTNER-001 GET /invoices/by-reference?reference_number=INV-42-001
data object is the same as POST /invoices (create invoice). Only HTTP status differs: 200 OK here vs 201 Created on create. Fields such as status reflect the current invoice state (e.g. issued before payment, paid after).
{
"status": true,
"message": "Mission completed successfully",
"data": {
"external_id": "INV-PARTNER-001",
"reference_number": "INV-42-001",
"status": "paid",
"amount": 103.5,
"payment_url": "https://payment.rsompay.com/pay/invoice/...",
"customer": {
"id": "CUST-9",
"fullname": "Ahmed Ali",
"email": "customer@example.com",
"phone": "+966501234567"
},
"totals": {
"subtotal": 100,
"discount_total": 10,
"tax_total": 13.5,
"grand_total": 103.5
},
"items": [
{
"description": "Service fee",
"item_type": "service",
"quantity": 1,
"unit_price": 100,
"discount_amount": 10,
"tax_rate": 15,
"tax_amount": 13.5,
"total_amount": 103.5,
"reference_id": "LINE-1"
}
]
}
}
| HTTP | Cause |
|---|---|
422 | No query parameter — provide external_id or reference_number |
404 | Invoice not found for your client |
List customer payments across your invoices.
GET /transactions?customer_id={id}&page=1&per_page=20
| Parameter | Required | Default | Max |
|---|---|---|---|
customer_id | Yes | — | 255 |
page | No | 1 | — |
per_page | No | 20 | 100 |
Same envelope as other endpoints (status, message, data). data is an array of payment records; paginated responses include meta. payment_method reflects how the customer paid — e.g. card or tamara. refund_status is only present once a refund has been requested on that transaction — poll it to track asynchronous refund confirmation.
{
"status": true,
"message": "Mission completed successfully",
"data": [
{
"reference": "TX-REF-1",
"status": "completed",
"refund_status": null,
"amount": 103.5,
"currency_code": "SAR",
"payment_method": "card",
"invoice_external_id": "INV-PARTNER-001",
"captured_at": "2026-05-18 12:00:00",
"created_at": "2026-05-18 11:55:00"
},
{
"reference": "TX-REF-2",
"status": "completed",
"refund_status": "confirmed",
"amount": 250,
"currency_code": "SAR",
"payment_method": "tamara",
"invoice_external_id": "INV-PARTNER-002",
"captured_at": "2026-05-17 15:30:00",
"created_at": "2026-05-17 15:28:00"
}
],
"meta": {
"total": 2,
"per_page": 20,
"current_page": 1,
"last_page": 1
}
}
RsomPay POSTs to your notification_url after payment activity. No webhook is sent when the invoice is created. Delivery is asynchronous — respond with HTTP 2xx quickly.
| Event | When |
|---|---|
invoice.status_changed | Status changes after payment (previous_status in payload) |
payment.completed | Payment succeeded |
payment.failed | Payment failed |
POST {notification_url}
Content-Type: application/json
X-Rsom-Signature: a1b2c3d4e5f6...
Event details are in the JSON body. For authenticity, read header X-Rsom-Signature (see §7.5).
{
"event": "payment.completed",
"event_id": "550e8400-e29b-41d4-a716-446655440000",
"occurred_at": "2026-05-18T12:00:00+00:00",
"customer": { "id": "CUST-9", "fullname": "Ahmed Ali", ... },
"totals": { "subtotal": 100, "discount_total": 10, "tax_total": 13.5, "grand_total": 103.5 },
"invoice": {
"external_id": "INV-PARTNER-001",
"reference_number": "INV-42-001",
"status": "paid",
"amount": 103.5,
"payment_url": "https://payment.rsompay.com/pay/invoice/..."
},
"payment": {
"uuid": "660e8400-e29b-41d4-a716-446655440001",
"payment_method": "card",
"status": "completed",
"amount": 103.5,
"paid_at": "2026-05-18 12:00:00"
}
}
payment_method reflects how the customer paid — e.g. card (Mada/Visa/Mastercard), tamara (Tamara BNPL). Card payments may also return a specific brand when available (e.g. mada, visa).
2xx within a few seconds.event_id in the JSON body.X-Rsom-Signature before trusting the body (see §7.5).X-Rsom-Signature)RsomPay includes a signature on every webhook so you can confirm the request is genuine.
| Header | Value |
|---|---|
X-Rsom-Signature |
Signature sent by RsomPay. Read this header from the incoming request and verify it on your server before processing the JSON body. |
Webhook signing secret and how to verify are provided by RsomPay when your integration is set up. Request them from your integration / IT contact or tech@bseeds.sa.
event_id across retries — deduplicate on your side.payment_url.payment.rsompay.com.return_url with query parameters (UX only).GET /invoices/by-reference (primary) — call from your return_url handler or right after redirect.payment.completed / payment.failed arrives later, asynchronously on notification_url (after the redirect).return_url first. RsomPay sends the webhook to notification_url afterward (async). Do not wait for the webhook on the return page — confirm with GET /invoices/by-reference first.
On your return_url page, use GET /invoices/by-reference as your main check before you fulfill an order:
GET /invoices/by-reference?external_id=INV-PARTNER-001
Confirm data.status is paid. Poll briefly if status is still issued or pending (payment may still be confirming).
| Channel | When | Role |
|---|---|---|
return_url | Right after checkout | UX — show success/failure; not proof of payment alone |
GET /invoices/by-reference | On return page (primary) | Authoritative — confirm paid before fulfilling |
Webhook payment.completed | Later (async) | Backup — optional reconciliation; still use by-reference if webhook is delayed |
| Parameter | Description |
|---|---|
status | success, failed, or pending |
external_id | Your invoice id |
reference_number | RsomPay invoice number (e.g. INV-42-001) |
payment_reference | Payment reference (if available) |
amount_paid | Amount for this payment |
currency_code | e.g. SAR |
payment_method | How the customer paid — e.g. card, tamara, or card brand (mada, visa, …) when available |
https://partner.example.com/payment/return?status=success&external_id=INV-PARTNER-001&reference_number=INV-42-001&payment_reference=GW-123&amount_paid=103.5¤cy_code=SAR&payment_method=card
On data.status and webhook invoice.status for external API invoices:
| Status | Meaning |
|---|---|
issued | Issued — awaiting payment |
paid | Paid in full |
canceled | Cancelled — do not collect |
failed | Last payment attempt failed; customer may try again via payment_url |
| HTTP | Typical cause |
|---|---|
401 | Missing or invalid token |
403 | Wrong token type or suspended client |
404 | Invoice not found |
422 | Validation error |
500 | Server error |
| Issue | Fix |
|---|---|
| URL rejected | notification_url / return_url must be HTTPS and publicly reachable |
| by-reference 422 | Provide external_id or reference_number |
customer_id on by-reference | Not supported — use GET /transactions instead |
payment_method: "tamara" rejected (422 on payment_method) | Tamara isn't enabled for your account — omit the field, use mada/credit_card/apple_pay, or contact RsomPay to enable Tamara |
Validation messages may be localized — rely on HTTP status and field keys.
client-external-api token from RsomPay.X-Rsom-Signature (see §7.5).POST /invoices with a unique external_id — save payment_url.GET /invoices/by-reference?external_id=... — confirm status is issued.payment_url.return_url with query parameters (happens before webhook).GET /invoices/by-reference from your return handler — status is paid.payment.completed webhook on notification_url arrives later (if delivered).Refund a previously captured Dhamen payment on one of your invoices — in full or in part.
POST /invoices/{reference}/refund
{reference} is your invoice's external_id or its RsomPay reference_number (same identifiers accepted by GET /invoices/by-reference).
| Field | Required | Type | Description |
|---|---|---|---|
amount | No | number | Omit for a full refund of the remaining captured amount. Provide for a partial refund (minimum 1). |
reason | No | string | Free-text reason, max 500 characters — recorded for audit purposes. |
403 until settlement finishes.200 response below means "refund request accepted", not "refund completed." RsomPay submits the refund to the payment gateway and waits for the gateway's own confirmation before the refund is final. Poll GET /transactions and check the refund_status field on the matching transaction to see the outcome:
refund_status | Meaning |
|---|---|
pending_gateway | Submitted, awaiting gateway confirmation — not refunded yet. |
confirmed | Refund confirmed by the gateway — money has moved. |
stuck | No confirmation received after an extended period — under investigation by RsomPay. Contact support if you see this. |
submit_failed | The gateway rejected the request outright (see the error response below) — safe to correct and retry. |
{
"amount": 50.00,
"reason": "Customer requested partial refund"
}
{
"status": true,
"message": "Mission completed successfully",
"data": {
"reference": "DHAMEN-REFUND-9f2c1e6a-...",
"refund_status": "pending_gateway",
"amount": 50.00,
"currency_code": "SAR",
"created_at": "2026-07-28 10:15:00"
}
}
| HTTP | Cause |
|---|---|
403 | Refunds not enabled for your account, or the payment is currently mid-settlement / already settled |
404 | Invoice not found for your client, or no completed Dhamen payment exists on it |
422 | Refund amount invalid or exceeds the remaining refundable amount, or the gateway rejected the request |
Guide version v1.2.0 — API base path /api/external/v1 (unchanged).
| Method | Path | Purpose |
|---|---|---|
POST | /invoices | Create invoice |
GET | /invoices/by-reference | Query status (external_id or reference_number) |
POST | /invoices/{reference}/refund | Refund a captured payment, full or partial (requires refunds enabled on your account) |
GET | /transactions | Customer transactions (customer_id required) |
| Production | Sandbox | |
|---|---|---|
| Integration API | integration.rsompay.com | demo-integration.rsompay.com |
| Payment page | payment.rsompay.com | demo-payment.rsompay.com |
Download Postman collection (JSON)
customer_id in Postman is only for GET /transactions, not invoice lookup.
Technical support: tech@bseeds.sa
Website: https://rsompay.com
| Date | Notes |
|---|---|
| 2026-07-28 | Guide v1.2.0 — added POST /invoices/{reference}/refund (full/partial refunds, disabled by default, requires an enabled account) and a refund_status field on GET /transactions to track asynchronous refund confirmation. |
| 2026-07-13 | Guide v1.1.0 — added optional payment_method field to POST /invoices to pre-select mada, credit_card (Visa/Mastercard), apple_pay, or tamara, and skip the payment-method screen on the hosted checkout page. |
| 2026-05-19 | Guide v1.0.1 — partner-facing fields, payment flow, webhook signature docs |
| 2026-05-18 | Initial partner guide; docs site split to static hosting (docs.rsompay.com) |