HomeGuidesAPI Reference
API Reference

Token Payment

Recent Requests
Log in to see full request history
TimeStatusUser Agent
Retrieving recent requests…
LoadingLoading…

This guide explains how to perform a SALE transaction while saving the customer’s card for future use.

This flow is identical to a standard SALE transaction, with the addition of tokenization using the save_token parameter.


Endpoint

POST https://api.edfapay.com/payment/post

Content-Type: multipart/form-data


Request Parameters

FieldTypeRequiredDescription
actionStringYesTransaction type. Use "SALE" for standard sale transactions.
client_keyStringYesYour unique merchant identifier issued by Edfapay.
order_idStringYesUnique identifier for the transaction/order.
order_amountDecimalYesAmount to be charged (e.g., 0.11).
order_currencyStringYesCurrency code in ISO 4217 format (e.g., SAR).
order_descriptionStringYesDescription of the order.
req_tokenStringOptional"Y" to request a tokenized transaction; "N" otherwise.
payer_first_nameStringYesFirst name of the customer.
payer_last_nameStringYesLast name of the customer.
payer_addressStringYesThe email or address of the customer.
payer_countryStringYesCountry code (e.g., SA, UAE).
payer_cityStringYesCity of the payer.
payer_zipStringYesZIP or postal code of the payer.
payer_emailStringYesThe email address of the customer.
payer_phoneStringYesThe customer’s phone number with country code.
payer_ipStringYesIP address of the Customer
term_url_3dsStringYesURL that the customer is redirected to after completing 3D Secure authentication
authStringOptional"Y" to authorize only, "N" for authorize+ capture (default).
recurring_initStringOptional"Y"If this transaction is a recurring initiation
hashStringYesSecure hash for request authentication.
payment_typeStringYesMust be "TOKEN" to save card
tokenStringYesSaved card token
bypass_3dsStringYesControls 3DS flow ("Y" or "N" )

⚠️

Critical Requirement

You must send:

payment_type = "TOKEN"
token = saved card token

Otherwise, the request will be processed as a normal card payment.

⚠️

Important — 3D Secure Control (bypass_3ds)

This parameter controls whether the transaction goes through 3D Secure authentication.

bypass_3ds = "N" → 3DS is enforced (recommended)

bypass_3ds = "Y" → 3DS is skipped (frictionless flow)

Important Notes:

• Skipping 3DS may increase the risk of declines or fraud

• Liability shift typically applies only when 3DS is performed

• Some issuers may still force 3DS even if bypass is requested

Recommendation:

Use "N" for most transactions unless required otherwise.


Hash Generation

var password = "Merchant_Password";  
var token = "Saved_token";  
var email = "[email protected]";  
const ReverseString = str => [...str].reverse().join('');  
var final = (ReverseString(email) + password + ReverseString(token)).toUpperCase();
var finalHash = CryptoJS.MD5(final).toString();  
postman.setEnvironmentVariable('operation_hash', finalHash);  
// md5(strtoupper(strrev(email).PASSWORD.strrev(token)))  
❗️

Common Mistakes

Make sure to reverse the email and card segments correctly. Any mismatch between hash calculation on your side and our validation will cause the request to fail.


Notes:

  • password → Your secret hash key from EdfaPay.
  • cardNumber → The full card number entered by the customer.
  • email → The customer’s email used in hash generation.

Example cURL Request

curl --location 'https://apidev.edfapay.com/payment/post' \
--form 'client_key="XXXXXXXX"' \
--form 'order_id="Saved_Card_0000"' \
--form 'hash="HASH_VALUE"' \
--form 'order_amount="100"' \
--form 'payer_phone="+966556644333"' \
--form 'payer_country="SA"' \
--form 'payer_address="[email protected]"' \
--form 'action="SALE"' \
--form 'payer_zip="623524"' \
--form 'payer_ip="176.44.76.100"' \
--form 'order_currency="SAR"' \
--form 'payer_first_name="Test"' \
--form 'payer_city="Riyadh"' \
--form 'auth="N"' \
--form 'payer_last_name="User"' \
--form 'order_description="Test Order"' \
--form 'payer_email="[email protected]"' \
--form 'term_url_3ds="https://your-webhook.com"' \
--form 'recurring_init="N"' \
--form 'req_token="N"' \
--form 'payment_type="TOKEN"' \
--form 'token="TKN-XXXXXXXXXXXXXXXXX"' \
--form 'bypass_3ds="N"'
❗️

Important Note — Hash Generation

The hash parameter included in the request body is dynamically generated for each request and must not be hardcoded.

The hash value is calculated using specific request parameters combined with your merchant secret key. Any change in the request data requires regenerating the hash before sending the request.


Response Example

{
    "action": "SALE",
    "result": "REDIRECT",
    "status": "REDIRECT",
    "order_id": "Saved_Card_0000",
    "trans_id": "XXXXXXXXXXXXXXXX",
    "trans_date": "22-04-2026 15:44:05",
    "amount": "100.00",
    "currency": "SAR",
    "redirect_url": "https://api.edfapay.com/payment/Collector",
    "redirect_params": {
        "body": "EDFPAY_REF_f27ec0fd-1234-5678-9d56-9d9f22608beb"
    },
    "redirect_method": "POST"
}
{
    "action": "SALE",
    "result": "SUCCESS",
    "status": "SUCCESS",
    "order_id": "Test_Save_Token01",
    "trans_id": "XXXXXXXXXXXXXXXXX",
    "trans_date": "23-04-2026 01:27:58",
    "amount": "100.00",
    "currency": "SAR"
}
  • action: The type of transaction performed (always SALE).
  • result: Tells you what to do next (REDIRECT means further action is needed).
  • status: Current transaction status (also REDIRECT here).
  • order_id: The order ID you sent in the original request.
  • trans_id: Unique transaction ID generated by EdfaPay (also used at the end of the redirect_url).
  • trans_date: The date and time of the transaction.
  • amount: The transaction amount.
  • currency: The currency used (e.g., SAR).
  • redirect_url: The URL to which you should send the next POST request.
  • redirect_params.body: Base64-encoded data to include in the POST request body.
  • redirect_method: HTTP method to use for the redirect (always POST).
  • merchant_id: Merchant Name.

Redirect to Collector

POST https://api.edfapay.com/payment/Collector

Content-Type: application/json

{
  "body": "BASE64_ENCODED_JSON_STRING"
}
📘

Important Note

The body must be sent exactly as received from redirect_params.body. It is Base64-encoded JSON that the collector uses to complete the transaction.


Response

This request will return an HTML page (3DS challenge, OTP, etc.) which must be rendered to the user. You can open this in:

  • A browser (web integration)
  • A WebView (mobile apps)

Webhook Response

After the customer completes the payment (3DS / OTP), EdfaPay will send a server-to-server webhook to your configured endpoint.

This webhook contains the final transaction result.


Webhook Payload Example

{
  "action": "SALE",
  "amount": "65.00",
  "card": "512345xxxxxx0008",
  "card_brand": "Mastercard",
  "card_expiration_date": "01/2039",
  "currency": "SAR",
  "hash": "XXXXXX",
  "methods": "card",
  "order_id": "SAVING_TEST_0001",
  "processor_mid": "MID",
  "result": "SUCCESS",
  "rrn": "XXXXXXXX",
  "status": "SETTLED",
  "trans_date": "22-04-2026 16:17:30",
  "trans_id": "XXXXXXXXXXXXXX"
}

Field Explanation

  • action → Transaction type (SALE)
  • amount → Final charged amount
  • card → Masked card number
  • card_brand → Card scheme (e.g., Mastercard, Visa)
  • card_expiration_date → Expiry date of the card
  • currency → Transaction currency
  • result → Transaction result (SUCCESS / FAILED)
  • status → Final status (e.g., SETTLED, DECLINED)
  • order_id → Your original order ID
  • trans_id → Unique EdfaPay transaction ID
  • rrn → Retrieval reference number (used for reconciliation)
  • trans_date → Transaction date and time

⚠️

Important — Do Not Rely on Redirect


The webhook is the only reliable source for the final transaction status.


Do NOT rely on browser redirects or frontend responses for confirming payments.


💡

Best Practice


Always log webhook responses for debugging and reconciliation purposes.


Missing or failed webhook handling is the most common cause of payment mismatches.

Response
200
Language
LoadingLoading…
Response
Click Try It! to start a request and see the response here!