Skip to content

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/v1

All 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

  1. Log in to the VIO Admin Portal
  2. Navigate to Settings > API Keys
  3. Click Create API Key
  4. Select the scopes (permissions) for the key
  5. Optionally configure IP whitelisting
  6. 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:

ScopeDescriptionEndpoints
vouchersManage vouchers and claims/vouchers/*
usersManage users/users/*
campaignsManage campaigns/campaigns/*
tokensManage tokens and balances/tokens/*
analyticsAccess analytics data/analytics/*

IP Whitelisting

For additional security, you can restrict API key usage to specific IP addresses:

  1. Go to Admin Portal > Settings > API Keys
  2. Edit your API key
  3. Add allowed IP addresses or CIDR ranges
  4. 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 TypeDefault Value
Per Minute60 requests
Per Day10,000 requests

Rate Limit Headers

Every response includes rate limit information in the headers:

HeaderDescription
X-RateLimit-LimitMaximum requests allowed in the current window
X-RateLimit-RemainingRequests remaining in the current window
X-RateLimit-ResetUnix timestamp when the rate limit resets

Example Response Headers

X-RateLimit-Limit: 60
X-RateLimit-Remaining: 45
X-RateLimit-Reset: 1699574400

Rate 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 429 responses
  • 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/json header 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

ParameterTypeDefaultDescription
pageinteger1Page number (1-indexed)
limitinteger20Items 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 CodeMeaning
200 OKRequest succeeded
201 CreatedResource created successfully
400 Bad RequestInvalid request parameters or body
401 UnauthorizedMissing or invalid API key
403 ForbiddenAPI key lacks required scope or IP not whitelisted
404 Not FoundResource not found
429 Too Many RequestsRate limit exceeded
500 Internal Server ErrorServer error

Error Codes

Error CodeDescription
VALIDATION_ERRORRequest body or parameters failed validation
UNAUTHORIZEDAPI key is missing or invalid
FORBIDDENAPI key does not have required scope
NOT_FOUNDRequested resource does not exist
RATE_LIMIT_EXCEEDEDToo many requests
ALREADY_EXISTSResource already exists (e.g., duplicate user)
INSUFFICIENT_BALANCENot enough token balance for operation
ALREADY_REDEEMEDVoucher has already been redeemed
EXPIREDVoucher or token has expired
INTERNAL_ERRORUnexpected 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 /vouchers

Query Parameters:

ParameterTypeRequiredDescription
pageintegerNoPage number (default: 1)
limitintegerNoItems per page (default: 20, max: 100)
statusstringNoFilter by status: active, claimed, redeemed, expired
visibilitystringNoFilter by visibility: private, public, shared
isActivebooleanNoFilter by active status
categorystringNoFilter by category
searchstringNoSearch by name
subCompanyIdstringNoFilter 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 /vouchers

Request Body:

FieldTypeRequiredDescription
namestringYesVoucher name
descriptionstringNoVoucher description
visibilitystringNoprivate, public, or shared (default: private)
sharedWithTenantsstring[]NoTenant IDs to share with
sharedWithUsersstring[]NoUser IDs to share with
termsstringNoTerms and conditions
valuenumberNoVoucher value (default: 0)
valueTypestringNofixed, percentage (default: fixed)
valueCurrencystringNoCurrency code (default: THB)
minSpendnumberNoMinimum spend required (default: 0)
maxDiscountnumberNoMaximum discount amount
totalQuantityintegerNoTotal available quantity (-1 for unlimited, default: -1)
startDatedatetimeNoWhen voucher becomes valid
endDatedatetimeNoWhen voucher expires
maxClaimsPerUserintegerNoMax claims per user (default: 1)
settlementAmountnumberNoSettlement amount (default: 0)
settlementCurrencystringNoSettlement 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.
crossTenantReceivableTimingstringNoWhen to record cross-tenant settlements: redemption (default) or consumption
categoriesstring[]NoCategory tags
imagesstring[]NoImage URLs
targetTiersstring[]NoTarget user tiers
targetUserGroupsstring[]NoTarget user groups
subCompanyIdstringNoSub-company ID
consumptionTypestringNoHow voucher is consumed: vio_code, url, qr_code, coupon_code, manual (default: vio_code)
consumptionUrlstringNoExternal URL for url consumption type
consumptionMessagestringNoCustom 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/:voucherId

Path Parameters:

ParameterTypeRequiredDescription
voucherIdstringYesVoucher 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/:voucherId

Path Parameters:

ParameterTypeRequiredDescription
voucherIdstringYesVoucher ID

Request Body:

All fields are optional. Include only the fields you want to update.

FieldTypeDescription
namestringVoucher name
descriptionstringVoucher description
visibilitystringprivate, public, or shared
sharedWithTenantsstring[]Tenant IDs to share with
sharedWithUsersstring[]User IDs to share with
termsstringTerms and conditions
valuenumberVoucher value
valueTypestringfixed or percentage
valueCurrencystringCurrency code
minSpendnumberMinimum spend required
maxDiscountnumberMaximum discount amount
totalQuantityintegerTotal available quantity
startDatedatetimeWhen voucher becomes valid
endDatedatetimeWhen voucher expires
maxClaimsPerUserintegerMax claims per user
settlementAmountnumberSettlement amount
settlementCurrencystringSettlement currency (defaults to tenant's primary currency). All settlement records are stored in the tenant's primary currency.
crossTenantReceivableTimingstringWhen to record cross-tenant settlements: redemption or consumption
isActivebooleanActive status
categoriesstring[]Category tags
imagesstring[]Image URLs
targetTiersstring[]Target user tiers
targetUserGroupsstring[]Target user groups
consumptionTypestringHow voucher is consumed: vio_code, url, qr_code, coupon_code, manual
consumptionUrlstringExternal URL for url consumption type
consumptionMessagestringCustom 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/:voucherId

Path Parameters:

ParameterTypeRequiredDescription
voucherIdstringYesVoucher 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/duplicate

Path Parameters:

ParameterTypeRequiredDescription
voucherIdstringYesVoucher 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/send

Path Parameters:

ParameterTypeRequiredDescription
voucherIdstringYesVoucher ID to send

Request Body:

FieldTypeRequiredDescription
userIdstringYesUser 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:

StatusCodeDescription
400VALIDATION_ERRORVoucher is not active, expired, sold out, or user at claim limit
404NOT_FOUNDVoucher or user not found

List Voucher Claims

Get a list of all voucher claims for your tenant.

GET /vouchers/claims/list

Query Parameters:

ParameterTypeRequiredDescription
pageintegerNoPage number (default: 1)
limitintegerNoItems per page (default: 20)
voucherIdstringNoFilter by voucher ID
statusstringNoFilter by status: active, redeemed, expired
fromDatedatetimeNoFilter claims from this date
toDatedatetimeNoFilter claims until this date
searchstringNoSearch 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-code

Request Body:

FieldTypeRequiredDescription
redemptionCodestringYesThe redemption code from the voucher claim
locationstringNoWhere the redemption occurred (e.g., store name)
notesstringNoAdditional 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/info

Path Parameters:

ParameterTypeRequiredDescription
codestringYesRedemption 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/pin

Path Parameters:

ParameterTypeRequiredDescription
codestringYesThe redemption code from the voucher claim

Request Body:

FieldTypeRequiredDescription
pinstringYesStaff 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:

StatusCodeDescription
400VALIDATION_ERRORInvalid PIN format (must be 6 characters)
400VALIDATION_ERRORInvalid PIN (wrong prefix or PIN doesn't match any staff)
400VALIDATION_ERRORVoucher is already redeemed or expired
404NOT_FOUNDVoucher 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 /users

Query Parameters:

ParameterTypeRequiredDescription
pageintegerNoPage number (default: 1)
limitintegerNoItems per page (default: 20)
rolestringNoFilter by role: super_admin, tenant_admin, sub_company_admin, member
searchstringNoSearch by email, phone, or name
isActivebooleanNoFilter by active status
subCompanyIdstringNoFilter 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 /users

Request Body:

FieldTypeRequiredDescription
emailstringNo*User email address
phonestringNo*User phone number
passwordstringYesPassword (min 6 characters)
displayNamestringNoUser display name
rolestringNomember or sub_company_admin (default: member)
subCompanyIdstringNoSub-company ID to assign user to
metadataobjectNoCustom metadata key-value pairs

*At least one of email or phone is 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/:userId

Path Parameters:

ParameterTypeRequiredDescription
userIdstringYesUser 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/:userId

Path Parameters:

ParameterTypeRequiredDescription
userIdstringYesUser ID

Request Body:

FieldTypeDescription
displayNamestringUser display name
avatarstringAvatar URL
isActivebooleanActive status
subCompanyIdstringSub-company ID
metadataobjectCustom 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/:userId

Path Parameters:

ParameterTypeRequiredDescription
userIdstringYesUser 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/balances

Path Parameters:

ParameterTypeRequiredDescription
userIdstringYesUser 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/vouchers

Path Parameters:

ParameterTypeRequiredDescription
userIdstringYesUser ID

Query Parameters:

ParameterTypeRequiredDescription
pageintegerNoPage number (default: 1)
limitintegerNoItems per page (default: 20)
statusstringNoFilter 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-identifier

Query Parameters:

ParameterTypeRequiredDescription
emailstringNo*User email address
phonestringNo*User phone number
walletAddressstringNo*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 /campaigns

Query Parameters:

ParameterTypeRequiredDescription
pageintegerNoPage number (default: 1)
limitintegerNoItems per page (default: 20)
searchstringNoSearch by name
isActivebooleanNoFilter 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 /campaigns

Request Body:

FieldTypeRequiredDescription
namestringYesCampaign name
descriptionstringNoCampaign description
slugstringNoURL-friendly slug (auto-generated if not provided)
tokenIdstringYesToken ID for the campaign
startDatedatetimeNoCampaign start date
endDatedatetimeNoCampaign end date
isActivebooleanNoActive status (default: true)
isPublicbooleanNoPublic visibility (default: true)
imagesstring[]NoCampaign 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/:campaignId

Path Parameters:

ParameterTypeRequiredDescription
campaignIdstringYesCampaign 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/:campaignId

Path Parameters:

ParameterTypeRequiredDescription
campaignIdstringYesCampaign ID

Request Body:

All fields are optional. Include only the fields you want to update.

FieldTypeDescription
namestringCampaign name
descriptionstringCampaign description
slugstringURL-friendly slug
startDatedatetimeCampaign start date
endDatedatetimeCampaign end date
isActivebooleanActive status
isPublicbooleanPublic visibility
imagesstring[]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/:campaignId

Path Parameters:

ParameterTypeRequiredDescription
campaignIdstringYesCampaign 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/vouchers

Path Parameters:

ParameterTypeRequiredDescription
campaignIdstringYesCampaign ID

Query Parameters:

ParameterTypeRequiredDescription
pageintegerNoPage number (default: 1)
limitintegerNoItems 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/vouchers

Path Parameters:

ParameterTypeRequiredDescription
campaignIdstringYesCampaign ID

Request Body:

FieldTypeRequiredDescription
voucherIdsstring[]YesArray of voucher IDs to add
tokenAmountstringYesToken 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/:voucherId

Path Parameters:

ParameterTypeRequiredDescription
campaignIdstringYesCampaign ID
voucherIdstringYesVoucher ID

Request Body:

FieldTypeDescription
tokenAmountstringToken amount required to claim
sortOrderintegerDisplay order
isActivebooleanActive 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/:voucherId

Path Parameters:

ParameterTypeRequiredDescription
campaignIdstringYesCampaign ID
voucherIdstringYesVoucher 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-vouchers

Path Parameters:

ParameterTypeRequiredDescription
campaignIdstringYesCampaign ID

Query Parameters:

ParameterTypeRequiredDescription
pageintegerNoPage number (default: 1)
limitintegerNoItems per page (default: 20)
searchstringNoSearch 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:

TypeDescription
permanentTokens never expire (default)
fixed_dateTokens expire at a specific date/time
duration_daysTokens 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 expiryBreakdown field in balance responses shows all active lots with their expiry details

List Tokens

Retrieve a list of tokens for your tenant.

GET /tokens

Query Parameters:

ParameterTypeRequiredDescription
pageintegerNoPage number (default: 1)
limitintegerNoItems per page (default: 20)
isActivebooleanNoFilter by active status
subCompanyIdstringNoFilter 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/:tokenId

Path Parameters:

ParameterTypeRequiredDescription
tokenIdstringYesToken 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/stats

Example 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/holders

Path Parameters:

ParameterTypeRequiredDescription
tokenIdstringYesToken ID

Query Parameters:

ParameterTypeRequiredDescription
pageintegerNoPage number (default: 1)
limitintegerNoItems per page (default: 20)
sortstringNoSort by: balance, name, recent (default: balance)
searchstringNoSearch 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/mint

Request Body:

FieldTypeRequiredDescription
toUserIdstringYesUser ID to receive tokens
amountstringYesAmount to mint
memostringNoTransaction memo
expiryTypestringNoToken expiry type: permanent (default), fixed_date, or duration_days
expiresAtstringConditionalISO 8601 datetime. Required when expiryType is fixed_date
expiryDaysnumberConditionalNumber 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/burn

Request Body:

FieldTypeRequiredDescription
fromUserIdstringYesUser ID to burn from
amountstringYesAmount to burn
memostringNoTransaction 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/adjust

Request Body:

FieldTypeRequiredDescription
userIdstringYesUser ID
amountstringYesAmount to adjust
operationstringYessend or recall
reasonstringYesReason 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/send

Request Body:

FieldTypeRequiredDescription
userIdstringYesUser ID to send tokens to
amountstringYesAmount of tokens to send
reasonstringNoReason 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:

StatusCodeDescription
400VALIDATION_ERRORInsufficient company balance for sending tokens
404NOT_FOUNDToken or user not found

Recall Tokens

Recall tokens from a user back to the company admin balance pool.

POST /tokens/:tokenId/recall

Request Body:

FieldTypeRequiredDescription
userIdstringYesUser ID to recall tokens from
amountstringYesAmount of tokens to recall
reasonstringNoReason 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:

StatusCodeDescription
400VALIDATION_ERRORInsufficient user balance for recalling tokens
404NOT_FOUNDToken or user not found

List Token Transactions

Retrieve a list of token transactions.

GET /tokens/transactions/list

Query Parameters:

ParameterTypeRequiredDescription
pageintegerNoPage number (default: 1)
limitintegerNoItems per page (default: 20)
tokenIdstringNoFilter by token ID
typestringNoFilter by type: mint, transfer, burn, reward, redeem, expire
fromDatedatetimeNoFilter from this date
toDatedatetimeNoFilter until this date
searchstringNoSearch 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/:userId

Path Parameters:

ParameterTypeRequiredDescription
userIdstringYesUser 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/overview

Example 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/vouchers

Query Parameters:

ParameterTypeRequiredDescription
fromDatedatetimeNoStart date for analytics
toDatedatetimeNoEnd 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/users

Query Parameters:

ParameterTypeRequiredDescription
fromDatedatetimeNoStart date for analytics
toDatedatetimeNoEnd 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/tokens

Query Parameters:

ParameterTypeRequiredDescription
fromDatedatetimeNoStart date for analytics
toDatedatetimeNoEnd 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

FieldTypeDescription
_idstringUnique identifier
namestringVoucher name
descriptionstringVoucher description
valuenumberVoucher value
valueTypestringfixed, percentage
valueCurrencystringCurrency code
termsstringTerms and conditions
imagesstring[]Image URLs
isActivebooleanActive status
totalQuantityintegerTotal available (-1 for unlimited)
claimedQuantityintegerNumber claimed
maxClaimsPerUserintegerMax claims per user
startDatedatetimeValidity start date
endDatedatetimeExpiry date
visibilitystringprivate, public, shared (also controls transfer scope)
categoriesstring[]Category tags
minSpendnumberMinimum spend required
maxDiscountnumberMaximum discount amount
consumptionTypestringHow voucher is consumed: vio_code, url, qr_code, coupon_code, manual
consumptionUrlstringExternal URL for url consumption type
consumptionQrCodestringQR code image path for qr_code consumption type (uploaded image)
consumptionMessagestringCustom message/instructions for manual consumption type
createdAtdatetimeCreation timestamp
updatedAtdatetimeLast 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)

FieldTypeDescription
_idstringUnique identifier
voucherIdstringAssociated voucher ID
userIdstringOwner user ID
statusstringactive, redeemed, expired, transferred
redemptionCodestringUnique redemption code
claimedAtdatetimeClaim timestamp
redeemedAtdatetimeRedemption timestamp
expiresAtdatetimeExpiry timestamp
redeemedLocationstringWhere redeemed
notesstringRedemption notes

User

FieldTypeDescription
_idstringUnique identifier
emailstringEmail address
phonestringPhone number
displayNamestringDisplay name
avatarstringAvatar URL
rolestringmember, sub_company_admin, tenant_admin, super_admin
isActivebooleanActive status
walletAddressstringWeb3 custodial wallet address (auto-provisioned on user creation)
registrationSourcestringHow the user was registered: created, direct, store, campaign
storeIdobjectPopulated store reference (if registered via store). Contains _id, name
campaignIdobjectPopulated campaign reference (if registered via campaign). Contains _id, name, slug
metadataobjectCustom metadata
createdAtdatetimeRegistration timestamp
updatedAtdatetimeLast update timestamp

Campaign

FieldTypeDescription
_idstringUnique identifier
namestringCampaign name
descriptionstringCampaign description
slugstringURL-friendly identifier
tokenIdstringAssociated token ID
isActivebooleanActive status
isPublicbooleanPublic visibility
startDatedatetimeCampaign start date
endDatedatetimeCampaign end date
imagesstring[]Campaign images
createdAtdatetimeCreation timestamp

Token

FieldTypeDescription
_idstringUnique identifier
namestringToken name
symbolstringToken symbol
descriptionstringToken description
totalSupplystringTotal supply
decimalsintegerDecimal places
isActivebooleanActive status
createdAtdatetimeCreation timestamp
updatedAtdatetimeLast update timestamp

TokenBalance

FieldTypeDescription
tokenIdstringToken ID
tokenNamestringToken name
symbolstringToken symbol
balancestringAvailable balance
lockedBalancestringLocked balance

Transaction

FieldTypeDescription
_idstringUnique identifier
tokenIdstringToken ID
typestringmint, transfer, burn, reward, redeem, expire
amountstringTransaction amount
fromUserIdstringSender user ID
toUserIdstringRecipient user ID
memostringTransaction memo
createdAtdatetimeTransaction timestamp

Pagination

FieldTypeDescription
pageintegerCurrent page number
limitintegerItems per page
totalintegerTotal items
totalPagesintegerTotal pages
hasNextPagebooleanMore pages available
hasPrevPagebooleanPrevious 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" | jq

13. Changelog

Version 1.1.0 (April 2026)

Registration Source & Campaign Analytics

  • Added registrationSource field to User model (created, direct, store, campaign)
  • Added storeId and campaignId populated references in User responses
  • Added campaign visit and registration tracking analytics
  • New public endpoint: POST /api/campaigns/:id/track-visit for campaign page visit tracking
  • Campaign list now includes analytics object with visits and registrations counts

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.

VIO v4 Platform Documentation