Payments Guide
This guide covers everything you need to know about creating and managing payments through the 123hub MultiHub API. All payment operations use a single endpoint with method-based routing.Overview
The MultiHub API provides three payment methods through a single endpoint:| Method | Direction | Description |
|---|---|---|
payment.in | Inbound | Customer pays to merchant (deposit) |
payment.out | Outbound | Merchant pays to customer/vendor (withdrawal) |
payment.status | Query | Check the current status of a payment |
Endpoint
All requests are sent to a single endpoint:success field in the response body to determine the outcome.
Authentication
Every request requires two headers:| Header | Description | Example |
|---|---|---|
X-Data-Application-Id | Your application ID (integer) | 42 |
X-Data-Hash | SHA-512 hash of the request body concatenated with your secret key | a1b2c3d4... |
requestBody is the raw JSON string of the request body, and secretKey is your merchant secret key.
Request Format
All requests follow the same envelope:| Field | Type | Required | Description |
|---|---|---|---|
method | string | Yes | The operation to perform |
service_id | integer | No | Your service/project identifier |
params | object | Yes | Contains the payment object with operation-specific fields |
Response Format
All responses follow a consistent envelope:| Field | Type | Description |
|---|---|---|
success | boolean | Whether the operation succeeded |
result | object or null | Contains the payment object on success |
error | object or null | Contains code, message, details, and context on failure |
request_id | string | Unique identifier for this request (useful for debugging) |
processing_time | number | Server processing time in milliseconds |
Identifiers
Every payment uses three identifiers that appear in theidentifiers object:
| Identifier | Type | Description |
|---|---|---|
c_id | integer | Client ID — your merchant reference. You provide this when creating a payment. Must be unique per payment. |
h_id | integer | Hub ID — system-assigned payment ID. Assigned automatically when the payment is created. |
p_id | string | Provider ID — the payment provider’s transaction reference. Assigned when the payment reaches the provider. |
Use
c_id as your primary reference for tracking payments. It is the key you control and should map to your internal order or transaction ID.Creating a Deposit (payment.in)
Usepayment.in to create a deposit where a customer pays you.
Build the request body
Include the payment amount, currency, customer (payer) details, and your unique
c_id.Compute the authentication hash
Compute
sha512(requestBody + secretKey) and set it in the X-Data-Hash header.Request
Deposit Request Fields
| Field | Type | Required | Description |
|---|---|---|---|
description | string | No | Human-readable description for the payment |
identifiers.c_id | integer | Yes | Your unique client reference for this payment |
amount.value | integer | Yes | Payment amount in minor units (e.g., paise for INR) |
amount.currency | string | Yes | ISO 4217 currency code |
payer.email | string | Yes | Customer email address |
payer.phone | string | No | Customer phone number |
payer.person.first_name | string | No | Customer first name |
payer.person.last_name | string | No | Customer last name |
payer.customer_account.id | string | No | Customer account identifier in your system |
client.language | string | No | ISO 639-1 language code for the payment page |
client.country | string | No | ISO 3166-1 alpha-2 country code |
Response
For UPI payments (India), the response may include a
redirect object with UPI deep-link URLs in the redirect.to field. For other payment methods, redirect may not be present in the initial response.Creating a Withdrawal (payment.out)
Usepayment.out to send money to a recipient (payout).
Request
Withdrawal Request Fields
| Field | Type | Required | Description |
|---|---|---|---|
description | string | No | Human-readable description for the payout |
identifiers.c_id | integer | Yes | Your unique client reference for this payment |
amount.value | integer | Yes | Payout amount in minor units |
amount.currency | string | Yes | ISO 4217 currency code |
receiver.bank.account.id | string | Yes | Recipient bank account number |
receiver.bank.ifsc | string | Depends on region | Bank routing code (IFSC for India, etc.) |
receiver.email | string | No | Recipient email address |
receiver.phone | string | No | Recipient phone number |
receiver.person.first_name | string | No | Recipient first name |
receiver.person.last_name | string | No | Recipient last name |
Deposits use
payer, withdrawals use receiver. The payer object describes who is sending the money (deposit), while the receiver object describes who is receiving the money (withdrawal). Both contain contact information and, for receiver, bank account details.Response
Checking Payment Status (payment.status)
Usepayment.status to query the current state of a payment. You can look up a payment by either c_id (your reference) or h_id (system-assigned ID).
Query by c_id
Query by h_id
You can also look up a payment using the system-assignedh_id. When using h_id, the service_id field is not required:
Response
The response contains the full payment object with its current status:Payment Statuses
Each payment has a status object with the current status name, and boolean flags indicating whether it is final and whether it represents a success.| Status | Description | final | success |
|---|---|---|---|
created | Payment created, waiting for processing | false | null |
processing | Payment is being processed | false | null |
success | Payment completed successfully | true | true |
error | Payment failed | true | false |
canceled | Payment was cancelled | true | false |
declined | Payment expired or was declined | true | false |
refunded | Full refund processed | true | true |
partially_refunded | Partial refund processed | true | true |
Terminal statuses are indicated by
final: true. Once a payment reaches a terminal status, it will not transition to any other status.Status Object Structure
Every payment includes astatus object with the following fields:
history array contains every status transition the payment has gone through, in chronological order. This is useful for debugging and auditing.
Handling Status Changes
Redirect URLs
For deposit payments (payment.in), the response may include a redirect object. For UPI payments (India), this contains deep-link URLs for mobile payment apps:
| Field | Description |
|---|---|
to | A URL string or array of URLs for completing the payment. For UPI, this contains deep-link URIs for different payment apps |
on_fail | The URL the customer is redirected to if the payment fails (when available) |
on_success | The URL the customer is redirected to after a successful payment (when available) |
The
redirect.to field contains UPI deep-link URLs for mobile payment apps (when applicable). Provider HTTPS payment page URLs are not included in the redirect. The redirect field may be absent if no redirect URLs are available for the payment method.Customer Data
Deposits: the payer Object
For payment.in requests, the payer object describes the customer making the payment:
Withdrawals: the receiver Object
For payment.out requests, the receiver object describes who receives the payout, including their bank details:
receiver.bank object contains the banking details required to execute the transfer. The specific fields depend on the region and payment method (e.g., ifsc for India, clabe for Mexico).
Idempotency
Thec_id (Client ID) serves as your idempotency key. If you send a payment.in or payment.out request with a c_id that was already used, the API will return error code 6009 (Payment already exists) instead of creating a duplicate.
Error Handling
When a request fails, the response will havesuccess: false and include an error object. Error responses return HTTP 400:
Successful responses return HTTP 200. Error responses return HTTP 400 (or HTTP 404 for unknown methods). Always check the
success field in the response body to determine the outcome.Error Codes
| Code | Description | Recommended Action |
|---|---|---|
1005 | Invalid request format (missing required field) | Check the details field for specifics on which field is missing |
6001 | Incorrect transaction amount | Verify amount is a positive integer in minor units |
6002 | Incorrect currency code | Ensure currency matches the service_id configuration |
6004 | Insufficient funds (withdrawals) | Top up your merchant balance before retrying |
6009 | Payment already exists (duplicate c_id) | Use payment.status to retrieve the existing payment |
6010 | Payment does not exist | Verify the c_id or h_id is correct |
7001 | Provider interaction error | Retry after a delay or contact support |
8801 | Invalid status transition | Check current payment status before attempting operations |
Error Handling Example
Best Practices
Use Unique c_id Values
Always assign a unique
c_id to each payment. This serves as your idempotency key and prevents duplicate payments.Compute Hashes Server-Side
Never expose your secret key to the client. Always compute the
X-Data-Hash on your server.Check success Field
Always check the
success boolean in the response body to determine the outcome. Success returns HTTP 200, errors return HTTP 400.Store All Identifiers
Save
c_id, h_id, and p_id from the response for reconciliation, debugging, and support inquiries.Handle Redirects
For deposits, always check for a
redirect.to URL and redirect the customer to complete their payment.Use Status History
The
status.history array provides a complete audit trail. Use it for debugging and tracking payment lifecycle.