Built for the way ambitious Indian businesses move moneyExplore business banking
EXPERIA360 API KIT · V1

Integrate collections
without handling payment credentials.

Create amount-bound payment orders from your server, send customers to the Experia360 hosted UPI checkout, and confirm orders only from an authenticated status response or a signature-verified callback.

Server-to-server authentication Idempotent financial writes Signed callback delivery
DEVELOPER PACKAGE

Everything required to start.

  • OpenAPI 3.1 specification
  • Postman collection
  • PHP & Node webhook verifiers
  • WooCommerce gateway v1.1.0
Production access remains subject to KYC, product and provider activation.
01
OVERVIEW

A small, deliberate merchant surface.

The stable v1 merchant API covers hosted PayIn collections and directly authorized PayOut instructions. Your API secret never enters customer browsers, and bank/provider credentials remain behind Experia360.

BASE URLhttps://api.experia360.com/api/v1
CONTENT TYPEapplication/json
CURRENCYINR · amount_paise
VERSIONINGURL versioned · /v1

PCI boundary: Experia360 merchant APIs do not ask for card numbers, UPI PINs or customer OTPs. Never collect or forward those values.

02
AUTHENTICATION

Two server-side credentials.

Generate a client under Dashboard → APIHub. The secret is displayed once. Store it in a secrets manager or protected server environment.

HeaderValueRequired
X-Experia-Client-Idexc_…Every authenticated request
AuthorizationBearer exs_…Every authenticated request
Idempotency-KeyUUID v4Every financial create request
collections:write

Create payment orders.

collections:read

Retrieve the authoritative order status.

payouts:write

Authorize and submit a payout directly to the configured provider route.

payouts:read

Retrieve payout status, UTR and attempts.

Network restriction: Configure the public outbound IPv4 or IPv6 addresses of your servers in APIHub. Once at least one address is saved, all other source IPs receive API_IP_NOT_ALLOWED.

03
QUICK START

Create the first hosted payment.

  1. 1
    Activate Experia Collect and APIHub

    Complete onboarding and configure an approved collection route.

  2. 2
    Create a scoped client

    Select collections:write and collections:read.

  3. 3
    Create a payment order from your backend

    Persist your UUID idempotency key against the merchant order.

  4. 4
    Follow next_action

    Redirect to hosted checkout or render the returned UPI intent without altering its payload.

  5. 5
    Confirm server-side

    Verify the signed callback and retrieve the order before fulfilment.

POST/merchant/payment-orderscollections:write

Create payment order

Creates one amount-bound payment order. Use CHECKOUT for the complete Experia360-hosted page or INTENT to receive an app-ready UPI URI and QR payload. Repeating the same idempotency key returns the original order.

RECOMMENDEDHosted checkoutresponse_mode: CHECKOUT

Experia360 collects payer details, presents the dynamic QR, tracks expiry and shows the final payment state.

ADVANCEDDirect intentresponse_mode: INTENT

Your application renders the exact returned UPI URI. Customer details and explicit consent are mandatory.

FieldTypeRule
amount_paiseintegerRequired · 100 to 10,000,000,000
purposestringRequired · 3–255 characters
merchant_order_referencestringOptional · max 120
response_modeenumCHECKOUT (default) or INTENT
customer_namestringRequired for INTENT · max 120
customer_emailemailRequired for INTENT · max 190
customer_phonestringRequired for INTENT · Indian 10-digit mobile
customer_consentbooleanMust be true for INTENT
expires_in_minutesintegerOptional · 5–1,440; QR begins after payer details
callback_urlHTTPS URLOptional; required with callback_secret
callback_secretstringOptional · 32–500; required with callback_url
return_urlHTTPS URLOptional; browser convenience only
Hosted checkout request
curl --request POST \
  --url https://api.experia360.com/api/v1/merchant/payment-orders \
  --header 'Authorization: Bearer exs_your_secret' \
  --header 'X-Experia-Client-Id: exc_your_client_id' \
  --header 'Idempotency-Key: 72566cd5-39bf-4f58-92a8-66a993e74f17' \
  --header 'Content-Type: application/json' \
  --data '{
    "amount_paise": 125000,
    "purpose": "Invoice INV-1042",
    "merchant_order_reference": "ORDER-1042",
    "response_mode": "CHECKOUT",
    "customer_name": "Aarav Mehta",
    "customer_email": "aarav@example.com",
    "customer_phone": "9876543210",
    "expires_in_minutes": 15,
    "callback_url": "https://merchant.example/webhooks/experia360",
    "callback_secret": "use-at-least-32-random-characters",
    "return_url": "https://merchant.example/orders/ORDER-1042"
  }'
Hosted checkout response
{
  "success": true,
  "data": {
    "id": "019...",
    "order_id": "EUPI...",
    "merchant_order_reference": "ORDER-1042",
    "amount_paise": 125000,
    "currency": "INR",
    "status": "AWAITING_CUSTOMER",
    "response_mode": "CHECKOUT",
    "verification_mode": "TREXO_PAYIN_STATUS_API",
    "next_action": {
      "type": "HOSTED_CHECKOUT",
      "url": "https://experia360.com/pay/..."
    },
    "checkout_url": "https://experia360.com/pay/..."
  },
  "request_id": "..."
}
Direct intent bodyOpen example
Direct intent body
{
  "amount_paise": 125000,
  "purpose": "Invoice INV-1042",
  "merchant_order_reference": "ORDER-1042",
  "response_mode": "INTENT",
  "customer_name": "Aarav Mehta",
  "customer_email": "aarav@example.com",
  "customer_phone": "9876543210",
  "customer_consent": true,
  "expires_in_minutes": 15
}
Direct intent responseOpen example
Direct intent response
{
  "success": true,
  "data": {
    "order_id": "EUPI...",
    "status": "PENDING_PAYMENT",
    "response_mode": "INTENT",
    "next_action": {
      "type": "UPI_INTENT",
      "upi_uri": "upi://pay?pa=...&am=1250.00&cu=INR&tr=EUPI...",
      "qr_payload": "upi://pay?pa=...&am=1250.00&cu=INR&tr=EUPI...",
      "expires_at": "2026-10-08T13:00:00Z"
    },
    "upi_intent": "upi://pay?pa=...&am=1250.00&cu=INR&tr=EUPI...",
    "checkout_url": "https://experia360.com/pay/..."
  },
  "request_id": "..."
}

Do not mark an order paid from a redirect. Fulfil only after a valid signed collection.received callback or an authenticated status response reports status: PAID and provider_status: SUCCESS. Provider callbacks are acknowledged before merchant delivery, so a slow merchant endpoint cannot delay provider processing.

GET/merchant/payment-orders/{order}collections:read

Retrieve payment order

Use the Experia360 UUID or order_id. For an open Trexo or PayOnTop payment, this endpoint performs a lock-protected live provider check when the previous check is older than two seconds, then returns the authoritative payment state, provider status, UTR and confirmation time. Browser return parameters never establish settlement.

cURL request
curl --request GET \
  --url https://api.experia360.com/api/v1/merchant/payment-orders/EUPI... \
  --header 'Authorization: Bearer exs_your_secret' \
  --header 'X-Experia-Client-Id: exc_your_client_id'
POST/merchant/payoutspayouts:write

Create payout instruction

Creates an idempotent payout and submits it directly to the configured provider route. The authenticated client with payouts:write is treated as the merchant's server-side authorization, so no secondary dashboard approval is requested. Supply either an existing beneficiary_id or beneficiary bank details inline. Inline details are IFSC-checked and stored as a reusable confirmed beneficiary.

FieldTypeRule
beneficiary_idUUIDRequired when beneficiary is omitted · active confirmed beneficiary
beneficiaryobjectRequired when beneficiary_id is omitted
beneficiary.namestringRequired inline · max 160
beneficiary.account_numberstringRequired inline · 8–20 digits
beneficiary.ifscstringRequired inline · valid 11-character Indian IFSC
beneficiary.mobilestringRequired inline · Indian 10-digit mobile
beneficiary.details_confirmationbooleanMust be true for inline details
bank_connection_idUUIDOptional · selected active payout route
amount_paiseintegerRequired · 100 to 10,000,000,000
modeenumIMPS, NEFT or RTGS as enabled on the route
client_referencestringOptional · max 100
remarksstringOptional · max 255
cURL request
curl --request POST \
  --url https://api.experia360.com/api/v1/merchant/payouts \
  --header 'Authorization: Bearer exs_your_secret' \
  --header 'X-Experia-Client-Id: exc_your_client_id' \
  --header 'Idempotency-Key: a90f9328-c328-4f32-92dc-668cc14fd9d4' \
  --header 'Content-Type: application/json' \
  --data '{
    "beneficiary": {
      "name": "Aarav Mehta",
      "account_number": "50100123456789",
      "ifsc": "HDFC0001234",
      "mobile": "9876543210",
      "details_confirmation": true
    },
    "amount_paise": 250000,
    "mode": "IMPS",
    "client_reference": "VENDOR-INV-2041",
    "remarks": "Approved vendor invoice"
  }'
201 response
{
  "success": true,
  "data": {
    "id": "019...",
    "transaction_id": "EPO1234567890",
    "client_reference": "VENDOR-INV-2041",
    "amount_paise": 250000,
    "currency": "INR",
    "mode": "IMPS",
    "status": "PROCESSING",
    "beneficiary": {
      "id": "019...",
      "name": "Aarav Mehta",
      "account_number_last4": "6789",
      "ifsc": "HDFC0001234",
      "bank_name": "HDFC Bank"
    },
    "attempts": [{
      "status": "PROCESSING",
      "bank_reference": "POT-API-001",
      "utr": null
    }]
  },
  "approval_required": false,
  "message": "The payout instruction was submitted directly to the configured provider route.",
  "request_id": "..."
}

Experia360 never returns the full destination account number in responses or callbacks. Merchants receive the beneficiary ID, masked last four digits, IFSC, bank name, UTR and bank reference.

A successful create response means Experia360 submitted the instruction directly. Funds are final only when the authenticated status response or signed callback reports SUCCESS and provides the provider reference or UTR. Dashboard, bulk and manually created payouts continue to use maker-checker approval.

GET/merchant/payouts/{payout}payouts:read

Retrieve payout status

Use the Experia360 payout UUID or transaction ID. The response includes provider attempts, bank reference and UTR when available and remains scoped to the API client that created it.

cURL request
curl --request GET \
  --url https://api.experia360.com/api/v1/merchant/payouts/EPO1234567890 \
  --header 'Authorization: Bearer exs_your_secret' \
  --header 'X-Experia-Client-Id: exc_your_client_id'
04
STATE MODEL

Make every outcome explicit.

AWAITING_CUSTOMER

Hosted checkout is waiting for verified payer details.

PENDING_PAYMENT

A dynamic UPI intent is active and provider confirmation is pending.

AWAITING_CONFIRMATION

A payer reference was supplied; bank/provider confirmation is pending.

PAID

Payment is confirmed and contains a bank transaction reference.

MANUALLY_CONFIRMED

An authorized operations review confirmed payment evidence.

FAILED

The provider returned a terminal failure; create a new order to retry.

EXPIRED

The payment window ended without confirmation.

CANCELLED

The merchant cancelled an open request.

REFUNDED

The confirmed collection was fully refunded after review and processing.

05
CALLBACK SECURITY

Verify the exact raw body.

APIHub supports separate PayIn and PayOut callback URLs. Each destination receives its own signing secret when first configured. Verify timestamp + "." + rawBody against the exact request body.

These are Experia360-to-merchant callbacks. Do not give merchants the Trexo-to-Experia360 provider callback URL. Configure the merchant's public HTTPS PayIn and PayOut destinations separately in APIHub.

HeaderPurpose
X-Experia-Event-IdReplay-protection identifier
X-Experia-TimestampUnix timestamp; reject stale delivery
X-Experia-Signaturev1= followed by lowercase HMAC-SHA256
DestinationEventsWhen to act
PayIn callbackcollection.received, collection.refund.requested, collection.refund.completedFulfil only on a valid collection.received event with status: PAID.
PayOut callbackpayout.created, payout.success, payout.failedTreat only payout.success as a completed bank transfer; retain its UTR.
callback payload
{
  "event": "collection.received",
  "event_id": "6be7b76e-...",
  "created_at": "2026-09-25T04:30:00Z",
  "data": {
    "order_id": "EUPI...",
    "merchant_order_reference": "ORDER-1042",
    "status": "PAID",
    "provider_status": "SUCCESS",
    "amount_paise": 125000,
    "currency": "INR",
    "bank_transaction_id": "RRN123456789012",
    "confirmed_at": "2026-09-25T04:29:58Z"
  }
}

Test a PayIn callback

Use the PayIn destination and its own one-time signing secret. A confirmed collection is delivered as collection.received.

PayIn callback cURLOpen example
PayIn callback cURL
CALLBACK_URL="https://merchant.example.com/webhooks/experia360/payin"
CALLBACK_SECRET="whsec_replace_with_payin_signing_secret"
TIMESTAMP="$(date +%s)"
EVENT_ID="payin-test-$(date +%s)"

BODY='{
  "event": "collection.received",
  "event_id": "'"${EVENT_ID}"'",
  "created_at": "2026-10-09T10:30:00Z",
  "data": {
    "order_id": "EUPI1234567890",
    "merchant_order_reference": "ORDER-1042",
    "amount_paise": 125000,
    "currency": "INR",
    "status": "PAID",
    "bank_transaction_id": "615276353375",
    "confirmed_at": "2026-10-09T10:29:58Z"
  }
}'

SIGNATURE="v1=$(printf '%s' "${TIMESTAMP}.${BODY}" |
  openssl dgst -sha256 -hmac "${CALLBACK_SECRET}" -hex |
  sed 's/^.* //')"

curl --request POST \
  --url "${CALLBACK_URL}" \
  --header 'Content-Type: application/json' \
  --header 'Accept: application/json' \
  --header "X-Experia-Event-Id: ${EVENT_ID}" \
  --header "X-Experia-Timestamp: ${TIMESTAMP}" \
  --header "X-Experia-Signature: ${SIGNATURE}" \
  --data-binary "${BODY}"

Test a PayOut callback

Use the separate PayOut destination and signing secret. Replace payout.success with payout.created or payout.failed when testing those lifecycle events.

PayOut callback cURLOpen example
PayOut callback cURL
CALLBACK_URL="https://merchant.example.com/webhooks/experia360/payout"
CALLBACK_SECRET="whsec_replace_with_payout_signing_secret"
TIMESTAMP="$(date +%s)"
EVENT_ID="payout-test-$(date +%s)"

BODY='{
  "event": "payout.success",
  "event_id": "'"${EVENT_ID}"'",
  "created_at": "2026-10-09T10:35:00Z",
  "data": {
    "payout_id": "01912345-6789-7000-8000-123456789abc",
    "transaction_id": "EPO1234567890",
    "client_reference": "VENDOR-INV-2041",
    "amount_paise": 250000,
    "currency": "INR",
    "mode": "IMPS",
    "status": "SUCCESS",
    "beneficiary": {
      "id": "01912345-6789-7000-8000-abcdef123456",
      "name": "Aarav Mehta",
      "account_number_last4": "6789",
      "ifsc": "HDFC0001234",
      "bank_name": "HDFC Bank"
    },
    "bank_reference": "BANKREF123456",
    "utr": "615276353375",
    "processed_at": "2026-10-09T10:34:58Z"
  }
}'

SIGNATURE="v1=$(printf '%s' "${TIMESTAMP}.${BODY}" |
  openssl dgst -sha256 -hmac "${CALLBACK_SECRET}" -hex |
  sed 's/^.* //')"

curl --request POST \
  --url "${CALLBACK_URL}" \
  --header 'Content-Type: application/json' \
  --header 'Accept: application/json' \
  --header "X-Experia-Event-Id: ${EVENT_ID}" \
  --header "X-Experia-Timestamp: ${TIMESTAMP}" \
  --header "X-Experia-Signature: ${SIGNATURE}" \
  --data-binary "${BODY}"
PHP verifier
$timestamp = $_SERVER['HTTP_X_EXPERIA_TIMESTAMP'] ?? '';
$signature = $_SERVER['HTTP_X_EXPERIA_SIGNATURE'] ?? '';
$rawBody = file_get_contents('php://input');

if (!ctype_digit($timestamp) || abs(time() - (int) $timestamp) > 300) {
    http_response_code(401); exit;
}

$expected = 'v1=' . hash_hmac(
    'sha256',
    $timestamp . '.' . $rawBody,
    getenv('EXPERIA360_CALLBACK_SECRET')
);

if (!hash_equals($expected, $signature)) {
    http_response_code(401); exit;
}

Return HTTP 2xx promptly. Use constant-time comparison, reject events older than five minutes, store processed event IDs, and retrieve the payment order before fulfilment.

06
FAILURE MODEL

Retry only when it is safe.

400 / 422Fix the request

Do not retry unchanged validation failures.

401 / 403Check credentials and scope

Rotate compromised secrets; never log them.

404Check tenant and order reference

Resources are organization-scoped.

429Back off with jitter

Respect the configured client rate limit.

5xx / timeoutRetry with the same key

Never generate a new idempotency key for an uncertain create.

error envelope
{
  "success": false,
  "error": {
    "code": "API_SCOPE_DENIED",
    "message": "The API client is not permitted to perform this operation.",
    "request_id": "..."
  }
}
07
WORDPRESS + WOOCOMMERCE

Install the supported gateway.

Version 1.1.0 creates orders server-side, redirects customers to the hosted QR checkout, verifies signed callbacks, and performs bounded authenticated status reconciliation.

  • Classic checkout and Checkout Blocks
  • WooCommerce HPOS declared compatible
  • AES-256-GCM encrypted saved secrets
  • Replay and amount mismatch protection
  • PHP 7.4+ and WordPress 6.4+
Download WordPress plugin
  1. 1Upload and activatePlugins → Add New → Upload Plugin.
  2. 2Create API clientAssign collection read and write scopes.
  3. 3Configure WooCommerceSettings → Payments → Experia360 UPI.
  4. 4Run a controlled orderValidate QR, callback and order reconciliation.
08
DOWNLOADS

Use versioned integration assets.

READY TO INTEGRATE?

Create a Sandbox client and make your first idempotent request.

Open APIHub