Create Payment Request
Overview
Payment requests are the core of Unter's payment system. When you create a payment request, you're asking someone to pay a specific amount of a cryptocurrency token to a designated wallet address. Each payment request gets a unique payment URL that you can share with your customers.
Endpoint
POST /api/payment-requestsRequired Permission: create_payments
Request Body
Required Fields
amount
string
The amount to request in the token's smallest unit (wei-like format)
"1000000" (1 USDC with 6 decimals)
token_id
integer
The ID of the token to receive
1
chain_id
integer
The ID of the blockchain network
1
recipient_address
string
The wallet address to receive the payment
"0x742C4B8C2515Ad1D8e1C71e8e24c8D5F9A1a8B5A"
Optional Fields
external_id
string
Your internal reference ID for this payment request (max 255 chars)
"order_12345"
description
string
Description of what this payment is for (max 1000 chars)
"Payment for premium subscription"
redirect_url
string
URL to redirect to after successful payment (max 500 chars)
"https://yourapp.com/payment/success"
cancel_url
string
URL to redirect to if payment is cancelled (max 500 chars)
"https://yourapp.com/payment/cancel"
expires_at
string (ISO 8601)
When this payment request expires (max 30 days from now)
"2024-12-31T23:59:59Z"
metadata
object
Additional key-value data for the payment request
{"customer_id": "12345", "product": "premium"}
Understanding Amounts
Cryptocurrency amounts are handled in their smallest unit (similar to how cents relate to dollars):
USDC (6 decimals):
"1000000"= $1.00 USDCETH (18 decimals):
"1000000000000000000"= 1.0 ETHUSDT (6 decimals):
"500000"= $0.50 USDT
The amount must be a string containing only digits, with no decimal points or commas.
Address Validation
Recipient addresses are validated based on the blockchain type:
Ethereum-compatible chains (EVM)
Must be 42 characters long
Must start with
0xExample:
0x742C4B8C2515Ad1D8e1C71e8e24c8D5F9A1a8B5A
Solana
Must use Base58 encoding
Example:
9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM
Automatic Behavior
When you create a payment request, several things happen automatically:
Unique identifiers are generated:
public_id: A UUID for internal trackingshortcode: An 8-character code for the payment URL (e.g.,A4B2C8XZ)
Default expiration is set:
If you don't specify
expires_at, it defaults to 24 hours from creation
Payment URL is created:
Format:
https://unter.tech/pay/{shortcode}This is where customers go to complete payment
Example Requests
Minimal Request
curl -X POST https://api.unter.tech/api/payment-requests \
-H "X-API-Key: unter_YOUR_API_KEY_HERE" \
-H "Content-Type: application/json" \
-d '{
"amount": "2500000",
"token_id": 1,
"chain_id": 1,
"recipient_address": "0x742C4B8C2515Ad1D8e1C71e8e24c8D5F9A1a8B5A"
}'Full Request with All Options
curl -X POST https://api.unter.tech/api/payment-requests \
-H "X-API-Key: unter_YOUR_API_KEY_HERE" \
-H "Content-Type: application/json" \
-d '{
"amount": "5000000",
"token_id": 1,
"chain_id": 1,
"recipient_address": "0x742C4B8C2515Ad1D8e1C71e8e24c8D5F9A1a8B5A",
"external_id": "invoice_789",
"description": "Pro Plan Subscription - Monthly",
"redirect_url": "https://myapp.com/success?order=789",
"cancel_url": "https://myapp.com/cancelled?order=789",
"expires_at": "2024-08-15T18:00:00Z",
"metadata": {
"customer_id": "cust_abc123",
"plan": "pro",
"billing_cycle": "monthly"
}
}'Success Response (201 Created)
{
"data": {
"public_id": "550e8400-e29b-41d4-a716-446655440000",
"shortcode": "A4B2C8XZ",
"amount": {
"raw": "5000000",
"formatted": "5.00",
"decimals": 6
},
"token": {
"id": 1,
"symbol": "USDC",
"name": "USD Coin",
"decimals": 6
},
"chain": {
"id": 1,
"slug": "ethereum",
"name": "Ethereum"
},
"recipient_address": "0x742C4B8C2515Ad1D8e1C71e8e24c8D5F9A1a8B5A",
"status": "active",
"description": "Pro Plan Subscription - Monthly",
"external_id": "invoice_789",
"payment_url": "https://pay.unter.tech/pay/A4B2C8XZ",
"redirect_url": "https://myapp.com/success?order=789",
"cancel_url": "https://myapp.com/cancelled?order=789",
"paid_amount": {
"raw": "0",
"formatted": "0.00",
"decimals": 6
},
"remaining_amount": {
"raw": "5000000",
"formatted": "5.00",
"decimals": 6
},
"payment_attempts": 0,
"expires_at": "2024-08-15T18:00:00.000Z",
"created_at": "2024-08-14T12:30:00.000Z",
"completed_at": null,
"metadata": {
"customer_id": "cust_abc123",
"plan": "pro",
"billing_cycle": "monthly"
},
"payments": []
}
}Code Examples
JavaScript (Node.js)
const axios = require('axios');
const apiKey = process.env.UNTER_API_KEY;
const client = axios.create({
baseURL: 'https://api.unter.tech/api',
headers: {
'X-API-Key': apiKey,
'Content-Type': 'application/json'
}
});
async function createPaymentRequest(data) {
try {
const response = await client.post('/payment-requests', {
amount: "1000000", // $1.00 USDC
token_id: 1,
chain_id: 1,
recipient_address: "0x742C4B8C2515Ad1D8e1C71e8e24c8D5F9A1a8B5A",
external_id: "order_123",
description: "Monthly subscription",
redirect_url: "https://myapp.com/success",
expires_at: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString()
});
console.log('Payment request created:', response.data.data.payment_url);
return response.data.data;
} catch (error) {
if (error.response?.status === 422) {
console.error('Validation errors:', error.response.data.errors);
} else {
console.error('Error:', error.response?.data || error.message);
}
throw error;
}
}Payment Request Lifecycle
Active: Payment request is created and ready to receive payments
Completed: Full amount has been received
Expired: Past the expiration date without full payment
Cancelled: Manually cancelled via API
Best Practices
Always set reasonable expiration times
Use external_id for tracking
Link payment requests to your internal order/invoice system
Handle webhook notifications
Set up webhooks to get notified of payment status changes
Validate token/chain combinations
Use the chains and tokens endpoints to get valid combinations
Not all tokens are available as receiving token on all chains
Getting Available Tokens and Chains
Before creating payment requests, you need to know which tokens and chains are supported. Use these public endpoints (no authentication required):
List All Supported Chains
GET /api/public/chains?include_tokens=trueList Tokens for a Specific Chain
GET /api/public/chains/{chain_id}/tokensLast updated