Recommended: You can use infini-skill to integrate with Infini APIs faster. The skill provides ready-to-use integration capabilities and can help you connect to the hosted checkout flow before implementing the raw APIs below.
Hosted Checkout mode is Infini's most recommended integration method. Merchants only need to create orders, redirect to checkout_url, and handle Webhooks to complete payment integration. This chapter only contains API documentation and corresponding field descriptions for Hosted Checkout mode.
For organization card APIs, see Card API Documentation. Card APIs now use the independent /v2/cards prefix.
For organization fund APIs, see Fund API Documentation. Fund APIs use the independent /v2/funds prefix.
All API prefix:
/v1/acquiring
GET /v1/acquiring/currency
Returns the blockchain and token combinations currently available for acquiring payments. Use this endpoint to populate or validate payment currency options instead of maintaining a hard-coded list.
Date: {GMT Time}
Authorization: Signature ...This endpoint has no query parameters or request body.
{
"list": [
{
"chain": "TRON",
"token_id": "USDT",
"contract": "TXLAQ63Xg1NAzckPwKHvzw7CSEmLMEqcdj"
},
{
"chain": "ETHEREUM",
"token_id": "USDC",
"contract": "0xA0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
}
]
}| Field | Type | Description |
|---|---|---|
| list | array | Supported blockchain and token combinations |
| list[].chain | string | Blockchain network name |
| list[].token_id | string | Token identifier |
| list[].contract | string | Token contract address, when applicable |
Note: Supported currencies may differ between Sandbox and Production. Always use the response from the target environment as the source of truth.
POST /v1/acquiring/order
Used to create an order and return the hosted checkout access URL (checkout_url).
Content-Type: application/json
Date: {GMT Time}
Authorization: Signature ...| Field | Type | Required | Description |
|---|---|---|---|
| amount | string/number | Yes | Order amount (up to 6 decimal places). The minimum is greater than 0.1 for crypto acquiring; fiat payment methods require at least 16 |
| request_id | string | Yes | Merchant-generated idempotency key (UUID). Duplicate request_id returns the existing order instead of creating a new one |
| client_reference | string | No | Merchant custom order number, recommended to be unique |
| order_desc | string | No | Order description |
| expires_in | number | No | Order expiration relative time (Unix seconds); use backend default if not provided |
| merchant_alias | string | No | Merchant display name (overrides backend configuration) |
| success_url | string | No | Redirect address after successful order payment |
| failure_url | string | No | Redirect address after failed order payment |
| pay_methods | array of integers | No | Payment methods: [1] crypto, [2] card, [3] Binance Pay, [5] Apple Pay, [6] Google Pay, [1,2,3,5,6] all three are supported. Defaults to merchant config |
| string | No | Payer email (optional). If provided, must be a valid email address; the server normalizes it to lowercase | |
| currency | string | No | Order currency (USD, EUR, KWR, GBP, SGD, JPY, AUD, HKD), default to USD |
Minimum amount: Crypto acquiring orders must be greater than
0.1. Fiat payment methods (card, Apple Pay, and Google Pay) require an amount of at least16.
{
"order_id": "10290d05-xxxx",
"request_id": "your request_id",
"checkout_url": "https://checkout.infini.money/pay/xxxx",
"client_reference": "client_reference"
}This endpoint is idempotent by request_id within the same merchant:
- If an order with the same
request_idalready exists, the API returns that order’s information (order_id,checkout_url, etc.) instead of creating a new order. - Safe for retries after network timeouts or client failures: resubmitting the same
request_idyields the same order result.
GET /v1/acquiring/order?order_id ={order_id}
Returns real-time order status information.
Database stored field recording the order's processing status.
| Value | Description |
|---|---|
pending | Awaiting payment |
processing | Processing (partial funds received) |
paid | Paid |
partial_paid | Partial payment expired |
expired | Expired without payment |
{
"order_id": "ord-123",
"status": "processing",
"amount": "100",
"currency": "USD",
"amount_confirming": "0",
"amount_confirmed": "0.5",
"expires_at": 1763512195,
"created_at": 1763512000,
"exception_tags": ["wrong_currency"],
"client_reference": "ORDER-001",
"email": "user@example.com"
}| Field | Type | Description |
|---|---|---|
| string | Payer email submitted at order creation (omitted when not provided) | |
| kyc_required | boolean | When true, the buyer must complete login and approved Infini KYC before a payment can be created for this order. |
POST /v1/acquiring/token/reissue
Used to regenerate the hosted checkout URL, suitable for scenarios such as payment page closure or Token expiration.
| Field | Type | Required | Description |
|---|---|---|---|
| order_id | string | Yes | Unique order ID |
{
"order_id": "ord-123",
"checkout_url": "https://checkout.infini.money/pay/xxxx"
}Note: For most merchants, you only need to create an order and redirect to the checkout URL. The Payment APIs below are optional and require additional development work. They allow you to programmatically create and manage payments instead of using the hosted checkout.
POST /v1/acquiring/payment
Create a payment for an order programmatically.
Request Body:
order_id(string, required): Order IDchain(string, required): Blockchain network nametoken_id(string, required): Token identifierpayment_method(integer, optional): Payment method (currently only supports 1 for crypto)force_create(boolean, optional): Defaults tofalse. When omitted, Infini may return an existing reusable payment for the same order/network/token. Settrueonly when you need a fresh payment address instead of reuse.
Response:
{
"payment_id": "pay-123",
"amount": "100.00",
"due_amount_fiat": "100.00",
"amount_confirmed": "0",
"amount_confirming": "0",
"address": "0x1234567890abcdef1234567890abcdef12345678",
"expires_at": 1763512195,
"quoted_token_amount": "100.00",
"quoted_token_currency": "USDT",
"quoted_token_price_usdc": "0"
}If GET /v1/acquiring/order returns kyc_required=true, unauthenticated payment creation is blocked and this endpoint returns 46001 until the buyer completes the required Infini login and approved KYC flow.
POST /v1/acquiring/payment/quote
Preview the payable token amount without allocating an address or creating a payment record.
Request Body:
order_id(string, required): Order IDchain(string, required): Blockchain network nametoken_id(string, required): Token identifierpayment_method(integer, optional): Payment method (currently only supports 1 for crypto)
Response:
{
"amount": "100.00",
"due_amount_fiat": "100.00",
"amount_confirmed": "0",
"amount_confirming": "0",
"quoted_token_amount": "100.00",
"quoted_token_currency": "USDT",
"quoted_token_price_usdc": "0"
}GET /v1/acquiring/payment?payment_id={payment_id}
Query payment details including transaction history.
GET /v1/acquiring/payment/list?order_id={order_id}
Get all payments associated with an order.
POST /v1/acquiring/subscription
Used to create a subscription and return the hosted checkout access URL (checkout_url). The first payment order is created simultaneously.
Content-Type: application/json
Date: {GMT Time}
Authorization: Signature ...| Field | Type | Required | Description |
|---|---|---|---|
| amount | string/number | Yes | Order fiat amount (up to 6 decimal places) |
| request_id | string | Yes | Merchant-generated idempotency key, UUID format |
| client_reference | string | No | Merchant custom order number |
| expires_in | number | No | Order expiration relative time (Unix seconds); use backend default if not provided |
| merchant_alias | string | No | Merchant display name (overrides backend configuration) |
| success_url | string | No | Redirect URL after successful payment |
| failure_url | string | No | Redirect URL after failed payment |
| pay_methods | array of integers | No | Payment modes: [1] crypto, [2] card, [1,2] both. Defaults to merchant config |
| subscription | object | Yes | Subscription parameters (see below) |
subscription object:
| Field | Type | Required | Description |
|---|---|---|---|
| merchant_sub_id | string | Yes | Merchant-defined subscription ID (must be unique per merchant) |
| plan_name | string | Yes | Subscription plan name |
| amount | string/number | Yes | Recurring amount per billing period (up to 6 decimal places) |
| interval_unit | string | Yes | Billing interval unit: DAY or MONTH |
| interval_count | integer | Yes | Number of intervals per billing cycle |
| payer_email | string | Yes | Payer email address (used for invoice notifications) |
| invoice_lead_days | integer | Yes | Days before period end to send renewal invoice (min: 0). Required in invoice mode |
| invoice_due_days | integer | Yes | Days after invoice creation before it expires (min: 1). Required in invoice mode |
| subscription_end_at | integer | No | Unix timestamp for subscription termination (0 = never) |
| canceled_url | string | No | Redirect URL after subscription cancellation |
{
"order_id": "10290d05-xxxx",
"request_id": "your request_id",
"client_reference": "client_reference",
"checkout_url": "https://checkout.infini.money/subscription/xxxx",
"token": "eyJhbGciOiJIUzI1NiIs...",
"subscription": {
"subscription_id": "sub-xxxx",
"merchant_sub_id": "msub_001",
"status": "pending"
}
}GET /v1/acquiring/subscription?merchant_sub_id={merchant_sub_id}
Returns the subscription detail by merchant subscription ID.
| Value | Description |
|---|---|
pending | Awaiting first payment |
active | Active subscription |
canceled | Canceled |
{
"subscription_id": "sub-xxxx",
"merchant_sub_id": "msub_001",
"plan_name": "Monthly Plan",
"trigger_method": "invoice",
"status": "active",
"currency": "USD",
"first_amount": "10.00",
"amount": "9.99",
"interval_unit": "MONTH",
"interval_count": 1,
"current_period_start": 1740000000,
"current_period_end": 1742678400,
"subscription_end_at": 0,
"next_invoice_at": 1742592000,
"payer_email": "user@example.com",
"created_at": 1740000000,
"updated_at": 1740000100
}POST /v1/acquiring/subscription/cancel
Used to cancel an active subscription. The subscription remains usable until the end of the current billing period.
| Field | Type | Required | Description |
|---|---|---|---|
| merchant_sub_id | string | Yes | Merchant-defined subscription ID |
| cancel_reason | string | Yes | Cancel reason: user_request, by_merchant_api, or by_operation |
| note | string | No | Optional cancellation note |
{
"subscription_id": "sub-xxxx",
"merchant_sub_id": "msub_001",
"status": "canceled",
"canceled_at": 1742678400,
"cancel_reason": "by_merchant_api"
}Merchants can configure Webhook receiving address in the backend. When order or subscription status changes, Infini will actively push the following events:
Order events:
- order.created
- order.processing
- order.completed
- order.expired
- order.late_payment
Subscription events:
- subscription.update
- subscription.cancel
| Header | Description |
|---|---|
| X-Webhook-Timestamp | Unix timestamp |
| X-Webhook-Event-Id | Unique event ID |
| X-Webhook-Signature | Webhook HMAC signature |
{
"event": "order.completed",
"order_id": "ord-123",
"client_reference": "ORDER-001",
"amount": "100",
"currency": "USD",
"status": "paid",
"amount_confirmed": "100",
"amount_confirming": "0",
"created_at": 1763512195,
"updated_at": 1763512573,
"exception_tags": []
}{
"event": "subscription.update",
"subscription_id": "sub-xxxx",
"merchant_sub_id": "msub_001",
"plan_name": "Monthly Plan",
"trigger_method": "invoice",
"status": "active",
"currency": "USD",
"amount": "9.99",
"interval_unit": "MONTH",
"interval_count": 1,
"payer_email": "user@example.com",
"current_period_start": 1740000000,
"current_period_end": 1742678400,
"next_invoice_at": 1742592000,
"cancel_reason": "by_merchant_api",
"canceled_at": 1742678400,
"created_at": 1740000000,
"updated_at": 1740000100
}Note:
next_invoice_at,cancel_reason, andcanceled_atare only included when the corresponding values are present. For example,cancel_reasonandcanceled_atonly appear insubscription.cancelevents.
For Webhook signature verification methods, please refer to Chapter 4: Authorization and Security Mechanisms.
All error response format:
{
"code": 40001,
"message": "Invalid request",
"detail": "expires_at must be greater than current timestamp"
}| HTTP | Code | Description |
|---|---|---|
| 400 | 40003 | amount must be positive |
| 400 | 40006 | amount must be greater than 0.1 |
| 401 | 401 | Invalid HMAC signature |
| 404 | 40401 | Order does not exist |
| 409 | 40902 | client_reference duplicate |
| 409 | 40906 | Order expired |
| 404 | 43000 | Subscription not found |
| 400 | 43002 | Subscription already canceled |
The following example demonstrates the complete flow: Create Order → Redirect to Checkout → Webhook → Reissue Token.
import hmac, hashlib, base64, time
from datetime import datetime, timezone
import requests
key_id = "merchant-001-prod"
secret_key = b"your-secret-key"
def create_order(amount):
method = "POST"
path = "/v1/acquiring/order"
gmt_time = datetime.now(timezone.utc).strftime('%a, %d %b %Y %H:%M:%S GMT')
signing_string = f"{key_id}\n{method} {path}\ndate: {gmt_time}\n"
signature = base64.b64encode(
hmac.new(secret_key, signing_string.encode(), hashlib.sha256).digest()
).decode()
response = requests.post(
f"https://openapi.infini.money{path}",
json={
"amount": amount,
"currency": "USD",
"client_reference": "ORDER-2024-001",
"description": "Product purchase",
"expires_at": int(time.time()) + 3600
},
headers={
"Date": gmt_time,
"Authorization": f'Signature keyId="{key_id}",algorithm="hmac-sha256",headers="@request-target date",signature="{signature}"',
"Content-Type": "application/json"
}
)
response.raise_for_status()
return response.json()@app.route('/create-payment', methods=['POST'])
def create_payment():
order = create_order(amount=request.json['amount'])
return {"checkout_url": order["checkout_url"]}@app.route('/webhook', methods=['POST'])
def handle_webhook():
event = request.json
if event['event'] == 'order.completed':
process_fulfillment(event['order_id'], event['amount_confirmed'])
elif event['event'] == 'order.processing':
update_order_progress(event['order_id'], event['status'])
elif event['event'] == 'order.expired':
mark_order_expired(event['order_id'])
return {"status": "ok"}def reissue_checkout_token(order_id):
method = "POST"
path = "/v1/acquiring/token/reissue"
gmt_time = datetime.now(timezone.utc).strftime('%a, %d %b %Y %H:%M:%S GMT')
signing_string = f"{key_id}\n{method} {path}\ndate: {gmt_time}\n"
signature = base64.b64encode(
hmac.new(secret_key, signing_string.encode(), hashlib.sha256).digest()
).decode()
response = requests.post(
f"https://api.infini.money{path}",
json={"order_id": order_id},
headers={
"Date": gmt_time,
"Authorization": f'Signature keyId="{key_id}",algorithm="hmac-sha256",headers="@request-target date",signature="{signature}"',
"Content-Type": "application/json"
}
)
response.raise_for_status()
return response.json()