Phoenix Gamification
Coupon Codes

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

Example Request:

GET /v1/coupons/definitions

Response:

{
  "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_123

Response:

{
  "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-446655440002

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": "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:

ParameterTypeDescription
user_idstringUser ID to validate against (optional)

Example Request:

GET /v1/coupons/validate/WELCOME8X4F2K9P?user_id=user_123

Response:

{
  "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 exceeded
  • 404 - Coupon code doesn't exist

Get Redemption History

Get a user's coupon redemption history.

Endpoint:

GET /v1/coupons/user/{user_id}/redemptions

Query Parameters:

ParameterTypeDescription
limitintegerPage size (default: 20)
offsetintegerPage offset

Example Request:

GET /v1/coupons/user/user_123/redemptions?limit=10&offset=0

Response:

{
  "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

  1. Validate Before Redeeming: Always validate coupon codes before attempting redemption
  2. Handle Errors Gracefully: Show clear error messages for invalid, expired, or already-redeemed coupons
  3. Case Sensitivity: Remember that codes are case-insensitive by default (unless configured otherwise)
  4. Display Expiration: Show expiration dates to users so they know when coupons expire
  5. Redemption History: Display redemption history so users can see what they've redeemed

Next Steps

On this page