Skip to content

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

{
    "status": "ok",
    "message": "Service is healthy"
}
⚠️ This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body
{
    "type": "object",
    "properties": {
        "status": {
            "type": "string",
            "example": "ok"
        },
        "message": {
            "type": "string",
            "example": "Service is healthy"
        }
    }
}

Response 503 Service Unavailable

{
    "status": "error",
    "message": "Database unavailable"
}
⚠️ This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body
{
    "type": "object",
    "properties": {
        "status": {
            "type": "string",
            "example": "error"
        },
        "message": {
            "type": "string",
            "example": "Database 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"
    }
}
⚠️ This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

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"
        }
    ]
}
⚠️ This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

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"
}
⚠️ This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

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

{
    "error": "Either id or slotId parameter is required"
}
⚠️ This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body
{
    "type": "object",
    "properties": {
        "error": {
            "type": "string",
            "example": "Either id or slotId parameter is required"
        }
    }
}

Response 404 Not Found

{
    "error": "Card not found"
}
⚠️ This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body
{
    "type": "object",
    "properties": {
        "error": {
            "type": "string",
            "example": "Card 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 or depositERC20
  • Multiple Cards (quantity > 1): Uses bulkDepositETH or bulkDepositERC20

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

  1. 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
  2. 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
  3. Event Processing:
    • Listens for CardCreated events
    • Extracts card IDs and slot IDs
    • Maps cards to friendly secrets
    • Prepares card details for callback
  4. 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!"
}
⚠️ This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

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"
}
⚠️ This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

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"
}
⚠️ This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

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

  1. Request Submission: You submit a card creation request
  2. Immediate Response: API returns 202 Accepted with pending status
  3. Transaction Processing: API processes approval and creation transactions
  4. 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"
    ]
}
⚠️ This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

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

{
    "error": "Chain not found or inactive"
}
⚠️ This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body
{
    "type": "object",
    "properties": {
        "error": {
            "type": "string",
            "example": "Chain not found or inactive"
        }
    }
}

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..."
        }
    ]
}
⚠️ This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

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

{
    "error": "Chain not found"
}
⚠️ This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body
{
    "type": "object",
    "properties": {
        "error": {
            "type": "string",
            "example": "Chain 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

Schema of the response body
{
    "oneOf": [
        {
            "type": "object",
            "description": "All chains",
            "properties": {
                "chains": {
                    "type": "array",
                    "items": {
                        "$ref": "#/components/schemas/Chain"
                    }
                }
            }
        },
        {
            "type": "object",
            "description": "Specific chain",
            "$ref": "#/components/schemas/Chain"
        }
    ]
}

Response 404 Not Found

{
    "error": "Chain not found"
}
⚠️ This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body
{
    "type": "object",
    "properties": {
        "error": {
            "type": "string",
            "example": "Chain 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

{
    "error": "Internal server error",
    "message": "An unexpected error occurred"
}
⚠️ This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body
{
    "type": "object",
    "properties": {
        "error": {
            "type": "string",
            "example": "Internal server error"
        },
        "message": {
            "type": "string",
            "example": "An unexpected error occurred"
        }
    }
}

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