API Reference¶
This page provides a comprehensive reference for the UniVoucher API.
UniVoucher API 1.0.0¶
UniVoucher is the world's first decentralized tangible crypto gift card protocol that allows users to create and redeem crypto gift cards across multiple blockchains.
This API is completely free and public to use - no API key required! With a single version, you can directly integrate with our endpoints without any registration or authentication process.
This API provides both read-only endpoints for querying the UniVoucher ecosystem and write endpoints for creating gift cards. You can use it to retrieve details about gift cards, query cards associated with specific addresses or blockchains, check current protocol fees, and create new gift cards.
For card redemption, you must interact directly with the UniVoucher smart contract. Please refer to our Integration Guide for guidance.
As a decentralized application, UniVoucher stores all gift card data securely on the blockchain. This API is designed to index the blockchain data and provide a way to query and create cards. Gift cards are generated with secure cryptographic methods and user-friendly secrets.
Full API specification: openapi.yaml
UniVoucher Support: Telegram Group
Servers¶
Description | URL |
---|---|
Production API Server | https://api.univoucher.com/v1 |
General¶
GET /health¶
Health Check
Description
Checks if the API is running properly and database is connected
Response 200 OK
Response 503 Service Unavailable
GET /¶
API Information
Description
Returns API documentation and available endpoints
Response 200 OK
{
"name": "UniVoucher API v1",
"version": "1.0.0",
"description": "string",
"endpoints": {
"/cards": "Card-related endpoints",
"/fees": "Fee-related endpoints",
"/chains": "Chain-related endpoints",
"/admin": "Admin endpoints"
}
}
Schema of the response body
{
"type": "object",
"properties": {
"name": {
"type": "string",
"example": "UniVoucher API v1"
},
"version": {
"type": "string",
"example": "1.0.0"
},
"description": {
"type": "string"
},
"endpoints": {
"type": "object",
"properties": {
"/cards": {
"type": "string",
"example": "Card-related endpoints"
},
"/fees": {
"type": "string",
"example": "Fee-related endpoints"
},
"/chains": {
"type": "string",
"example": "Chain-related endpoints"
},
"/admin": {
"type": "string",
"example": "Admin endpoints"
}
}
}
}
}
Cards¶
GET /cards/all¶
Get All Cards
Description
Overview
This endpoint retrieves cards with flexible filtering options and provides comprehensive statistics.
Statistics Only Mode
Setting limit=0 returns only statistics without card data:
GET /cards/all?creator=0x123&chain=56&limit=0 { "total": 250, "active": 150, "redeemed": 80, "cancelled": 20 }
This is useful for dashboards or when you only need counts.
The belongTo Parameter
The belongTo parameter enables retrieving all cards associated with an address (as either creator or redeemer) in a single query.
Usage Scenarios:
- Basic usage: /cards/all?belongTo=0x123
Returns all cards where creator=0x123 OR redeemedBy=0x123 - With creator:
/cards/all?belongTo=0x123&creator=0x456
Returns cards where creator=0x456 AND redeemedBy=0x123 - With redeemedBy:
/cards/all?belongTo=0x123&redeemedBy=0x456
Returns cards where creator=0x123 AND redeemedBy=0x456 - With both:
/cards/all?belongTo=0x123&creator=0x456&redeemedBy=0x789
Returns cards where creator=0x456 AND redeemedBy=0x789 (ignoring belongTo)
Note: When both belongTo and specific filters (creator/redeemedBy) are provided, the explicit filters take precedence over the corresponding parts of belongTo.
Common Use Cases
- Wallet integration: /cards/all?belongTo={userAddress} to show all cards a user has created or received
- Gift tracking: /cards/all?creator={userAddress}&status=active to show unredeemed gifts sent
- Portfolio view: /cards/all?redeemedBy={userAddress} to show received gifts
Input parameters
Parameter | In | Type | Default | Nullable | Description |
---|---|---|---|---|---|
belongTo |
query | string | No | Filter to cards created by OR redeemed by this address. If creator or redeemedBy are also specified, they take precedence over the corresponding parts of belongTo. | |
chain |
query | integer | No | Filter by chain ID | |
creator |
query | string | No | Filter by creator address | |
limit |
query | integer | 20 | No | Results per page. Set to 0 for stats only. |
page |
query | integer | 1 | No | Page number for pagination |
partner |
query | string | No | Filter by partner address used during redemption | |
redeemedBy |
query | string | No | Filter by redeemer address | |
sortDirection |
query | string | desc | No | Sort direction for results based on creation date |
status |
query | string | No | Filter by card status | |
tokenAddress |
query | string | No | Filter by token address (use 0x0000000000000000000000000000000000000000 for native currency) |
Response 200 OK
{
"total": 250,
"active": 150,
"redeemed": 80,
"cancelled": 20,
"page": 1,
"limit": 20,
"totalPages": 13,
"cards": [
{
"cardId": 1026123,
"slotId": "0xabcdef1234567890abcdef1234567890abcdef12",
"chainId": 1,
"chainName": "Ethereum",
"active": true,
"status": "active",
"tokenAddress": "0x0000000000000000000000000000000000000000",
"tokenAmount": "1000000000000000000",
"creator": "0x1234567890abcdef1234567890abcdef12345678",
"message": "Happy Birthday!",
"encryptedPrivateKey": "string",
"feePaid": "10000000000000000",
"createdAt": "2025-05-01T12:00:00.000Z",
"createdOnBlock": 22516300,
"creationHash": "0xabcdef...",
"redeemedBy": "0x9876543210abcdef1234567890abcdef12345678",
"partner": "0x1111222233334444555566667777888899990000",
"redeemedAt": "2022-04-13T15:42:05.901Z",
"redeemedOnBlock": 0,
"redemptionHash": "string",
"cancelledBy": "string",
"cancelledAt": "2022-04-13T15:42:05.901Z",
"cancelledOnBlock": 0,
"cancellationHash": "string"
}
]
}
Schema of the response body
{
"type": "object",
"properties": {
"total": {
"type": "integer",
"description": "Total number of cards matching criteria",
"example": 250
},
"active": {
"type": "integer",
"description": "Number of active cards",
"example": 150
},
"redeemed": {
"type": "integer",
"description": "Number of redeemed cards",
"example": 80
},
"cancelled": {
"type": "integer",
"description": "Number of cancelled cards",
"example": 20
},
"page": {
"type": "integer",
"description": "Current page number",
"example": 1
},
"limit": {
"type": "integer",
"description": "Results per page",
"example": 20
},
"totalPages": {
"type": "integer",
"description": "Total number of pages",
"example": 13
},
"cards": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Card"
}
}
}
}
Response 500 Internal Server Error
Refer to the common response description: InternalServerError.
GET /cards/single¶
Get Single Card
Description
Get a single card by ID or slot ID
Input parameters
Parameter | In | Type | Default | Nullable | Description |
---|---|---|---|---|---|
id |
query | integer | No | Card ID to look up (mutually exclusive with slotId) | |
slotId |
query | string | No | Slot ID to look up (mutually exclusive with id) |
Response 200 OK
{
"cardId": 1026123,
"slotId": "0xabcdef1234567890abcdef1234567890abcdef12",
"chainId": 1,
"chainName": "Ethereum",
"active": true,
"status": "active",
"tokenAddress": "0x0000000000000000000000000000000000000000",
"tokenAmount": "1000000000000000000",
"creator": "0x1234567890abcdef1234567890abcdef12345678",
"message": "Happy Birthday!",
"encryptedPrivateKey": "string",
"feePaid": "10000000000000000",
"createdAt": "2025-05-01T12:00:00.000Z",
"createdOnBlock": 22516300,
"creationHash": "0xabcdef...",
"redeemedBy": "0x9876543210abcdef1234567890abcdef12345678",
"partner": "0x1111222233334444555566667777888899990000",
"redeemedAt": "2022-04-13T15:42:05.901Z",
"redeemedOnBlock": 0,
"redemptionHash": "string",
"cancelledBy": "string",
"cancelledAt": "2022-04-13T15:42:05.901Z",
"cancelledOnBlock": 0,
"cancellationHash": "string"
}
Schema of the response body
{
"type": "object",
"properties": {
"cardId": {
"type": "integer",
"description": "Unique identifier for the card",
"example": 1026123
},
"slotId": {
"type": "string",
"description": "Address/public key of the card",
"example": "0xabcdef1234567890abcdef1234567890abcdef12"
},
"chainId": {
"type": "integer",
"description": "Blockchain chain ID",
"example": 1
},
"chainName": {
"type": "string",
"description": "Name of the blockchain",
"example": "Ethereum"
},
"active": {
"type": "boolean",
"description": "Whether the card is active",
"example": true
},
"status": {
"type": "string",
"description": "Status of the card",
"enum": [
"active",
"redeemed",
"cancelled"
],
"example": "active"
},
"tokenAddress": {
"type": "string",
"description": "Address of the token (address(0) for native currency)",
"example": "0x0000000000000000000000000000000000000000"
},
"tokenAmount": {
"type": "string",
"description": "Amount of tokens stored (as string to handle large numbers)",
"example": "1000000000000000000"
},
"creator": {
"type": "string",
"description": "Address of the card creator",
"example": "0x1234567890abcdef1234567890abcdef12345678"
},
"message": {
"type": "string",
"description": "Optional message attached to the card",
"example": "Happy Birthday!"
},
"encryptedPrivateKey": {
"type": "string",
"description": "Encrypted private key (optional)"
},
"feePaid": {
"type": "string",
"description": "Fee paid when creating the card",
"example": "10000000000000000"
},
"createdAt": {
"type": "string",
"format": "date-time",
"description": "Timestamp when the card was created",
"example": "2025-05-01T12:00:00.000Z"
},
"createdOnBlock": {
"type": "integer",
"description": "Block number when the card was created",
"example": 22516300
},
"creationHash": {
"type": "string",
"description": "Transaction hash of the creation transaction",
"example": "0xabcdef..."
},
"redeemedBy": {
"type": "string",
"description": "Address that redeemed the card (null if not redeemed)",
"example": "0x9876543210abcdef1234567890abcdef12345678"
},
"partner": {
"type": "string",
"description": "Partner address used during redemption (0x0000000000000000000000000000000000000000 if no partner or null if not redeemed)",
"example": "0x1111222233334444555566667777888899990000"
},
"redeemedAt": {
"type": "string",
"format": "date-time",
"description": "Timestamp when the card was redeemed (null if not redeemed)"
},
"redeemedOnBlock": {
"type": "integer",
"description": "Block number when the card was redeemed (null if not redeemed)"
},
"redemptionHash": {
"type": "string",
"description": "Transaction hash of the redemption transaction (null if not redeemed)"
},
"cancelledBy": {
"type": "string",
"description": "Address that cancelled the card (null if not cancelled)"
},
"cancelledAt": {
"type": "string",
"format": "date-time",
"description": "Timestamp when the card was cancelled (null if not cancelled)"
},
"cancelledOnBlock": {
"type": "integer",
"description": "Block number when the card was cancelled (null if not cancelled)"
},
"cancellationHash": {
"type": "string",
"description": "Transaction hash of the cancellation transaction (null if not cancelled)"
}
}
}
Response 400 Bad Request
Response 404 Not Found
Response 500 Internal Server Error
Refer to the common response description: InternalServerError.
POST /cards/create¶
Create Gift Cards
Description
Create new UniVoucher gift cards on the blockchain using your own crypto wallet private key. this wallet must have enough balance to cover the gas fees (UniVoucher never store your private key). You can choose to receive notifications via callback URL or get the card details directly in the response after processing. This endpoint handles both single and bulk card creation.
Security Features
- Private Key Encryption: Card private keys are encrypted using PBKDF2 and AES-GCM
- Friendly Secrets: User-friendly card secrets in format XXXXX-XXXXX-XXXXX-XXXXX
- Balance Validation: Automatic balance checking before transaction
- Callback Notifications: Optional webhook notifications for order status
Supported Networks
- 1 - Ethereum
- 8453 - Base
- 56 - BNB Chain
- 137 - Polygon
- 42161 - Arbitrum
- 10 - Optimism
- 43114 - Avalanche
Token Support
- Native Tokens: Use zero address (0x0000000000000000000000000000000000000000)
- ERC-20 Tokens: Any ERC-20 token address
Fee Structure
Protocol fee is paid in the same token as the card.
ERC-20 Token Approval
For ERC-20 tokens, the API automatically approves unlimited allowance (MaxUint256) to the UniVoucher contract. This eliminates the need for multiple approval transactions and ensures smooth bulk card creation.
Bulk Creation
For quantities > 1, cards are created using the UniVoucher contract's bulk functions:
- Single Card (quantity = 1): Uses
depositETH
ordepositERC20
- Multiple Cards (quantity > 1): Uses
bulkDepositETH
orbulkDepositERC20
Bulk creation is more gas-efficient as it creates all cards in a single transaction. Each card gets a unique secret.
Request Processing Modes
The API supports two modes of operation:
1. Callback Mode (Asynchronous)
When callbackUrl
is
provided, the API operates asynchronously:
- Immediate Response: Returns 202 Accepted with pending status
- Background Processing: Processes transactions in the background
- Callback Notification: Sends POST request to callback URL with results
- Use Case: Web applications, mobile apps, or any scenario requiring non-blocking operation
2. Direct Response Mode (Synchronous)
When
callbackUrl
is not provided, the API operates
synchronously:
- Blocking Response: Waits for transaction completion
- Direct Return: Returns card details directly in the response
- No Callback: No webhook notifications sent
- Use Case: Command-line tools, scripts, or when immediate results are needed
Request Processing Flow
The card creation process follows a specific flow with immediate validation and processing:
1. Immediate Validation (Synchronous)
Before returning any response, the API performs comprehensive validation:
- Parameter Validation: Checks all required fields are present and valid
- Network Validation: Verifies the network is supported
- Token Address Validation: Validates ERC-20 token address format
- Amount Validation: Ensures amount is positive and valid
- Private Key Validation: Validates private key format
- Callback URL Validation: Validates URL format
- Quantity Validation: Ensures quantity is between 1-100
2. Balance & Gas Estimation (Synchronous)
After validation, the API performs financial checks:
- Fee Calculation: Calculates protocol fee using smart contract
- Gas Price Estimation: Gets optimal gas price from Alchemy API
- Gas Limit Estimation: Estimates gas needed for transaction
- Balance Validation: Checks if wallet has sufficient funds
- Token Balance Check: For ERC-20 tokens, checks token balance
- Native Balance Check: Ensures enough native tokens for gas fees
3. Pending Status Response
If all validations pass, the API immediately returns a 202 Accepted response with pending status:
- Immediate Response: No waiting for blockchain transactions
- Status: "pending" - indicates processing has started
- Order Tracking: Includes orderId for tracking
- Fee Information: Shows calculated fees and amounts
- Callback Promise: Assures callback will be sent
4. Asynchronous Processing
After returning the pending response, the API processes transactions asynchronously:
- Approval Transaction: For ERC-20 tokens, approves unlimited allowance
- Creation Transaction: Creates cards on the blockchain
- Event Processing: Waits for CardCreated events
- Callback Notification: Sends success/error callback
Pending Status Response
The pending response includes all the information needed to track the order:
{ "success": true, "status": "pending", "orderId": "order_12345", "issuerAddress": "0x1234567890abcdef1234567890abcdef12345678", "network": 8453, "tokenAddress": "0xfde4c96c8593536e31f229ea8f37b2ada2699bb2", "amountPerCard": "1000000000000000000", "feePerCard": "50000000000000000", "totalPerCard": "1050000000000000000", "quantity": 1, "totalAmount": "1050000000000000000", "message": "Happy Birthday!", "callbackUrl": "https://your-app.com/webhook", "createdAt": "2025-01-15T10:30:00.000Z" }
What Happens After Pending Status
- Approval Transaction (ERC-20 only):
- Checks current token allowance
- If insufficient, sends approval transaction
- Waits for approval confirmation (30-minute timeout)
- Records approval transaction hash
- Card Creation Transaction:
- Generates random wallet for each card
- Creates friendly secret (XXXXX-XXXXX-XXXXX-XXXXX)
- Encrypts card private key with friendly secret
- Sends creation transaction to blockchain
- Waits for transaction confirmation (30-minute timeout)
- Records creation transaction hash
- Event Processing:
- Listens for CardCreated events
- Extracts card IDs and slot IDs
- Maps cards to friendly secrets
- Prepares card details for callback
- Callback Notification:
- Sends POST request to callback URL
- Includes all card details and transaction hashes
- Retries up to 3 times if delivery fails
Error Scenarios During Processing
- Approval Timeout: 30-minute timeout for approval transaction
- Creation Timeout: 30-minute timeout for creation transaction
- Insufficient Funds: Transaction fails due to low balance
- Network Congestion: High gas prices or network issues
- Contract Errors: Smart contract validation failures
- Callback Failures: Webhook delivery issues (retried automatically)
Callback Notifications
The API sends POST requests to your callback URL with detailed transaction information. Callbacks include transaction hashes for both approval and creation transactions.
Success Callback
Sent when card creation is successful:
POST {callbackUrl} Content-Type: application/json { "orderId": "order_12345", "status": "success", "issuerAddress": "0x1234567890abcdef1234567890abcdef12345678", "network": 8453, "tokenAddress": "0xfde4c96c8593536e31f229ea8f37b2ada2699bb2", "amountPerCard": "1000000000000000000", "feePerCard": "50000000000000000", "totalPerCard": "1050000000000000000", "quantity": 1, "totalAmount": "1050000000000000000", "cards": [ { "cardId": 1026123, "cardSecret": "ABCDE-FGHIJ-KLMNO-PQRST", "slotId": "0xabcdef1234567890abcdef1234567890abcdef12", "amount": "1000000000000000000", "tokenAddress": "0xfde4c96c8593536e31f229ea8f37b2ada2699bb2", "message": "Happy Birthday!", "orderId": "order_12345" } ], "approvalTransactionHashes": ["0x1234..."], "creationTransactionHashes": ["0x5678..."], "message": "Happy Birthday!", "authToken": "your-auth-token" }
Note: The message
field in the
success callback contains the message that was attached to the gift cards,
not a status message.
Error Callback
Sent when card creation fails:
POST {callbackUrl} Content-Type: application/json { "orderId": "order_12345", "status": "error", "error": "insufficient funds for intrinsic transaction cost", "approvalTransactionHashes": ["0x1234..."], "creationTransactionHashes": [], "authToken": "your-auth-token" }
Callback Retry Logic
- Retry Attempts: 3 attempts with exponential backoff
- Retry Delays: 1s, 5s, 15s
- Timeout: 10 seconds per attempt
- Headers: Includes User-Agent and timestamp headers
Transaction Hash Tracking
- approvalTransactionHashes: Array of approval transaction hashes (if ERC-20 token)
- creationTransactionHashes: Array of card creation transaction hashes
- Empty Arrays: Indicates no transactions were completed
Request body
{
"network": 1,
"tokenAddress": "0x0000000000000000000000000000000000000000",
"amount": "1000000000000000000",
"quantity": 1,
"privateKey": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
"orderId": "order_12345",
"callbackUrl": "https://your-app.com/webhook",
"authToken": "your-auth-token-123",
"message": "Happy Birthday!"
}
Schema of the request body
{
"type": "object",
"required": [
"network",
"tokenAddress",
"amount",
"privateKey",
"orderId"
],
"properties": {
"network": {
"type": "integer",
"description": "Chain ID for the network",
"example": 1
},
"tokenAddress": {
"type": "string",
"description": "Token address (use zero address for native tokens)",
"example": "0x0000000000000000000000000000000000000000"
},
"amount": {
"type": "string",
"description": "Amount in wei (as string to handle large numbers)",
"example": "1000000000000000000"
},
"quantity": {
"type": "integer",
"description": "Number of cards to create (1-100)",
"minimum": 1,
"maximum": 100,
"default": 1,
"example": 1
},
"privateKey": {
"type": "string",
"description": "Issuer's private key (with or without 0x prefix)",
"example": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"
},
"orderId": {
"type": "string",
"description": "Order ID for user reference",
"example": "order_12345"
},
"callbackUrl": {
"type": "string",
"format": "uri",
"description": "Callback URL for notifications (optional - if not provided, card details will be returned in response after processing)",
"example": "https://your-app.com/webhook"
},
"authToken": {
"type": "string",
"description": "Authentication token for callback verification (optional - required if callbackUrl is provided)",
"example": "your-auth-token-123"
},
"message": {
"type": "string",
"description": "Optional message to attach to cards",
"maxLength": 100,
"example": "Happy Birthday!"
}
}
}
Response 202 Accepted
{
"success": true,
"status": "pending",
"orderId": "order_12345",
"issuerAddress": "0x1234567890abcdef1234567890abcdef12345678",
"network": 1,
"tokenAddress": "0x0000000000000000000000000000000000000000",
"amountPerCard": "1000000000000000000",
"feePerCard": "10000000000000000",
"totalPerCard": "1010000000000000000",
"quantity": 1,
"totalAmount": "1010000000000000000",
"message": "Happy Birthday!",
"callbackUrl": "https://your-app.com/webhook",
"createdAt": "2025-01-15T10:30:00.000Z"
}
Schema of the response body
{
"type": "object",
"properties": {
"success": {
"type": "boolean",
"example": true
},
"status": {
"type": "string",
"example": "pending"
},
"orderId": {
"type": "string",
"example": "order_12345"
},
"issuerAddress": {
"type": "string",
"example": "0x1234567890abcdef1234567890abcdef12345678"
},
"network": {
"type": "integer",
"example": 1
},
"tokenAddress": {
"type": "string",
"example": "0x0000000000000000000000000000000000000000"
},
"amountPerCard": {
"type": "string",
"example": "1000000000000000000"
},
"feePerCard": {
"type": "string",
"example": "10000000000000000"
},
"totalPerCard": {
"type": "string",
"example": "1010000000000000000"
},
"quantity": {
"type": "integer",
"example": 1
},
"totalAmount": {
"type": "string",
"example": "1010000000000000000"
},
"message": {
"type": "string",
"description": "The message attached to the gift cards (same as request message)",
"example": "Happy Birthday!"
},
"callbackUrl": {
"type": "string",
"example": "https://your-app.com/webhook"
},
"createdAt": {
"type": "string",
"format": "date-time",
"example": "2025-01-15T10:30:00.000Z"
}
}
}
Response 200 OK
{
"success": true,
"status": "success",
"orderId": "order_12345",
"issuerAddress": "0x1234567890abcdef1234567890abcdef12345678",
"network": 1,
"tokenAddress": "0x0000000000000000000000000000000000000000",
"amountPerCard": "1000000000000000000",
"feePerCard": "10000000000000000",
"totalPerCard": "1010000000000000000",
"quantity": 1,
"totalAmount": "1010000000000000000",
"cards": [
{
"cardId": 1026123,
"cardSecret": "ABCDE-FGHIJ-KLMNO-PQRST",
"slotId": "0xabcdef1234567890abcdef1234567890abcdef12",
"amount": "1000000000000000000",
"tokenAddress": "0x0000000000000000000000000000000000000000",
"message": "Happy Birthday!",
"orderId": "order_12345"
}
],
"approvalTransactionHashes": [
"0x1234..."
],
"creationTransactionHashes": [
"0x5678..."
],
"message": "Happy Birthday!",
"createdAt": "2025-01-15T10:30:00.000Z"
}
Schema of the response body
{
"type": "object",
"properties": {
"success": {
"type": "boolean",
"example": true
},
"status": {
"type": "string",
"example": "success"
},
"orderId": {
"type": "string",
"example": "order_12345"
},
"issuerAddress": {
"type": "string",
"example": "0x1234567890abcdef1234567890abcdef12345678"
},
"network": {
"type": "integer",
"example": 1
},
"tokenAddress": {
"type": "string",
"example": "0x0000000000000000000000000000000000000000"
},
"amountPerCard": {
"type": "string",
"example": "1000000000000000000"
},
"feePerCard": {
"type": "string",
"example": "10000000000000000"
},
"totalPerCard": {
"type": "string",
"example": "1010000000000000000"
},
"quantity": {
"type": "integer",
"example": 1
},
"totalAmount": {
"type": "string",
"example": "1010000000000000000"
},
"cards": {
"type": "array",
"items": {
"type": "object",
"properties": {
"cardId": {
"type": "integer",
"example": 1026123
},
"cardSecret": {
"type": "string",
"example": "ABCDE-FGHIJ-KLMNO-PQRST"
},
"slotId": {
"type": "string",
"example": "0xabcdef1234567890abcdef1234567890abcdef12"
},
"amount": {
"type": "string",
"example": "1000000000000000000"
},
"tokenAddress": {
"type": "string",
"example": "0x0000000000000000000000000000000000000000"
},
"message": {
"type": "string",
"example": "Happy Birthday!"
},
"orderId": {
"type": "string",
"example": "order_12345"
}
}
}
},
"approvalTransactionHashes": {
"type": "array",
"items": {
"type": "string"
},
"example": [
"0x1234..."
]
},
"creationTransactionHashes": {
"type": "array",
"items": {
"type": "string"
},
"example": [
"0x5678..."
]
},
"message": {
"type": "string",
"description": "The message attached to the gift cards (same as request message)",
"example": "Happy Birthday!"
},
"createdAt": {
"type": "string",
"format": "date-time",
"example": "2025-01-15T10:30:00.000Z"
}
}
}
Response 400 Bad Request
Schema of the response body
{
"oneOf": [
{
"type": "object",
"properties": {
"error": {
"type": "string",
"example": "Missing required parameters"
},
"required": {
"type": "array",
"items": {
"type": "string"
},
"example": [
"network",
"tokenAddress",
"amount",
"privateKey",
"orderId"
]
}
}
},
{
"type": "object",
"properties": {
"error": {
"type": "string",
"example": "Invalid private key format"
}
}
},
{
"type": "object",
"properties": {
"error": {
"type": "string",
"example": "Invalid network"
},
"supportedNetworks": {
"type": "array",
"items": {
"type": "integer"
},
"example": [
1,
8453,
56,
137,
42161,
10,
43114
]
}
}
},
{
"type": "object",
"properties": {
"error": {
"type": "string",
"example": "Invalid token address"
}
}
},
{
"type": "object",
"properties": {
"error": {
"type": "string",
"example": "Invalid amount format"
}
}
},
{
"type": "object",
"properties": {
"error": {
"type": "string",
"example": "Quantity must be between 1 and 100"
}
}
},
{
"type": "object",
"properties": {
"error": {
"type": "string",
"example": "Invalid callback URL"
}
}
},
{
"type": "object",
"properties": {
"error": {
"type": "string",
"example": "Insufficient balance"
},
"required": {
"type": "string",
"example": "1015000000000000000"
},
"available": {
"type": "string",
"example": "1000000000000000000"
},
"breakdown": {
"type": "object",
"properties": {
"cardAmount": {
"type": "string",
"example": "1010000000000000000"
},
"gasCost": {
"type": "string",
"example": "50000000000000000"
},
"gasPrice": {
"type": "string",
"example": "20000000000"
},
"gasLimit": {
"type": "string",
"example": "2500000"
}
}
},
"tokenAddress": {
"type": "string",
"example": "0x0000000000000000000000000000000000000000"
}
}
},
{
"type": "object",
"properties": {
"error": {
"type": "string",
"example": "Insufficient token balance"
},
"required": {
"type": "string",
"example": "1010000000000000000"
},
"available": {
"type": "string",
"example": "1000000000000000000"
},
"tokenAddress": {
"type": "string",
"example": "0xA0b86a33E6441b8c4C8C1C1C1C1C1C1C1C1C1C1C"
}
}
},
{
"type": "object",
"properties": {
"error": {
"type": "string",
"example": "Insufficient native balance for gas fees"
},
"required": {
"type": "string",
"example": "50000000000000000"
},
"available": {
"type": "string",
"example": "10000000000000000"
},
"breakdown": {
"type": "object",
"properties": {
"gasCost": {
"type": "string",
"example": "50000000000000000"
},
"gasPrice": {
"type": "string",
"example": "20000000000"
},
"gasLimit": {
"type": "string",
"example": "2500000"
}
}
}
}
}
]
}
Response 500 Internal Server Error
Refer to the common response description: InternalServerError.
Callbacks¶
GET /callbacks¶
Callback Documentation
Description
Callback Notification System
UniVoucher API uses webhook callbacks to notify your application about the status of card creation requests. This system provides real-time updates and includes detailed transaction information.
Request Processing & Pending Status
When you submit a card creation request, the API follows this flow:
1. Immediate Processing (Synchronous)
The API performs comprehensive validation and checks before any response:
- Input Validation: Validates all parameters, network, token address, amounts
- Balance Checks: Verifies sufficient funds for card amount + fees + gas
- Gas Estimation: Calculates optimal gas price and estimated gas limit
- Financial Validation: Ensures total cost doesn't exceed available balance
2. Pending Status Response (202 Accepted)
If all validations pass, the API immediately returns:
- Status Code: 202 Accepted (not 200 OK)
- Status Field: "pending" (not "success")
- Immediate Response: No waiting for blockchain transactions
- Order Tracking: Includes orderId for future reference
- Fee Breakdown: Shows calculated fees and total amounts
3. Asynchronous Processing
After the pending response, processing continues in the background:
- Approval Transaction: For ERC-20 tokens, approves unlimited allowance
- Creation Transaction: Creates cards on the blockchain
- Event Processing: Waits for CardCreated events
- Callback Notification: Sends final result via webhook
Callback Flow
- Request Submission: You submit a card creation request
- Immediate Response: API returns 202 Accepted with pending status
- Transaction Processing: API processes approval and creation transactions
- Callback Notification: API sends POST request to your callback URL
Callback Scenarios
1. Successful Card Creation
When: All transactions succeed (approval + creation)
Status: "success"
Includes: Card details, secrets, transaction hashes
2. Approval Success, Creation Failure
When: Approval succeeds but creation fails
Status: "error"
Includes: Approval transaction hash, creation error
3. Approval Failure
When: Approval transaction fails
Status: "error"
Includes: Error message, no transaction hashes
4. Network/System Errors
When: System errors, network issues, timeouts
Status: "error"
Includes: Error message, partial transaction hashes if any
Callback Headers
Content-Type: application/json User-Agent: UniVoucher-API/1.0.0 X-UniVoucher-Timestamp: 1703123456789
Response Codes
- 200 OK: Callback received successfully
- 4xx/5xx: Callback will be retried
Response 200 OK
{
"title": "UniVoucher Callback Documentation",
"description": "Complete guide to callback notifications",
"scenarios": {
"success": "Card creation successful",
"approval_success_creation_failure": "Approval succeeded but creation failed",
"approval_failure": "Approval transaction failed",
"system_error": "Network or system error"
},
"retry_logic": {
"attempts": 3,
"delays": [
1000,
5000,
15000
],
"timeout": 10000
},
"security": [
"Verify authToken",
"Verify orderId",
"Use HTTPS",
"Validate data"
]
}
Schema of the response body
{
"type": "object",
"properties": {
"title": {
"type": "string",
"example": "UniVoucher Callback Documentation"
},
"description": {
"type": "string",
"example": "Complete guide to callback notifications"
},
"scenarios": {
"type": "object",
"properties": {
"success": {
"type": "string",
"example": "Card creation successful"
},
"approval_success_creation_failure": {
"type": "string",
"example": "Approval succeeded but creation failed"
},
"approval_failure": {
"type": "string",
"example": "Approval transaction failed"
},
"system_error": {
"type": "string",
"example": "Network or system error"
}
}
},
"retry_logic": {
"type": "object",
"properties": {
"attempts": {
"type": "integer",
"example": 3
},
"delays": {
"type": "array",
"items": {
"type": "integer"
},
"example": [
1000,
5000,
15000
]
},
"timeout": {
"type": "integer",
"example": 10000
}
}
},
"security": {
"type": "array",
"items": {
"type": "string"
},
"example": [
"Verify authToken",
"Verify orderId",
"Use HTTPS",
"Validate data"
]
}
}
}
Fees¶
GET /fees/current¶
Get Current Fees
Description
Get current fee percentages for all chains or a specific chain
Input parameters
Parameter | In | Type | Default | Nullable | Description |
---|---|---|---|---|---|
chainId |
query | integer | No | Chain ID to filter by |
Response 200 OK
Schema of the response body
{
"oneOf": [
{
"type": "object",
"description": "Fees for all chains",
"additionalProperties": {
"type": "number",
"format": "float"
},
"example": {
"1": 0.01,
"8453": 0.01,
"56": 0.01
}
},
{
"type": "object",
"description": "Fee for specific chain",
"properties": {
"feePercentage": {
"type": "number",
"format": "float",
"example": 0.01
}
}
}
]
}
Response 404 Not Found
Response 500 Internal Server Error
Refer to the common response description: InternalServerError.
GET /fees/history/{chainId}¶
Get Fee History
Description
Get fee update history for a chain
Input parameters
Parameter | In | Type | Default | Nullable | Description |
---|---|---|---|---|---|
chainId |
path | integer | No | Chain ID |
Response 200 OK
{
"chainId": 1,
"chainName": "Ethereum",
"currentFeePercentage": 0.01,
"currentFeeBasisPoints": 100,
"history": [
{
"oldFeePercentage": 0.005,
"newFeePercentage": 0.01,
"oldFeeBasisPoints": 50,
"newFeeBasisPoints": 100,
"timestamp": "2025-04-15T10:23:45.000Z",
"transactionHash": "0xabcdef..."
}
]
}
Schema of the response body
{
"type": "object",
"properties": {
"chainId": {
"type": "integer",
"example": 1
},
"chainName": {
"type": "string",
"example": "Ethereum"
},
"currentFeePercentage": {
"type": "number",
"format": "float",
"example": 0.01
},
"currentFeeBasisPoints": {
"type": "integer",
"example": 100
},
"history": {
"type": "array",
"items": {
"type": "object",
"properties": {
"oldFeePercentage": {
"type": "number",
"format": "float",
"example": 0.005
},
"newFeePercentage": {
"type": "number",
"format": "float",
"example": 0.01
},
"oldFeeBasisPoints": {
"type": "integer",
"example": 50
},
"newFeeBasisPoints": {
"type": "integer",
"example": 100
},
"timestamp": {
"type": "string",
"format": "date-time",
"example": "2025-04-15T10:23:45.000Z"
},
"transactionHash": {
"type": "string",
"example": "0xabcdef..."
}
}
}
}
}
}
Response 404 Not Found
Response 500 Internal Server Error
Refer to the common response description: InternalServerError.
Chains¶
GET /chains¶
Get Chains
Description
Get all chains or details for a specific chain
Input parameters
Parameter | In | Type | Default | Nullable | Description |
---|---|---|---|---|---|
chain |
query | integer | No | Chain ID to filter by |
Response 200 OK
Response 404 Not Found
Response 500 Internal Server Error
Refer to the common response description: InternalServerError.
Schemas¶
Card¶
Name | Type |
---|---|
active |
boolean |
cancellationHash |
string |
cancelledAt |
string(date-time) |
cancelledBy |
string |
cancelledOnBlock |
integer |
cardId |
integer |
chainId |
integer |
chainName |
string |
createdAt |
string(date-time) |
createdOnBlock |
integer |
creationHash |
string |
creator |
string |
encryptedPrivateKey |
string |
feePaid |
string |
message |
string |
partner |
string |
redeemedAt |
string(date-time) |
redeemedBy |
string |
redeemedOnBlock |
integer |
redemptionHash |
string |
slotId |
string |
status |
string |
tokenAddress |
string |
tokenAmount |
string |
Chain¶
Name | Type |
---|---|
assetPlatformId |
string |
chainLogo |
string |
chainPrefix |
string |
contractAddress |
string |
deploymentBlock |
integer |
explorerUrl |
string |
feePercentage |
number(float) |
id |
integer |
name |
string |
nativeCurrencyDecimals |
integer |
nativeCurrencyLogo |
string |
nativeCurrencyName |
string |
nativeCurrencySymbol |
string |
rpcUrl |
string |
rpcUrl2 |
string |
Common responses¶
This section describes common responses that are reused across operations.
InternalServerError¶
Internal server error
Tags¶
Name | Description |
---|---|
General | General API information and health endpoints |
Cards | Card-related endpoints for gift card management |
Fees | Fee-related endpoints for protocol fee management |
Chains | Chain-related endpoints for blockchain information |
Callbacks | Callback notification documentation and examples |