Phoenix Gamification
Coupon Codes

Creating Coupon Codes

This guide explains how to create coupon definitions and generate coupons for users via the Admin Gateway.

Authentication

Coupon admin endpoints require admin-level authentication:

POST /v1/tenants/{tenant_id}/coupons
Authorization: Bearer <admin_jwt_token>
Content-Type: application/json

The JWT must contain in its payload:

  • sub_type: "admin"
  • sub_id: API key UUID (returned when creating the API key)
  • Signed with the API key value (the plaintext key like pk_abc123...)

Option 2: API Key Header (Server-to-Server)

POST /v1/tenants/{tenant_id}/coupons
X-API-Key: {api_key}
Content-Type: application/json

Prerequisites: Create a Reward Item

Before creating a coupon, you need a reward item that the coupon will grant:

POST /v1/tenants/{tenant_id}/rewards
Authorization: Bearer <admin_jwt>
Content-Type: application/json

{
  "name": "100 Bonus Points",
  "description": "Grants 100 bonus points to the user",
  "reward_type": "points",
  "payload": {
    "amount": 100
  }
}

Response:

{
  "item_id": "550e8400-e29b-41d4-a716-446655440000",
  "tenant_id": "your-tenant-id",
  "name": "100 Bonus Points",
  "description": "Grants 100 bonus points to the user",
  "reward_type": "points",
  "payload": {"amount": 100},
  "created_at": "2025-01-15T10:00:00Z",
  "updated_at": "2025-01-15T10:00:00Z"
}

Save the item_id - you'll need it for the coupon configuration.

Creating a Coupon Definition

Basic Reward Coupon

POST /v1/tenants/{tenant_id}/coupons
Authorization: Bearer <admin_jwt>
Content-Type: application/json

{
  "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,
    "usage_limit": {
      "limit_type": "per_user",
      "max_uses": 1
    }
  }
}

Response:

{
  "id": "660e8400-e29b-41d4-a716-446655440001",
  "tenant_id": "your-tenant-id",
  "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",
  "created_at": "2025-01-15T10:00:00Z",
  "updated_at": "2025-01-15T10:00:00Z"
}

Custom Promotional Code

For marketing campaigns with a specific code:

POST /v1/tenants/{tenant_id}/coupons
Authorization: Bearer <admin_jwt>
Content-Type: application/json

{
  "name": "New Year 2025 Promo",
  "description": "Special New Year promotion",
  "config": {
    "reward_item_id": "550e8400-e29b-41d4-a716-446655440000",
    "code_format": "custom",
    "custom_code": "NEWYEAR2025",
    "starts_at": "2025-01-01T00:00:00Z",
    "expires_at": "2025-01-31T23:59:59Z",
    "usage_limit": {
      "limit_type": "unlimited"
    }
  }
}

Auto-Generated Streak Reward

Automatically generate coupons when users hit streak milestones:

POST /v1/tenants/{tenant_id}/coupons
Authorization: Bearer <admin_jwt>
Content-Type: application/json

{
  "name": "7-Day Streak Reward",
  "description": "Reward for maintaining a 7-day streak",
  "config": {
    "reward_item_id": "550e8400-e29b-41d4-a716-446655440000",
    "code_format": "random",
    "code_prefix": "STREAK7",
    "code_length": 8,
    "usage_limit": {
      "limit_type": "per_user",
      "max_uses": 1
    },
    "auto_generate": {
      "enabled": true,
      "trigger": "streak_milestone",
      "trigger_config": {
        "streak_id": "770e8400-e29b-41d4-a716-446655440002",
        "milestone_threshold": 7
      }
    }
  }
}

Generating Coupons

Bulk Generation

Generate coupons for multiple users at once:

POST /v1/tenants/{tenant_id}/coupons/{definition_id}/generate
Authorization: Bearer <admin_jwt>
Content-Type: application/json

{
  "user_ids": ["user_123", "user_456", "user_789"]
}

Response:

{
  "generated": 3,
  "coupons": [
    {"user_id": "user_123", "code": "WELCOME8X4F2K9P"},
    {"user_id": "user_456", "code": "WELCOMEJ7K2L5M3"},
    {"user_id": "user_789", "code": "WELCOMEP9Q1R8S6"}
  ]
}

Bulk Generation with Custom Codes

For custom code format, provide matching codes:

POST /v1/tenants/{tenant_id}/coupons/{definition_id}/generate
Authorization: Bearer <admin_jwt>
Content-Type: application/json

{
  "user_ids": ["user_123", "user_456"],
  "custom_codes": ["VIP-USER-123", "VIP-USER-456"]
}

Managing Coupon Definitions

List All Definitions (Admin-Only)

List all definitions across all tenants (requires API key auth):

GET /v1/coupons
X-API-Key: {api_key}

List Tenant Definitions

GET /v1/tenants/{tenant_id}/coupons
Authorization: Bearer <admin_jwt>

Response:

{
  "definitions": [
    {
      "id": "660e8400-e29b-41d4-a716-446655440001",
      "tenant_id": "your-tenant-id",
      "name": "Welcome Bonus",
      "description": "Welcome bonus for new users",
      "config": {...},
      "status": "active",
      "created_at": "2025-01-15T10:00:00Z",
      "updated_at": "2025-01-15T10:00:00Z"
    }
  ],
  "total": 1
}

Get Single Definition

GET /v1/tenants/{tenant_id}/coupons/{definition_id}
Authorization: Bearer <admin_jwt>

Update Definition

Only name, description, and config can be updated:

PUT /v1/tenants/{tenant_id}/coupons/{definition_id}
Authorization: Bearer <admin_jwt>
Content-Type: application/json

{
  "name": "Updated Name",
  "description": "Updated description"
}

Update Status (Pause/Activate)

PUT /v1/tenants/{tenant_id}/coupons/{definition_id}/status
Authorization: Bearer <admin_jwt>
Content-Type: application/json

{
  "status": "paused"
}

Valid statuses: active, paused

Archive (Soft Delete)

DELETE /v1/tenants/{tenant_id}/coupons/{definition_id}
Authorization: Bearer <admin_jwt>

Returns 204 No Content. The definition is marked as archived and no longer processes events.

Configuration Reference

CouponConfig Schema

interface CouponConfig {
  // Required: UUID of the reward item to grant
  reward_item_id: string;
  
  // Required: How codes are generated
  code_format: "random" | "custom";
  
  // For random format: prefix added to generated codes
  code_prefix?: string;
  
  // For random format: length of random portion (4-32, default: 8)
  code_length?: number;
  
  // For custom format: the exact code to use
  custom_code?: string;
  
  // Whether codes are case-sensitive (default: false)
  case_sensitive?: boolean;
  
  // When the coupon becomes valid (optional)
  starts_at?: string;  // ISO 8601 datetime
  
  // When the coupon expires (optional)
  expires_at?: string;  // ISO 8601 datetime
  
  // Required: Usage limit configuration
  usage_limit: {
    limit_type: "per_user" | "global" | "unlimited";
    max_uses?: number;  // Required for per_user/global
  };
  
  // Optional: Auto-generation configuration
  auto_generate?: {
    enabled: boolean;
    trigger?: "achievement_completed" | "streak_milestone" | "leaderboard_rank";
    trigger_config?: {
      // For achievement_completed:
      achievement_id?: string;
      // For streak_milestone:
      streak_id?: string;
      milestone_threshold?: number;
      // For leaderboard_rank:
      leaderboard_id?: string;
      rank_threshold?: number;
    };
  };
}

Validation Rules

RuleDescription
reward_item_idMust be a valid UUID of an existing reward item
code_lengthMust be between 4 and 32 for random format
custom_codeAlphanumeric, hyphens, underscores only; max 255 chars
starts_at / expires_atstarts_at must be before expires_at if both provided
max_usesRequired and must be > 0 for per_user and global limits
auto_generateIf enabled, trigger is required

Scopes Required

Admin API key scopes for coupon operations:

OperationRequired Scope
List definitionscoupons:read
Get definitioncoupons:read
Create definitioncoupons:write
Update definitioncoupons:write
Update statuscoupons:write
Delete/archivecoupons:write
Bulk generatecoupons:write