Pay by Token
Charge a saved card token for Card-on-File (CoF) transactions — use a previously tokenized payment method for recurring or one-click payments.
Pay by Token
API Version: 3.0.0
The Pay by Token endpoint charges a previously tokenized card for Card-on-File (CoF) transactions. It uses a secure payment_token generated through the Add Card (AUTH REVERSAL) flow to process payments without requiring the customer to re-enter their card details. This is ideal for recurring billing, subscriptions, and one-click checkout.
Use class: "CAUTH" with action: "SALE" or "AUTH". See Class by API for the full mapping.
Navigate to Developers → API Keys → Add new API key → Select Hosted Solution in the Channel Dropdown to generate your API credentials.
Prerequisites
Before initiating a Card-on-File (CoF) transaction, ensure that the following prerequisites are met:
- CAUTH MID must be enabled for the merchant. If it is not enabled, please contact the PayOrc Support Team to activate it.
- A valid payment token must be available.
- Token is generated through ECOM class with the Add Card (AUTH REVERSAL) endpoint
- Action can be
AUTH,AUTH_REVERSAL, andSALEdepending upon the required functionality
- The
m_customer_idmust be provided to securely process the transaction and associate the payment token with the customer. - Payment tokens are PSP-specific. A token generated (tokenized) through one PSP cannot be used with another PSP.
- If the configured PSP is changed, any existing tokens associated with the previous PSP will become invalid.
- In such cases, the customer must verify their card again to generate a new token with the newly configured PSP.
Payment tokens are PSP-specific. If you switch your Payment Service Provider, all existing tokens will be invalidated and customers must re-enter their card details.
Endpoint
| Method | URL |
|---|---|
| POST | https://api.payorc.com/orders/v1/create |
Please use the test credentials for sandbox testing.
Headers
| Header | Type | Required | Description |
|---|---|---|---|
merchant-key | String | Yes | Your merchant API key (e.g., live-D111PIS13YK) |
merchant-secret | String | Yes | Your merchant API secret (e.g., sec-JI11G0P13Z0) |
Content-Type | String | Yes | Must be application/json |
Request Body — Top-Level Fields
All fields are nested inside a top-level data object: { "data": { ... } }. Same schema as Payment Request API — focus fields are class: "CAUTH", payment_token, and customer_details.m_customer_id.
| Field | Type | Required | Description |
|---|---|---|---|
class | String | Yes | Must be CAUTH |
action | String | Yes | SALE or AUTH — see Transaction Actions |
capture_method | String | No | AUTOMATIC or MANUAL — only when action is AUTH. Default: AUTOMATIC if omitted. Ignored for SALE |
payment_token | String | Yes | Token from Add Card (AUTH REVERSAL) |
customer_details | Object | Yes | m_customer_id required — see Customer Details |
order_details | Object | Yes | Order amount, currency, and description — see Order Details |
billing_details | Object | Yes | Billing address — see Billing Details |
shipping_details | Object | Yes | Shipping address — see Shipping Details |
items | Array | No | Line items — see Items |
urls | Object | Yes | Redirect and webhook URLs — see URLs |
parameters | Array | No | Merchant metadata echoed in webhooks — see Parameters |
custom_data | Array | No | MID Group / Split Payment — see Custom Data |
Same request body as Payment Request API. Include urls.webhook_url the same way. Focus: class: "CAUTH", payment_token, and customer_details.m_customer_id (must match the token).
Transaction Classes
The class field determines the type of transaction.
| Value | Name | Description |
|---|---|---|
CAUTH | Card Auth | Card-on-File transaction using a tokenized card |
For Pay by Token, class must be CAUTH. Use class: "ECOM" only for hosted checkout flows (Payment Request) and card tokenization (AUTH REVERSAL).
Transaction Actions
The action field determines the type of transaction to perform with the tokenized card.
| Value | Name | Description |
|---|---|---|
SALE | Sale | Authorize AND capture in one step — funds are taken immediately |
AUTH | Auth (Pre-Authorization) | Hold funds on the card without capturing — capture later via Manage Payment API |
For card tokenization (Add Card), use class: "ECOM" with action: "AUTH_REVERSAL" — not Pay by Token. See AUTH REVERSAL.
Customer Details
The customer_details object is required. For this API, m_customer_id is mandatory so the token is linked to the customer.
| Field | Type | Required | Description |
|---|---|---|---|
m_customer_id | String | Yes | Your internal customer identifier — required to link the token to the customer |
name | String | Yes* | Customer's full name (first and last name) — may be "" |
email | String | Yes* | Customer's email address — may be "" |
mobile | String | No | Customer's mobile phone number (digits only) |
code | String | No | Country dialing code (e.g., 91 for India, 971 for UAE) |
* Required by schema; pass an empty string if not available.
m_customer_id is required. The m_customer_id must match the customer used when the payment_token was created.
Order Details
| Field | Type | Required | Description |
|---|---|---|---|
m_order_id | String | No | Your internal order identifier |
amount | Number | Yes | Order amount — minimum 1 (e.g., 60.20) |
convenience_fee | Number | Yes* | Additional fee — may be 0 or "" |
quantity | Number | Yes* | Number of items — may be ""; defaults to 1 in processing |
currency | String | Yes | ISO 4217 currency code (e.g., AED, USD, EUR, GBP, INR) |
description | String | Yes* | Human-readable order description — may be "" |
return_url | String | No | Optional return URL stored with the order |
* Required by schema; pass an empty string or 0 if not applicable.
The amount field must be a number without currency symbols, commas, or spaces. Minimum value is 1.
Billing Details
The billing_details object is required. Fields may be empty strings if not collected.
| Field | Type | Required | Description |
|---|---|---|---|
address_line1 | String | Yes* | Billing address line 1 — may be "" |
address_line2 | String | Yes* | Billing address line 2 — may be "" |
city | String | Yes* | Billing city — may be "" |
province | String | Yes* | Billing state or province — may be "" |
country | String | Yes* | ISO 3166-1 alpha-2 country code (e.g., AE) — may be "" |
pin | String | Yes* | Billing postal/ZIP code — may be "" |
Shipping Details
The shipping_details object is required. Fields may be empty strings if not collected.
| Field | Type | Required | Description |
|---|---|---|---|
shipping_name | String | Yes* | Recipient's full name — may be "" |
shipping_email | String | Yes* | Recipient's email — may be "" |
shipping_code | String | No | Country dialing code for shipping mobile |
shipping_mobile | String | No | Recipient's phone number (digits only) |
address_line1 | String | Yes* | Shipping address line 1 — may be "" |
address_line2 | String | Yes* | Shipping address line 2 — may be "" |
city | String | Yes* | Shipping city — may be "" |
province | String | Yes* | Shipping state or province — may be "" |
country | String | Yes* | ISO 3166-1 alpha-2 country code — may be "" |
pin | String | Yes* | Shipping postal/ZIP code — may be "" |
location_pin | String | Yes* | Google Maps location URL — may be "" |
shipping_currency | String | Yes* | ISO 4217 currency for shipping — may be "" |
shipping_amount | Number | Yes* | Shipping cost — may be 0 or "" |
Items
The items array is optional. When provided, each item supports the fields below. Use title (not name) and reference_id (not sku) — these match what the API accepts and stores.
| Field | Type | Required | Description |
|---|---|---|---|
title | String | No | Product name |
description | String | No | Product description |
quantity | Number | No | Quantity ordered (minimum 1) |
unit_price | String | No | Price per unit (e.g., "10.00") |
discount_amount | String | No | Discount applied |
reference_id | String | No | Merchant product identifier |
image_url | String | No | Product image URL |
product_url | String | No | Product page URL |
gender | String | No | Male, Female, Kids, or Other |
category | String | No | Product category |
color | String | No | Product color |
product_material | String | No | e.g., cotton, polyester |
size_type | String | No | Size type label |
size | String | No | e.g., L, XL, 12 |
brand | String | No | Brand name |
is_refundable | Boolean | No | Whether the product can be returned |
URLs
The urls object is required. Redirect URLs may be empty strings — PayOrc falls back to MID default URLs when not provided.
| Field | Type | Required | Description |
|---|---|---|---|
success | String | No | URL to redirect after successful payment |
cancel | String | No | URL to redirect if customer cancels |
failure | String | No | URL to redirect if payment fails |
webhook_url | String | No | Per-order webhook URL (HTTPS). Overrides dashboard webhook for this order when set |
You can configure a default webhook URL in the PayOrc Merchant Portal. Use urls.webhook_url to override it for a specific order. The URL must use HTTPS (localhost is allowed for testing).
Parameters
parameters is an array of objects — one object per field. PayOrc echoes these values in webhook notifications.
"parameters": [
{ "alpha": "your-value" },
{ "beta": "" },
{ "gamma": "" },
{ "delta": "" },
{ "epsilon": "" }
]| Field | Type | Required | Description |
|---|---|---|---|
alpha | String | No | Merchant-defined data |
beta | String | No | Merchant-defined data |
gamma | String | No | Merchant-defined data |
delta | String | No | Merchant-defined data |
epsilon | String | No | Merchant-defined data |
Custom Data
custom_data is an array of objects — same shape as parameters. Use it for MID Group and Split Payment configuration. See Custom Data.
"custom_data": [
{ "alpha": "" },
{ "beta": "" },
{ "gamma": "" },
{ "delta": "" },
{ "epsilon": "" }
]| Field | Type | Required | Description |
|---|---|---|---|
alpha | String | No | Feature flag / routing key (e.g. MID_GROUP, ` |
beta | String | No | Feature value (e.g. MID label or split rule) |
gamma | String | No | Additional rule / reserved |
delta | String | No | Additional rule / reserved |
epsilon | String | No | Additional rule / reserved |
Response — Success
Pay by Token has two outcomes on POST /orders/v1/create:
Path 1: Immediate payment (MIT success)
When the stored card is eligible for merchant-initiated payment, the API processes the charge synchronously and returns the same webhook-style payload wrapped in a standard API envelope. The data object matches what you would receive in a webhook notification.
{
"status": "success",
"code": "00",
"message": "Transaction success with PAYMOB",
"data": {
"action": "CAPTURE",
"status": "SUCCESS",
"order_status": "CAPTURED",
"m_order_id": "ORD-2024-001",
"p_order_id": "1000010240",
"p_request_id": "1000010200",
"psp_ref_id": "8902217",
"transaction_id": "1000010658",
"is_live": false,
"terminal_label": "paymob-terminal-01",
"currency": "AED",
"amount": "200.00",
"shipping_fee": "0.00",
"convenience_fee": "0.00",
"channel": "ORD API",
"channel_id": "",
"customer_details": {
"name": "John Doe",
"email": "[email protected]",
"code": "91",
"mobile": "9876543210",
"m_customer_id": "CUST-1234"
},
"billing_address": {
"address_line_1": "123 Main Street",
"address_line_2": "",
"city": "Dubai",
"state": "Dubai",
"country": "AE",
"pincode": "54044"
},
"shipping_address": {
"address_line_1": "123 Main Street",
"address_line_2": "",
"city": "Dubai",
"state": "Dubai",
"country": "AE",
"pincode": "54044"
},
"ip_country": "AE",
"remark": "payment",
"reason": "",
"psp": "PAYMOB",
"payment_method": "DEBIT CARD",
"m_payment_token": "B2JmcSabcd85UDEwZXdTVElx12JNUT09",
"transaction_time": "15/06/2023 12:20:27",
"payment_method_data": {
"scheme": "VISA",
"card_country": "UAE",
"card_type": "CREDIT",
"mask_card_number": "4111****1111",
"expiry_month": "12",
"expiry_year": "2045"
},
"apm_name": "",
"apm_identifier": "",
"sub_merchant_identifier": "",
"parameters": [
{ "alpha": "" },
{ "beta": "" },
{ "gamma": "" },
{ "delta": "" },
{ "epsilon": "" }
],
"custom_data": [
{ "alpha": "" },
{ "beta": "" },
{ "gamma": "" },
{ "delta": "" },
{ "epsilon": "" }
]
}
}- Top-level
statusis"success"andcodeis"00"for MIT success. - The
dataobject is the full webhook payload — see Webhook Payload Structure for all fields. - For
action: "AUTH",order_statusmay beAUTHORISEDandactionwill beAUTHinstead ofCAPTURE. messageincludes the PSP name (e.g.,"Transaction success with PAYMOB").
Path 1b: Immediate payment failed (MIT failure)
When MIT is attempted but the PSP declines the payment:
{
"status": "failed",
"code": "PAYMENT_FAILED",
"message": "Transaction Failed",
"data": {
"action": "SALE",
"status": "FAILED",
"order_status": "FAILED",
"m_order_id": "ORD-2024-001",
"p_order_id": "1000010240",
"p_request_id": "1000010200",
"transaction_id": "1000010658",
"currency": "AED",
"amount": "200.00",
"m_payment_token": "B2JmcS85UDEwZXdTVElxc0swc1JNUT09",
"payment_method_data": {
"scheme": "VISA",
"card_country": "UAE",
"card_type": "CREDIT",
"mask_card_number": "4111****1111"
}
},
"payment_link": "https://checkout.payorc.com/pay/xxxxx",
"iframe_link": "https://checkout.payorc.com/iframe/xxxxx"
}Path 2: Payment link fallback
When the card is not yet eligible for MIT (e.g., mandate not registered), the API returns the standard hosted create response. The message explains why a payment link was returned (e.g., "Card is not tokenized. Please complete payment again using the payment link."):
{
"status": "SUCCESS",
"status_code": "00",
"message": "Card is not tokenized. Please complete payment again using the payment link.",
"p_order_id": 1000010240,
"m_order_id": "ORD-2024-001",
"p_request_id": 1000010200,
"order_creation_date": "15/06/2023 12:20:27",
"amount": "AED 200.00",
"payment_link": "https://checkout.payorc.com/pay/xxxxx",
"iframe_link": "https://checkout.payorc.com/iframe/xxxxx"
}Final transaction status for Path 2 is delivered via webhook notification after the customer completes payment on the hosted page.
Response Codes
| Code | Status | Meaning |
|---|---|---|
00 | SUCCESS | Transaction processed successfully |
400 | fail | Bad Request — missing or invalid parameters |
401 | fail | Unauthorized — invalid merchant key or secret |
403 | fail | Forbidden — account restrictions |
422 | fail | Unprocessable Entity — validation error |
429 | fail | Too Many Requests — rate limit exceeded |
500 | fail | Internal Server Error — retry with backoff |
Error Handling
| Scenario | HTTP Code | Error Message | Resolution |
|---|---|---|---|
| Invalid credentials | 401 | Invalid merchant key and secret | Verify your merchant-key and merchant-secret |
| Missing amount | 400 | Amount is required | Include amount in order_details |
| Invalid currency | 422 | Unsupported currency | Use a supported ISO 4217 code |
| Duplicate order ID | 400 | Order ID already exists | Use a unique m_order_id |
| Rate limited | 429 | Too many requests | Wait and retry with exponential backoff |
| CAUTH MID not enabled | 403 | CAUTH MID not enabled | Contact PayOrc Support to activate CAUTH MID |
| Invalid token | 422 | Invalid payment token | Token may be expired or PSP-specific — generate a new token |
| PSP mismatch | 422 | Token PSP mismatch | Token was generated with a different PSP — re-tokenize the card |
Always implement proper error handling. Check both the HTTP status code AND the status field in the response body before proceeding.
Code Examples
Replace {URL} with https://api.payorc.com/orders/v1/create, and {merchant-key} / {merchant-secret} with your actual credentials.
Example 1: Pay by Token — SALE
Same full body as Payment Request API. Focus fields: class: "CAUTH", payment_token, and customer_details.m_customer_id.
curl --location --globoff 'https://api.payorc.com/orders/v1/create' \
--header 'merchant-key: {merchant-key}' \
--header 'merchant-secret: {merchant-secret}' \
--header 'Content-Type: application/json' \
--data-raw '{
"data": {
"class": "CAUTH",
"action": "SALE",
"capture_method": "",
"payment_token": "B2JmcS85UDEwZXdTVElxc0swc1JNUT09",
"customer_details": {
"m_customer_id": "123",
"name": "John Doe",
"email": "[email protected]",
"mobile": "9876543210",
"code": "91"
},
"order_details": {
"m_order_id": "ORD-2024-001",
"amount": 200,
"quantity": 1,
"convenience_fee": "",
"currency": "AED",
"description": "Subscription payment",
"return_url": ""
},
"billing_details": {
"address_line1": "123 Main Street",
"address_line2": "",
"city": "Dubai",
"province": "Dubai",
"country": "AE",
"pin": "54044"
},
"shipping_details": {
"shipping_name": "John Doe",
"shipping_email": "[email protected]",
"shipping_code": "",
"shipping_mobile": "",
"address_line1": "123 Main Street",
"address_line2": "",
"city": "Dubai",
"province": "Dubai",
"country": "AE",
"pin": "54044",
"location_pin": "",
"shipping_currency": "AED",
"shipping_amount": 0
},
"urls": {
"success": "https://yourdomain.com/payment/success",
"cancel": "https://yourdomain.com/payment/cancel",
"failure": "https://yourdomain.com/payment/failure",
"webhook_url": "https://yourdomain.com/webhook"
},
"parameters": [
{
"alpha": ""
},
{
"beta": ""
},
{
"gamma": ""
},
{
"delta": ""
},
{
"epsilon": ""
}
],
"custom_data": [
{
"alpha": ""
},
{
"beta": ""
},
{
"gamma": ""
},
{
"delta": ""
},
{
"epsilon": ""
}
],
"items": [
{
"title": "Premium Plan",
"description": "Monthly subscription",
"quantity": 1,
"unit_price": "100.00",
"discount_amount": "0.00",
"reference_id": "SKU-001",
"image_url": "https://example.com/image.png",
"product_url": "https://example.com/product",
"gender": "Male",
"category": "Subscription",
"color": "",
"product_material": "",
"size_type": "",
"size": "",
"brand": "PayOrc",
"is_refundable": true
}
]
}
}'Supported Currency Codes
| Code | Currency | Symbol |
|---|---|---|
AED | UAE Dirham | د.إ |
USD | US Dollar | $ |
EUR | Euro | € |
GBP | British Pound | £ |
INR | Indian Rupee | ₹ |
SAR | Saudi Riyal | ﷼ |
QAR | Qatari Riyal | ﷼ |
KWD | Kuwaiti Dinar | د.ك |
BHD | Bahraini Dinar | .د.ب |
OMR | Omani Rial | ر.ع. |