S2S Card
Create card payments from your backend using FiatPe’s server-to-server payment flow.
Test cards by authentication flow
Use these card details only in the FiatPe test environment. They are designed to return the indicated next.action flow.
Create the order on your server
Create a new FiatPe order for each payment attempt. Amounts use the smallest currency sub-unit: for INR, 5000 represents ₹50.00. Store the returned order ID against your internal order before using it in the S2S payment request.
Server request example
Use your FiatPe credentials only from a trusted backend environment.
REQUEST
curl --request POST \
--url https://api.fiatpe.com/v1/orders/ \
--header "Authorization: Basic YOUR_BASE64_CREDENTIALS" \
--header "Content-Type: application/json" \
--data '{
"amount": 5000,
"currency": "INR"
}'Response
Store the returned data.id and pass it as the order_id in Step 2.
{
"data": {
"id": "order_2f40f08f4baa4e5b",
"amount": 5000,
"entity": "order",
"status": "created",
"currency": "INR",
"metadata": {},
"created_at": 1788148983,
"return_url": null,
"amount_paid": 0,
"bank_details": null,
"return_method": "POST",
"amount_pending": 5000
},
"message": "order created successfully."
}Initiate a native card payment
Send the card payment request from your PCI-compliant backend. Generate the Basic authorization value by Base64 encoding api_key:secret_key.
Never log, persist, cache, or expose the full card number or CVV. Use the test card below only in the FiatPe test environment.
REQUEST
curl --location 'https://api.fiatpe.com/v1/payments/create/s2s/' \
--header 'Authorization: Basic <base64(api_key:secret_key)>' \
--header 'Content-Type: application/json' \
--data-raw '{
"amount": 5000,
"currency": "INR",
"contact": "+919898989898",
"name": "Aftab Hussain",
"email": "customer@example.com",
"order_id": "order_75db8a5703ba4d3a",
"return_url": "https://example.com/payment/return",
"description": "Test payment",
"method": "card",
"card": {
"number": "4111111111111111",
"name": "Gaurav",
"expiry_month": "11",
"expiry_year": "26",
"cvv": "100"
},
"metadata": {
"note_key": "value1"
}
}'Request fields
Native OTP flow
Native flow: Send OTP
The initial card payment request sends an OTP to the customer for a native OTP payment. Store the returned payment_id. The next array provides the actions required to submit or resend the OTP.
{
"payment_id": "FIATPESTCM3YWO15VB1790705241",
"next": [
{
"action": "otp_submit",
"url": "https://api.fiatpe.com/v1/payments/FIATPESTCM3YWO15VB1790705241/otp/submit/"
},
{
"action": "resend_otp",
"url": "https://api.fiatpe.com/v1/payments/FIATPESTCM3YWO15VB1790705241/otp/resend/"
}
]
}Native flow: Submit OTP
After the customer enters the OTP, submit it from your secure backend using the payment_id returned in Step 2. Never log or persist the OTP.
REQUEST
curl --location 'https://api.fiatpe.com/v1/payments/FIATPESTCM3YWO15VB1790705241/otp/submit/' \
--header 'Authorization: Basic <base64(api_key:secret_key)>' \
--header 'Content-Type: application/json' \
--data '{
"otp": "123456"
}'Successful response
Verify the returned signature on your server before fulfilling the order. Match the payment ID and order ID with your stored records.
{
"payment_id": "FIATPESTCM3YWO15VB1790705241",
"order_id": "order_75db8a5703ba4d3a",
"signature": "223e419c39bc40a8f63a22b82bb44a084b0d2f7462e88799dd8592ae7eed6c5f836f595716fa76c4a07dae9cf00d4096ac4d26d32ef01a6d15b5bce657988881"
}Native flow: Resend OTP
If the customer does not receive the OTP, call the resend endpoint using the same payment_id. Trigger this request only after an explicit customer action and prevent repeated rapid requests.
REQUEST
curl --location --request POST 'https://api.fiatpe.com/v1/payments/FIATPESTCM3YWO15VB1790705241/otp/resend/' \
--header 'Authorization: Basic <base64(api_key:secret_key)>' \
--data ''Response
{
"message": "OTP Resend successfully"
}Alternative card flows
Redirect flow
Some cards return next[0].action as redirect. The following test-card example demonstrates this flow.
REQUEST
curl --location 'https://api.fiatpe.com/v1/payments/create/s2s/' \
--header 'Authorization: Basic <base64(api_key:secret_key)>' \
--header 'Content-Type: application/json' \
--data-raw '{
"amount": 5000,
"currency": "INR",
"contact": "+919898989898",
"name": "Aftab Hussain",
"email": "customer@example.com",
"order_id": "order_b515d1952d194824",
"return_url": "https://example.com/payment/return",
"description": "Test payment",
"method": "card",
"card": {
"number": "4242424242424242",
"name": "Gaurav",
"expiry_month": "11",
"expiry_year": "26",
"cvv": "100"
},
"metadata": {
"note_key": "value1"
}
}'{
"payment_id": "FIATPESTK1CU1FNRXR1790705821",
"next": [
{
"action": "redirect",
"url": "https://api.fiatpe.com/v1/payments/FIATPESTK1CU1FNRXR1790705821/authentication/"
}
]
}Redirect the customer’s browser to next[0].url to complete card authentication. Do not call this URL from your backend.
HTML form flow
A card can also return next[0].action as html_form. The following test-card example demonstrates this response flow.
REQUEST
curl --location 'https://api.fiatpe.com/v1/payments/create/s2s/' \
--header 'Authorization: Basic <base64(api_key:secret_key)>' \
--header 'Content-Type: application/json' \
--data-raw '{
"amount": 5000,
"currency": "INR",
"contact": "+919898989898",
"name": "Aftab Hussain",
"email": "customer@example.com",
"order_id": "order_b515d1952d194824",
"return_url": "https://example.com/payment/return",
"description": "Test payment",
"method": "card",
"card": {
"number": "4000000000000002",
"name": "Gaurav",
"expiry_month": "11",
"expiry_year": "26",
"cvv": "100"
},
"metadata": {
"note_key": "value1"
}
}'{
"payment_id": "FIATPEST8OJ7CDB2BI1790705845",
"next": [
{
"action": "html_form",
"html_content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>Redirecting | FiatPe</title>\n <script src=\"https://cdnjs.cloudflare.com/ajax/libs/lottie-web/5.12.2/lottie.min.js\"></script>\n</head>\n<body>\n <div class=\"redirect-container\">\n <div id=\"lottie-loader\"></div>\n <h1>Redirecting...</h1>\n <p>Please wait while we redirect you securely. Do not close this window.</p>\n <form id=\"payment-form\" method=\"GET\"\n action=\"https://api.fiatpe.com/v1/payments/FIATPEST8OJ7CDB2BI1790705845/authentication/\"\n hidden>\n <input type=\"hidden\" name=\"paymentMode\" value=\"CARD\">\n </form>\n <noscript>\n <button type=\"submit\" form=\"payment-form\">Continue to payment</button>\n </noscript>\n </div>\n <script>\n if (window.lottie) {\n lottie.loadAnimation({\n container: document.getElementById(\"lottie-loader\"),\n renderer: \"svg\",\n loop: true,\n autoplay: true,\n path: \"https://bucket.fiatpe.com/static/animation/lottie/fiatpe_pg_processing_loader.json\"\n });\n }\n window.setTimeout(function () {\n document.getElementById(\"payment-form\").submit();\n }, 1000);\n </script>\n</body>\n</html>"
}
]
}Render the returned html_content as a full HTML document in the customer’s browser. The included form continues the card authentication flow automatically.
Complete card authentication
- Use the URL associated with
otp_submitto submit the customer’s OTP. - Use the URL associated with
resend_otponly when the customer requests another OTP. - For a
redirectaction, navigate the customer’s browser to the returned URL. - For an
html_formaction, return the HTML document to the browser with atext/htmlcontent type. - Never log or persist OTP values.
- Do not treat OTP submission as proof of payment success.
- Confirm the final status on your backend and process webhooks idempotently.