API v1FiatPe Home
FiatPeDocs
SERVER 2 SERVER

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.

Test flowCard numberExpiryCVVExpected action
Native OTP4111 1111 1111 111111/26100otp_submit and resend_otp
Redirect4242 4242 4242 424211/26100redirect
HTML form4000 0000 0000 000211/26100html_form
STEP 1

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.

Open the Create Order API reference

Server request example

Use your FiatPe credentials only from a trusted backend environment.

REQUEST

Curl
Copy
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.

200 OK
Copy
{
  "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."
}
STEP 2

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.

Card data requires PCI DSS compliance.

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
Copy
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

FieldRequiredDescription
amountYesPayment amount in the currency’s smallest sub-unit.
currencyYesThree-letter currency code, such as INR.
contactYesCustomer phone number including the country code.
nameYesCustomer’s full name.
emailYesCustomer email address.
order_idYesOrder ID returned in Step 1.
return_urlYesHTTPS URL used after card authentication completes.
methodYesSet to card.
card.numberYesCard number without spaces. Never store or log this value.
card.nameYesName printed on the card.
card.expiry_monthYesTwo-digit expiry month.
card.expiry_yearYesTwo-digit expiry year.
card.cvvYesCard verification value. Never store this value.
metadataNoMerchant-defined key-value data associated with the payment.

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.

200 OK
Copy
{
  "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/"
    }
  ]
}
STEP 3

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
Copy
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.

200 OK
Copy
{
  "payment_id": "FIATPESTCM3YWO15VB1790705241",
  "order_id": "order_75db8a5703ba4d3a",
  "signature": "223e419c39bc40a8f63a22b82bb44a084b0d2f7462e88799dd8592ae7eed6c5f836f595716fa76c4a07dae9cf00d4096ac4d26d32ef01a6d15b5bce657988881"
}
STEP 4

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
Copy
curl --location --request POST 'https://api.fiatpe.com/v1/payments/FIATPESTCM3YWO15VB1790705241/otp/resend/' \
  --header 'Authorization: Basic <base64(api_key:secret_key)>' \
  --data ''

Response

200 OK
Copy
{
  "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
Copy
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"
    }
  }'
200 OK
Copy
{
  "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
Copy
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"
    }
  }'
200 OK
Copy
{
  "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_submit to submit the customer’s OTP.
  • Use the URL associated with resend_otp only when the customer requests another OTP.
  • For a redirect action, navigate the customer’s browser to the returned URL.
  • For an html_form action, return the HTML document to the browser with a text/html content 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.