Skip to navigation

— API Reference · v1

Finglo Payments API

Public API for creating orders, charging cards, checking status, and issuing refunds.

Base URL

https://api.finglo.net

Auth

X-Api-Key: <publishable key>

Content type

application/json

Conventions#

Money#

amount is a decimal in major units (e.g. 1500.00 INR). currency is ISO‑4217.

Timestamps#

createdAt, updatedAt, expiresAt are integer epoch milliseconds.

IDs#

All id fields (orders, transactions, refunds, customers, MIDs) are ULIDs.

Statuses#

The status field on Orders, Transactions, and Refunds uses the same enum:

StatusMeaning
CREATEDResource created, not yet in a terminal state
SUCCESSTerminal — payment / refund succeeded
FAILEDTerminal — payment / refund failed
EXPIREDTerminal — order's expiresAt passed before payment

Errors#

All errors share the same envelope:

json
{
  "code": "DUPLICATE_MERCHANT_REF",
  "message": "An existing order already uses this merchantRef.",
  "details": { "merchantRef": "ORD-1777135255" }
}
HTTPcodeWhen
400INVALID_REQUESTMalformed JSON, missing required field, bad types
400INVALID_FIELDSpecific field-level validation failed
401UNAUTHORIZEDMissing or invalid X-Api-Key
403FORBIDDENKey lacks permission for this resource
404NOT_FOUNDOrder / transaction / refund not found
409DUPLICATE_MERCHANT_REFAn existing order already uses this merchantRef
422ORDER_EXPIREDTransaction attempted after order.expiresAt
422ORDER_ALREADY_PAIDTransaction attempted on an order in SUCCESS state
422ORDER_NOT_REFUNDABLERefund on an unpaid / failed / expired / already-refunded order
500INTERNAL_ERRORUnhandled server error

End-to-end flow#

bash
1. POST /orders                         → orderId, status=CREATED
2. POST /transactions (orderId, card)   → paymentUrl, pspCode
3. Open paymentUrl, drive the page (2D / 3D OTP / DUMMY approve|decline)
4. Poll GET /orders/{orderId}/status    → SUCCESS | FAILED | EXPIRED
5. (optional) POST /orders/{orderId}/refund   if status == SUCCESS

1. Create Order#

POST/api/v1/orders

Creates an order that a transaction can later be attached to.

Request#

FieldTypeRequiredNotes
merchantRefstringyesUnique on the merchant side. Reusing returns 409.
amountnumberyesDecimal, major units, > 0.
currencystringyesISO‑4217 (e.g. INR).
customer.namestringyes
customer.emailstringyes
customer.phonestringnoE.164 recommended.
redirectUrlstringnoWhere the user lands after the payment page completes.
webhookUrlstringnoReceives status-change POSTs (see Webhooks).
descriptionstringno
metadataobjectnoFree-form key/value.

Example#

bash
curl https://api.finglo.net/api/v1/orders \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: $FINGLO_API_KEY" \
  -d '{
    "merchantRef": "ORD-1777135255",
    "amount": 1500.00,
    "currency": "INR",
    "customer": {
      "name": "Rahul Sharma",
      "email": "rahul@example.com",
      "phone": "+91-9988776655"
    },
    "redirectUrl": "https://www.google.com",
    "webhookUrl": "https://merchant-site.com/api/webhook",
    "description": "Premium Plan Subscription"
  }'

Response — 201 Created#

json
{
  "id": "01KQ2W5V82FX9HNWJ14ESEE1PJ",
  "merchantId": "01KPX7N2TY3NXVEWE5ARKXX0TR",
  "merchantRef": "ORD-1777135255",
  "amount": 1500.00,
  "currency": "INR",
  "customer": {
    "id": "01KPX7WNTS6X1GD0V8DWD4EKQP",
    "name": "Rahul Sharma",
    "email": "rahul@example.com",
    "phone": "+91-9988776655"
  },
  "status": "CREATED",
  "redirectUrl": "https://www.google.com",
  "webhookUrl": "https://merchant-site.com/api/webhook",
  "description": "Premium Plan Subscription",
  "metadata": { "plan": "premium", "billing_cycle": "monthly" },
  "createdAt": 1777139379458,
  "updatedAt": 1777139379458,
  "expiresAt": 1777225779458
}

Errors#

  • 400 INVALID_REQUEST / INVALID_FIELD
  • 401 UNAUTHORIZED
  • 409 DUPLICATE_MERCHANT_REF

2. Create Transaction#

POST/api/v1/transactions

Attaches a card to an order and returns a paymentUrl. Open the URL in a browser to complete payment. Depending on the PSP that the dashboard's routing rules selected, the page is one of:

  • 2D — redirects on its own, no user action required
  • 3D — OTP page; user submits OTP
  • DUMMY — Approve / Decline buttons (test environment only)

After driving the page, poll GET /api/v1/orders/{orderId}/status until terminal.

Request#

FieldTypeRequiredNotes
orderIdstringyesFrom the order response.
paymentMethodstringyesCARD
card.cardNumberstringyes
card.expMonthstringyes"01" – "12"
card.expYearstringyes4-digit year
card.cvvstringyes
card.cardHolderNamestringyes

Example#

bash
curl https://api.finglo.net/api/v1/transactions \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: $FINGLO_API_KEY" \
  -d '{
    "orderId": "01KQ2W5V82FX9HNWJ14ESEE1PJ",
    "paymentMethod": "CARD",
    "card": {
      "cardNumber": "4111111111111111",
      "expMonth": "12",
      "expYear": "2028",
      "cvv": "123",
      "cardHolderName": "Rahul Sharma"
    }
  }'

Response — 201 Created#

json
{
  "id": "01KQ2W8732BYXSKYBKKH3KD1JT",
  "orderId": "01KQ2W5V82FX9HNWJ14ESEE1PJ",
  "merchantId": "01KPX7N2TY3NXVEWE5ARKXX0TR",
  "amount": 1500.00,
  "currency": "INR",
  "paymentMethod": "CARD",
  "paymentDetails": {
    "last4": "1111",
    "card_number": "4111111111111111",
    "cvv": "123",
    "card_network": "VISA",
    "card_holder_name": "Rahul Sharma",
    "exp_month": "12",
    "exp_year": "2028"
  },
  "pspCode": "DUMMY",
  "midId": "01KQ2R28H6W10XGXA927C9MCEH",
  "pspTransactionId": null,
  "status": "CREATED",
  "errorCode": null,
  "errorMessage": null,
  "createdAt": 1777139457122,
  "updatedAt": 1777139457122,
  "paymentUrl": "https://api.finglo.net/pay/01KQ2W8732BYXSKYBKKH3KD1JT"
}

pspCode tells you which PSP routing landed on. paymentUrl is the page to drive.

Errors#

  • 400 INVALID_REQUEST / INVALID_FIELD
  • 401 UNAUTHORIZED
  • 404 NOT_FOUND — orderId doesn't exist
  • 422 ORDER_EXPIRED / ORDER_ALREADY_PAID

3. Get Order Status#

GET/api/v1/orders/{orderId}/status

Returns the current state of the order. Poll this until status is terminal.

Recommended polling schedule#

WindowInterval
0 – 1 min10 s
1 – 6 min60 s
6 – 36 min5 min
36 min – 2 hr30 min

Stop on SUCCESS, FAILED, or EXPIRED.

Example#

bash
curl https://api.finglo.net/api/v1/orders/01KQ2W5V82FX9HNWJ14ESEE1PJ/status \
  -H "X-Api-Key: $FINGLO_API_KEY"

Response — 200 OK#

json
{
  "id": "01KQ2W5V82FX9HNWJ14ESEE1PJ",
  "merchantId": "01KPX7N2TY3NXVEWE5ARKXX0TR",
  "merchantRef": "ORD-1777135255",
  "amount": 1500.00,
  "currency": "INR",
  "customer": {
    "id": "01KPX7WNTS6X1GD0V8DWD4EKQP",
    "name": "Rahul Sharma",
    "email": "rahul@example.com",
    "phone": "+91-9988776655"
  },
  "status": "SUCCESS",
  "redirectUrl": "https://www.google.com",
  "webhookUrl": "https://merchant-site.com/api/webhook",
  "description": "Premium Plan Subscription",
  "metadata": { "plan": "premium", "billing_cycle": "monthly" },
  "createdAt": 1777139379458,
  "updatedAt": 1777139486752,
  "expiresAt": 1777225779458
}

Errors#

  • 401 UNAUTHORIZED
  • 404 NOT_FOUND

4. Refund Order#

POST/api/v1/orders/{orderId}/refund

Initiates a full refund for the order's successful transaction. Partial refunds are not supported. No request body.

Example#

bash
curl -X POST https://api.finglo.net/api/v1/orders/01KQ2W5V82FX9HNWJ14ESEE1PJ/refund \
  -H "X-Api-Key: $FINGLO_API_KEY"

Response — 201 Created#

json
{
  "id": "01KQ2X3PRN09WDB7TVMWK17DZG",
  "transactionId": "01KQ2W8732BYXSKYBKKH3KD1JT",
  "orderId": "01KQ2W5V82FX9HNWJ14ESEE1PJ",
  "merchantId": "01KPX7N2TY3NXVEWE5ARKXX0TR",
  "midId": "01KQ2R28H6W10XGXA927C9MCEH",
  "requestedAmount": 1500.00,
  "refundedAmount": null,
  "currency": "INR",
  "status": "CREATED",
  "pspRefundId": "DUMMY_PENDING_01KQ2X3PRN09WDB7TVMWK17DZG",
  "reason": null,
  "errorCode": null,
  "errorMessage": null,
  "createdAt": 1777140357909,
  "updatedAt": 1777140357909
}

refundedAmount is null until the refund reaches SUCCESS.

Errors#

  • 401 UNAUTHORIZED
  • 404 NOT_FOUND
  • 422 ORDER_NOT_REFUNDABLE — order is unpaid, failed, expired, or already refunded

Webhooks#

If webhookUrl was supplied on order creation, Finglo POSTs to it on every status change. The body is the same shape as the response from GET /api/v1/orders/{orderId}/status.

The endpoint should:

  • accept POST application/json
  • return any 2xx within 10s — non-2xx responses are retried with exponential backoff
  • be idempotent (the same status update may arrive more than once)