Appearance
VIO External API Reference
This document provides a comprehensive reference for integrating with the VIO External API.
Table of Contents
1. Overview
What is the VIO External API?
The VIO External API allows tenants to integrate their systems with the VIO platform programmatically. Use this API to:
- Manage vouchers (create, update, delete, redeem)
- Manage users and their data
- Create and manage voucher campaigns
- Handle tokens, balances, and transactions
- Access analytics and reporting data
Base URL
https://{your-domain}/api/external/v1All API endpoints are relative to this base URL.
API Versioning
The current API version is v1. The version is included in the URL path. When breaking changes are introduced, a new version will be released while maintaining backwards compatibility for existing versions.
Architecture
┌─────────────────────────────────────────────────────────────────┐
│ Your Application │
│ ┌───────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ 1. Include X-API-Key header │ │
│ │ 2. Make HTTPS request to /api/external/v1/* │ │
│ │ 3. Parse JSON response │ │
│ │ │ │
│ └───────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────┐
│ VIO API Server │
│ /api/external/v1 │
│ │
│ • Authentication │
│ • Rate Limiting │
│ • Scope Validation │
│ • Request Handler │
└─────────────────────┘
│
▼
┌─────────────────────┐
│ Database │
│ (Your Tenant Data) │
└─────────────────────┘2. Authentication
API Keys
All API requests require authentication using an API key. API keys are scoped to your tenant and can have different permission levels.
Obtaining an API Key
- Log in to the VIO Admin Portal
- Navigate to Settings > API Keys
- Click Create API Key
- Select the scopes (permissions) for the key
- Optionally configure IP whitelisting
- Copy and securely store the generated key
WARNING
API keys are shown only once upon creation. Store them securely.
Using Your API Key
Include your API key in the X-API-Key header with every request:
bash
curl -X GET "https://your-domain.com/api/external/v1/vouchers" \
-H "X-API-Key: vio_live_your_api_key_here"API Key Format
API keys follow this format:
- Live keys:
vio_live_xxxxxxxxxxxxxxxx - Test keys:
vio_test_xxxxxxxxxxxxxxxx
API Key Scopes
Each API key can be assigned one or more scopes that determine which endpoints it can access:
| Scope | Description | Endpoints |
|---|---|---|
vouchers | Manage vouchers and claims | /vouchers/* |
users | Manage users | /users/* |
campaigns | Manage campaigns | /campaigns/* |
tokens | Manage tokens and balances | /tokens/* |
analytics | Access analytics data | /analytics/* |
IP Whitelisting
For additional security, you can restrict API key usage to specific IP addresses:
- Go to Admin Portal > Settings > API Keys
- Edit your API key
- Add allowed IP addresses or CIDR ranges
- Save changes
Requests from non-whitelisted IPs will receive a 403 Forbidden response.
3. Rate Limiting
Default Limits
To ensure fair usage and platform stability, the API enforces rate limits:
| Limit Type | Default Value |
|---|---|
| Per Minute | 60 requests |
| Per Day | 10,000 requests |
Rate Limit Headers
Every response includes rate limit information in the headers:
| Header | Description |
|---|---|
X-RateLimit-Limit | Maximum requests allowed in the current window |
X-RateLimit-Remaining | Requests remaining in the current window |
X-RateLimit-Reset | Unix timestamp when the rate limit resets |
Example Response Headers
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 45
X-RateLimit-Reset: 1699574400Rate Limit Exceeded
When you exceed the rate limit, you'll receive a 429 Too Many Requests response:
json
{
"success": false,
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Too many requests. Please retry after 60 seconds."
}
}The response includes a Retry-After header indicating how long to wait before retrying.
Best Practices
- Implement exponential backoff when receiving
429responses - Cache responses when appropriate
- Batch operations when possible
- Monitor your usage via the rate limit headers
4. Request & Response Format
Request Format
- All request bodies must be JSON
- Include
Content-Type: application/jsonheader for POST/PATCH requests - Query parameters are used for filtering and pagination
Success Response
Successful responses follow this structure:
json
{
"success": true,
"data": { ... },
"message": "Optional success message"
}Paginated Response
List endpoints return paginated data:
json
{
"success": true,
"data": [ ... ],
"pagination": {
"page": 1,
"limit": 20,
"total": 150,
"totalPages": 8,
"hasNextPage": true,
"hasPrevPage": false
}
}Pagination Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
page | integer | 1 | Page number (1-indexed) |
limit | integer | 20 | Items per page (max: 100) |
Error Response
Error responses follow this structure:
json
{
"success": false,
"error": {
"code": "ERROR_CODE",
"message": "Human-readable error description"
}
}5. Error Handling
HTTP Status Codes
| Status Code | Meaning |
|---|---|
200 OK | Request succeeded |
201 Created | Resource created successfully |
400 Bad Request | Invalid request parameters or body |
401 Unauthorized | Missing or invalid API key |
403 Forbidden | API key lacks required scope or IP not whitelisted |
404 Not Found | Resource not found |
429 Too Many Requests | Rate limit exceeded |
500 Internal Server Error | Server error |
Error Codes
| Error Code | Description |
|---|---|
VALIDATION_ERROR | Request body or parameters failed validation |
UNAUTHORIZED | API key is missing or invalid |
FORBIDDEN | API key does not have required scope |
NOT_FOUND | Requested resource does not exist |
RATE_LIMIT_EXCEEDED | Too many requests |
ALREADY_EXISTS | Resource already exists (e.g., duplicate user) |
INSUFFICIENT_BALANCE | Not enough token balance for operation |
ALREADY_REDEEMED | Voucher has already been redeemed |
EXPIRED | Voucher or token has expired |
INTERNAL_ERROR | Unexpected server error |
Example Error Response
json
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid request parameters",
"details": [
{
"field": "email",
"message": "Invalid email format"
}
]
}
}6. API Reference: Vouchers
Required Scope: vouchers
List Vouchers
Retrieve a paginated list of vouchers for your tenant.
GET /vouchersQuery Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
page | integer | No | Page number (default: 1) |
limit | integer | No | Items per page (default: 20, max: 100) |
status | string | No | Filter by status: active, claimed, redeemed, expired |
visibility | string | No | Filter by visibility: private, public, shared |
isActive | boolean | No | Filter by active status |
category | string | No | Filter by category |
search | string | No | Search by name |
subCompanyId | string | No | Filter by sub-company |
Example Request:
bash
curl -X GET "https://your-domain.com/api/external/v1/vouchers?page=1&limit=10&isActive=true" \
-H "X-API-Key: vio_live_your_api_key_here"Example Response:
jsonc
{
"success": true, // Whether the request was successful
"data": [ // Array of voucher objects
{
"_id": "507f1f77bcf86cd799439011", // Unique voucher identifier
"name": "20% Off Discount", // Voucher display name
"description": "Get 20% off your next purchase", // Voucher description
"value": 20, // Discount value (number)
"valueType": "percentage", // Value type: "fixed" or "percentage"
"terms": "Valid on orders over $50", // Terms and conditions
"images": ["https://example.com/image.jpg"], // Array of voucher image URLs
"isActive": true, // Whether voucher is currently active
"totalQuantity": 100, // Total available quantity (-1 for unlimited)
"claimedQuantity": 45, // Number of vouchers already claimed
"maxClaimsPerUser": 1, // Maximum claims allowed per user
"startDate": "2024-01-01T00:00:00.000Z", // Voucher validity start date (ISO 8601)
"endDate": "2024-12-31T23:59:59.000Z", // Voucher expiry date (ISO 8601)
"visibility": "public", // Visibility: "private", "public", or "shared" (also controls transfer scope)
"consumptionType": "vio_code", // How voucher is consumed: "vio_code", "url", "qr_code", "coupon_code", "manual"
"createdAt": "2024-01-01T00:00:00.000Z", // Creation timestamp (ISO 8601)
"updatedAt": "2024-01-15T10:30:00.000Z" // Last update timestamp (ISO 8601)
}
],
"pagination": { // Pagination information
"page": 1, // Current page number
"limit": 10, // Items per page
"total": 45, // Total number of vouchers
"totalPages": 5, // Total number of pages
"hasNextPage": true, // Whether more pages exist after current
"hasPrevPage": false // Whether pages exist before current
}
}Create Voucher
Create a new voucher for your tenant.
POST /vouchersRequest Body:
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Voucher name |
description | string | No | Voucher description |
visibility | string | No | private, public, or shared (default: private) |
sharedWithTenants | string[] | No | Tenant IDs to share with |
sharedWithUsers | string[] | No | User IDs to share with |
terms | string | No | Terms and conditions |
value | number | No | Voucher value (default: 0) |
valueType | string | No | fixed, percentage (default: fixed) |
valueCurrency | string | No | Currency code (default: THB) |
minSpend | number | No | Minimum spend required (default: 0) |
maxDiscount | number | No | Maximum discount amount |
totalQuantity | integer | No | Total available quantity (-1 for unlimited, default: -1) |
startDate | datetime | No | When voucher becomes valid |
endDate | datetime | No | When voucher expires |
maxClaimsPerUser | integer | No | Max claims per user (default: 1) |
settlementAmount | number | No | Settlement amount (default: 0) |
settlementCurrency | string | No | Settlement currency (defaults to tenant's primary currency from Billing Settings). All settlement records are automatically stored in the tenant's primary currency regardless of this value. |
crossTenantReceivableTiming | string | No | When to record cross-tenant settlements: redemption (default) or consumption |
categories | string[] | No | Category tags |
images | string[] | No | Image URLs |
targetTiers | string[] | No | Target user tiers |
targetUserGroups | string[] | No | Target user groups |
subCompanyId | string | No | Sub-company ID |
consumptionType | string | No | How voucher is consumed: vio_code, url, qr_code, coupon_code, manual (default: vio_code) |
consumptionUrl | string | No | External URL for url consumption type |
consumptionMessage | string | No | Custom message for manual consumption type |
Example Request:
bash
curl -X POST "https://your-domain.com/api/external/v1/vouchers" \
-H "X-API-Key: vio_live_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"name": "Summer Sale 20% Off",
"description": "Valid for summer collection",
"value": 20,
"valueType": "percentage",
"totalQuantity": 100,
"maxClaimsPerUser": 1,
"startDate": "2024-06-01T00:00:00.000Z",
"endDate": "2024-08-31T23:59:59.000Z",
"visibility": "public",
"terms": "Cannot be combined with other offers"
}'Example Response:
jsonc
{
"success": true, // Whether the request was successful
"data": {
"_id": "507f1f77bcf86cd799439012", // Unique voucher identifier
"name": "Summer Sale 20% Off", // Voucher display name
"description": "Valid for summer collection", // Voucher description
"value": 20, // Discount value
"valueType": "percentage", // Value type: "fixed" or "percentage"
"totalQuantity": 100, // Total available quantity (-1 for unlimited)
"claimedQuantity": 0, // Number of vouchers claimed (starts at 0)
"maxClaimsPerUser": 1, // Maximum claims allowed per user
"startDate": "2024-06-01T00:00:00.000Z", // Voucher validity start date (ISO 8601)
"endDate": "2024-08-31T23:59:59.000Z", // Voucher expiry date (ISO 8601)
"visibility": "public", // Visibility: "private", "public", or "shared"
"isActive": true, // Whether voucher is currently active
"createdAt": "2024-05-15T10:00:00.000Z" // Creation timestamp (ISO 8601)
},
"message": "Voucher created" // Success message
}Get Voucher Details
Retrieve details of a specific voucher.
GET /vouchers/:voucherIdPath Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
voucherId | string | Yes | Voucher ID |
Example Request:
bash
curl -X GET "https://your-domain.com/api/external/v1/vouchers/507f1f77bcf86cd799439011" \
-H "X-API-Key: vio_live_your_api_key_here"Example Response:
jsonc
{
"success": true, // Whether the request was successful
"data": {
"_id": "507f1f77bcf86cd799439011", // Unique voucher identifier
"name": "20% Off Discount", // Voucher display name
"description": "Get 20% off your next purchase", // Voucher description
"value": 20, // Discount value
"valueType": "percentage", // Value type: "fixed" or "percentage"
"terms": "Valid on orders over $50", // Terms and conditions
"images": ["https://example.com/image.jpg"], // Array of voucher image URLs
"isActive": true, // Whether voucher is currently active
"totalQuantity": 100, // Total available quantity (-1 for unlimited)
"claimedQuantity": 45, // Number of vouchers already claimed
"maxClaimsPerUser": 1, // Maximum claims allowed per user
"startDate": "2024-01-01T00:00:00.000Z", // Voucher validity start date (ISO 8601)
"endDate": "2024-12-31T23:59:59.000Z", // Voucher expiry date (ISO 8601)
"visibility": "public", // Visibility: "private", "public", or "shared" (also controls transfer scope)
"consumptionType": "vio_code", // How voucher is consumed: "vio_code", "url", "qr_code", "coupon_code", "manual"
"createdAt": "2024-01-01T00:00:00.000Z", // Creation timestamp (ISO 8601)
"updatedAt": "2024-01-15T10:30:00.000Z" // Last update timestamp (ISO 8601)
}
}Update Voucher
Update an existing voucher.
PATCH /vouchers/:voucherIdPath Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
voucherId | string | Yes | Voucher ID |
Request Body:
All fields are optional. Include only the fields you want to update.
| Field | Type | Description |
|---|---|---|
name | string | Voucher name |
description | string | Voucher description |
visibility | string | private, public, or shared |
sharedWithTenants | string[] | Tenant IDs to share with |
sharedWithUsers | string[] | User IDs to share with |
terms | string | Terms and conditions |
value | number | Voucher value |
valueType | string | fixed or percentage |
valueCurrency | string | Currency code |
minSpend | number | Minimum spend required |
maxDiscount | number | Maximum discount amount |
totalQuantity | integer | Total available quantity |
startDate | datetime | When voucher becomes valid |
endDate | datetime | When voucher expires |
maxClaimsPerUser | integer | Max claims per user |
settlementAmount | number | Settlement amount |
settlementCurrency | string | Settlement currency (defaults to tenant's primary currency). All settlement records are stored in the tenant's primary currency. |
crossTenantReceivableTiming | string | When to record cross-tenant settlements: redemption or consumption |
isActive | boolean | Active status |
categories | string[] | Category tags |
images | string[] | Image URLs |
targetTiers | string[] | Target user tiers |
targetUserGroups | string[] | Target user groups |
consumptionType | string | How voucher is consumed: vio_code, url, qr_code, coupon_code, manual |
consumptionUrl | string | External URL for url consumption type |
consumptionMessage | string | Custom message for manual consumption type |
Example Request:
bash
curl -X PATCH "https://your-domain.com/api/external/v1/vouchers/507f1f77bcf86cd799439011" \
-H "X-API-Key: vio_live_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"name": "Updated Voucher Name",
"isActive": false
}'Example Response:
jsonc
{
"success": true, // Whether the request was successful
"data": {
"_id": "507f1f77bcf86cd799439011", // Unique voucher identifier
"name": "Updated Voucher Name", // Updated voucher name
"isActive": false, // Updated active status
"updatedAt": "2024-02-01T12:00:00.000Z" // Last update timestamp (ISO 8601)
},
"message": "Voucher updated" // Success message
}Delete Voucher
Soft delete a voucher (marks as deleted, not permanently removed).
DELETE /vouchers/:voucherIdPath Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
voucherId | string | Yes | Voucher ID |
Example Request:
bash
curl -X DELETE "https://your-domain.com/api/external/v1/vouchers/507f1f77bcf86cd799439011" \
-H "X-API-Key: vio_live_your_api_key_here"Example Response:
jsonc
{
"success": true, // Whether the request was successful
"data": {
"_id": "507f1f77bcf86cd799439011", // Unique voucher identifier
"isDeleted": true // Deletion status (soft delete)
},
"message": "Voucher deleted" // Success message
}Duplicate Voucher
Create a copy of an existing voucher.
POST /vouchers/:voucherId/duplicatePath Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
voucherId | string | Yes | Voucher ID to duplicate |
Example Request:
bash
curl -X POST "https://your-domain.com/api/external/v1/vouchers/507f1f77bcf86cd799439011/duplicate" \
-H "X-API-Key: vio_live_your_api_key_here"Example Response:
jsonc
{
"success": true, // Whether the request was successful
"data": {
"_id": "507f1f77bcf86cd799439013", // New voucher identifier (different from original)
"name": "20% Off Discount (Copy)", // Duplicated voucher name with "(Copy)" suffix
"description": "Get 20% off your next purchase", // Copied description from original
"value": 20, // Copied discount value
"valueType": "percentage", // Copied value type
"claimedQuantity": 0, // Claimed quantity reset to 0
"createdAt": "2024-02-01T12:00:00.000Z" // New creation timestamp (ISO 8601)
},
"message": "Voucher duplicated" // Success message
}Send Voucher to User
Send (issue) a voucher directly to a user. This mints an NFT and creates an active voucher claim for the specified user, bypassing the campaign claim flow.
POST /vouchers/:voucherId/sendPath Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
voucherId | string | Yes | Voucher ID to send |
Request Body:
| Field | Type | Required | Description |
|---|---|---|---|
userId | string | Yes | User ID to send the voucher to |
Example Request:
bash
curl -X POST "https://your-domain.com/api/external/v1/vouchers/507f1f77bcf86cd799439011/send" \
-H "X-API-Key: vio_live_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"userId": "507f1f77bcf86cd799439015"
}'Example Response:
jsonc
{
"success": true, // Whether the request was successful
"data": {
"_id": "507f1f77bcf86cd799439050", // Unique voucher claim identifier
"userId": "507f1f77bcf86cd799439015", // ID of the user who received the voucher
"voucherId": "507f1f77bcf86cd799439011", // ID of the voucher that was sent
"tenantId": "507f1f77bcf86cd799439001", // Tenant ID the voucher belongs to
"nftTokenId": "42", // On-chain NFT token ID
"status": "active", // Claim status: "active", "redeemed", "expired"
"redemptionCode": "VCH-M1ABC2-XY3Z", // Unique code for redeeming this voucher
"expiresAt": "2024-08-31T23:59:59.000Z", // Voucher claim expiry date (ISO 8601)
"settlementAmount": 0, // Settlement amount for cross-tenant billing
"settlementCurrency": "HKD", // Currency for settlement
"claimedAt": "2024-02-01T12:00:00.000Z", // When the voucher was claimed/sent (ISO 8601)
"createdAt": "2024-02-01T12:00:00.000Z" // Creation timestamp (ISO 8601)
},
"message": "Voucher sent to user" // Success message
}Error Responses:
| Status | Code | Description |
|---|---|---|
| 400 | VALIDATION_ERROR | Voucher is not active, expired, sold out, or user at claim limit |
| 404 | NOT_FOUND | Voucher or user not found |
List Voucher Claims
Get a list of all voucher claims for your tenant.
GET /vouchers/claims/listQuery Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
page | integer | No | Page number (default: 1) |
limit | integer | No | Items per page (default: 20) |
voucherId | string | No | Filter by voucher ID |
status | string | No | Filter by status: active, redeemed, expired |
fromDate | datetime | No | Filter claims from this date |
toDate | datetime | No | Filter claims until this date |
search | string | No | Search by user name or email |
Example Request:
bash
curl -X GET "https://your-domain.com/api/external/v1/vouchers/claims/list?status=active&limit=10" \
-H "X-API-Key: vio_live_your_api_key_here"Example Response:
jsonc
{
"success": true, // Whether the request was successful
"data": [ // Array of voucher claim objects
{
"_id": "507f1f77bcf86cd799439014", // Unique voucher claim identifier
"voucherId": "507f1f77bcf86cd799439011", // ID of the associated voucher
"userId": "507f1f77bcf86cd799439015", // ID of the user who claimed the voucher
"status": "active", // Claim status: "active", "redeemed", "expired"
"redemptionCode": "ABC123XYZ", // Unique code for redeeming this voucher
"claimedAt": "2024-01-15T14:30:00.000Z", // When the voucher was claimed (ISO 8601)
"expiresAt": "2024-12-31T23:59:59.000Z", // Voucher claim expiry date (ISO 8601)
"voucher": { // Populated voucher details
"name": "20% Off Discount" // Voucher display name
},
"user": { // Populated user details
"displayName": "John Doe", // User's display name
"email": "john@example.com" // User's email address
}
}
],
"pagination": { // Pagination information
"page": 1, // Current page number
"limit": 10, // Items per page
"total": 45, // Total number of claims
"totalPages": 5, // Total number of pages
"hasNextPage": true, // Whether more pages exist after current
"hasPrevPage": false // Whether pages exist before current
}
}Redeem Voucher by Code
Redeem a voucher using its redemption code. Use this when a customer presents their voucher code at your store or checkout.
POST /vouchers/redeem-by-codeRequest Body:
| Field | Type | Required | Description |
|---|---|---|---|
redemptionCode | string | Yes | The redemption code from the voucher claim |
location | string | No | Where the redemption occurred (e.g., store name) |
notes | string | No | Additional notes about the redemption |
Example Request:
bash
curl -X POST "https://your-domain.com/api/external/v1/vouchers/redeem-by-code" \
-H "X-API-Key: vio_live_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"redemptionCode": "ABC123XYZ",
"location": "Store #42",
"notes": "Customer purchased item XYZ"
}'Example Response:
jsonc
{
"success": true, // Whether the request was successful
"data": {
"_id": "507f1f77bcf86cd799439014", // Unique voucher claim identifier
"voucherId": "507f1f77bcf86cd799439011", // ID of the associated voucher
"userId": "507f1f77bcf86cd799439015", // ID of the user who owns the voucher
"status": "redeemed", // Updated claim status (now "redeemed")
"redemptionCode": "ABC123XYZ", // Redemption code that was used
"claimedAt": "2024-01-15T14:30:00.000Z", // When the voucher was originally claimed (ISO 8601)
"redeemedAt": "2024-02-01T10:15:00.000Z", // When the voucher was redeemed (ISO 8601)
"redeemedLocation": "Store #42" // Location where the voucher was redeemed
},
"message": "Voucher redeemed successfully" // Success message
}Get Voucher Info by Redemption Code
Retrieve voucher information using the redemption code before redeeming. Useful for verifying voucher details before processing.
GET /vouchers/redeem/:code/infoPath Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
code | string | Yes | Redemption code |
Example Request:
bash
curl -X GET "https://your-domain.com/api/external/v1/vouchers/redeem/ABC123XYZ/info" \
-H "X-API-Key: vio_live_your_api_key_here"Example Response:
jsonc
{
"success": true, // Whether the request was successful
"data": {
"claim": { // Voucher claim details
"_id": "507f1f77bcf86cd799439014", // Unique voucher claim identifier
"status": "active", // Claim status: "active", "redeemed", "expired"
"redemptionCode": "ABC123XYZ", // Unique redemption code
"claimedAt": "2024-01-15T14:30:00.000Z", // When the voucher was claimed (ISO 8601)
"expiresAt": "2024-12-31T23:59:59.000Z" // Voucher claim expiry date (ISO 8601)
},
"voucher": { // Associated voucher details
"_id": "507f1f77bcf86cd799439011", // Unique voucher identifier
"name": "20% Off Discount", // Voucher display name
"description": "Get 20% off your next purchase", // Voucher description
"value": 20, // Discount value
"valueType": "percentage", // Value type: "fixed" or "percentage"
"terms": "Valid on orders over $50" // Terms and conditions
},
"user": { // Voucher owner details
"displayName": "John Doe", // User's display name
"email": "john@example.com" // User's email address
}
}
}Consume Voucher by PIN
Consume a voucher using a staff PIN. This endpoint verifies the staff member's identity via their personal PIN before marking the voucher as consumed. Use this when staff members need to authenticate themselves at the point of consumption.
Redeem by Code vs Consume by PIN
- Redeem by Code (
POST /vouchers/redeem-by-code): Uses the API key for authorization. The API key owner is recorded as the redeemer. Best for server-to-server integrations. - Consume by PIN (
POST /vouchers/redeem/:code/pin): Requires a staff PIN for verification. The specific staff member is recorded. Best for in-store scenarios where individual staff accountability is needed.
POST /vouchers/redeem/:code/pinPath Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
code | string | Yes | The redemption code from the voucher claim |
Request Body:
| Field | Type | Required | Description |
|---|---|---|---|
pin | string | Yes | Staff PIN (6 characters: 2-letter prefix + 4-digit PIN, e.g., HA1234) |
Example Request:
bash
curl -X POST "https://your-domain.com/api/external/v1/vouchers/redeem/ABC123XYZ/pin" \
-H "X-API-Key: vio_live_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"pin": "HA1234"
}'Example Response:
jsonc
{
"success": true, // Whether the request was successful
"data": {
"success": true, // Whether the consumption was successful
"voucher": { // Consumed voucher details
"name": "20% Off Discount", // Voucher display name
"value": 20, // Discount value
"valueType": "percentage", // Value type: "fixed" or "percentage"
"valueCurrency": "THB" // Currency code for the voucher value
},
"redeemedAt": "2024-02-01T10:15:00.000Z", // When the voucher was consumed (ISO 8601)
"redeemedBy": "John Staff" // Name of the staff member who consumed it
},
"message": "Voucher consumed" // Success message
}Error Responses:
| Status | Code | Description |
|---|---|---|
| 400 | VALIDATION_ERROR | Invalid PIN format (must be 6 characters) |
| 400 | VALIDATION_ERROR | Invalid PIN (wrong prefix or PIN doesn't match any staff) |
| 400 | VALIDATION_ERROR | Voucher is already redeemed or expired |
| 404 | NOT_FOUND | Voucher not found with the given redemption code |
7. API Reference: Users
Required Scope: users
List Users
Retrieve a paginated list of users for your tenant.
GET /usersQuery Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
page | integer | No | Page number (default: 1) |
limit | integer | No | Items per page (default: 20) |
role | string | No | Filter by role: super_admin, tenant_admin, sub_company_admin, member |
search | string | No | Search by email, phone, or name |
isActive | boolean | No | Filter by active status |
subCompanyId | string | No | Filter by sub-company |
Example Request:
bash
curl -X GET "https://your-domain.com/api/external/v1/users?role=member&isActive=true&limit=10" \
-H "X-API-Key: vio_live_your_api_key_here"Example Response:
jsonc
{
"success": true, // Whether the request was successful
"data": [ // Array of user objects
{
"_id": "507f1f77bcf86cd799439015", // Unique user identifier
"email": "john@example.com", // User's email address
"phone": "+66812345678", // User's phone number (E.164 format)
"displayName": "John Doe", // User's display name
"role": "member", // User role: "member", "sub_company_admin", "tenant_admin", "super_admin"
"isActive": true, // Whether user account is active
"walletAddress": "0x1234567890abcdef...", // User's Web3 custodial wallet address
"registrationSource": "direct", // How user registered: "created", "direct", "store", "campaign"
"storeId": null, // Populated store object (if registered via store)
"campaignId": null, // Populated campaign object (if registered via campaign)
"createdAt": "2024-01-01T00:00:00.000Z", // Registration timestamp (ISO 8601)
"updatedAt": "2024-01-15T10:30:00.000Z" // Last update timestamp (ISO 8601)
}
],
"pagination": { // Pagination information
"page": 1, // Current page number
"limit": 10, // Items per page
"total": 150, // Total number of users
"totalPages": 15, // Total number of pages
"hasNextPage": true, // Whether more pages exist after current
"hasPrevPage": false // Whether pages exist before current
}
}Create User
Create a new user for your tenant.
POST /usersRequest Body:
| Field | Type | Required | Description |
|---|---|---|---|
email | string | No* | User email address |
phone | string | No* | User phone number |
password | string | Yes | Password (min 6 characters) |
displayName | string | No | User display name |
role | string | No | member or sub_company_admin (default: member) |
subCompanyId | string | No | Sub-company ID to assign user to |
metadata | object | No | Custom metadata key-value pairs |
*At least one of
phoneis required.
Example Request:
bash
curl -X POST "https://your-domain.com/api/external/v1/users" \
-H "X-API-Key: vio_live_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"email": "newuser@example.com",
"phone": "+66812345678",
"password": "securepassword123",
"displayName": "New User",
"role": "member",
"metadata": {
"referralSource": "website",
"tier": "gold"
}
}'Example Response:
jsonc
{
"success": true, // Whether the request was successful
"data": {
"_id": "507f1f77bcf86cd799439016", // Unique user identifier
"email": "newuser@example.com", // User's email address
"phone": "+66812345678", // User's phone number (E.164 format)
"displayName": "New User", // User's display name
"role": "member", // User role: "member" or "sub_company_admin"
"isActive": true, // Whether user account is active (default: true)
"walletAddress": "0xabcdef1234567890...", // Auto-provisioned Web3 custodial wallet address
"metadata": { // Custom metadata key-value pairs
"referralSource": "website", // Example custom field
"tier": "gold" // Example custom field
},
"createdAt": "2024-02-01T12:00:00.000Z" // Registration timestamp (ISO 8601)
},
"message": "User created" // Success message
}Get User Details
Retrieve details of a specific user.
GET /users/:userIdPath Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
userId | string | Yes | User ID |
Example Request:
bash
curl -X GET "https://your-domain.com/api/external/v1/users/507f1f77bcf86cd799439015" \
-H "X-API-Key: vio_live_your_api_key_here"Example Response:
jsonc
{
"success": true, // Whether the request was successful
"data": {
"_id": "507f1f77bcf86cd799439015", // Unique user identifier
"email": "john@example.com", // User's email address
"phone": "+66812345678", // User's phone number (E.164 format)
"displayName": "John Doe", // User's display name
"role": "member", // User role: "member", "sub_company_admin", "tenant_admin", "super_admin"
"isActive": true, // Whether user account is active
"walletAddress": "0x1234567890abcdef...", // User's Web3 custodial wallet address
"avatar": "https://example.com/avatar.jpg", // User's avatar image URL
"metadata": { // Custom metadata key-value pairs
"tier": "gold" // Example custom field
},
"createdAt": "2024-01-01T00:00:00.000Z", // Registration timestamp (ISO 8601)
"updatedAt": "2024-01-15T10:30:00.000Z" // Last update timestamp (ISO 8601)
}
}Update User
Update an existing user.
PATCH /users/:userIdPath Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
userId | string | Yes | User ID |
Request Body:
| Field | Type | Description |
|---|---|---|
displayName | string | User display name |
avatar | string | Avatar URL |
isActive | boolean | Active status |
subCompanyId | string | Sub-company ID |
metadata | object | Custom metadata |
Example Request:
bash
curl -X PATCH "https://your-domain.com/api/external/v1/users/507f1f77bcf86cd799439015" \
-H "X-API-Key: vio_live_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"displayName": "John Smith",
"metadata": {
"tier": "platinum"
}
}'Example Response:
jsonc
{
"success": true, // Whether the request was successful
"data": {
"_id": "507f1f77bcf86cd799439015", // Unique user identifier
"displayName": "John Smith", // Updated display name
"metadata": { // Updated custom metadata
"tier": "platinum" // Updated custom field
},
"updatedAt": "2024-02-01T12:00:00.000Z" // Last update timestamp (ISO 8601)
},
"message": "User updated" // Success message
}Deactivate User
Soft delete a user (sets isActive to false).
DELETE /users/:userIdPath Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
userId | string | Yes | User ID |
Example Request:
bash
curl -X DELETE "https://your-domain.com/api/external/v1/users/507f1f77bcf86cd799439015" \
-H "X-API-Key: vio_live_your_api_key_here"Example Response:
jsonc
{
"success": true, // Whether the request was successful
"data": null, // No data returned for deactivation
"message": "User deactivated" // Success message
}Get User Token Balances
Retrieve all token balances for a specific user.
GET /users/:userId/balancesPath Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
userId | string | Yes | User ID |
Example Request:
bash
curl -X GET "https://your-domain.com/api/external/v1/users/507f1f77bcf86cd799439015/balances" \
-H "X-API-Key: vio_live_your_api_key_here"Example Response:
jsonc
{
"success": true, // Whether the request was successful
"data": [ // Array of token balance objects
{
"tokenId": "507f1f77bcf86cd799439020", // Unique token identifier
"tokenName": "Loyalty Points", // Token display name
"symbol": "LP", // Token symbol
"balance": "1500", // User's available token balance
"lockedBalance": "0" // Tokens locked (e.g., pending transactions)
},
{
"tokenId": "507f1f77bcf86cd799439021", // Unique token identifier
"tokenName": "Reward Coins", // Token display name
"symbol": "RC", // Token symbol
"balance": "250", // User's available token balance
"lockedBalance": "50" // Tokens locked (e.g., pending transactions)
}
]
}Get User Vouchers
Retrieve all vouchers claimed by a specific user.
GET /users/:userId/vouchersPath Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
userId | string | Yes | User ID |
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
page | integer | No | Page number (default: 1) |
limit | integer | No | Items per page (default: 20) |
status | string | No | Filter by status: active, redeemed, expired |
Example Request:
bash
curl -X GET "https://your-domain.com/api/external/v1/users/507f1f77bcf86cd799439015/vouchers?status=active" \
-H "X-API-Key: vio_live_your_api_key_here"Example Response:
jsonc
{
"success": true, // Whether the request was successful
"data": [ // Array of user's voucher claim objects
{
"_id": "507f1f77bcf86cd799439014", // Unique voucher claim identifier
"voucherId": "507f1f77bcf86cd799439011", // ID of the associated voucher
"status": "active", // Claim status: "active", "redeemed", "expired"
"redemptionCode": "ABC123XYZ", // Unique code for redeeming this voucher
"claimedAt": "2024-01-15T14:30:00.000Z", // When the voucher was claimed (ISO 8601)
"expiresAt": "2024-12-31T23:59:59.000Z", // Voucher claim expiry date (ISO 8601)
"voucher": { // Populated voucher details
"name": "20% Off Discount", // Voucher display name
"value": 20, // Discount value
"valueType": "percentage" // Value type: "fixed" or "percentage"
}
}
],
"pagination": { // Pagination information
"page": 1, // Current page number
"limit": 20, // Items per page
"total": 5, // Total number of voucher claims
"totalPages": 1, // Total number of pages
"hasNextPage": false, // Whether more pages exist after current
"hasPrevPage": false // Whether pages exist before current
}
}Search User by Identifier
Find a user by email, phone, or wallet address.
GET /users/search/by-identifierQuery Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
email | string | No* | User email address |
phone | string | No* | User phone number |
walletAddress | string | No* | User wallet address |
*At least one identifier is required.
Example Request:
bash
curl -X GET "https://your-domain.com/api/external/v1/users/search/by-identifier?email=john@example.com" \
-H "X-API-Key: vio_live_your_api_key_here"Example Response:
jsonc
{
"success": true, // Whether the request was successful
"data": {
"_id": "507f1f77bcf86cd799439015", // Unique user identifier
"email": "john@example.com", // User's email address
"phone": "+66812345678", // User's phone number (E.164 format)
"displayName": "John Doe", // User's display name
"role": "member", // User role: "member", "sub_company_admin", "tenant_admin", "super_admin"
"isActive": true, // Whether user account is active
"walletAddress": "0x1234567890abcdef..." // User's Web3 custodial wallet address
}
}8. API Reference: Campaigns
Required Scope: campaigns
List Campaigns
Retrieve a paginated list of campaigns.
GET /campaignsQuery Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
page | integer | No | Page number (default: 1) |
limit | integer | No | Items per page (default: 20) |
search | string | No | Search by name |
isActive | boolean | No | Filter by active status |
Example Request:
bash
curl -X GET "https://your-domain.com/api/external/v1/campaigns?isActive=true&limit=10" \
-H "X-API-Key: vio_live_your_api_key_here"Example Response:
jsonc
{
"success": true, // Whether the request was successful
"data": [ // Array of campaign objects
{
"_id": "507f1f77bcf86cd799439030", // Unique campaign identifier
"name": "Summer Promotion", // Campaign display name
"description": "Summer 2024 voucher campaign", // Campaign description
"slug": "summer-promotion", // URL-friendly campaign identifier
"tokenId": "507f1f77bcf86cd799439020", // Associated token ID for the campaign
"isActive": true, // Whether campaign is currently active
"isPublic": true, // Whether campaign is publicly visible
"startDate": "2024-06-01T00:00:00.000Z", // Campaign start date (ISO 8601)
"endDate": "2024-08-31T23:59:59.000Z", // Campaign end date (ISO 8601)
"images": ["https://example.com/campaign.jpg"], // Array of campaign image URLs
"createdAt": "2024-05-15T10:00:00.000Z" // Creation timestamp (ISO 8601)
}
],
"pagination": { // Pagination information
"page": 1, // Current page number
"limit": 10, // Items per page
"total": 5, // Total number of campaigns
"totalPages": 1, // Total number of pages
"hasNextPage": false, // Whether more pages exist after current
"hasPrevPage": false // Whether pages exist before current
}
}Create Campaign
Create a new voucher campaign.
POST /campaignsRequest Body:
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Campaign name |
description | string | No | Campaign description |
slug | string | No | URL-friendly slug (auto-generated if not provided) |
tokenId | string | Yes | Token ID for the campaign |
startDate | datetime | No | Campaign start date |
endDate | datetime | No | Campaign end date |
isActive | boolean | No | Active status (default: true) |
isPublic | boolean | No | Public visibility (default: true) |
images | string[] | No | Campaign image URLs |
Example Request:
bash
curl -X POST "https://your-domain.com/api/external/v1/campaigns" \
-H "X-API-Key: vio_live_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"name": "Summer Promotion 2024",
"description": "Exclusive summer deals for loyal customers",
"tokenId": "507f1f77bcf86cd799439020",
"startDate": "2024-06-01T00:00:00.000Z",
"endDate": "2024-08-31T23:59:59.000Z",
"isPublic": true
}'Example Response:
jsonc
{
"success": true, // Whether the request was successful
"data": {
"_id": "507f1f77bcf86cd799439031", // Unique campaign identifier
"name": "Summer Promotion 2024", // Campaign display name
"description": "Exclusive summer deals for loyal customers", // Campaign description
"slug": "summer-promotion-2024", // Auto-generated URL-friendly slug
"tokenId": "507f1f77bcf86cd799439020", // Associated token ID for the campaign
"isActive": true, // Whether campaign is currently active
"isPublic": true, // Whether campaign is publicly visible
"startDate": "2024-06-01T00:00:00.000Z", // Campaign start date (ISO 8601)
"endDate": "2024-08-31T23:59:59.000Z", // Campaign end date (ISO 8601)
"createdAt": "2024-05-15T10:00:00.000Z" // Creation timestamp (ISO 8601)
},
"message": "Campaign created" // Success message
}Get Campaign Details
Retrieve details of a specific campaign.
GET /campaigns/:campaignIdPath Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
campaignId | string | Yes | Campaign ID |
Example Request:
bash
curl -X GET "https://your-domain.com/api/external/v1/campaigns/507f1f77bcf86cd799439030" \
-H "X-API-Key: vio_live_your_api_key_here"Example Response:
jsonc
{
"success": true, // Whether the request was successful
"data": {
"_id": "507f1f77bcf86cd799439030", // Unique campaign identifier
"name": "Summer Promotion", // Campaign display name
"description": "Summer 2024 voucher campaign", // Campaign description
"slug": "summer-promotion", // URL-friendly campaign identifier
"tokenId": "507f1f77bcf86cd799439020", // Associated token ID for the campaign
"isActive": true, // Whether campaign is currently active
"isPublic": true, // Whether campaign is publicly visible
"startDate": "2024-06-01T00:00:00.000Z", // Campaign start date (ISO 8601)
"endDate": "2024-08-31T23:59:59.000Z", // Campaign end date (ISO 8601)
"images": ["https://example.com/campaign.jpg"], // Array of campaign image URLs
"createdAt": "2024-05-15T10:00:00.000Z", // Creation timestamp (ISO 8601)
"updatedAt": "2024-05-20T08:00:00.000Z" // Last update timestamp (ISO 8601)
}
}Update Campaign
Update an existing campaign.
PATCH /campaigns/:campaignIdPath Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
campaignId | string | Yes | Campaign ID |
Request Body:
All fields are optional. Include only the fields you want to update.
| Field | Type | Description |
|---|---|---|
name | string | Campaign name |
description | string | Campaign description |
slug | string | URL-friendly slug |
startDate | datetime | Campaign start date |
endDate | datetime | Campaign end date |
isActive | boolean | Active status |
isPublic | boolean | Public visibility |
images | string[] | Campaign image URLs |
Example Request:
bash
curl -X PATCH "https://your-domain.com/api/external/v1/campaigns/507f1f77bcf86cd799439030" \
-H "X-API-Key: vio_live_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"name": "Summer Promotion - Extended",
"endDate": "2024-09-30T23:59:59.000Z"
}'Example Response:
jsonc
{
"success": true, // Whether the request was successful
"data": {
"_id": "507f1f77bcf86cd799439030", // Unique campaign identifier
"name": "Summer Promotion - Extended", // Updated campaign name
"endDate": "2024-09-30T23:59:59.000Z", // Updated end date (ISO 8601)
"updatedAt": "2024-07-01T12:00:00.000Z" // Last update timestamp (ISO 8601)
},
"message": "Campaign updated" // Success message
}Delete Campaign
Soft delete a campaign.
DELETE /campaigns/:campaignIdPath Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
campaignId | string | Yes | Campaign ID |
Example Request:
bash
curl -X DELETE "https://your-domain.com/api/external/v1/campaigns/507f1f77bcf86cd799439030" \
-H "X-API-Key: vio_live_your_api_key_here"Example Response:
jsonc
{
"success": true, // Whether the request was successful
"data": {
"_id": "507f1f77bcf86cd799439030", // Unique campaign identifier
"isDeleted": true // Deletion status (soft delete)
},
"message": "Campaign deleted" // Success message
}Get Campaign Vouchers
Retrieve vouchers associated with a campaign.
GET /campaigns/:campaignId/vouchersPath Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
campaignId | string | Yes | Campaign ID |
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
page | integer | No | Page number (default: 1) |
limit | integer | No | Items per page (default: 20) |
Example Request:
bash
curl -X GET "https://your-domain.com/api/external/v1/campaigns/507f1f77bcf86cd799439030/vouchers" \
-H "X-API-Key: vio_live_your_api_key_here"Example Response:
jsonc
{
"success": true, // Whether the request was successful
"data": [ // Array of campaign voucher objects
{
"voucherId": "507f1f77bcf86cd799439011", // Voucher ID
"tokenAmount": "100", // Token amount required to claim this voucher
"sortOrder": 1, // Display order in the campaign
"isActive": true, // Whether voucher is active in this campaign
"voucher": { // Populated voucher details
"_id": "507f1f77bcf86cd799439011", // Unique voucher identifier
"name": "20% Off Discount", // Voucher display name
"value": 20, // Discount value
"valueType": "percentage", // Value type: "fixed" or "percentage"
"totalQuantity": 100, // Total available quantity
"claimedQuantity": 45 // Number of vouchers already claimed
}
}
],
"pagination": { // Pagination information
"page": 1, // Current page number
"limit": 20, // Items per page
"total": 3, // Total vouchers in campaign
"totalPages": 1, // Total number of pages
"hasNextPage": false, // Whether more pages exist after current
"hasPrevPage": false // Whether pages exist before current
}
}Add Vouchers to Campaign
Add one or more vouchers to a campaign.
POST /campaigns/:campaignId/vouchersPath Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
campaignId | string | Yes | Campaign ID |
Request Body:
| Field | Type | Required | Description |
|---|---|---|---|
voucherIds | string[] | Yes | Array of voucher IDs to add |
tokenAmount | string | Yes | Token amount required to claim |
Example Request:
bash
curl -X POST "https://your-domain.com/api/external/v1/campaigns/507f1f77bcf86cd799439030/vouchers" \
-H "X-API-Key: vio_live_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"voucherIds": ["507f1f77bcf86cd799439011", "507f1f77bcf86cd799439012"],
"tokenAmount": "100"
}'Example Response:
jsonc
{
"success": true, // Whether the request was successful
"data": {
"campaignId": "507f1f77bcf86cd799439030", // Campaign ID
"addedVouchers": 2 // Number of vouchers added
},
"message": "Vouchers added to campaign" // Success message
}Update Campaign Voucher
Update a voucher's settings within a campaign.
PATCH /campaigns/:campaignId/vouchers/:voucherIdPath Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
campaignId | string | Yes | Campaign ID |
voucherId | string | Yes | Voucher ID |
Request Body:
| Field | Type | Description |
|---|---|---|
tokenAmount | string | Token amount required to claim |
sortOrder | integer | Display order |
isActive | boolean | Active status in campaign |
Example Request:
bash
curl -X PATCH "https://your-domain.com/api/external/v1/campaigns/507f1f77bcf86cd799439030/vouchers/507f1f77bcf86cd799439011" \
-H "X-API-Key: vio_live_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"tokenAmount": "150",
"sortOrder": 2
}'Example Response:
jsonc
{
"success": true, // Whether the request was successful
"data": {
"voucherId": "507f1f77bcf86cd799439011", // Voucher ID
"tokenAmount": "150", // Updated token amount
"sortOrder": 2, // Updated display order
"isActive": true // Active status in campaign
},
"message": "Campaign voucher updated" // Success message
}Remove Voucher from Campaign
Remove a voucher from a campaign.
DELETE /campaigns/:campaignId/vouchers/:voucherIdPath Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
campaignId | string | Yes | Campaign ID |
voucherId | string | Yes | Voucher ID to remove |
Example Request:
bash
curl -X DELETE "https://your-domain.com/api/external/v1/campaigns/507f1f77bcf86cd799439030/vouchers/507f1f77bcf86cd799439011" \
-H "X-API-Key: vio_live_your_api_key_here"Example Response:
jsonc
{
"success": true, // Whether the request was successful
"data": null, // No data returned for removal
"message": "Voucher removed from campaign" // Success message
}Get Available Vouchers for Campaign
Retrieve vouchers that can be added to a campaign (not already in the campaign).
GET /campaigns/:campaignId/available-vouchersPath Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
campaignId | string | Yes | Campaign ID |
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
page | integer | No | Page number (default: 1) |
limit | integer | No | Items per page (default: 20) |
search | string | No | Search by voucher name |
Example Request:
bash
curl -X GET "https://your-domain.com/api/external/v1/campaigns/507f1f77bcf86cd799439030/available-vouchers" \
-H "X-API-Key: vio_live_your_api_key_here"Example Response:
jsonc
{
"success": true, // Whether the request was successful
"data": [ // Array of available voucher objects
{
"_id": "507f1f77bcf86cd799439018", // Unique voucher identifier
"name": "Free Shipping", // Voucher display name
"value": 0, // Discount value
"valueType": "fixed", // Value type: "fixed" or "percentage"
"totalQuantity": 500, // Total available quantity
"claimedQuantity": 120, // Number of vouchers already claimed
"isActive": true // Whether voucher is currently active
}
],
"pagination": { // Pagination information
"page": 1, // Current page number
"limit": 20, // Items per page
"total": 8, // Total available vouchers
"totalPages": 1, // Total number of pages
"hasNextPage": false, // Whether more pages exist after current
"hasPrevPage": false // Whether pages exist before current
}
}9. API Reference: Tokens
Required Scope: tokens
Understanding Token Lots and Expiry
VIO uses a token lot system to manage token balances with expiry. Here's how it works:
Token Lots:
- Each time tokens are minted, a new token lot is created with its own expiry settings
- A user's total balance is the sum of all their active (non-expired) token lots
- When tokens are transferred or spent, the system uses FIFO (First In, First Out) by default, consuming tokens from the oldest lots first
Token Expiry Types:
| Type | Description |
|---|---|
permanent | Tokens never expire (default) |
fixed_date | Tokens expire at a specific date/time |
duration_days | Tokens expire after N days from the mint date |
Important Rules:
- Token expiry can only be set when minting new tokens
- When transferring existing tokens, they retain their original expiry dates
- Expired tokens are automatically excluded from the user's effective balance
- The
expiryBreakdownfield in balance responses shows all active lots with their expiry details
List Tokens
Retrieve a list of tokens for your tenant.
GET /tokensQuery Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
page | integer | No | Page number (default: 1) |
limit | integer | No | Items per page (default: 20) |
isActive | boolean | No | Filter by active status |
subCompanyId | string | No | Filter by sub-company |
Example Request:
bash
curl -X GET "https://your-domain.com/api/external/v1/tokens?isActive=true" \
-H "X-API-Key: vio_live_your_api_key_here"Example Response:
jsonc
{
"success": true, // Whether the request was successful
"data": [ // Array of token objects
{
"_id": "507f1f77bcf86cd799439020", // Unique token identifier
"name": "Loyalty Points", // Token display name
"symbol": "LP", // Token symbol (short abbreviation)
"description": "Earn points on every purchase", // Token description
"totalSupply": "1000000", // Total token supply (string for precision)
"isActive": true, // Whether token is currently active
"createdAt": "2024-01-01T00:00:00.000Z" // Creation timestamp (ISO 8601)
}
],
"pagination": { // Pagination information
"page": 1, // Current page number
"limit": 20, // Items per page
"total": 2, // Total number of tokens
"totalPages": 1, // Total number of pages
"hasNextPage": false, // Whether more pages exist after current
"hasPrevPage": false // Whether pages exist before current
}
}Get Token Details
Retrieve details of a specific token.
GET /tokens/:tokenIdPath Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
tokenId | string | Yes | Token ID |
Example Request:
bash
curl -X GET "https://your-domain.com/api/external/v1/tokens/507f1f77bcf86cd799439020" \
-H "X-API-Key: vio_live_your_api_key_here"Example Response:
jsonc
{
"success": true, // Whether the request was successful
"data": {
"_id": "507f1f77bcf86cd799439020", // Unique token identifier
"name": "Loyalty Points", // Token display name
"symbol": "LP", // Token symbol (short abbreviation)
"description": "Earn points on every purchase", // Token description
"totalSupply": "1000000", // Total token supply (string for precision)
"decimals": 0, // Number of decimal places
"isActive": true, // Whether token is currently active
"createdAt": "2024-01-01T00:00:00.000Z", // Creation timestamp (ISO 8601)
"updatedAt": "2024-01-10T08:00:00.000Z" // Last update timestamp (ISO 8601)
}
}Get Token Statistics
GET /tokens/:tokenId/statsExample Response:
jsonc
{
"success": true, // Whether the request was successful
"data": {
"totalSupply": "1000000", // Total token supply ever minted
"circulatingSupply": "750000", // Tokens currently in circulation
"holdersCount": 1250, // Number of unique token holders
"totalTransactions": 15000, // Total number of token transactions
"averageBalance": "600" // Average token balance per holder
}
}Get Token Holders
Retrieve a paginated list of token holders.
GET /tokens/:tokenId/holdersPath Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
tokenId | string | Yes | Token ID |
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
page | integer | No | Page number (default: 1) |
limit | integer | No | Items per page (default: 20) |
sort | string | No | Sort by: balance, name, recent (default: balance) |
search | string | No | Search by user name or email |
Example Request:
bash
curl -X GET "https://your-domain.com/api/external/v1/tokens/507f1f77bcf86cd799439020/holders?sort=balance&limit=10" \
-H "X-API-Key: vio_live_your_api_key_here"Example Response:
jsonc
{
"success": true, // Whether the request was successful
"data": [ // Array of token holder objects
{
"userId": "507f1f77bcf86cd799439015", // Unique user identifier
"displayName": "John Doe", // User's display name
"email": "john@example.com", // User's email address
"balance": "1500", // User's token balance (string for precision)
"lockedBalance": "0" // Tokens locked (e.g., pending transactions)
}
],
"pagination": { // Pagination information
"page": 1, // Current page number
"limit": 10, // Items per page
"total": 1250, // Total number of holders
"totalPages": 125, // Total number of pages
"hasNextPage": true, // Whether more pages exist after current
"hasPrevPage": false // Whether pages exist before current
}
}Mint Tokens
Create new tokens and add them to a user's balance. Each mint operation creates a new token lot with its own expiry settings.
POST /tokens/:tokenId/mintRequest Body:
| Field | Type | Required | Description |
|---|---|---|---|
toUserId | string | Yes | User ID to receive tokens |
amount | string | Yes | Amount to mint |
memo | string | No | Transaction memo |
expiryType | string | No | Token expiry type: permanent (default), fixed_date, or duration_days |
expiresAt | string | Conditional | ISO 8601 datetime. Required when expiryType is fixed_date |
expiryDays | number | Conditional | Number of days until expiry. Required when expiryType is duration_days |
Important: Token expiry can only be set when minting new tokens. When transferring existing tokens, they retain their original expiry dates from when they were minted. The system uses FIFO (First In, First Out) by default when transferring tokens, meaning tokens closest to expiry are transferred first.
Example Request:
bash
curl -X POST "https://your-domain.com/api/external/v1/tokens/507f1f77bcf86cd799439020/mint" \
-H "X-API-Key: vio_live_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"toUserId": "507f1f77bcf86cd799439015",
"amount": "1000",
"memo": "Welcome bonus",
"expiryType": "duration_days",
"expiryDays": 30
}'Example Response:
jsonc
{
"success": true, // Whether the request was successful
"data": {
"_id": "507f1f77bcf86cd799439040", // Unique transaction identifier
"tokenId": "507f1f77bcf86cd799439020", // ID of the token that was minted
"type": "mint", // Transaction type: "mint", "transfer", "burn", "reward", "redeem"
"amount": "1000", // Amount of tokens minted (string for precision)
"toUserId": "507f1f77bcf86cd799439015", // ID of the user who received the tokens
"memo": "Welcome bonus", // Transaction memo/note
"createdAt": "2024-02-01T12:00:00.000Z" // Transaction timestamp (ISO 8601)
},
"message": "Tokens minted successfully" // Success message
}Burn Tokens
Remove tokens from a user's balance.
POST /tokens/:tokenId/burnRequest Body:
| Field | Type | Required | Description |
|---|---|---|---|
fromUserId | string | Yes | User ID to burn from |
amount | string | Yes | Amount to burn |
memo | string | No | Transaction memo |
Example Request:
bash
curl -X POST "https://your-domain.com/api/external/v1/tokens/507f1f77bcf86cd799439020/burn" \
-H "X-API-Key: vio_live_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"fromUserId": "507f1f77bcf86cd799439015",
"amount": "500",
"memo": "Expired points cleanup"
}'Example Response:
jsonc
{
"success": true, // Whether the request was successful
"data": {
"_id": "507f1f77bcf86cd799439041", // Unique transaction identifier
"tokenId": "507f1f77bcf86cd799439020", // ID of the token that was burned
"type": "burn", // Transaction type
"amount": "500", // Amount of tokens burned (string for precision)
"fromUserId": "507f1f77bcf86cd799439015", // ID of the user tokens were burned from
"memo": "Expired points cleanup", // Transaction memo/note
"createdAt": "2024-02-01T12:00:00.000Z" // Transaction timestamp (ISO 8601)
},
"message": "Tokens burned successfully" // Success message
}Adjust User Balance
Send or recall tokens between the company admin balance and a user.
POST /tokens/:tokenId/adjustRequest Body:
| Field | Type | Required | Description |
|---|---|---|---|
userId | string | Yes | User ID |
amount | string | Yes | Amount to adjust |
operation | string | Yes | send or recall |
reason | string | Yes | Reason for adjustment |
Example Request:
bash
curl -X POST "https://your-domain.com/api/external/v1/tokens/507f1f77bcf86cd799439020/adjust" \
-H "X-API-Key: vio_live_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"userId": "507f1f77bcf86cd799439015",
"amount": "200",
"operation": "send",
"reason": "Customer service compensation"
}'Example Response:
jsonc
{
"success": true, // Whether the request was successful
"data": {
"_id": "507f1f77bcf86cd799439042", // Unique transaction identifier
"tokenId": "507f1f77bcf86cd799439020", // ID of the token
"type": "transfer", // Transaction type
"amount": "200", // Amount of tokens adjusted (string for precision)
"toUserId": "507f1f77bcf86cd799439015", // ID of the user
"memo": "Customer service compensation", // Reason for adjustment
"createdAt": "2024-02-01T12:00:00.000Z" // Transaction timestamp (ISO 8601)
},
"message": "Balance adjusted successfully" // Success message
}Send Tokens
Send tokens from the company admin balance pool to a user.
POST /tokens/:tokenId/sendRequest Body:
| Field | Type | Required | Description |
|---|---|---|---|
userId | string | Yes | User ID to send tokens to |
amount | string | Yes | Amount of tokens to send |
reason | string | No | Reason for sending tokens |
Example Request:
bash
curl -X POST "https://your-domain.com/api/external/v1/tokens/507f1f77bcf86cd799439020/send" \
-H "X-API-Key: vio_live_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"userId": "507f1f77bcf86cd799439015",
"amount": "500",
"reason": "Loyalty reward"
}'Example Response:
jsonc
{
"success": true, // Whether the request was successful
"data": {
"_id": "507f1f77bcf86cd799439043", // Unique transaction identifier
"tokenId": "507f1f77bcf86cd799439020", // ID of the token
"type": "transfer", // Transaction type
"amount": "500", // Amount of tokens sent (string for precision)
"toUserId": "507f1f77bcf86cd799439015", // ID of the user who received the tokens
"memo": "Loyalty reward", // Reason for sending
"createdAt": "2024-02-01T12:00:00.000Z" // Transaction timestamp (ISO 8601)
},
"message": "Tokens sent successfully" // Success message
}Error Responses:
| Status | Code | Description |
|---|---|---|
| 400 | VALIDATION_ERROR | Insufficient company balance for sending tokens |
| 404 | NOT_FOUND | Token or user not found |
Recall Tokens
Recall tokens from a user back to the company admin balance pool.
POST /tokens/:tokenId/recallRequest Body:
| Field | Type | Required | Description |
|---|---|---|---|
userId | string | Yes | User ID to recall tokens from |
amount | string | Yes | Amount of tokens to recall |
reason | string | No | Reason for recalling tokens |
Example Request:
bash
curl -X POST "https://your-domain.com/api/external/v1/tokens/507f1f77bcf86cd799439020/recall" \
-H "X-API-Key: vio_live_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"userId": "507f1f77bcf86cd799439015",
"amount": "100",
"reason": "Order refund adjustment"
}'Example Response:
jsonc
{
"success": true, // Whether the request was successful
"data": {
"_id": "507f1f77bcf86cd799439044", // Unique transaction identifier
"tokenId": "507f1f77bcf86cd799439020", // ID of the token
"type": "transfer", // Transaction type
"amount": "100", // Amount of tokens recalled (string for precision)
"fromUserId": "507f1f77bcf86cd799439015", // ID of the user tokens were recalled from
"memo": "Order refund adjustment", // Reason for recalling
"createdAt": "2024-02-01T12:00:00.000Z" // Transaction timestamp (ISO 8601)
},
"message": "Tokens recalled successfully" // Success message
}Error Responses:
| Status | Code | Description |
|---|---|---|
| 400 | VALIDATION_ERROR | Insufficient user balance for recalling tokens |
| 404 | NOT_FOUND | Token or user not found |
List Token Transactions
Retrieve a list of token transactions.
GET /tokens/transactions/listQuery Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
page | integer | No | Page number (default: 1) |
limit | integer | No | Items per page (default: 20) |
tokenId | string | No | Filter by token ID |
type | string | No | Filter by type: mint, transfer, burn, reward, redeem, expire |
fromDate | datetime | No | Filter from this date |
toDate | datetime | No | Filter until this date |
search | string | No | Search by user name or memo |
Example Request:
bash
curl -X GET "https://your-domain.com/api/external/v1/tokens/transactions/list?tokenId=507f1f77bcf86cd799439020&type=mint&limit=10" \
-H "X-API-Key: vio_live_your_api_key_here"Example Response:
jsonc
{
"success": true, // Whether the request was successful
"data": [ // Array of transaction objects
{
"_id": "507f1f77bcf86cd799439040", // Unique transaction identifier
"tokenId": "507f1f77bcf86cd799439020", // ID of the token involved
"type": "mint", // Transaction type: "mint", "transfer", "burn", "reward", "redeem"
"amount": "1000", // Transaction amount (string for precision)
"fromUserId": null, // Sender user ID (null for mints)
"toUserId": "507f1f77bcf86cd799439015", // Recipient user ID
"memo": "Welcome bonus", // Transaction memo/note
"createdAt": "2024-02-01T12:00:00.000Z" // Transaction timestamp (ISO 8601)
}
],
"pagination": { // Pagination information
"page": 1, // Current page number
"limit": 10, // Items per page
"total": 15000, // Total number of transactions
"totalPages": 1500, // Total number of pages
"hasNextPage": true, // Whether more pages exist after current
"hasPrevPage": false // Whether pages exist before current
}
}Get User Token Balances
Retrieve all token balances for a specific user.
GET /tokens/balance/user/:userIdPath Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
userId | string | Yes | User ID |
Example Request:
bash
curl -X GET "https://your-domain.com/api/external/v1/tokens/balance/user/507f1f77bcf86cd799439015" \
-H "X-API-Key: vio_live_your_api_key_here"Example Response:
jsonc
{
"success": true, // Whether the request was successful
"data": [ // Array of token balance objects
{
"tokenId": "507f1f77bcf86cd799439020", // Unique token identifier
"tokenName": "Loyalty Points", // Token display name
"symbol": "LP", // Token symbol
"balance": "1500", // User's available token balance
"lockedBalance": "0", // Tokens locked (e.g., pending transactions)
"effectiveBalance": "1200", // Balance excluding expired tokens (non-expired lots only)
"nearestExpiry": "2026-04-15T00:00:00.000Z", // Nearest expiry date among active lots (null if all permanent)
"expiryBreakdown": [ // Breakdown of token lots by expiry
{
"lotId": "507f1f77bcf86cd799439030",
"remainingAmount": "700",
"expiryType": "fixed_date",
"expiresAt": "2026-04-15T00:00:00.000Z",
"createdAt": "2026-03-01T10:00:00.000Z",
"sourceType": "mint"
},
{
"lotId": "507f1f77bcf86cd799439031",
"remainingAmount": "500",
"expiryType": "permanent",
"expiresAt": null,
"createdAt": "2026-02-15T10:00:00.000Z",
"sourceType": "mint"
}
]
}
]
}10. API Reference: Analytics
Required Scope: analytics
Get Analytics Overview
Get overall tenant analytics including users, vouchers, and transactions.
GET /analytics/overviewExample Response:
jsonc
{
"success": true, // Whether the request was successful
"data": {
"users": { // User analytics summary
"total": 5000, // Total registered users
"active": 4500, // Currently active users
"newThisMonth": 250 // Users registered this month
},
"vouchers": { // Voucher analytics summary
"totalClaims": 12000, // Total voucher claims across all vouchers
"redeemed": 8500, // Number of vouchers redeemed
"active": 3500, // Number of active (unredeemed) claims
"redemptionRate": "70.83%" // Percentage of claims that were redeemed
},
"transactions": { // Token transaction analytics summary
"total": 25000, // Total token transactions
"thisMonth": 3500 // Token transactions this month
},
"generatedAt": "2024-02-01T12:00:00.000Z" // When the analytics data was generated (ISO 8601)
}
}Get Voucher Analytics
Get detailed analytics about voucher performance.
GET /analytics/vouchersQuery Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
fromDate | datetime | No | Start date for analytics |
toDate | datetime | No | End date for analytics |
Example Request:
bash
curl -X GET "https://your-domain.com/api/external/v1/analytics/vouchers?fromDate=2024-01-01T00:00:00.000Z&toDate=2024-12-31T23:59:59.000Z" \
-H "X-API-Key: vio_live_your_api_key_here"Example Response:
jsonc
{
"success": true, // Whether the request was successful
"data": {
"totalVouchers": 50, // Total number of vouchers created
"activeVouchers": 35, // Number of currently active vouchers
"totalClaims": 12000, // Total voucher claims in the period
"totalRedemptions": 8500, // Total vouchers redeemed in the period
"redemptionRate": "70.83%", // Percentage of claims that were redeemed
"topVouchers": [ // Most claimed vouchers
{
"voucherId": "507f1f77bcf86cd799439011", // Voucher identifier
"name": "20% Off Discount", // Voucher name
"claims": 450, // Number of claims
"redemptions": 320 // Number of redemptions
}
],
"periodStart": "2024-01-01T00:00:00.000Z", // Analytics period start (ISO 8601)
"periodEnd": "2024-12-31T23:59:59.000Z" // Analytics period end (ISO 8601)
}
}Get User Analytics
Get detailed analytics about user activity.
GET /analytics/usersQuery Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
fromDate | datetime | No | Start date for analytics |
toDate | datetime | No | End date for analytics |
Example Request:
bash
curl -X GET "https://your-domain.com/api/external/v1/analytics/users?fromDate=2024-01-01T00:00:00.000Z&toDate=2024-12-31T23:59:59.000Z" \
-H "X-API-Key: vio_live_your_api_key_here"Example Response:
jsonc
{
"success": true, // Whether the request was successful
"data": {
"totalUsers": 5000, // Total registered users
"activeUsers": 4500, // Currently active users
"newUsers": 1200, // New users registered in the period
"usersByRole": { // User count breakdown by role
"member": 4800, // Number of members
"sub_company_admin": 150, // Number of sub-company admins
"tenant_admin": 50 // Number of tenant admins
},
"periodStart": "2024-01-01T00:00:00.000Z", // Analytics period start (ISO 8601)
"periodEnd": "2024-12-31T23:59:59.000Z" // Analytics period end (ISO 8601)
}
}Get Token Analytics
Get detailed analytics about token activity.
GET /analytics/tokensQuery Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
fromDate | datetime | No | Start date for analytics |
toDate | datetime | No | End date for analytics |
Example Request:
bash
curl -X GET "https://your-domain.com/api/external/v1/analytics/tokens?fromDate=2024-01-01T00:00:00.000Z&toDate=2024-12-31T23:59:59.000Z" \
-H "X-API-Key: vio_live_your_api_key_here"Example Response:
jsonc
{
"success": true, // Whether the request was successful
"data": {
"totalTokens": 3, // Total number of token types
"totalTransactions": 25000, // Total token transactions in the period
"totalMinted": "5000000", // Total tokens minted in the period
"totalBurned": "500000", // Total tokens burned in the period
"tokenBreakdown": [ // Per-token analytics
{
"tokenId": "507f1f77bcf86cd799439020", // Token identifier
"name": "Loyalty Points", // Token name
"symbol": "LP", // Token symbol
"totalSupply": "1000000", // Current total supply
"circulatingSupply": "750000", // Tokens in circulation
"holdersCount": 1250, // Number of holders
"transactions": 15000 // Number of transactions in the period
}
],
"periodStart": "2024-01-01T00:00:00.000Z", // Analytics period start (ISO 8601)
"periodEnd": "2024-12-31T23:59:59.000Z" // Analytics period end (ISO 8601)
}
}11. Data Models
Voucher
| Field | Type | Description |
|---|---|---|
_id | string | Unique identifier |
name | string | Voucher name |
description | string | Voucher description |
value | number | Voucher value |
valueType | string | fixed, percentage |
valueCurrency | string | Currency code |
terms | string | Terms and conditions |
images | string[] | Image URLs |
isActive | boolean | Active status |
totalQuantity | integer | Total available (-1 for unlimited) |
claimedQuantity | integer | Number claimed |
maxClaimsPerUser | integer | Max claims per user |
startDate | datetime | Validity start date |
endDate | datetime | Expiry date |
visibility | string | private, public, shared (also controls transfer scope) |
categories | string[] | Category tags |
minSpend | number | Minimum spend required |
maxDiscount | number | Maximum discount amount |
consumptionType | string | How voucher is consumed: vio_code, url, qr_code, coupon_code, manual |
consumptionUrl | string | External URL for url consumption type |
consumptionQrCode | string | QR code image path for qr_code consumption type (uploaded image) |
consumptionMessage | string | Custom message/instructions for manual consumption type |
createdAt | datetime | Creation timestamp |
updatedAt | datetime | Last update timestamp |
Consumption Types Explained
- vio_code: Default - member shows VIO redemption QR code to be scanned
- url: Member clicks to open an external redemption URL
- qr_code: Member displays a merchant-provided QR code image
- coupon_code: Member uses the redemption code as a coupon at checkout
- manual: Custom redemption process with instructions in
consumptionMessage
VoucherClaim (UserVoucher)
| Field | Type | Description |
|---|---|---|
_id | string | Unique identifier |
voucherId | string | Associated voucher ID |
userId | string | Owner user ID |
status | string | active, redeemed, expired, transferred |
redemptionCode | string | Unique redemption code |
claimedAt | datetime | Claim timestamp |
redeemedAt | datetime | Redemption timestamp |
expiresAt | datetime | Expiry timestamp |
redeemedLocation | string | Where redeemed |
notes | string | Redemption notes |
User
| Field | Type | Description |
|---|---|---|
_id | string | Unique identifier |
email | string | Email address |
phone | string | Phone number |
displayName | string | Display name |
avatar | string | Avatar URL |
role | string | member, sub_company_admin, tenant_admin, super_admin |
isActive | boolean | Active status |
walletAddress | string | Web3 custodial wallet address (auto-provisioned on user creation) |
registrationSource | string | How the user was registered: created, direct, store, campaign |
storeId | object | Populated store reference (if registered via store). Contains _id, name |
campaignId | object | Populated campaign reference (if registered via campaign). Contains _id, name, slug |
metadata | object | Custom metadata |
createdAt | datetime | Registration timestamp |
updatedAt | datetime | Last update timestamp |
Campaign
| Field | Type | Description |
|---|---|---|
_id | string | Unique identifier |
name | string | Campaign name |
description | string | Campaign description |
slug | string | URL-friendly identifier |
tokenId | string | Associated token ID |
isActive | boolean | Active status |
isPublic | boolean | Public visibility |
startDate | datetime | Campaign start date |
endDate | datetime | Campaign end date |
images | string[] | Campaign images |
createdAt | datetime | Creation timestamp |
Token
| Field | Type | Description |
|---|---|---|
_id | string | Unique identifier |
name | string | Token name |
symbol | string | Token symbol |
description | string | Token description |
totalSupply | string | Total supply |
decimals | integer | Decimal places |
isActive | boolean | Active status |
createdAt | datetime | Creation timestamp |
updatedAt | datetime | Last update timestamp |
TokenBalance
| Field | Type | Description |
|---|---|---|
tokenId | string | Token ID |
tokenName | string | Token name |
symbol | string | Token symbol |
balance | string | Available balance |
lockedBalance | string | Locked balance |
Transaction
| Field | Type | Description |
|---|---|---|
_id | string | Unique identifier |
tokenId | string | Token ID |
type | string | mint, transfer, burn, reward, redeem, expire |
amount | string | Transaction amount |
fromUserId | string | Sender user ID |
toUserId | string | Recipient user ID |
memo | string | Transaction memo |
createdAt | datetime | Transaction timestamp |
Pagination
| Field | Type | Description |
|---|---|---|
page | integer | Current page number |
limit | integer | Items per page |
total | integer | Total items |
totalPages | integer | Total pages |
hasNextPage | boolean | More pages available |
hasPrevPage | boolean | Previous pages available |
12. Code Examples
JavaScript/Node.js
javascript
// VIO API Client Example
const VIO_API_BASE = 'https://your-domain.com/api/external/v1';
const API_KEY = 'vio_live_your_api_key_here';
// Helper function for API calls
async function vioApi(method, endpoint, body = null) {
const options = {
method,
headers: {
'X-API-Key': API_KEY,
'Content-Type': 'application/json',
},
};
if (body) {
options.body = JSON.stringify(body);
}
const response = await fetch(`${VIO_API_BASE}${endpoint}`, options);
const data = await response.json();
if (!data.success) {
throw new Error(data.error?.message || 'API request failed');
}
return data;
}javascript
// Create a voucher
async function createVoucher() {
const result = await vioApi('POST', '/vouchers', {
name: 'Welcome Discount',
description: '10% off your first purchase',
value: 10,
valueType: 'percentage',
totalQuantity: 1000,
maxClaimsPerUser: 1,
visibility: 'public',
endDate: '2024-12-31T23:59:59.000Z',
});
console.log('Created voucher:', result.data._id);
return result.data;
}javascript
// Mint tokens to a user
async function mintTokensToUser(tokenId, userId, amount) {
const result = await vioApi('POST', `/tokens/${tokenId}/mint`, {
toUserId: userId,
amount: amount.toString(),
memo: 'Reward for purchase',
});
console.log('Minted tokens:', result.data);
return result.data;
}javascript
// Redeem a voucher by code
async function redeemVoucher(redemptionCode, location) {
const result = await vioApi('POST', '/vouchers/redeem-by-code', {
redemptionCode,
location,
notes: 'Redeemed at checkout',
});
console.log('Voucher redeemed:', result.data);
return result.data;
}javascript
// Consume a voucher with staff PIN
async function consumeVoucherByPin(redemptionCode, staffPin) {
const result = await vioApi('POST', `/vouchers/redeem/${redemptionCode}/pin`, {
pin: staffPin, // e.g., 'HA1234'
});
console.log('Voucher consumed by:', result.data.redeemedBy);
return result.data;
}Python
python
import requests
from typing import Optional, Dict, Any
VIO_API_BASE = 'https://your-domain.com/api/external/v1'
API_KEY = 'vio_live_your_api_key_here'
def vio_api(method: str, endpoint: str, body: Optional[Dict] = None) -> Dict[str, Any]:
"""Make a request to the VIO API."""
headers = {
'X-API-Key': API_KEY,
'Content-Type': 'application/json',
}
url = f'{VIO_API_BASE}{endpoint}'
if method == 'GET':
response = requests.get(url, headers=headers)
elif method == 'POST':
response = requests.post(url, headers=headers, json=body)
elif method == 'PATCH':
response = requests.patch(url, headers=headers, json=body)
elif method == 'DELETE':
response = requests.delete(url, headers=headers)
else:
raise ValueError(f'Unsupported method: {method}')
data = response.json()
if not data.get('success'):
error = data.get('error', {})
raise Exception(error.get('message', 'API request failed'))
return data
# Example: List active vouchers
def list_vouchers(page: int = 1, limit: int = 20):
result = vio_api('GET', f'/vouchers?page={page}&limit={limit}&isActive=true')
return result['data'], result['pagination']
# Example: Create a user
def create_user(email: str, password: str, display_name: str):
result = vio_api('POST', '/users', {
'email': email,
'password': password,
'displayName': display_name,
'role': 'member',
})
return result['data']
# Example: Get analytics overview
def get_analytics_overview():
result = vio_api('GET', '/analytics/overview')
return result['data']
# Usage
if __name__ == '__main__':
vouchers, pagination = list_vouchers()
print(f'Found {pagination["total"]} vouchers')
analytics = get_analytics_overview()
print(f'Total users: {analytics["users"]["total"]}')Complete Workflow (cURL)
bash
#!/bin/bash
# Complete workflow example using cURL
API_BASE="https://your-domain.com/api/external/v1"
API_KEY="vio_live_your_api_key_here"
# 1. Create a new voucher
echo "Creating voucher..."
VOUCHER_RESPONSE=$(curl -s -X POST "$API_BASE/vouchers" \
-H "X-API-Key: $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Flash Sale 25% Off",
"description": "Limited time offer - 25% discount",
"value": 25,
"valueType": "percentage",
"totalQuantity": 100,
"maxClaimsPerUser": 1,
"visibility": "public",
"startDate": "2024-02-01T00:00:00.000Z",
"endDate": "2024-02-28T23:59:59.000Z"
}')
VOUCHER_ID=$(echo $VOUCHER_RESPONSE | jq -r '.data._id')
echo "Created voucher: $VOUCHER_ID"
# 2. Check voucher details
echo "Fetching voucher details..."
curl -s -X GET "$API_BASE/vouchers/$VOUCHER_ID" \
-H "X-API-Key: $API_KEY" | jq
# 3. List claims for this voucher
echo "Listing claims..."
curl -s -X GET "$API_BASE/vouchers/claims/list?voucherId=$VOUCHER_ID" \
-H "X-API-Key: $API_KEY" | jq
# 4. Redeem a voucher
REDEMPTION_CODE="ABC123XYZ"
echo "Redeeming voucher..."
curl -s -X POST "$API_BASE/vouchers/redeem-by-code" \
-H "X-API-Key: $API_KEY" \
-H "Content-Type: application/json" \
-d "{
\"redemptionCode\": \"$REDEMPTION_CODE\",
\"location\": \"Main Store\",
\"notes\": \"Customer order #12345\"
}" | jq
# 5. Check analytics
echo "Fetching voucher analytics..."
curl -s -X GET "$API_BASE/analytics/vouchers" \
-H "X-API-Key: $API_KEY" | jq13. Changelog
Version 1.1.0 (April 2026)
Registration Source & Campaign Analytics
- Added
registrationSourcefield to User model (created,direct,store,campaign) - Added
storeIdandcampaignIdpopulated references in User responses - Added campaign visit and registration tracking analytics
- New public endpoint:
POST /api/campaigns/:id/track-visitfor campaign page visit tracking - Campaign list now includes
analyticsobject withvisitsandregistrationscounts
Version 1.0.0 (February 2024)
Initial Release
- Full CRUD operations for Vouchers
- Full CRUD operations for Users
- Full CRUD operations for Campaigns
- Token management (list, mint, burn, adjust)
- Analytics endpoints for vouchers, users, and tokens
- API key authentication with scopes
- Rate limiting (60/min, 10,000/day)
- IP whitelisting support
Need Help?
- Admin Portal: Create and manage API keys at Settings > API Keys
- Swagger UI: Interactive API documentation at
/api-docs - Support: Contact VIO Support for assistance
This documentation is for VIO External API v1.