API Documentation
Learn how to integrate Volia vouchers into your application.
Getting Started
Volia provides a RESTful API for voucher generation, validation, and redemption. All API endpoints are available at the base URL of your Volia instance.
Base URL
Authentication Methods
Volia supports two authentication methods:
- Session Cookie — Used by the web application after login. Automatically handled by the browser.
- API Key — For server-to-server integration. Include via
Authorization: Bearer <key>header.
API Keys
Generate API keys from the API Keys page in your dashboard. Keys are prefixed with vh_live_ and are shown only once upon creation.
Using API Keys
⚠️ Keep your API keys secure
Never expose API keys in client-side code. Always use them from a backend service.
Voucher Types
Vouchers are split into two categories:
Voucher · Fixed
Fixed dollar amount discount. Category: discount
Voucher amount of $20.00 per use. Fund is reserved.
Voucher · Percentage
Percentage discount with a dollar cap.
10% off, capped at $50.00 per use.
Benefit
Non-monetary benefit (e.g. free shipping, early access).
No fund reservation. type and value are ignored.
Note: Percentage vouchers require maxRedeemValue. Benefit vouchers require description instead.
Voucher Status
Each voucher follows a status lifecycle:
| Status | Description | Redeemable |
|---|---|---|
| active | Voucher is valid and ready to be redeemed. | ✅ Yes |
| used | All max uses have been exhausted. | ❌ No |
| expired | Voucher has passed its expiration date. | ❌ No |
| revoked | Administratively voided or campaign deleted. | ❌ No |
Automatic transitions:
- active → used — When
redeemCount >= maxUses - active → expired — When
expiresAt < now(checked on redeem/validate) - active → revoked — Campaign or group is deleted
Code Format
Voucher codes are generated from a format pattern. Each X in the pattern is replaced with a random alphanumeric character (A-Z, 0-9).
Pattern Rules
- Maximum 50 characters
- Allowed characters:
A-Z,0-9,X,- - If
count > 1, pattern must containX - No consecutive, leading, or trailing dashes
Examples
Pattern
SUMMER-XXXX
Possible codes
SUMMER-A3K9, SUMMER-7XQ2, SUMMER-P5MN
Pattern
XXXXXX
Possible codes
B7K9M2, XR4PQ8, 3VN2WJ
Pattern
SALE-XX-2024
Possible codes
SALE-A3-2024, SALE-9K-2024
Pattern
VIP
Possible codes
VIP (single code, no X needed)
The prefix is automatically derived from the pattern — everything before the first X, with trailing dashes removed. If no prefix is found, defaults to GEN.
Generate Vouchers
Create one or more vouchers for a customer. Requires authentication (session or API key).
/api/vouchersRequest Body
{
"format": "SUMMER-XXXX",
"type": "fixed",
"value": 20,
"campaignId": "uuid-here",
"count": 5,
"maxUses": 1,
"expiresAt": "2026-12-31",
"maxRedeemValue": 50,
"group": "Batch-1",
"minPurchase": 100
}Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| format | string | Yes | Code pattern (e.g. "SUMMER-XXXX") |
| type | string | Yes | "fixed" or "percentage" |
| value | number | Yes | Voucher amount in dollars or percent |
| campaignId | string | Yes | Campaign to reserve fund from |
| count | number | No | Quantity (1-100, default: 1) |
| maxUses | number | No | Max redemptions per voucher (default: 1) |
| expiresAt | date | No | Expiration date (ISO 8601) |
| maxRedeemValue | number | * | Required for percentage type |
| group | string | No | Group name within campaign |
| minPurchase | number | No | Minimum cart total to redeem |
Example — cURL
Example — JavaScript
Response
[
{
"id": "uuid",
"code": "SUMMER-A3K9",
"prefix": "SUMMER",
"type": "fixed",
"value": 20,
"status": "active",
"redeemCount": 0,
"maxUses": 1,
"maxRedeemValue": null,
"expiresAt": "2026-12-31T00:00:00.000Z",
"group": "Batch-1",
"customerId": "user-uuid",
"createdAt": "2026-07-06T12:00:00.000Z"
}
]Validate a Voucher
Check whether a voucher code is valid without redeeming it. Requires authentication — call this endpoint from your backend with a valid API key.
/api/validateRequest Body
{
"code": "SUMMER-A3K9",
"cartTotal": 150 // optional — used to compute percentage discount
}Success Response (200)
{
"valid": true,
"voucher": {
"code": "SUMMER-A3K9",
"category": "discount",
"description": null,
"type": "fixed",
"value": 20,
"maxRedeemValue": 50,
"minPurchase": 100,
"computedDiscount": 20
}
}Error Response (200)
{
"valid": false,
"error": "Voucher has expired"
}📌 Discount Calculation
computedDiscount depends on voucher category and type:
- Fixed:
computedDiscount = value— cartTotal is ignored - Percentage:
computedDiscount = min(cartTotal × value%, maxRedeemValue)— requires cartTotal; returnswarningif omitted - Benefit:
computedDiscount = null— non-monetary
Example — cURL
Redeem a Voucher
There are two ways to redeem a voucher:
1. Redeem by Code
Requires authentication — call this endpoint from your backend with a valid API key.
/api/redeemRequest Body
{
"code": "SUMMER-A3K9",
"customerEmail": "user@example.com",
"cartTotal": 150
}Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| code | string | Yes | Voucher code (case-insensitive) |
| customerEmail | string | No | For tracking purposes |
| cartTotal | number | No | Cart total for percentage discount calculation (ignored for fixed/benefit) |
Validation Order
- Voucher code exists
- Voucher is not revoked (deleted)
- Voucher status is active
- Voucher has not expired
- Usage count is below maxUses
- Cart total meets minPurchase (if set)
Example — cURL
Success Response
{
"success": true,
"voucher": {
"code": "SUMMER-A3K9",
"category": "discount",
"description": null,
"type": "fixed",
"value": 20,
"maxRedeemValue": 50,
"computedDiscount": 20
}
}Response — Percentage without cartTotal
{
"success": true,
"voucher": {
"code": "SUMMER-PCT",
"category": "discount",
"type": "percentage",
"value": 15,
"maxRedeemValue": 50,
"computedDiscount": null,
"warning": "cartTotal is required to compute percentage discount"
}
}Error Response
{
"statusCode": 400,
"message": "This voucher has expired"
}2. Authenticated Redeem (by ID)
Requires authentication. Redeem a voucher by its ID. Only the voucher owner can redeem via this method.
/api/vouchers/{id}/redeemBody (optional): { "trackingEmail": "...", "trackingIdentifier": "..." }
Campaigns
Campaigns organize vouchers and manage budgets. Each campaign has a fund (total budget) and usedFund (budget consumed by created vouchers).
Fund Mechanics
When you create vouchers in a campaign, the fund is reserved at creation time:
perVoucher = (type === 'fixed') ? value : maxRedeemValue totalReserve = perVoucher × maxUses × count remaining = campaign.fund - campaign.usedFund // If totalReserve > remaining → Error: Insufficient campaign fund // Otherwise → campaign.usedFund += totalReserve
Fund is not released on redemption. To free up budget, delete a voucher group (which recalculates usedFund based on remaining active vouchers).
Campaign API
/api/campaigns— List your campaigns/api/campaigns— Create a campaign/api/campaigns/{id}— Campaign detail with vouchersCampaign Statuses
Campaign status is computed dynamically:
- scheduled —
startsAt > now - active — Within the date range or no dates set
- ended —
endsAt < now
Voucher Groups
Within a campaign, vouchers can be organized into groups — logical labels set at creation time.
- Group is an optional free-text field
- Vouchers without a group belong to "Ungrouped"
- Deleting a group deletes all vouchers in it and recalculates the campaign fund
Error Handling
API errors follow a consistent format:
{
"statusCode": 400,
"message": "Description of what went wrong"
}Common HTTP Status Codes
| Code | Meaning | Typical Cause |
|---|---|---|
| 200 | Success | Request completed successfully |
| 400 | Bad Request | Invalid body, missing fields, or voucher errors (expired, used, revoked) |
| 401 | Unauthorized | Missing or invalid API key / session |
| 403 | Forbidden | Insufficient permissions (not admin) |
| 404 | Not Found | Resource not found (voucher, campaign, etc.) |
| 409 | Conflict | Duplicate voucher code, insufficient campaign fund |
| 500 | Server Error | Unexpected error — contact support |
Common Voucher Errors
| Error Message | Cause |
|---|---|
| Voucher not found | Code does not exist |
| Voucher has been revoked | Voucher was deleted or revoked |
| Voucher has expired | expiresAt date has passed |
| Voucher is used | All max uses exhausted |
| Insufficient campaign fund | Campaign budget is fully reserved |
| Format pattern is required | Missing format in generate request |
| maxRedeemValue is required for percentage type | Missing required field |