TPIPAY API integration
Forward a payment request, redirect the customer to the secure checkout, and verify the resulting transaction.
Copy-paste cURL (Sandbox / Test Mode)
Use these exact headers and payloads in Postman. This matches the project’s sandbox API implementation.
curl --location --request POST 'https://staging.login.tpipay.ai/api/sandbox/payment' \
--header 'X-API-KEY: pk_test_XXXXXXXX' \
--header 'Authorization: sk_test_XXXXXXXX' \
--header 'Content-Type: application/json' \
--data '{
"amount": 1500.00,
"currency": "INR",
"customer_name": "Raj Sharma",
"customer_phone": "9876543210",
"customer_email": "raj@example.com",
"transaction_id": "ORD-SANDBOX-1001",
"description": "Sandbox payment test",
"success_url": "https://yourdomain.com/payment/success",
"failure_url": "https://yourdomain.com/payment/failure",
"cancel_url": "https://yourdomain.com/payment/cancel",
"webhook_url": "https://yourdomain.com/webhook",
"payment_method": "UPI"
}'
Sandbox status check
curl --location --request GET
'https://staging.login.tpipay.ai/api/sandbox/payments-status/ORD-SANDBOX-1001' \
--header 'X-API-KEY: pk_test_XXXXXXXX' \
--header 'Authorization: sk_test_XXXXXXXX'
Sandbox base URL
Use the sandbox/test environment for merchant API testing. The current application exposes sandbox endpoints under the API prefix.
| Endpoint | Method | Purpose |
|---|---|---|
/api/sandbox/payment |
POST | Create a sandbox payment. |
/api/sandbox/payments-status/{transactionId} |
GET | Current transaction status route defined in the sandbox API. |
/sandbox/checkout/{token}/status |
GET | Sandbox checkout status endpoint used by the checkout page. |
Sandbox authentication
The sandbox API authenticates using merchant API credentials generated for the test environment.
| Header | Example | Description |
|---|---|---|
X-API-KEY |
pk_test_XXXXXXXX |
Merchant API key for the sandbox/test environment. |
X-API-SECRET |
sk_test_XXXXXXXX |
Merchant API secret for the sandbox/test environment. Authorization: Bearer <api_secret> is also accepted. |
Authorization |
Bearer sk_test_XXXXXXXX |
Alternative to X-API-SECRET. |
Example request headers
{
"X-API-KEY": "pk_test_XXXXXXXX",
"X-API-SECRET": "sk_test_XXXXXXXX",
"Content-Type": "application/json",
}
Credential generation is handled by the existing merchant API credential service, which stores
api_key and a hashed secret for the selected test environment. The code checks
MerchantApiCredential::where('environment', 'test') and validates the secret using Laravel
Hash.
Create sandbox payment
Creates a sandbox payment record and returns a checkout URL for the sandbox checkout flow.
| Field | Type | Required | Description |
|---|---|---|---|
transaction_id |
string | No | Custom transaction reference. If omitted, the app creates one automatically. |
amount |
numeric | Yes | Amount in rupees, accepted as a decimal; minimum 0.01 and maximum 100000000. |
currency |
string | No | Must be INR. |
customer_name |
string | Yes | Customer name. |
customer_email |
string | No | Valid email. |
customer_phone |
string | Yes | Customer mobile number. |
description |
string | No | Payment description. |
success_url |
string | No | Optional success redirect URL. |
failure_url |
string | No | Optional failure redirect URL. |
cancel_url |
string | No | Optional cancel redirect URL. |
webhook_url |
string | No | Optional webhook callback URL. |
gateway |
string | No | Optional gateway name field. |
idempotency_key |
string | No | |
payment_method |
string | No | Allowed: UPI, CARD, NET_BANKING, EMI,
WALLET, PAY_LATTER. |
Example request
{
"amount": 1500.00,
"currency": "INR",
"customer_name": "Raj Sharma",
"customer_phone": "9876543210",
"customer_email": "raj@example.com",
"transaction_id": "ORD-SANDBOX-1001",
"description": "Sandbox payment test",
"success_url": "https://yourdomain.com/payment/success",
"failure_url": "https://yourdomain.com/payment/failure",
"webhook_url": "https://yourdomain.com/webhook"
}
Example response
{
"success": true,
"message": "Sandbox payment created successfully.",
"data": {
"payment_id": 123,
"transaction_id": "ORD-SANDBOX-1001",
"amount": "1500.00",
"status": "created",
"environment": "sandbox",
"checkout_url": "https://login.tpipay.ai/sandbox/checkout/abcd1234"
}
}
Sandbox test scenarios
These scenarios are seeded in the project and are used by the sandbox checkout screen and simulator. They are the actual values currently supported by the application.
| Method | Scenario | Result | Inputs |
|---|---|---|---|
UPI |
UPI_SUCCESS |
success |
success@tpipay |
UPI |
UPI_FAILED |
failed |
failure@tpipay |
UPI |
UPI_PENDING |
pending |
pending@tpipay |
CARD |
CARD_SUCCESS |
success |
4111111111111111, expiry 12/30, CVV 123 |
CARD |
CARD_FAILED |
failed |
4000000000000002, expiry 12/30, CVV 123 |
CARD |
CARD_PENDING |
pending |
4000000000009995, expiry 12/30, CVV 123 |
NET_BANKING |
NB_SUCCESS |
success |
Bank TPITEST, username testuser, password test123
|
NET_BANKING |
NB_FAILED |
failed |
Bank TPITEST, username faileduser, password failed123
|
WALLET |
WALLET_SUCCESS |
success |
Wallet TPITESTWALLET, mobile 9999999999, OTP 123456
|
WALLET |
WALLET_FAILED |
failed |
Wallet TPITESTWALLET, mobile 9999999998, OTP 000000
|
EMI |
EMI_SUCCESS |
success |
Card 4111111111111111, tenure 6, CVV 123 |
EMI |
EMI_FAILED |
failed |
Card 4000000000000002, tenure 6, CVV 123 |
PAY_LATTER |
PAY_LATER_SUCCESS |
success |
Provider TPIPAY_LATER, mobile 9999999999, OTP 123456
|
PAY_LATTER |
PAY_LATER_FAILED |
failed |
Provider TPIPAY_LATER, mobile 9999999998, OTP 000000
|
Sandbox status
The app includes a sandbox checkout status endpoint that returns current payment state for a checkout token.
Example response
{
"success": true,
"message": "Payment status retrieved successfully.",
"data": {
"transaction_id": "ORD-SANDBOX-1001",
"payment_id": 123,
"currency": "INR",
"amount": "1500.00",
"status": "pending",
"payment_method": "UPI",
"paid_at": null,
"environment": "sandbox",
"success_url": "https://yourdomain.com/payment/success",
"failure_url": "https://yourdomain.com/payment/failure",
"cancel_url": "https://yourdomain.com/payment/cancel",
"webhook_url": "https://yourdomain.com/webhook"
}
}
There is also a direct sandbox status route defined as
/api/sandbox/payments-status/{transactionId}, but in the current code it is still a debug
handler that dumps request data and is not the stable, browser-facing status endpoint. The checkout-token
route is the implemented, tested status route used by the sandbox checkout flow.
Sandbox callback / webhook
The sandbox simulator dispatches a webhook payload when the status transitions to a terminal state. This is the implemented behavior from the queue jobs and simulator.
| Field | Type | Description |
|---|---|---|
event |
string | payment.updated |
payment_id |
integer | Local payment ID. |
transaction_id |
string | Merchant transaction ID. |
amount |
string | Amount formatted to 2 decimal places. |
currency |
string | Defaults to INR. |
status |
string | Final status: success, failed, or cancelled. |
environment |
string | sandbox |
payment_method |
string | Payment method selected in the test scenario. |
Example webhook payload
{
"event": "payment.updated",
"payment_id": 123,
"transaction_id": "ORD-SANDBOX-1001",
"amount": "1500.00",
"currency": "INR",
"status": "success",
"environment": "sandbox",
"payment_method": "UPI"
}
Sandbox error handling
The sandbox API returns structured JSON error payloads when authentication fails, credentials are missing, the merchant is invalid, or validation fails.
| Code | Meaning | Example |
|---|---|---|
INVALID_SANDBOX_CREDENTIALS |
Authentication failed or invalid credentials. | { "success": false, "message": "Sandbox authentication failed.", "error_code":
"INVALID_SANDBOX_CREDENTIALS" } |
SANDBOX_CREDENTIALS_NOT_CONFIGURED |
No active sandbox credential exists. | { "success": false, "message": "Sandbox credentials are not configured.",
"error_code": "SANDBOX_CREDENTIALS_NOT_CONFIGURED" } |
SANDBOX_CREDENTIALS_INACTIVE |
Credential exists but disabled. | { "success": false, "message": "Sandbox credentials are inactive.", "error_code":
"SANDBOX_CREDENTIALS_INACTIVE" } |
PAYMENT_NOT_FOUND |
Requested checkout token or transaction was not found. | { "success": false, "message": "Payment not found.", "error_code": "PAYMENT_NOT_FOUND"
} |
TRANSACTION_ID_ALREADY_EXISTS |
Duplicate transaction ID. | { "success": false, "message": "Transaction ID already exists.", "error_code":
"TRANSACTION_ID_ALREADY_EXISTS" } |
Seamless Integration
Use the Seamless API when you want to create a payment request directly from your backend with a bearer token, without sending the customer through the merchant forwarding flow first. The route structure reuses the existing payment creation logic and the merchant-level method configuration.
Supported Seamless methods currently documented here are UPI and CARD. Wallet and Netbanking are kept as landing pages for now so you can expand them later without disturbing the main menu structure.
Issue a Seamless access token
Create a short-lived bearer token for the protected Seamless payment and ping endpoints.
Request data
Headers
| Header | Value | Description |
|---|---|---|
X-API-KEY | your-api-key | Merchant API key for the selected environment. |
Authorization | your-api-secret | Merchant API secret. Authorization: Bearer your-api-secret may also be used. |
Content-Type | application/json | Send the request body as JSON. |
{
"X-API-KEY": "your-api-key",
"Authorization": "your-api-secret",
"Content-Type": "application/json"
}
Body
| Field | Type | Required | Description |
|---|---|---|---|
scopes | array | No | Optional scopes to limit the token. Currently supported scopes are used for payment creation and ping access. |
scopes.* | string | No | Individual scope name, for example payments:create. |
environment | string | No | Environment to issue the token for: live or test. |
Example request
{
"scopes": ["payments:create"],
"environment": "test"
}
Verify Seamless token access
Use the ping endpoint to verify that the bearer token is valid and that the merchant context is correctly attached.
Request data
Headers
| Header | Value | Description |
|---|---|---|
Authorization | Bearer <seamless_token> | Seamless bearer token returned by the token endpoint. |
X-Seamless-Signature | optional-hmac-signature | Optional signature header when you want to verify the request payload using your merchant webhook secret. |
{
"Authorization": "Bearer <seamless_token>",
"X-Seamless-Signature": "<optional-hmac-signature>"
}
Example request
GET <?php echo e($apiBaseUrl); ?>/api/v1/pg/ping
UPI Integration
Use the Seamless API with the UPI payment method to create a payment request directly from your server. The request uses the bearer token returned in the token endpoint and the same merchant payment fields already used by the existing Merchant Payment API.
curl --location --request POST 'https://staging.login.tpipay.ai/api/v1/pg/payments' \
--header 'Authorization: Bearer ' \
--header 'Content-Type: application/json' \
--header 'X-Seamless-Signature: ' \
--data '{
"amount": 1500.00,
"currency": "INR",
"customer_name": "Raj Sharma",
"customer_phone": "9876543210",
"customer_email": "raj@example.com",
"transaction_id": "ORD-SEAMLESS-UPI-001",
"description": "Seamless UPI payment",
"success_url": "https://yourdomain.com/payment/success",
"failure_url": "https://yourdomain.com/payment/failure",
"cancel_url": "https://yourdomain.com/payment/cancel",
"webhook_url": "https://yourdomain.com/webhook",
"payment_method": "UPI"
}'
UPI request fields
All basic payment fields are the same as the existing Merchant Payment API. For Seamless, the important difference is that the token is sent in the Authorization header instead of merchant API credentials in each request.
Request data
Headers
| Header | Value | Description |
|---|---|---|
Authorization | Bearer <seamless_token> | Seamless bearer token returned by the token endpoint. |
Content-Type | application/json | Send the request body as JSON. |
X-Seamless-Signature | optional-hmac-signature | Optional signature that matches the request payload using your merchant webhook secret. |
Body
| Field | Type | Required | Description |
|---|---|---|---|
amount | numeric | Yes | Amount in rupees; minimum 0.01 and maximum 100000000. |
currency | string | No | Must be INR; defaults to INR. |
customer_name | string | Yes | Customer name. |
customer_phone | string | Yes | Customer mobile number. |
customer_email | string | No | Valid customer email. |
transaction_id | string | No | Your unique reference. If omitted, the app creates one automatically. |
description | string | No | Payment description. |
success_url | string | No | Optional success redirect URL. |
failure_url | string | No | Optional failure redirect URL. |
cancel_url | string | No | Optional cancel redirect URL. |
webhook_url | string | No | Optional webhook URL for status updates. |
gateway | string | No | Optional gateway override if you want to target a specific configured gateway. |
idempotency_key | string | No | Optional retry-safe key. |
payment_method | string | Yes | Must be UPI for this integration. |
Example request
{
"amount": 1500.00,
"currency": "INR",
"customer_name": "Raj Sharma",
"customer_phone": "9876543210",
"customer_email": "raj@example.com",
"transaction_id": "ORD-SEAMLESS-UPI-001",
"description": "Seamless UPI payment",
"success_url": "https://yourdomain.com/payment/success",
"failure_url": "https://yourdomain.com/payment/failure",
"cancel_url": "https://yourdomain.com/payment/cancel",
"webhook_url": "https://yourdomain.com/webhook",
"payment_method": "UPI"
}
Card Integration
Use the same Seamless payment endpoint with payment_method set to CARD. The backend uses the merchant’s configured payment gateway and method permissions, then returns the checkout or redirect URL produced by that gateway.
curl --location --request POST 'https://staging.login.tpipay.ai/api/v1/pg/payments' \
--header 'Authorization: Bearer ' \
--header 'Content-Type: application/json' \
--header 'X-Seamless-Signature: ' \
--data '{
"amount": 1500.00,
"currency": "INR",
"customer_name": "Raj Sharma",
"customer_phone": "9876543210",
"customer_email": "raj@example.com",
"transaction_id": "ORD-SEAMLESS-CARD-001",
"description": "Seamless card payment",
"success_url": "https://yourdomain.com/payment/success",
"failure_url": "https://yourdomain.com/payment/failure",
"cancel_url": "https://yourdomain.com/payment/cancel",
"webhook_url": "https://yourdomain.com/webhook",
"payment_method": "CARD"
}'
Card request fields
The Seamless Card flow uses the same request envelope as the generic Seamless payment request. The chosen gateway handles the actual card checkout experience and the returned payment details.
Request data
Headers
| Header | Value | Description |
|---|---|---|
Authorization | Bearer <seamless_token> | Seamless bearer token for the merchant and environment. |
Content-Type | application/json | Send the request body as JSON. |
X-Seamless-Signature | optional-hmac-signature | Optional request signature header using the merchant webhook secret. |
Body
| Field | Type | Required | Description |
|---|---|---|---|
amount | numeric | Yes | Amount in rupees; minimum 0.01 and maximum 100000000. |
currency | string | No | Must be INR; defaults to INR. |
customer_name | string | Yes | Customer name. |
customer_phone | string | Yes | Customer mobile number. |
customer_email | string | No | Valid customer email. |
transaction_id | string | No | Your unique reference. If omitted, the app creates one automatically. |
description | string | No | Payment description. |
success_url | string | No | Optional success redirect URL. |
failure_url | string | No | Optional failure redirect URL. |
cancel_url | string | No | Optional cancel redirect URL. |
webhook_url | string | No | Optional webhook URL for status updates. |
gateway | string | No | Optional gateway override if you want to target a specific configured gateway. |
idempotency_key | string | No | Optional retry-safe key. |
payment_method | string | Yes | Must be CARD for this integration. |
Example request
{
"amount": 1500.00,
"currency": "INR",
"customer_name": "Raj Sharma",
"customer_phone": "9876543210",
"customer_email": "raj@example.com",
"transaction_id": "ORD-SEAMLESS-CARD-001",
"description": "Seamless card payment",
"success_url": "https://yourdomain.com/payment/success",
"failure_url": "https://yourdomain.com/payment/failure",
"cancel_url": "https://yourdomain.com/payment/cancel",
"webhook_url": "https://yourdomain.com/webhook",
"payment_method": "CARD"
}
Wallet Integration
Wallet integration is reserved as a landing page for now. The Seamless menu entry is already in place, but the full wallet implementation and detailed documentation will be added in a later update.
Netbanking Integration
Netbanking integration is also kept as a landing page for now. The Seamless menu item is ready, and the full details can be added later without changing the current API structure.
