Querying Coupons
How users can view their coupons, validate coupon codes, and redeem them. Covers listing definitions, user coupons, validation, redemption, and history.
Querying Coupons
This guide explains how users can view their coupons, validate coupon codes, and redeem them.
Overview
The Query API provides endpoints for:
- Listing active coupon definitions
- Getting a user's coupons
- Validating coupon codes
- Redeeming coupons
- Viewing redemption history
All endpoints require authentication. See Getting Started for authentication setup.
List Coupon Definitions
Get all active coupon definitions available for a tenant.
Endpoint:
GET /v1/coupons/definitionsExample Request:
GET /v1/coupons/definitionsResponse:
{
"definitions": [
{
"id": "660e8400-e29b-41d4-a716-446655440001",
"tenant_id": "your_tenant",
"name": "Welcome Bonus",
"description": "Welcome bonus for new users",
"config": {
"reward_item_id": "550e8400-e29b-41d4-a716-446655440000",
"code_format": "random",
"code_prefix": "WELCOME",
"code_length": 8,
"case_sensitive": false,
"usage_limit": {
"limit_type": "per_user",
"max_uses": 1
}
},
"status": "active"
}
],
"total": 1
}Get User's Coupons
Get all coupons assigned to a user.
Endpoint:
GET /v1/coupons/user/{user_id}Example Request:
GET /v1/coupons/user/user_123Response:
{
"coupons": [
{
"id": "770e8400-e29b-41d4-a716-446655440002",
"definition_id": "660e8400-e29b-41d4-a716-446655440001",
"definition_name": "Welcome Bonus",
"tenant_id": "your_tenant",
"user_id": "user_123",
"code": "WELCOME8X4F2K9P",
"status": "active",
"generated_at": "2025-01-15T10:00:00Z",
"expires_at": "2025-12-31T23:59:59Z",
"redeemed_at": null,
"redemption_count": 0
}
],
"total": 1
}Get Specific Coupon
Get details for a specific user coupon.
Endpoint:
GET /v1/coupons/user/{user_id}/{coupon_id}Example Request:
GET /v1/coupons/user/user_123/770e8400-e29b-41d4-a716-446655440002Response:
{
"id": "770e8400-e29b-41d4-a716-446655440002",
"definition_id": "660e8400-e29b-41d4-a716-446655440001",
"definition_name": "Welcome Bonus",
"tenant_id": "your_tenant",
"user_id": "user_123",
"code": "WELCOME8X4F2K9P",
"status": "active",
"generated_at": "2025-01-15T10:00:00Z",
"expires_at": "2025-12-31T23:59:59Z",
"redeemed_at": null,
"redemption_count": 0
}Validate Coupon Code
Validate a coupon code before redemption to check if it's valid and can be used.
Endpoint:
GET /v1/coupons/validate/{code}Query Parameters:
| Parameter | Type | Description |
|---|---|---|
user_id | string | User ID to validate against (optional) |
Example Request:
GET /v1/coupons/validate/WELCOME8X4F2K9P?user_id=user_123Response:
{
"valid": true,
"coupon": {
"id": "770e8400-e29b-41d4-a716-446655440002",
"definition_id": "660e8400-e29b-41d4-a716-446655440001",
"definition_name": "Welcome Bonus",
"code": "WELCOME8X4F2K9P",
"status": "active",
"expires_at": "2025-12-31T23:59:59Z"
},
"definition": {
"id": "660e8400-e29b-41d4-a716-446655440001",
"name": "Welcome Bonus",
"config": {
"reward_item_id": "550e8400-e29b-41d4-a716-446655440000"
}
},
"error": null
}Invalid Coupon Response:
{
"valid": false,
"coupon": null,
"definition": null,
"error": "Coupon not found"
}Redeem Coupon
Redeem a coupon code for a user. This grants the reward item to the user.
Endpoint:
POST /v1/coupons/redeem/{code}Request Body:
{
"user_id": "user_123"
}Example Request:
POST /v1/coupons/redeem/WELCOME8X4F2K9P
Content-Type: application/json
{
"user_id": "user_123"
}Response:
{
"id": "770e8400-e29b-41d4-a716-446655440002",
"definition_id": "660e8400-e29b-41d4-a716-446655440001",
"definition_name": "Welcome Bonus",
"tenant_id": "your_tenant",
"user_id": "user_123",
"code": "WELCOME8X4F2K9P",
"status": "redeemed",
"generated_at": "2025-01-15T10:00:00Z",
"expires_at": "2025-12-31T23:59:59Z",
"redeemed_at": "2025-01-15T10:05:00Z",
"redemption_count": 1,
"reward_item": {
"item_id": "550e8400-e29b-41d4-a716-446655440000",
"name": "100 Bonus Points",
"reward_type": "points",
"payload": {
"amount": 100
}
}
}Error Responses:
400- Coupon not found, expired, already redeemed, or usage limit exceeded404- Coupon code doesn't exist
Get Redemption History
Get a user's coupon redemption history.
Endpoint:
GET /v1/coupons/user/{user_id}/redemptionsQuery Parameters:
| Parameter | Type | Description |
|---|---|---|
limit | integer | Page size (default: 20) |
offset | integer | Page offset |
Example Request:
GET /v1/coupons/user/user_123/redemptions?limit=10&offset=0Response:
{
"redemptions": [
{
"id": "770e8400-e29b-41d4-a716-446655440002",
"definition_id": "660e8400-e29b-41d4-a716-446655440001",
"definition_name": "Welcome Bonus",
"code": "WELCOME8X4F2K9P",
"redeemed_at": "2025-01-15T10:05:00Z",
"reward_item": {
"item_id": "550e8400-e29b-41d4-a716-446655440000",
"name": "100 Bonus Points",
"reward_type": "points"
}
}
],
"total": 1
}JavaScript Example
class CouponClient {
constructor(apiUrl, jwt) {
this.apiUrl = apiUrl;
this.jwt = jwt;
}
async listDefinitions() {
const response = await fetch(
`${this.apiUrl}/v1/coupons/definitions`,
{
headers: {
'Authorization': `Bearer ${this.jwt}`,
'Content-Type': 'application/json'
}
}
);
return response.json();
}
async getUserCoupons(userId) {
const response = await fetch(
`${this.apiUrl}/v1/coupons/user/${userId}`,
{
headers: {
'Authorization': `Bearer ${this.jwt}`,
'Content-Type': 'application/json'
}
}
);
return response.json();
}
async validateCoupon(code, userId = null) {
const params = new URLSearchParams();
if (userId) {
params.set('user_id', userId);
}
const response = await fetch(
`${this.apiUrl}/v1/coupons/validate/${code}?${params}`,
{
headers: {
'Authorization': `Bearer ${this.jwt}`,
'Content-Type': 'application/json'
}
}
);
return response.json();
}
async redeemCoupon(code, userId) {
const response = await fetch(
`${this.apiUrl}/v1/coupons/redeem/${code}`,
{
method: 'POST',
headers: {
'Authorization': `Bearer ${this.jwt}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ user_id: userId })
}
);
if (!response.ok) {
const error = await response.json();
throw new Error(error.message || 'Redemption failed');
}
return response.json();
}
async getRedemptionHistory(userId, options = {}) {
const params = new URLSearchParams(options);
const response = await fetch(
`${this.apiUrl}/v1/coupons/user/${userId}/redemptions?${params}`,
{
headers: {
'Authorization': `Bearer ${this.jwt}`,
'Content-Type': 'application/json'
}
}
);
return response.json();
}
}
// Example usage
const coupons = new CouponClient('https://query.phoenix.example.com', userJwt);
// List available coupon definitions (tenant from JWT)
const { definitions } = await coupons.listDefinitions();
console.log(`Available coupons: ${definitions.length}`);
// Get user's coupons
const { coupons: userCoupons } = await coupons.getUserCoupons('user_123');
userCoupons.forEach(c => {
console.log(`${c.code}: ${c.status}`);
});
// Validate before redeeming
const validation = await coupons.validateCoupon('WELCOME8X4F2K9P', 'user_123');
if (validation.valid) {
console.log(`Coupon is valid: ${validation.coupon.definition_name}`);
// Redeem the coupon
const redeemed = await coupons.redeemCoupon('WELCOME8X4F2K9P', 'user_123');
console.log(`Redeemed: ${redeemed.reward_item.name}`);
} else {
console.log(`Coupon invalid: ${validation.error}`);
}
// Get redemption history
const { redemptions } = await coupons.getRedemptionHistory('user_123');
redemptions.forEach(r => {
console.log(`Redeemed ${r.code} on ${r.redeemed_at}`);
});Best Practices
- Validate Before Redeeming: Always validate coupon codes before attempting redemption
- Handle Errors Gracefully: Show clear error messages for invalid, expired, or already-redeemed coupons
- Case Sensitivity: Remember that codes are case-insensitive by default (unless configured otherwise)
- Display Expiration: Show expiration dates to users so they know when coupons expire
- Redemption History: Display redemption history so users can see what they've redeemed
Next Steps
- Creating Coupons - Learn how to create coupon definitions
- Coupon Overview - Understand the coupon system