# Create campaign claim

Process campaign reward claims using role-based detection.
**Understanding Campaign Claim Flow:**
1. **WHO can claim (campaign.trigger.triggerType):**
  - `CLAIM_BY_USER`: End users initiate claims (scan QR, tap NFC, enter geofence)
  - `CLAIM_BY_BUSINESS`: Business claims on behalf of users (POS, kiosk)
  - `CLAIM_BY_SYSTEM`: Server/webhook automated claims
2. **HOW to claim (campaign.triggerSources[].type):**
  - `QR_CODE`: User scans QR code → App extracts triggerSourceId
  - `NFC_TAG`: User taps NFC tag → App reads triggerSourceId
  - `GPS_GEOFENCE`: User enters location → App sends lat/lng
  - `API_WEBHOOK`: External system triggers via API
  - `TRANSACTION`: Purchase event triggers claim

**Request Body Fields:**
- `triggerSourceId` (preferred): The specific trigger source ID from QR/NFC/etc
- `campaignId` (legacy, deprecated): Will be removed Q2 2026
- `latitude/longitude`: Required for GPS_GEOFENCE or distance-validated claims
- `userIdentifier`: Email/external ID for business/system claims
- `userInfo`: Additional user data if required by campaign
- `metadata`: Custom claim data
- `multiplier`: Reward multiplier (default: 1.0)
- `context`: Dynamic context for ERC721 token personalization (see below)

**ERC721 Dynamic Context & Template Interpolation:**
For ERC721 tokens, you can provide a `context` object whose values become available as `{{context.xxx}}` placeholders in the token's name/description and AI prompts.
**Context sources (merge order):**
1. `TokenMetadata.defaultPromptContext` → `{{defaults.xxx}}`
2. `TriggerSource.context` (admin QR/NFC) → `{{context.xxx}}` (always applied)
3. `CampaignClaimRequest.context` (this field) → `{{context.xxx}}` (only if `allowExternalContextOverwrite=true`)

**Example - Hotel check-in:**

```json
{
  "triggerSourceId": "room-305-qr-uuid",
  "context": {
    "guestName": "María García",
    "roomNumber": "305",
    "validityEndDate": "2026-04-20T11:00:00Z"
  }
}
```
With TokenMetadata name: `"Welcome {{context.guestName}} - Room {{context.roomNumber}}"`
Result: `"Welcome María García - Room 305"`
**App Integration Example:**

```typescript
// 1. Get campaign with trigger sources
const campaign = await getActiveCampaigns({ include: ['triggerSources'] });

// 2. Determine claim method
const triggerTypes = campaign.included?.triggerSources?.map(ts => ts.type);
// → ['QR_CODE', 'NFC_TAG']

// 3. Based on type, show appropriate UI and call claim
if (triggerTypes.includes('QR_CODE')) {
  // Open camera, scan QR, extract triggerSourceId
  claimCampaign({ triggerSourceId: 'scanned-id' });
}
```

Endpoint: POST /campaigns/claims
Version: 2.0.53
Security: authJWT

## Request fields (application/json):

  - `externalReferenceId` (string)
    External reference ID for idempotency. If a claim with this ID already exists, the request will be rejected. Use case: Stripe payment ID, order ID, webhook event ID, etc.

  - `triggerSourceId` (string)
    The trigger source ID (NEW - preferred). Use this for trigger-specific claims (QR codes, NFC tags, geofences, etc.). Takes precedence over campaignId if both are provided.

  - `metadata` (string)
    The campaign metadata associated with the claim.

  - `context` (object)
    **ERC721 only** - User-provided external context for template interpolation and AI prompts.
**SECURITY:** Only applied if TokenMetadata.allowExternalContextOverwrite is true (admin opt-in required). TriggerSource.context (admin-controlled QR/NFC data) is ALWAYS applied regardless.
**Template Interpolation:** Values become available as `{{context.keyName}}` placeholders in TokenMetadata name/description fields and AI prompts.
**Special validity keys:**
- `validityDate` - Base date for trigger-based validity
- `validityEndDate` - End date for date ranges (e.g., hotel checkout)
- `validityDuration` - Override duration in days/hours

**Custom keys:** Any arbitrary key becomes `{{context.keyName}}` placeholder.
**Example use cases:**
- Hotel: `{ guestName: "John", roomNumber: "305", validityEndDate: "2026-04-20T11:00:00Z" }`
- Event: `{ ticketType: "VIP", seatNumber: "A12" }`
- Retail: `{ productName: "Gold Watch", purchaseAmount: 299.99 }`
    Example: {"guestName":"John Doe","validityDate":"2026-04-15T14:00:00Z","validityEndDate":"2026-04-20T11:00:00Z"}

  - `multiplier` (number)
    The campaign multiplier that will be applied to the reward. This determines the final reward amount (reward * multiplier). Default is 1.0

  - `latitude` (number)
    User's current latitude for location-based validation. Required when CampaignTrigger has maxGeoDistanceInMeters configured. System validates user is within allowed distance from TriggerSource location (coordsLatitude) or Business location fallback.

  - `longitude` (number)
    User's current longitude for location-based validation. Required when CampaignTrigger has maxGeoDistanceInMeters configured. System validates user is within allowed distance from TriggerSource location (coordsLongitude) or Business location fallback.

  - `userIdentifier` (string)
    The user identifier, e.g. email or external id. This is used to identify the user making the claim, if not provided in request context

  - `userInfo` (object)
    User information required by the campaign trigger. Only needed if CampaignTrigger.requiredUserInfo is set AND the user profile does not already have these fields stored. Provide fields specified in CampaignTrigger.requiredUserInfo (e.g., email, phoneNumber, firstName, lastName, dateOfBirth, etc.). Backend validates that required fields are either already stored or provided here.
    Example: {"email":"user@example.com","phoneNumber":"+1234567890","firstName":"John"}

  - `businessId` (string)
    DEPRECATED: Use with triggerSource instead. Business identifier - provides additional context and validation for the claim. Will be removed in Q2 2026

  - `campaignId` (string)
    DEPRECATED: The campaign ID. Still supported for backward compatibility, but use triggerSourceId for new implementations. If both campaignId and triggerSourceId are provided, triggerSourceId takes precedence. NOTE: If campaign has trigger sources configured, triggerSourceId becomes required and campaignId alone will result in an error. Will be removed in Q2 2026

## Response 200 fields (application/json):

  - `id` (string, required)
    The id of the campaign user claim

  - `externalReferenceId` (string, required)
    External reference ID for idempotency. Used to prevent duplicate claims. Use case: Stripe payment ID, order ID, webhook event ID, etc.

  - `createdAt` (string, required)
    The date the campaign user claim was created

  - `userId` (string, required)
    User ID who claimed the campaign

  - `campaignId` (string, required)
    Campaign ID that was claimed

  - `businessId` (string)
    Business ID associated with this claim (if applicable)

  - `triggerSourceId` (string)
    Trigger Source ID that was used for this claim (e.g., specific QR code, NFC tag, etc.)

  - `user` (object, required)
    User object (DEPRECATED: use userId instead. Only contains {id} during migration. Will be removed in Q2 2026)
    Example: {"id":"user-uuid-123"}

  - `campaign` (object, required)
    Campaign object (DEPRECATED: use campaignId instead. Only contains {id} during migration. Will be removed in Q2 2026)
    Example: {"id":"campaign-uuid-123"}

  - `business` (object)
    Business object (DEPRECATED: use businessId instead. Only contains {id} during migration. Will be removed in Q2 2026)
    Example: {"id":"business-uuid-123"}

  - `userCountryCode` (string, required)
    Country code of the user claiming the campaign

  - `latitude` (number)
    Latitude coordinate where claim was made (reduced precision ~1.1km for privacy compliance)
    Example: 41.39

  - `longitude` (number)
    Longitude coordinate where claim was made (reduced precision ~1.1km for privacy compliance)
    Example: 2.18

  - `status` (string, required)
    Status of the claim processing (PENDING, PROCESSING, COMPLETED, FAILED)
    Enum: "PENDING", "PROCESSING", "COMPLETED", "FAILED"

  - `message` (string)
    Status or error message for the claim

  - `dataSource` (object)
    Analytics tracking: source/channel of this claim action
    Example: {"channel":"mobile","medium":"referral","campaign":"summer_promo"}

  - `included` (object)
    Included related entities. Only populated when include parameter is specified. Contains campaign, user, business, triggerSource, and/or transactions entities based on requested relations.

  - `included.campaign` (object)

  - `included.campaign.id` (string, required)
    Campaign id

  - `included.campaign.ownerBusinessId` (string, required)
    Optional owner business ID. If set, this campaign belongs to a specific business. If null, the campaign is tenant-owned (system-level).

  - `included.campaign.name` (string, required)
    Campaign name

  - `included.campaign.description` (string, required)
    Campaign description

  - `included.campaign.beneficiaryAccountAddress` (string, required)
    Campaign beneficiary account address

  - `included.campaign.startDate` (string, required)
    Campaign start date, default is the current date

  - `included.campaign.endDate` (string, required)
    Campaign end date

  - `included.campaign.imageUrl` (string, required)
    img url

  - `included.campaign.logoUrl` (string, required)
    Logo URL for the campaign

  - `included.campaign.externalUrl` (string, required)
    Campaign url

  - `included.campaign.isActive` (boolean, required)
    Campaign isActive

  - `included.campaign.approval` (object, required)
    Approval metadata for this campaign.

  - `included.campaign.approval.status` (string, required)
    Approval state: pending_approval = awaiting admin review, approved = active, rejected = denied.
    Enum: "pending_approval", "approved", "rejected"

  - `included.campaign.approval.approvedAt` (string)
    Timestamp when the entity was approved or rejected by an admin.

  - `included.campaign.approval.approvedBy` (string)
    Admin user ID who approved or rejected this entity.

  - `included.campaign.approval.rejectionReason` (string)
    Reason provided when the entity was rejected.

  - `included.campaign.isTestnet` (boolean)
    Campaign isTestnet, this means that the campaign is running on testnet, not mainnet

  - `included.campaign.createdAt` (string, required)
    create date

  - `included.campaign.updatedAt` (string, required)
    update date

  - `included.campaign.order` (number, required)
    Campaign order

  - `included.campaign.tags` (array, required)
    Campaign tags

  - `included.campaign.countryCodeRestrictions` (object)
    Country code restrictions as an array of strings (e.g., ["NOT_ES", "FR"])
    Example: ["NOT_ES","FR"]

  - `included.campaign.trigger` (object, required)
    Campaign trigger: what triggers the campaign, and what are the conditions for the trigger to be activated

  - `included.campaign.trigger.name` (number)
    Campaign trigger name

  - `included.campaign.trigger.description` (string)
    Campaign trigger description

  - `included.campaign.trigger.terms` (string)
    Terms and conditions for participation. Plain text or HTML. Multi-language handling at app level.

  - `included.campaign.trigger.maxPerDay` (number)
    DEPRECATED - use maxPerDayPerUser: Campaign trigger max per day

  - `included.campaign.trigger.maxPerDayPerUser` (number)
    Campaign trigger max per day per user

  - `included.campaign.trigger.maxPerUser` (number)
    Campaign trigger max per user

  - `included.campaign.trigger.minCooldownSeconds` (number)
    Campaign trigger min cooldown seconds

  - `included.campaign.trigger.maxGeoDistanceInMeters` (number)
    Campaign trigger max geo distance to Business in meters

  - `included.campaign.trigger.requiredUserInfo` (string)
    Campaign trigger required user info

  - `included.campaign.trigger.triggerType` (string)
    WHO can initiate a claim for this campaign.
**Values:**
- `CLAIM_BY_USER`: End users initiate claims (scan QR, tap NFC, enter geofence)
- `CLAIM_BY_BUSINESS`: Business claims on behalf of users (POS, kiosk, staff-assisted)
- `CLAIM_BY_SYSTEM`: Server/webhook automated claims (webhooks, scheduled jobs)

**Important:** This defines WHO can claim.
NOT to be confused with TriggerSource.type which defines HOW to claim (QR_CODE, NFC_TAG, GPS_GEOFENCE, etc.).
**App Logic:**
- If CLAIM_BY_USER: App shows claim UI based on triggerSources[].type
- If CLAIM_BY_BUSINESS: Requires business auth + userIdentifier in request
- If CLAIM_BY_SYSTEM: Server-to-server only, requires tenant API key
    Enum: "CLAIM_BY_USER", "CLAIM_BY_SYSTEM", "CLAIM_BY_BUSINESS"

  - `included.campaign.trigger.maxMultiplier` (number)
    Campaign trigger max multiplier

  - `included.campaign.trigger.completionThreshold` (number)
    Campaign trigger completion threshold. This indicates the number of completions required before the reward is granted

  - `included.campaign.trigger.maxTotal` (number)
    Campaign trigger max total completions across all users

  - `included.campaign.trigger.maxPerDayTotal` (number)
    Campaign trigger max total completions per day across all users

  - `included.campaign.trigger.maxPerSource` (number)
    Maximum claims per trigger source for this campaign. Limits how many times each individual trigger source can be used.

  - `included.campaign.trigger.conditions` (array)
    Campaign trigger conditions

  - `included.campaign.trigger.conditions.conditionType` (string, required)
    Trigger condition type
    Enum: "EQUALS", "NOT_EQUALS", "GREATER_THAN", "LESS_THAN", "CONTAINS", "IS_PART_OF"

  - `included.campaign.trigger.conditions.value` (object, required)
    Trigger condition value

  - `included.campaign.trigger.conditions.key` (string, required)
    Trigger condition key

  - `included.campaign.trigger.sourceLogic` (string)
    Source logic type defining how multiple trigger sources combine to activate the flow
    Enum: "any"

  - `included.campaign.trigger.id` (string, required)
    Campaign trigger id

  - `included.campaign.tokenUnits` (array, required)

  - `included.campaign.tokenUnits.id` (string, required)
    Database UUID for this token unit

  - `included.campaign.tokenUnits.token` (object, required)
    The token contract this unit references

  - `included.campaign.tokenUnits.token.id` (string, required)
    Database UUID for this token contract entity

  - `included.campaign.tokenUnits.token.contractAddress` (string, required)
    Smart contract address deployed on the blockchain

  - `included.campaign.tokenUnits.token.metadata` (array)
    Token metadata templates - blueprints used when minting NFTs. Each template defines properties (name, image, expiry) and has a unique tokenMetadataIncrementalId. Null for ERC20 (Points) tokens.

  - `included.campaign.tokenUnits.token.metadata.ownerBusinessId` (string)
    Optional owner business ID. If set, this token metadata belongs to a specific business. If null, the token metadata is tenant-owned (system-level).

  - `included.campaign.tokenUnits.token.metadata.isActive` (boolean)
    Whether this template is active and can be used for minting

  - `included.campaign.tokenUnits.token.metadata.imageUrl` (string)
    This is the URL to the image of the item. Can be just about any type of image (including SVGs, which will be cached into PNGs by OpenSea), IPFS or Arweave URLs or paths. We recommend using a minimum 3000 x 3000 image.

  - `included.campaign.tokenUnits.token.metadata.externalUrl` (string)
    This is the URL that will appear below the asset's image

  - `included.campaign.tokenUnits.token.metadata.description` (string)
    A human-readable description of the item. Markdown is supported.
**ERC721 Template Interpolation:** Supports `{{placeholder}}` syntax for dynamic personalization at mint time (without AI costs).
**Available placeholders:**
- `{{user.firstName}}`, `{{user.lastName}}` - User data
- `{{campaign.name}}`, `{{business.displayName}}` - Campaign/business
- `{{context.xxx}}` - Dynamic context values (TriggerSource.context or claim request)
- `{{defaults.xxx}}` - Default values from defaultPromptContext

**Example:** `"Thank you {{user.firstName}} for visiting {{business.displayName}}! Your exclusive reward for {{context.eventName}}."`
**Processing order:** Template interpolation runs first, then AI processing (if configured) can further enhance the result.

  - `included.campaign.tokenUnits.token.metadata.name` (string)
    Name of the item.
**ERC721 Template Interpolation:** Supports `{{placeholder}}` syntax for dynamic personalization at mint time (without AI costs).
**Available placeholders:**
- `{{user.firstName}}`, `{{user.lastName}}` - User data
- `{{campaign.name}}`, `{{business.displayName}}` - Campaign/business
- `{{context.xxx}}` - Dynamic context values (TriggerSource.context or claim request)
- `{{defaults.xxx}}` - Default values from defaultPromptContext

**Example:** `"Welcome {{context.guestName}} - VIP Pass"` or `"{{user.firstName}}'s {{campaign.name}} Reward"`
**Processing order:** Template interpolation runs first, then AI processing (if configured) can further enhance the result.

  - `included.campaign.tokenUnits.token.metadata.validityType` (string)
    **ERC721 only** - Validity type defines how token expiry is calculated. Use with validityDuration for relative types. Ignored for ERC1155 tokens.
    Enum: "fixed_date", "days_from_issuance", "hours_from_issuance", "months_from_issuance", "end_of_month", "end_of_year", "trigger_date", "trigger_date_range", "days_from_trigger", "hours_from_trigger"

  - `included.campaign.tokenUnits.token.metadata.validityDuration` (number)
    **ERC721 only** - Duration in days or hours (used with days_from_issuance, hours_from_issuance validity types). Ignored for ERC1155 tokens.
    Example: 30

  - `included.campaign.tokenUnits.token.metadata.expiryDate` (string)
    Fixed expiry date (used with fixed_date validity type). For other validity types, this is computed at issuance time.

  - `included.campaign.tokenUnits.token.metadata.animationUrl` (string)
    A URL to a multi-media attachment for the item. The file extensions GLTF, GLB, WEBM, MP4, M4V, OGV, and OGG are supported, along with the audio-only extensions MP3, WAV, and OGA. Animation_url also supports HTML pages, allowing you to build rich experiences and interactive NFTs using JavaScript canvas, WebGL, and more. Scripts and relative paths within the HTML page are now supported. However, access to browser extensions is not supported.

  - `included.campaign.tokenUnits.token.metadata.youtubeUrl` (string)
    A URL to a YouTube video (only used if animation_url is not provide

  - `included.campaign.tokenUnits.token.metadata.creatorAccountAddress` (string)
    Creator Address

  - `included.campaign.tokenUnits.token.metadata.previewUrl` (string)
    Preview Url

  - `included.campaign.tokenUnits.token.metadata.tags` (array)
    Tags for categorization and filtering
    Example: ["summer","vip","limited-edition"]

  - `included.campaign.tokenUnits.token.metadata.aiPromptConfigs` (array)
    **ERC721 only** - AI prompt configurations for dynamic content generation at mint time.
AI processing runs AFTER template interpolation, so prompts can reference already-interpolated values.
Results are mapped by key to override static fields (name, description, imageUrl). Ignored for ERC1155 tokens.
**Note:** For simple personalization without AI costs, use `{{placeholder}}` syntax directly in name/description fields instead.
    Example: [{"type":"TEXT_GENERATION","key":"name","prompt":"Generate a unique reward name for {{user.firstName}} at {{business.displayName}}"},{"type":"IMAGE_GENERATION","key":"imageUrl","prompt":"A {{defaults.…

  - `included.campaign.tokenUnits.token.metadata.aiPromptConfigs.type` (string, required)
    Type of AI operation to perform
    Enum: "TEXT_GENERATION", "IMAGE_GENERATION"

  - `included.campaign.tokenUnits.token.metadata.aiPromptConfigs.key` (string, required)
    Key to store the generated result under
    Example: name

  - `included.campaign.tokenUnits.token.metadata.aiPromptConfigs.prompt` (string, required)
    The prompt to send to the AI model. Supports dynamic placeholders that are replaced with context values.
**Available Placeholders:**
- `{{user.firstName}}`, `{{user.lastName}}`, `{{user.email}}` - User profile data
- `{{campaign.name}}`, `{{campaign.description}}` - Campaign data
- `{{tenant.projectName}}`, `{{tenant.projectDescription}}` - Tenant/project data
- `{{business.displayName}}`, `{{business.name}}` - Business data
- `{{triggerSource.name}}`, `{{triggerSource.type}}` - Trigger source data
- `{{redemption.name}}`, `{{redemption.description}}` - Redemption data
- `{{context.xxx}}` - Dynamic context from TriggerSource.context or CampaignClaimRequest.context
- `{{defaults.xxx}}` - Default values from TokenMetadata.defaultPromptContext

**Context Sources:**
1. TriggerSource.context (admin QR/NFC) - Always applied
2. CampaignClaimRequest.context (user API) - Only if allowExternalContextOverwrite=true
3. TokenMetadata.defaultPromptContext - Always applied as fallback

**Examples:**
- `"Generate a welcome message for {{user.firstName}} at {{business.displayName}}"`
- `"Create a VIP badge for guest {{context.guestName}} in room {{context.roomNumber}}"`
- `"Design a {{defaults.style}} reward image for {{campaign.name}}"`
    Example: Generate a unique reward name for {{user.firstName}} visiting {{business.displayName}}

  - `included.campaign.tokenUnits.token.metadata.allowExternalContextOverwrite` (boolean)
    **ERC721 only** - Allow USER-PROVIDED external context from claim/redeem requests to be used in template interpolation and AI prompts.
**Security model:**
- `false` (default): Only admin-controlled context (TriggerSource.context, Redemption.context, defaultPromptContext) is available
- `true`: User-provided context from API requests is also merged and available as `{{context.xxx}}`

**Note:** Admin-controlled context (QR/NFC data) is ALWAYS applied regardless of this flag.
    Example: true

  - `included.campaign.tokenUnits.token.metadata.defaultPromptContext` (object)
    **ERC721 only** - Default context values for template interpolation and AI prompts. Available as `{{defaults.xxx}}` placeholders.
Always applied regardless of allowExternalContextOverwrite. Use for brand defaults, styling preferences, or fallback values.
**Example usage in name:** `"{{defaults.brand}} - {{user.firstName}}'s Reward"`
    Example: {"brand":"PERS Rewards","style":"minimal","defaultLocation":"Online"}

  - `included.campaign.tokenUnits.token.metadata.businessIds` (array)
    Business IDs where this token can be redeemed/spent. Empty array means any business in the tenant.
    Example: ["business-uuid-1","business-uuid-2"]

  - `included.campaign.tokenUnits.token.metadata.webhookId` (string)
    **ERC721 only** - Webhook ID for dynamic data fetch at mint time.
If set, the webhook is executed before metadata generation and response data is merged into the NFT.
**Use cases:**
- Fetch guest data from PMS/CRM systems
- Get real-time pricing or availability
- Retrieve user-specific content from external APIs

**Processing order:** Webhook fetch runs AFTER template interpolation but BEFORE AI processing.
    Example: webhook-uuid-for-pms-lookup

  - `included.campaign.tokenUnits.token.metadata.webhookPayloadTemplate` (object)
    **ERC721 only** - Payload template for webhook request.
Supports `{{placeholder}}` interpolation with same context as AI prompts.
**Example:**

```json
{
  "userId": "{{user.id}}",
  "campaignId": "{{campaign.id}}",
  "bookingId": "{{context.bookingId}}"
}
```
    Example: {"userId":"{{user.id}}","bookingId":"{{context.bookingId}}"}

  - `included.campaign.tokenUnits.token.metadata.webhookFieldMapping` (object)
    **ERC721 only** - Field mapping from webhook response to metadata fields.
Keys are webhook response paths (dot notation for nested), values are target field names.
**Mapping rules:**
- Explicit mapping: `"response.path": "targetField"`
- Known fields (name, description, imageUrl): auto-mapped if present
- Unknown fields or `"attributes"` target: become NFT attributes

**Example:**

```json
{
  "guestName": "name",
  "data.guest.image": "imageUrl",
  "roomNumber": "attributes",
  "checkInDate": "attributes"
}
```
If null/undefined, uses auto-mapping.
    Example: {"guestName":"name","roomNumber":"attributes","data.image":"imageUrl"}

  - `included.campaign.tokenUnits.token.metadata.consumable` (boolean)
    Whether this token template is consumable (burned on redemption) or collectible (transferred). Applies to ERC1155 and ERC721 only — ERC20 is always transferred. When true, the token is destroyed (burn) when used as payment in a redemption. Defaults to true — most token templates are consumable. Set to false for collectible/non-burning use cases. Mirrored as a consumable attribute in the on-chain IPFS metadata.

  - `included.campaign.tokenUnits.token.metadata.id` (string, required)
    Database UUID for this token metadata template

  - `included.campaign.tokenUnits.token.metadata.animationWeb3StorageUrl` (string)
    IPFS/Arweave URL for animation file - immutable web3 storage

  - `included.campaign.tokenUnits.token.metadata.imageWeb3StorageUrl` (string)
    IPFS/Arweave URL for image - immutable web3 storage

  - `included.campaign.tokenUnits.token.metadata.web3StorageUrl` (string)
    IPFS/Arweave URL for complete metadata JSON - this URL is stored on-chain and links to off-chain metadata

  - `included.campaign.tokenUnits.token.metadata.tokenMetadataIncrementalId` (number, required)
    Incremental ID within the token contract. For ERC1155: becomes the on-chain tokenId. For ERC721: lookup key for template to generate unique metadata.

  - `included.campaign.tokenUnits.token.metadata.approval` (object, required)
    Approval metadata for this token metadata.

  - `included.campaign.tokenUnits.token.metadata.mintCount` (number)
    Total number of mints for this token metadata (via ?include=mintCount). Counts SUCCEEDED MINT transactions using tokenMetadataIncrementalId. Accurate for both ERC1155 and ERC721 (post v2.3.49). Historical ERC721 transactions before v2.3.49 are not counted.

  - `included.campaign.tokenUnits.token.metadata.burnCount` (number)
    Total number of burns for this token metadata (via ?include=burnCount). Counts SUCCEEDED BURN transactions using tokenMetadataIncrementalId. Accurate for both ERC1155 and ERC721 (post v2.3.49). Historical ERC721 transactions before v2.3.49 are not counted.

  - `included.campaign.tokenUnits.token.metadata.included` (object)
    Included related entities. Only populated when include parameter is specified.

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness` (object)

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.id` (string, required)
    The id of the business, this is unique and will be used to identify the business.

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.email` (string, required)
    The email of the business, this is unique and will be used to identify the business.

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.accountAddress` (string, required)
    The address of the business, this is the address that will be shown to the public.

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.currentSigningAccountId` (string, required)
    Current active signing account ID for external wallet operations

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.wallets` (array, required)
    Business-owned counterfactual smart contract wallets that can receive tokens

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.businessLegalName` (string, required)
    The legal name of the business, this is the name that will be used for legal purposes.

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.registrationNumber` (string, required)
    The business registration number (e.g., company registration, VAT number, EIN)

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.displayName` (string, required)
    The display name of the business, this is the name that will be shown to the public.

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.description` (string, required)
    The description of the business, this is the description that will be shown to the public.

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.shortDescription` (string, required)
    The short description of the business, this is the description that will be shown to the public.

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.websiteUrl` (string, required)
    The website of the business, this is the website that will be shown to the public.

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.imageUrl` (string, required)
    The image of the business, this is the image that will be shown to the public.

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.logoUrl` (string, required)
    Logo URL for the business

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.streetAddress` (string, required)
    The address of the business, this is the address that will be shown to the public.

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.phoneNumber` (string, required)
    The phone number of the business.

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.neighborhood` (string, required)
    Neighborhood/area name (e.g., "West Bay", "Pearl Qatar", "Lusail") - auto-populated from geocoding

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.district` (string, required)
    District/administrative area - auto-populated from geocoding

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.city` (string, required)
    The city of the business, this is the city that will be shown to the public.

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.postalCode` (string, required)
    The postal code of the business, this is the postal code that will be shown to the public.

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.country` (string, required)
    The country of the business (auto-populated from geocoding if coordinates provided)

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.countryCode` (string, required)
    ISO 3166-1 alpha-2 country code (e.g., QA, US, AE) - auto-populated from geocoding
    Example: QA

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.coordsLatitude` (number, required)
    The latitude of the business, this is the latitude that will be shown to the public.

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.coordsLongitude` (number, required)
    The longitude of the business, this is the longitude that will be shown to the public.

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.businessType` (object, required)
    The business type of the business, this is the business type that will be shown to the public.

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.isActive` (boolean, required)
    The status of the business, this is the status that will be shown to the public.

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.approval` (object, required)
    Approval metadata for this business.

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.canMintToken` (boolean, required)
    The ability to mint token for the business, this is the ability that will be shown to the public.

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.canChargeToken` (boolean, required)
    The ability to charge token for the business, this is the ability that will be shown to the public.

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.canManageUsers` (boolean, required)
    The ability to manage users for the business, this is the ability that will be shown to the public.

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.canReceiveDonation` (boolean, required)
    The ability to receive donation for the business, this is the ability that will be shown to the public.

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.tags` (array, required)
    Tags for categorization and filtering

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.customData` (object, required)
    Custom business data including Google Places information (placeID, currentOpeningHours)
    Example: {"placeID":"ChIJN1t_tDeuEmsRUsoyG83frY4","currentOpeningHours":{"open_now":true,"weekday_text":["Monday: 9:00 AM – 5:00 PM","Tuesday: 9:00 AM – 5:00 PM"]}}

  - `included.campaign.tokenUnits.token.metadata.included.token` (object)
    Parent token contract info (via ?include=token)

  - `included.campaign.tokenUnits.token.metadata.included.token.chainId` (number)
    Blockchain chain ID (mainnet or testnet)

  - `included.campaign.tokenUnits.token.metadata.included.token.contractAddress` (string)
    Smart contract address

  - `included.campaign.tokenUnits.token.metadata.included.token.type` (string)
    Token type (ERC721, ERC1155)

  - `included.campaign.tokenUnits.token.abi` (object, required)
    this is the abi of the contract, this is the interface of the contract to interact with it

  - `included.campaign.tokenUnits.token.chainId` (number, required)
    this is the chain id of the chain where the token is deployed

  - `included.campaign.tokenUnits.token.abiUrl` (string, required)
    this is the url of the abi of the contract, to be used to fetch the abi of the contract

  - `included.campaign.tokenUnits.token.name` (string)
    this is the name of the token contract

  - `included.campaign.tokenUnits.token.symbol` (string)
    this is the symbol of the token contract, this is optional and can be null

  - `included.campaign.tokenUnits.token.decimals` (number)
    this is the decimals of the token. This is optional and only used for ERC20 tokens (Points)

  - `included.campaign.tokenUnits.token.isActive` (boolean, required)
    This can be used to enable or disable the token

  - `included.campaign.tokenUnits.token.isGallery` (boolean, required)
    This can be used to enable or disable the token for gallery

  - `included.campaign.tokenUnits.token.type` (string, required)
    This is the underlying web3 native type of the token contract
    Enum: "ERC20", "ERC1155", "ERC721"

  - `included.campaign.tokenUnits.token.stampToken` (boolean, required)
    When true, this ERC1155 contract is used as a shared stamp contract. TokenMetadata entries are auto-provisioned per business and can be referenced in redemption priceTokenUnits with resolveByBusiness=true.

  - `included.campaign.tokenUnits.tokenMetadataIncrementalId` (number)
    Token metadata template ID. For ERC1155: becomes on-chain tokenId. For ERC721: lookup key for template to generate unique metadata.

  - `included.campaign.tokenUnits.amount` (number, required)
    Amount of tokens to mint/transfer. For ERC721 this is typically 1, for ERC1155/ERC20 can be any quantity.

  - `included.campaign.tokenUnits.maxAmount` (number)
    Token unit max amount. Applies to MINT/EARN contexts only (e.g. campaign reward capping where user earns tokens per revenue spent). Ignored for spend/transfer contexts such as redemption priceTokenUnits.

  - `included.campaign.businessEngagements` (array, required)

  - `included.campaign.businessEngagements.id` (string, required)
    id

  - `included.campaign.businessEngagements.shortDescription` (number, required)
    A short description of the business engagement with indications what to do etc

  - `included.campaign.businessEngagements.businessIds` (array, required)
    Business IDs associated with this engagement. Use CampaignDTO.included.businesses for full entities.

  - `included.campaign.businessEngagements.businesses` (array, required)
    Businesses (DEPRECATED: use businessIds + CampaignDTO.included.businesses instead. Will be removed in Q2 2026)
    Example: [{"id":"business-uuid-1"},{"id":"business-uuid-2"}]

  - `included.campaign.businessEngagements.campaignId` (string, required)
    Campaign id

  - `included.campaign.businessEngagements.maxPerBusiness` (number, required)
    max per business, the maximum number of times a user can engage with the buisness in the campaign

  - `included.campaign.businessEngagements.maxPerDay` (number, required)
    max per day, the maximum number of times a user can engage with the buisness in the campaign per day

  - `included.campaign.businessEngagements.externalUrl` (string, required)
    The external URL for the business engagement, e.g. a link to a website or app

  - `included.campaign.triggerSourceIds` (array, required)
    Trigger source IDs. Use to batch fetch or request via ?include=triggerSources
    Example: ["trigger-uuid-1","trigger-uuid-2"]

  - `included.campaign.included` (object)
    Included related data. Only populated when include parameter is specified.

  - `included.campaign.included.claimCount` (number)
    Total number of claims for this campaign (via ?include=claimCount)

  - `included.campaign.included.triggerSources` (array)
    Full trigger source entities (via ?include=triggerSources)

  - `included.campaign.included.triggerSources.type` (string, required)
    Type of trigger source - HOW to claim rewards.
**Available Types:**
- `QR_CODE`: Physical QR code scan. App opens camera, decodes QR, extracts triggerSourceId
- `NFC_TAG`: NFC tag tap. App activates NFC reader, reads tag data
- `GPS_GEOFENCE`: GPS-based geofence. App sends user coordinates for proximity validation
- `API_WEBHOOK`: Server-to-server webhook. External system triggers claim via API
- `TRANSACTION`: Purchase/transaction triggered. Claim activated by payment events

**Important:** This defines HOW claims are triggered (the touchpoint mechanism).
NOT to be confused with CampaignTriggerType which defines WHO can claim (CLAIM_BY_USER, CLAIM_BY_BUSINESS, CLAIM_BY_SYSTEM).
**App Integration:**

```typescript
const triggerTypes = campaign.included?.triggerSources?.map(ts => ts.type);
// Based on types, show appropriate UI (camera for QR, NFC prompt, location request, etc.)
```
    Enum: "QR_CODE", "NFC_TAG", "API_WEBHOOK", "GPS_GEOFENCE", "TRANSACTION"

  - `included.campaign.included.triggerSources.name` (string, required)
    Human-readable name for the trigger source
    Example: Main Entrance QR Code

  - `included.campaign.included.triggerSources.description` (number)
    Optional description explaining this trigger source
    Example: QR code located at the main entrance for visitor check-in

  - `included.campaign.included.triggerSources.context` (object)
    **ERC721 only** - Admin-controlled dynamic context for template interpolation and AI prompts. This data is ALWAYS applied (not subject to allowExternalContextOverwrite).
**Template Interpolation:** Values become available as `{{context.keyName}}` placeholders in TokenMetadata name/description fields and AI prompts.
**Special validity keys:**
- `validityDate` - Base date for trigger-based validity
- `validityEndDate` - End date for date ranges (e.g., hotel checkout)
- `validityDuration` - Override duration in days/hours

**Custom keys:** Any arbitrary key becomes `{{context.keyName}}` placeholder.
**Use cases:**
- QR at hotel room: `{ location: "Room 305", roomType: "Suite" }`
- NFC at event entrance: `{ eventName: "Summer Festival", zone: "VIP" }`
- Kiosk-specific: `{ deviceId: "kiosk-001", branch: "Downtown" }`
    Example: {"location":"Main Lobby","deviceId":"kiosk-001","validityDate":"2026-04-20T11:00:00Z"}

  - `included.campaign.included.triggerSources.maxUsage` (number)
    Maximum usage limit. null=unlimited, 1=single-use (receipt), 100=limited edition. Usage count calculated from claims via CQRS.
    Example: null

  - `included.campaign.included.triggerSources.businessId` (number)
    Reference to the business that owns this trigger source. Optional - can be tenant-wide trigger sources
    Example: business-uuid-123

  - `included.campaign.included.triggerSources.coordsLatitude` (number)
    Latitude. Geographic coordinates for location-based trigger validation.
**Universal Location Support:** ANY trigger type can use proximity validation (GPS_GEOFENCE, QR_CODE, NFC_TAG, API_WEBHOOK, TRANSACTION).
**Location Resolution Priority:**
1. TriggerSource coordinates (if set)
2. Business coordinates (if businessId exists)
3. Neither - No location validation

Distance constraints defined in CampaignTrigger.maxGeoDistanceInMeters. Both latitude and longitude must be provided together.
**Geocoding behavior:** Changing coords will auto-update address fields. To adjust pin position without changing address (e.g., parking entrance), set BOTH coordinates AND address fields in the same request.
    Example: 47.6062

  - `included.campaign.included.triggerSources.coordsLongitude` (number)
    Longitude. Geographic coordinates for location-based trigger validation.
**Universal Location Support:** ANY trigger type can use proximity validation (GPS_GEOFENCE, QR_CODE, NFC_TAG, API_WEBHOOK, TRANSACTION).
**Location Resolution Priority:**
1. TriggerSource coordinates (if set)
2. Business coordinates (if businessId exists)
3. Neither - No location validation

Distance constraints defined in CampaignTrigger.maxGeoDistanceInMeters. Both latitude and longitude must be provided together.
    Example: -122.3321

  - `included.campaign.included.triggerSources.streetAddress` (string)
    Street address (auto-populated from geocoding if coordinates provided)
    Example: 123 Main Street

  - `included.campaign.included.triggerSources.neighborhood` (string)
    Neighborhood/area name (e.g., "West Bay", "Pearl Qatar", "Lusail") - auto-populated from geocoding
    Example: West Bay

  - `included.campaign.included.triggerSources.district` (string)
    District/administrative area - auto-populated from geocoding
    Example: Doha Municipality

  - `included.campaign.included.triggerSources.city` (string)
    City. Auto-populated from geocoding if only coordinates provided. **Geocoding behavior:** Changing address fields will auto-update coordinates. To adjust pin without changing address, set BOTH coords AND address fields.
    Example: Doha

  - `included.campaign.included.triggerSources.postalCode` (string)
    Postal code (auto-populated from geocoding if coordinates provided)
    Example: 12345

  - `included.campaign.included.triggerSources.country` (string)
    Country (auto-populated from geocoding if coordinates provided)
    Example: Qatar

  - `included.campaign.included.triggerSources.countryCode` (string)
    ISO 3166-1 alpha-2 country code (auto-populated from geocoding)
    Example: QA

  - `included.campaign.included.triggerSources.id` (string, required)
    Unique identifier for the trigger source
    Example: source-12345

  - `included.campaign.included.triggerSources.isActive` (boolean, required)
    Whether this trigger source is currently active. Inactive sources won't trigger any flows
    Example: true

  - `included.campaign.included.triggerSources.isExhausted` (boolean, required)
    Whether this trigger source has been exhausted (agotado). Set via CQRS when claim count reaches maxUsage.

  - `included.campaign.included.triggerSources.createdAt` (object, required)
    Timestamp when the trigger source was created
    Example: 2024-01-01T12:00:00.000Z

  - `included.campaign.included.triggerSources.updatedAt` (object, required)
    Timestamp when the trigger source was last updated
    Example: 2024-01-10T12:00:00.000Z

  - `included.campaign.included.businesses` (array)
    Full business entities for all businessEngagements (via ?include=businesses)

  - `included.user` (object)

  - `included.user.id` (string, required)

  - `included.user.email` (string)

  - `included.user.identifierEmail` (string, required)
    Universal identifier email for deterministic operations. Generated from B2B inputs (email, externalId) for wallet salt generation and external integrations.
    Example: user123@user.pers.internal

  - `included.user.firstName` (string, required)
    User first name

  - `included.user.lastName` (string, required)
    User last name

  - `included.user.externalId` (string, required)
    User external id

  - `included.user.accountAddress` (string, required)
    User account address

  - `included.user.instagramAccountId` (string, required)
    Instagram account id

  - `included.user.googleAccountName` (string, required)
    Google account name

  - `included.user.customData` (object, required)
    Custom data

  - `included.user.publicProfile` (object, required)
    Public profile data

  - `included.user.isActive` (boolean, required)
    Is active

  - `included.user.currentSigningAccountId` (string)
    Current active signing account ID for external wallet operations

  - `included.user.wallets` (array, required)
    User-owned counterfactual smart contract wallets that can receive tokens

  - `included.user.wallets.id` (string, required)
    Unique identifier for the internal wallet

  - `included.user.wallets.ownerType` (string, required)
    Owner type for polymorphic ownership
    Enum: "user", "business", "tenant", "system", "external"

  - `included.user.wallets.ownerId` (string, required)
    Owner ID for polymorphic ownership
    Example: user_123

  - `included.user.wallets.walletManagementType` (string, required)
    Type of internal wallet
    Enum: "custodial", "non-custodial"

  - `included.user.wallets.address` (string, required)
    CREATE2 generated address that can receive tokens

  - `included.user.wallets.chainId` (number, required)
    Blockchain network chain identifier

  - `included.user.wallets.status` (string, required)
    Current status of the wallet
    Enum: "pending", "active", "suspended", "archived"

  - `included.user.wallets.ownerSigningAccountId` (string)
    ID of signing account that owns this internal wallet

  - `included.user.wallets.tags` (array, required)
    Tags associated with the wallet for categorization

  - `included.user.wallets.createdAt` (string, required)
    Timestamp when the wallet was created

  - `included.user.wallets.updatedAt` (string, required)
    Timestamp when the wallet was last updated

  - `included.user.createdAt` (string, required)
    Timestamp when the user was created

  - `included.user.updatedAt` (string, required)
    Timestamp when the user was last updated

  - `included.user.registrationSource` (object)
    Registration source tracking for analytics - captures channel and attribution when user was created
    Example: {"channel":"web","medium":"referral","campaign":"launch_2026"}

  - `included.user.lastActivityAt` (string)
    Last activity timestamp. Updated whenever user generates tokens (login or refresh). Tracks last time user was active (~1 hour precision).

  - `included.user.activityCount` (number)
    Total activity count. Increments on every token generation (login + refresh). Measures true user engagement.
    Example: 42

  - `included.user.included` (object)
    Included related entities. Only populated when include parameter is specified.

  - `included.user.included.statusTypes` (array)
    User status types earned based on token balances (via ?include=status)

  - `included.user.included.statusTypes.name` (string, required)
    User Status Type name

  - `included.user.included.statusTypes.description` (string)
    User Status Type description

  - `included.user.included.statusTypes.minTokenBalance` (string, required)
    User Status Type eligible Token Addresses

  - `included.user.included.statusTypes.discountPercentage` (number, required)
    User Status Type discount Rate in percentage

  - `included.user.included.statusTypes.imageUrl` (string)
    User Status Type image Url

  - `included.user.included.statusTypes.eligibleTokenAddresses` (array)
    Eligible token contract addresses for this status type
    Example: ["0x1234...","0x5678..."]

  - `included.user.included.statusTypes.tags` (array)
    Tags for categorization and filtering
    Example: ["vip","premium","gold"]

  - `included.user.included.statusTypes.order` (number)
    Explicit ordering for status hierarchy (higher = more prestigious). If not set, falls back to minTokenBalance for ordering.
    Example: 100

  - `included.user.included.statusTypes.id` (number, required)
    User Status Type id

  - `included.user.included.tokenBalances` (array)
    Token balances for user wallets (via ?include=balances)

  - `included.user.included.tokenBalances.accountAddress` (string, required)

  - `included.user.included.tokenBalances.tokenBalances` (array, required)

  - `included.user.included.tokenBalances.tokenBalances.contractAddress` (string, required)

  - `included.user.included.tokenBalances.tokenBalances.chainId` (number, required)

  - `included.user.included.tokenBalances.tokenBalances.balance` (number, required)

  - `included.user.included.tokenBalances.tokenBalances.tokenName` (string)

  - `included.user.included.tokenBalances.tokenBalances.tokenSymbol` (string)

  - `included.user.included.tokenBalances.tokenBalances.tokenType` (string, required)

  - `included.user.included.tokenBalances.tokenBalances.tokenId` (string, required)

  - `included.user.included.tokenBalances.tokenBalances.metadataUri` (string, required)

  - `included.user.included.tokenBalances.tokenBalances.metadata` (object, required)
    Token metadata (loaded from IPFS/storage when needed for filtering)

  - `included.transactions` (array)
    Included transaction entities created for this claim

  - `included.transactions.amount` (string, required)
    Transaction amount

  - `included.transactions.id` (string, required)
    Transaction id

  - `included.transactions.tokenAddress` (string, required)
    Transaction token address

  - `included.transactions.contractTokenId` (string, required)
    Transaction token contract id, this is the blockchain contract id of the token

  - `included.transactions.tokenType` (string, required)
    Transaction token type

  - `included.transactions.senderAddress` (string, required)
    Sender address

  - `included.transactions.recipientAddress` (string, required)
    Recipient address

  - `included.transactions.transactionHash` (string, required)
    Transaction hash

  - `included.transactions.type` (string, required)
    Transaction type
    Enum: "MINT", "TRANSFER", "BURN"

  - `included.transactions.triggerProcessType` (string, required)
    Trigger process type
    Enum: "PURCHASE", "SPEND", "TRANSFER", "EARN", "CAMPAIGN_USER_CLAIM", "CAMPAIGN_SYSTEM_CLAIM", "CAMPAIGN_BUSINESS_CLAIM", "REDEMPTION_SPEND", "REDEMPTION_RECEIVE", "REDEMPTION_PRICE_TOKEN_TRANSFER", "MIGRATION", "ADMIN_TRIGGERED", "BUSINESS_TRIGGERED"

  - `included.transactions.triggerProcessId` (string, required)
    Trigger process id, this is the id of the entity that triggered the transaction if applicable (e.g. CampaignUserClaim id)

  - `included.transactions.status` (string, required)
    Transaction status
    Enum: "created", "processing", "pending_signature", "pending_submission", "broadcasted", "succeeded", "failed", "cancelled", "expired"

  - `included.transactions.createdAt` (string, required)
    Transaction creation timestamp

  - `included.transactions.updatedAt` (string, required)
    Transaction last update timestamp

  - `included.transactions.tenantId` (string, required)
    Tenant ID for multi-tenant isolation

  - `included.transactions.chainId` (number, required)
    Blockchain chain ID

  - `included.transactions.senderId` (string, required)
    Sender entity ID (polymorphic reference)

  - `included.transactions.senderOwnerType` (string, required)
    Sender entity type (user, business, system etc.)
    Enum: "user", "business", "tenant", "system", "external"

  - `included.transactions.recipientId` (string, required)
    Recipient entity ID (polymorphic reference)

  - `included.transactions.recipientOwnerType` (string, required)
    Recipient entity type (user, Business, system, etc.)
    Enum: "user", "business", "tenant", "system", "external"

  - `included.transactions.message` (string, required)
    Optional message associated with the transaction, e.g. for error details

  - `included.transactions.engagedBusinessId` (string, required)
    Business commercially involved in this transaction (for stats/reporting)

  - `included.transactions.authorizedSubmitterId` (string, required)
    Entity authorized to submit this transaction (for POS flow security)

  - `included.transactions.authorizedSubmitterType` (string, required)
    Type of entity authorized to submit (USER, BUSINESS, etc.)
    Enum: "user", "business", "tenant", "system", "external"

  - `included.transactions.userCountryCode` (string, required)
    ISO 3166-1 alpha-2 country code derived from IP geolocation

  - `included.transactions.anonymizedIpAddress` (string, required)
    Anonymized IP address (last octet zeroed for privacy)

  - `included.transactions.metadataUri` (string, required)
    IPFS/storage URL for token metadata. For ERC721: unique URI per minted token. For ERC1155: shared URI per token type. Example: ipfs://Qm.../metadata.json
    Example: ipfs://QmXyz123.../metadata.json

  - `included.transactions.tokenMetadataIncrementalId` (number, required)
    Token metadata template ID - stable reference for mint/burn counting. For ERC1155: same as on-chain tokenId. For ERC721: template lookup key (preserved since on-chain ID differs).

  - `included.transactions.issuanceMode` (string)
    Economic issuance mechanism for reward transactions. TENANT_DELEGATED_MINT: master wallet mints. BUSINESS_OWNED_MINT: business owns the token contract. BUSINESS_BALANCE_TRANSFER: business transfers from own wallet balance. Null for non-reward or legacy transactions.
    Enum: "TENANT_DELEGATED_MINT", "BUSINESS_OWNED_MINT", "BUSINESS_BALANCE_TRANSFER"

  - `included.transactions.included` (object)
    Included related entities. Only populated when include parameter is specified. Contains sender, recipient, and/or engaged business entities based on requested relations.

  - `included.transactions.included.sender` (any)
    Included sender entity (User or Business)

  - `included.transactions.included.recipient` (any)
    Included recipient entity (User or Business)

## Response 201 fields (application/json):

  - `id` (string, required)
    The id of the campaign user claim

  - `externalReferenceId` (string, required)
    External reference ID for idempotency. Used to prevent duplicate claims. Use case: Stripe payment ID, order ID, webhook event ID, etc.

  - `createdAt` (string, required)
    The date the campaign user claim was created

  - `userId` (string, required)
    User ID who claimed the campaign

  - `campaignId` (string, required)
    Campaign ID that was claimed

  - `businessId` (string)
    Business ID associated with this claim (if applicable)

  - `triggerSourceId` (string)
    Trigger Source ID that was used for this claim (e.g., specific QR code, NFC tag, etc.)

  - `user` (object, required)
    User object (DEPRECATED: use userId instead. Only contains {id} during migration. Will be removed in Q2 2026)
    Example: {"id":"user-uuid-123"}

  - `campaign` (object, required)
    Campaign object (DEPRECATED: use campaignId instead. Only contains {id} during migration. Will be removed in Q2 2026)
    Example: {"id":"campaign-uuid-123"}

  - `business` (object)
    Business object (DEPRECATED: use businessId instead. Only contains {id} during migration. Will be removed in Q2 2026)
    Example: {"id":"business-uuid-123"}

  - `userCountryCode` (string, required)
    Country code of the user claiming the campaign

  - `latitude` (number)
    Latitude coordinate where claim was made (reduced precision ~1.1km for privacy compliance)
    Example: 41.39

  - `longitude` (number)
    Longitude coordinate where claim was made (reduced precision ~1.1km for privacy compliance)
    Example: 2.18

  - `status` (string, required)
    Status of the claim processing (PENDING, PROCESSING, COMPLETED, FAILED)
    Enum: "PENDING", "PROCESSING", "COMPLETED", "FAILED"

  - `message` (string)
    Status or error message for the claim

  - `dataSource` (object)
    Analytics tracking: source/channel of this claim action
    Example: {"channel":"mobile","medium":"referral","campaign":"summer_promo"}

  - `included` (object)
    Included related entities. Only populated when include parameter is specified. Contains campaign, user, business, triggerSource, and/or transactions entities based on requested relations.

  - `included.campaign` (object)

  - `included.campaign.id` (string, required)
    Campaign id

  - `included.campaign.ownerBusinessId` (string, required)
    Optional owner business ID. If set, this campaign belongs to a specific business. If null, the campaign is tenant-owned (system-level).

  - `included.campaign.name` (string, required)
    Campaign name

  - `included.campaign.description` (string, required)
    Campaign description

  - `included.campaign.beneficiaryAccountAddress` (string, required)
    Campaign beneficiary account address

  - `included.campaign.startDate` (string, required)
    Campaign start date, default is the current date

  - `included.campaign.endDate` (string, required)
    Campaign end date

  - `included.campaign.imageUrl` (string, required)
    img url

  - `included.campaign.logoUrl` (string, required)
    Logo URL for the campaign

  - `included.campaign.externalUrl` (string, required)
    Campaign url

  - `included.campaign.isActive` (boolean, required)
    Campaign isActive

  - `included.campaign.approval` (object, required)
    Approval metadata for this campaign.

  - `included.campaign.approval.status` (string, required)
    Approval state: pending_approval = awaiting admin review, approved = active, rejected = denied.
    Enum: "pending_approval", "approved", "rejected"

  - `included.campaign.approval.approvedAt` (string)
    Timestamp when the entity was approved or rejected by an admin.

  - `included.campaign.approval.approvedBy` (string)
    Admin user ID who approved or rejected this entity.

  - `included.campaign.approval.rejectionReason` (string)
    Reason provided when the entity was rejected.

  - `included.campaign.isTestnet` (boolean)
    Campaign isTestnet, this means that the campaign is running on testnet, not mainnet

  - `included.campaign.createdAt` (string, required)
    create date

  - `included.campaign.updatedAt` (string, required)
    update date

  - `included.campaign.order` (number, required)
    Campaign order

  - `included.campaign.tags` (array, required)
    Campaign tags

  - `included.campaign.countryCodeRestrictions` (object)
    Country code restrictions as an array of strings (e.g., ["NOT_ES", "FR"])
    Example: ["NOT_ES","FR"]

  - `included.campaign.trigger` (object, required)
    Campaign trigger: what triggers the campaign, and what are the conditions for the trigger to be activated

  - `included.campaign.trigger.name` (number)
    Campaign trigger name

  - `included.campaign.trigger.description` (string)
    Campaign trigger description

  - `included.campaign.trigger.terms` (string)
    Terms and conditions for participation. Plain text or HTML. Multi-language handling at app level.

  - `included.campaign.trigger.maxPerDay` (number)
    DEPRECATED - use maxPerDayPerUser: Campaign trigger max per day

  - `included.campaign.trigger.maxPerDayPerUser` (number)
    Campaign trigger max per day per user

  - `included.campaign.trigger.maxPerUser` (number)
    Campaign trigger max per user

  - `included.campaign.trigger.minCooldownSeconds` (number)
    Campaign trigger min cooldown seconds

  - `included.campaign.trigger.maxGeoDistanceInMeters` (number)
    Campaign trigger max geo distance to Business in meters

  - `included.campaign.trigger.requiredUserInfo` (string)
    Campaign trigger required user info

  - `included.campaign.trigger.triggerType` (string)
    WHO can initiate a claim for this campaign.
**Values:**
- `CLAIM_BY_USER`: End users initiate claims (scan QR, tap NFC, enter geofence)
- `CLAIM_BY_BUSINESS`: Business claims on behalf of users (POS, kiosk, staff-assisted)
- `CLAIM_BY_SYSTEM`: Server/webhook automated claims (webhooks, scheduled jobs)

**Important:** This defines WHO can claim.
NOT to be confused with TriggerSource.type which defines HOW to claim (QR_CODE, NFC_TAG, GPS_GEOFENCE, etc.).
**App Logic:**
- If CLAIM_BY_USER: App shows claim UI based on triggerSources[].type
- If CLAIM_BY_BUSINESS: Requires business auth + userIdentifier in request
- If CLAIM_BY_SYSTEM: Server-to-server only, requires tenant API key
    Enum: "CLAIM_BY_USER", "CLAIM_BY_SYSTEM", "CLAIM_BY_BUSINESS"

  - `included.campaign.trigger.maxMultiplier` (number)
    Campaign trigger max multiplier

  - `included.campaign.trigger.completionThreshold` (number)
    Campaign trigger completion threshold. This indicates the number of completions required before the reward is granted

  - `included.campaign.trigger.maxTotal` (number)
    Campaign trigger max total completions across all users

  - `included.campaign.trigger.maxPerDayTotal` (number)
    Campaign trigger max total completions per day across all users

  - `included.campaign.trigger.maxPerSource` (number)
    Maximum claims per trigger source for this campaign. Limits how many times each individual trigger source can be used.

  - `included.campaign.trigger.conditions` (array)
    Campaign trigger conditions

  - `included.campaign.trigger.conditions.conditionType` (string, required)
    Trigger condition type
    Enum: "EQUALS", "NOT_EQUALS", "GREATER_THAN", "LESS_THAN", "CONTAINS", "IS_PART_OF"

  - `included.campaign.trigger.conditions.value` (object, required)
    Trigger condition value

  - `included.campaign.trigger.conditions.key` (string, required)
    Trigger condition key

  - `included.campaign.trigger.sourceLogic` (string)
    Source logic type defining how multiple trigger sources combine to activate the flow
    Enum: "any"

  - `included.campaign.trigger.id` (string, required)
    Campaign trigger id

  - `included.campaign.tokenUnits` (array, required)

  - `included.campaign.tokenUnits.id` (string, required)
    Database UUID for this token unit

  - `included.campaign.tokenUnits.token` (object, required)
    The token contract this unit references

  - `included.campaign.tokenUnits.token.id` (string, required)
    Database UUID for this token contract entity

  - `included.campaign.tokenUnits.token.contractAddress` (string, required)
    Smart contract address deployed on the blockchain

  - `included.campaign.tokenUnits.token.metadata` (array)
    Token metadata templates - blueprints used when minting NFTs. Each template defines properties (name, image, expiry) and has a unique tokenMetadataIncrementalId. Null for ERC20 (Points) tokens.

  - `included.campaign.tokenUnits.token.metadata.ownerBusinessId` (string)
    Optional owner business ID. If set, this token metadata belongs to a specific business. If null, the token metadata is tenant-owned (system-level).

  - `included.campaign.tokenUnits.token.metadata.isActive` (boolean)
    Whether this template is active and can be used for minting

  - `included.campaign.tokenUnits.token.metadata.imageUrl` (string)
    This is the URL to the image of the item. Can be just about any type of image (including SVGs, which will be cached into PNGs by OpenSea), IPFS or Arweave URLs or paths. We recommend using a minimum 3000 x 3000 image.

  - `included.campaign.tokenUnits.token.metadata.externalUrl` (string)
    This is the URL that will appear below the asset's image

  - `included.campaign.tokenUnits.token.metadata.description` (string)
    A human-readable description of the item. Markdown is supported.
**ERC721 Template Interpolation:** Supports `{{placeholder}}` syntax for dynamic personalization at mint time (without AI costs).
**Available placeholders:**
- `{{user.firstName}}`, `{{user.lastName}}` - User data
- `{{campaign.name}}`, `{{business.displayName}}` - Campaign/business
- `{{context.xxx}}` - Dynamic context values (TriggerSource.context or claim request)
- `{{defaults.xxx}}` - Default values from defaultPromptContext

**Example:** `"Thank you {{user.firstName}} for visiting {{business.displayName}}! Your exclusive reward for {{context.eventName}}."`
**Processing order:** Template interpolation runs first, then AI processing (if configured) can further enhance the result.

  - `included.campaign.tokenUnits.token.metadata.name` (string)
    Name of the item.
**ERC721 Template Interpolation:** Supports `{{placeholder}}` syntax for dynamic personalization at mint time (without AI costs).
**Available placeholders:**
- `{{user.firstName}}`, `{{user.lastName}}` - User data
- `{{campaign.name}}`, `{{business.displayName}}` - Campaign/business
- `{{context.xxx}}` - Dynamic context values (TriggerSource.context or claim request)
- `{{defaults.xxx}}` - Default values from defaultPromptContext

**Example:** `"Welcome {{context.guestName}} - VIP Pass"` or `"{{user.firstName}}'s {{campaign.name}} Reward"`
**Processing order:** Template interpolation runs first, then AI processing (if configured) can further enhance the result.

  - `included.campaign.tokenUnits.token.metadata.validityType` (string)
    **ERC721 only** - Validity type defines how token expiry is calculated. Use with validityDuration for relative types. Ignored for ERC1155 tokens.
    Enum: "fixed_date", "days_from_issuance", "hours_from_issuance", "months_from_issuance", "end_of_month", "end_of_year", "trigger_date", "trigger_date_range", "days_from_trigger", "hours_from_trigger"

  - `included.campaign.tokenUnits.token.metadata.validityDuration` (number)
    **ERC721 only** - Duration in days or hours (used with days_from_issuance, hours_from_issuance validity types). Ignored for ERC1155 tokens.
    Example: 30

  - `included.campaign.tokenUnits.token.metadata.expiryDate` (string)
    Fixed expiry date (used with fixed_date validity type). For other validity types, this is computed at issuance time.

  - `included.campaign.tokenUnits.token.metadata.animationUrl` (string)
    A URL to a multi-media attachment for the item. The file extensions GLTF, GLB, WEBM, MP4, M4V, OGV, and OGG are supported, along with the audio-only extensions MP3, WAV, and OGA. Animation_url also supports HTML pages, allowing you to build rich experiences and interactive NFTs using JavaScript canvas, WebGL, and more. Scripts and relative paths within the HTML page are now supported. However, access to browser extensions is not supported.

  - `included.campaign.tokenUnits.token.metadata.youtubeUrl` (string)
    A URL to a YouTube video (only used if animation_url is not provide

  - `included.campaign.tokenUnits.token.metadata.creatorAccountAddress` (string)
    Creator Address

  - `included.campaign.tokenUnits.token.metadata.previewUrl` (string)
    Preview Url

  - `included.campaign.tokenUnits.token.metadata.tags` (array)
    Tags for categorization and filtering
    Example: ["summer","vip","limited-edition"]

  - `included.campaign.tokenUnits.token.metadata.aiPromptConfigs` (array)
    **ERC721 only** - AI prompt configurations for dynamic content generation at mint time.
AI processing runs AFTER template interpolation, so prompts can reference already-interpolated values.
Results are mapped by key to override static fields (name, description, imageUrl). Ignored for ERC1155 tokens.
**Note:** For simple personalization without AI costs, use `{{placeholder}}` syntax directly in name/description fields instead.
    Example: [{"type":"TEXT_GENERATION","key":"name","prompt":"Generate a unique reward name for {{user.firstName}} at {{business.displayName}}"},{"type":"IMAGE_GENERATION","key":"imageUrl","prompt":"A {{defaults.…

  - `included.campaign.tokenUnits.token.metadata.aiPromptConfigs.type` (string, required)
    Type of AI operation to perform
    Enum: "TEXT_GENERATION", "IMAGE_GENERATION"

  - `included.campaign.tokenUnits.token.metadata.aiPromptConfigs.key` (string, required)
    Key to store the generated result under
    Example: name

  - `included.campaign.tokenUnits.token.metadata.aiPromptConfigs.prompt` (string, required)
    The prompt to send to the AI model. Supports dynamic placeholders that are replaced with context values.
**Available Placeholders:**
- `{{user.firstName}}`, `{{user.lastName}}`, `{{user.email}}` - User profile data
- `{{campaign.name}}`, `{{campaign.description}}` - Campaign data
- `{{tenant.projectName}}`, `{{tenant.projectDescription}}` - Tenant/project data
- `{{business.displayName}}`, `{{business.name}}` - Business data
- `{{triggerSource.name}}`, `{{triggerSource.type}}` - Trigger source data
- `{{redemption.name}}`, `{{redemption.description}}` - Redemption data
- `{{context.xxx}}` - Dynamic context from TriggerSource.context or CampaignClaimRequest.context
- `{{defaults.xxx}}` - Default values from TokenMetadata.defaultPromptContext

**Context Sources:**
1. TriggerSource.context (admin QR/NFC) - Always applied
2. CampaignClaimRequest.context (user API) - Only if allowExternalContextOverwrite=true
3. TokenMetadata.defaultPromptContext - Always applied as fallback

**Examples:**
- `"Generate a welcome message for {{user.firstName}} at {{business.displayName}}"`
- `"Create a VIP badge for guest {{context.guestName}} in room {{context.roomNumber}}"`
- `"Design a {{defaults.style}} reward image for {{campaign.name}}"`
    Example: Generate a unique reward name for {{user.firstName}} visiting {{business.displayName}}

  - `included.campaign.tokenUnits.token.metadata.allowExternalContextOverwrite` (boolean)
    **ERC721 only** - Allow USER-PROVIDED external context from claim/redeem requests to be used in template interpolation and AI prompts.
**Security model:**
- `false` (default): Only admin-controlled context (TriggerSource.context, Redemption.context, defaultPromptContext) is available
- `true`: User-provided context from API requests is also merged and available as `{{context.xxx}}`

**Note:** Admin-controlled context (QR/NFC data) is ALWAYS applied regardless of this flag.
    Example: true

  - `included.campaign.tokenUnits.token.metadata.defaultPromptContext` (object)
    **ERC721 only** - Default context values for template interpolation and AI prompts. Available as `{{defaults.xxx}}` placeholders.
Always applied regardless of allowExternalContextOverwrite. Use for brand defaults, styling preferences, or fallback values.
**Example usage in name:** `"{{defaults.brand}} - {{user.firstName}}'s Reward"`
    Example: {"brand":"PERS Rewards","style":"minimal","defaultLocation":"Online"}

  - `included.campaign.tokenUnits.token.metadata.businessIds` (array)
    Business IDs where this token can be redeemed/spent. Empty array means any business in the tenant.
    Example: ["business-uuid-1","business-uuid-2"]

  - `included.campaign.tokenUnits.token.metadata.webhookId` (string)
    **ERC721 only** - Webhook ID for dynamic data fetch at mint time.
If set, the webhook is executed before metadata generation and response data is merged into the NFT.
**Use cases:**
- Fetch guest data from PMS/CRM systems
- Get real-time pricing or availability
- Retrieve user-specific content from external APIs

**Processing order:** Webhook fetch runs AFTER template interpolation but BEFORE AI processing.
    Example: webhook-uuid-for-pms-lookup

  - `included.campaign.tokenUnits.token.metadata.webhookPayloadTemplate` (object)
    **ERC721 only** - Payload template for webhook request.
Supports `{{placeholder}}` interpolation with same context as AI prompts.
**Example:**

```json
{
  "userId": "{{user.id}}",
  "campaignId": "{{campaign.id}}",
  "bookingId": "{{context.bookingId}}"
}
```
    Example: {"userId":"{{user.id}}","bookingId":"{{context.bookingId}}"}

  - `included.campaign.tokenUnits.token.metadata.webhookFieldMapping` (object)
    **ERC721 only** - Field mapping from webhook response to metadata fields.
Keys are webhook response paths (dot notation for nested), values are target field names.
**Mapping rules:**
- Explicit mapping: `"response.path": "targetField"`
- Known fields (name, description, imageUrl): auto-mapped if present
- Unknown fields or `"attributes"` target: become NFT attributes

**Example:**

```json
{
  "guestName": "name",
  "data.guest.image": "imageUrl",
  "roomNumber": "attributes",
  "checkInDate": "attributes"
}
```
If null/undefined, uses auto-mapping.
    Example: {"guestName":"name","roomNumber":"attributes","data.image":"imageUrl"}

  - `included.campaign.tokenUnits.token.metadata.consumable` (boolean)
    Whether this token template is consumable (burned on redemption) or collectible (transferred). Applies to ERC1155 and ERC721 only — ERC20 is always transferred. When true, the token is destroyed (burn) when used as payment in a redemption. Defaults to true — most token templates are consumable. Set to false for collectible/non-burning use cases. Mirrored as a consumable attribute in the on-chain IPFS metadata.

  - `included.campaign.tokenUnits.token.metadata.id` (string, required)
    Database UUID for this token metadata template

  - `included.campaign.tokenUnits.token.metadata.animationWeb3StorageUrl` (string)
    IPFS/Arweave URL for animation file - immutable web3 storage

  - `included.campaign.tokenUnits.token.metadata.imageWeb3StorageUrl` (string)
    IPFS/Arweave URL for image - immutable web3 storage

  - `included.campaign.tokenUnits.token.metadata.web3StorageUrl` (string)
    IPFS/Arweave URL for complete metadata JSON - this URL is stored on-chain and links to off-chain metadata

  - `included.campaign.tokenUnits.token.metadata.tokenMetadataIncrementalId` (number, required)
    Incremental ID within the token contract. For ERC1155: becomes the on-chain tokenId. For ERC721: lookup key for template to generate unique metadata.

  - `included.campaign.tokenUnits.token.metadata.approval` (object, required)
    Approval metadata for this token metadata.

  - `included.campaign.tokenUnits.token.metadata.mintCount` (number)
    Total number of mints for this token metadata (via ?include=mintCount). Counts SUCCEEDED MINT transactions using tokenMetadataIncrementalId. Accurate for both ERC1155 and ERC721 (post v2.3.49). Historical ERC721 transactions before v2.3.49 are not counted.

  - `included.campaign.tokenUnits.token.metadata.burnCount` (number)
    Total number of burns for this token metadata (via ?include=burnCount). Counts SUCCEEDED BURN transactions using tokenMetadataIncrementalId. Accurate for both ERC1155 and ERC721 (post v2.3.49). Historical ERC721 transactions before v2.3.49 are not counted.

  - `included.campaign.tokenUnits.token.metadata.included` (object)
    Included related entities. Only populated when include parameter is specified.

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness` (object)

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.id` (string, required)
    The id of the business, this is unique and will be used to identify the business.

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.email` (string, required)
    The email of the business, this is unique and will be used to identify the business.

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.accountAddress` (string, required)
    The address of the business, this is the address that will be shown to the public.

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.currentSigningAccountId` (string, required)
    Current active signing account ID for external wallet operations

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.wallets` (array, required)
    Business-owned counterfactual smart contract wallets that can receive tokens

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.businessLegalName` (string, required)
    The legal name of the business, this is the name that will be used for legal purposes.

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.registrationNumber` (string, required)
    The business registration number (e.g., company registration, VAT number, EIN)

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.displayName` (string, required)
    The display name of the business, this is the name that will be shown to the public.

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.description` (string, required)
    The description of the business, this is the description that will be shown to the public.

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.shortDescription` (string, required)
    The short description of the business, this is the description that will be shown to the public.

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.websiteUrl` (string, required)
    The website of the business, this is the website that will be shown to the public.

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.imageUrl` (string, required)
    The image of the business, this is the image that will be shown to the public.

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.logoUrl` (string, required)
    Logo URL for the business

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.streetAddress` (string, required)
    The address of the business, this is the address that will be shown to the public.

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.phoneNumber` (string, required)
    The phone number of the business.

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.neighborhood` (string, required)
    Neighborhood/area name (e.g., "West Bay", "Pearl Qatar", "Lusail") - auto-populated from geocoding

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.district` (string, required)
    District/administrative area - auto-populated from geocoding

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.city` (string, required)
    The city of the business, this is the city that will be shown to the public.

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.postalCode` (string, required)
    The postal code of the business, this is the postal code that will be shown to the public.

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.country` (string, required)
    The country of the business (auto-populated from geocoding if coordinates provided)

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.countryCode` (string, required)
    ISO 3166-1 alpha-2 country code (e.g., QA, US, AE) - auto-populated from geocoding
    Example: QA

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.coordsLatitude` (number, required)
    The latitude of the business, this is the latitude that will be shown to the public.

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.coordsLongitude` (number, required)
    The longitude of the business, this is the longitude that will be shown to the public.

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.businessType` (object, required)
    The business type of the business, this is the business type that will be shown to the public.

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.isActive` (boolean, required)
    The status of the business, this is the status that will be shown to the public.

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.approval` (object, required)
    Approval metadata for this business.

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.canMintToken` (boolean, required)
    The ability to mint token for the business, this is the ability that will be shown to the public.

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.canChargeToken` (boolean, required)
    The ability to charge token for the business, this is the ability that will be shown to the public.

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.canManageUsers` (boolean, required)
    The ability to manage users for the business, this is the ability that will be shown to the public.

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.canReceiveDonation` (boolean, required)
    The ability to receive donation for the business, this is the ability that will be shown to the public.

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.tags` (array, required)
    Tags for categorization and filtering

  - `included.campaign.tokenUnits.token.metadata.included.ownerBusiness.customData` (object, required)
    Custom business data including Google Places information (placeID, currentOpeningHours)
    Example: {"placeID":"ChIJN1t_tDeuEmsRUsoyG83frY4","currentOpeningHours":{"open_now":true,"weekday_text":["Monday: 9:00 AM – 5:00 PM","Tuesday: 9:00 AM – 5:00 PM"]}}

  - `included.campaign.tokenUnits.token.metadata.included.token` (object)
    Parent token contract info (via ?include=token)

  - `included.campaign.tokenUnits.token.metadata.included.token.chainId` (number)
    Blockchain chain ID (mainnet or testnet)

  - `included.campaign.tokenUnits.token.metadata.included.token.contractAddress` (string)
    Smart contract address

  - `included.campaign.tokenUnits.token.metadata.included.token.type` (string)
    Token type (ERC721, ERC1155)

  - `included.campaign.tokenUnits.token.abi` (object, required)
    this is the abi of the contract, this is the interface of the contract to interact with it

  - `included.campaign.tokenUnits.token.chainId` (number, required)
    this is the chain id of the chain where the token is deployed

  - `included.campaign.tokenUnits.token.abiUrl` (string, required)
    this is the url of the abi of the contract, to be used to fetch the abi of the contract

  - `included.campaign.tokenUnits.token.name` (string)
    this is the name of the token contract

  - `included.campaign.tokenUnits.token.symbol` (string)
    this is the symbol of the token contract, this is optional and can be null

  - `included.campaign.tokenUnits.token.decimals` (number)
    this is the decimals of the token. This is optional and only used for ERC20 tokens (Points)

  - `included.campaign.tokenUnits.token.isActive` (boolean, required)
    This can be used to enable or disable the token

  - `included.campaign.tokenUnits.token.isGallery` (boolean, required)
    This can be used to enable or disable the token for gallery

  - `included.campaign.tokenUnits.token.type` (string, required)
    This is the underlying web3 native type of the token contract
    Enum: "ERC20", "ERC1155", "ERC721"

  - `included.campaign.tokenUnits.token.stampToken` (boolean, required)
    When true, this ERC1155 contract is used as a shared stamp contract. TokenMetadata entries are auto-provisioned per business and can be referenced in redemption priceTokenUnits with resolveByBusiness=true.

  - `included.campaign.tokenUnits.tokenMetadataIncrementalId` (number)
    Token metadata template ID. For ERC1155: becomes on-chain tokenId. For ERC721: lookup key for template to generate unique metadata.

  - `included.campaign.tokenUnits.amount` (number, required)
    Amount of tokens to mint/transfer. For ERC721 this is typically 1, for ERC1155/ERC20 can be any quantity.

  - `included.campaign.tokenUnits.maxAmount` (number)
    Token unit max amount. Applies to MINT/EARN contexts only (e.g. campaign reward capping where user earns tokens per revenue spent). Ignored for spend/transfer contexts such as redemption priceTokenUnits.

  - `included.campaign.businessEngagements` (array, required)

  - `included.campaign.businessEngagements.id` (string, required)
    id

  - `included.campaign.businessEngagements.shortDescription` (number, required)
    A short description of the business engagement with indications what to do etc

  - `included.campaign.businessEngagements.businessIds` (array, required)
    Business IDs associated with this engagement. Use CampaignDTO.included.businesses for full entities.

  - `included.campaign.businessEngagements.businesses` (array, required)
    Businesses (DEPRECATED: use businessIds + CampaignDTO.included.businesses instead. Will be removed in Q2 2026)
    Example: [{"id":"business-uuid-1"},{"id":"business-uuid-2"}]

  - `included.campaign.businessEngagements.campaignId` (string, required)
    Campaign id

  - `included.campaign.businessEngagements.maxPerBusiness` (number, required)
    max per business, the maximum number of times a user can engage with the buisness in the campaign

  - `included.campaign.businessEngagements.maxPerDay` (number, required)
    max per day, the maximum number of times a user can engage with the buisness in the campaign per day

  - `included.campaign.businessEngagements.externalUrl` (string, required)
    The external URL for the business engagement, e.g. a link to a website or app

  - `included.campaign.triggerSourceIds` (array, required)
    Trigger source IDs. Use to batch fetch or request via ?include=triggerSources
    Example: ["trigger-uuid-1","trigger-uuid-2"]

  - `included.campaign.included` (object)
    Included related data. Only populated when include parameter is specified.

  - `included.campaign.included.claimCount` (number)
    Total number of claims for this campaign (via ?include=claimCount)

  - `included.campaign.included.triggerSources` (array)
    Full trigger source entities (via ?include=triggerSources)

  - `included.campaign.included.triggerSources.type` (string, required)
    Type of trigger source - HOW to claim rewards.
**Available Types:**
- `QR_CODE`: Physical QR code scan. App opens camera, decodes QR, extracts triggerSourceId
- `NFC_TAG`: NFC tag tap. App activates NFC reader, reads tag data
- `GPS_GEOFENCE`: GPS-based geofence. App sends user coordinates for proximity validation
- `API_WEBHOOK`: Server-to-server webhook. External system triggers claim via API
- `TRANSACTION`: Purchase/transaction triggered. Claim activated by payment events

**Important:** This defines HOW claims are triggered (the touchpoint mechanism).
NOT to be confused with CampaignTriggerType which defines WHO can claim (CLAIM_BY_USER, CLAIM_BY_BUSINESS, CLAIM_BY_SYSTEM).
**App Integration:**

```typescript
const triggerTypes = campaign.included?.triggerSources?.map(ts => ts.type);
// Based on types, show appropriate UI (camera for QR, NFC prompt, location request, etc.)
```
    Enum: "QR_CODE", "NFC_TAG", "API_WEBHOOK", "GPS_GEOFENCE", "TRANSACTION"

  - `included.campaign.included.triggerSources.name` (string, required)
    Human-readable name for the trigger source
    Example: Main Entrance QR Code

  - `included.campaign.included.triggerSources.description` (number)
    Optional description explaining this trigger source
    Example: QR code located at the main entrance for visitor check-in

  - `included.campaign.included.triggerSources.context` (object)
    **ERC721 only** - Admin-controlled dynamic context for template interpolation and AI prompts. This data is ALWAYS applied (not subject to allowExternalContextOverwrite).
**Template Interpolation:** Values become available as `{{context.keyName}}` placeholders in TokenMetadata name/description fields and AI prompts.
**Special validity keys:**
- `validityDate` - Base date for trigger-based validity
- `validityEndDate` - End date for date ranges (e.g., hotel checkout)
- `validityDuration` - Override duration in days/hours

**Custom keys:** Any arbitrary key becomes `{{context.keyName}}` placeholder.
**Use cases:**
- QR at hotel room: `{ location: "Room 305", roomType: "Suite" }`
- NFC at event entrance: `{ eventName: "Summer Festival", zone: "VIP" }`
- Kiosk-specific: `{ deviceId: "kiosk-001", branch: "Downtown" }`
    Example: {"location":"Main Lobby","deviceId":"kiosk-001","validityDate":"2026-04-20T11:00:00Z"}

  - `included.campaign.included.triggerSources.maxUsage` (number)
    Maximum usage limit. null=unlimited, 1=single-use (receipt), 100=limited edition. Usage count calculated from claims via CQRS.
    Example: null

  - `included.campaign.included.triggerSources.businessId` (number)
    Reference to the business that owns this trigger source. Optional - can be tenant-wide trigger sources
    Example: business-uuid-123

  - `included.campaign.included.triggerSources.coordsLatitude` (number)
    Latitude. Geographic coordinates for location-based trigger validation.
**Universal Location Support:** ANY trigger type can use proximity validation (GPS_GEOFENCE, QR_CODE, NFC_TAG, API_WEBHOOK, TRANSACTION).
**Location Resolution Priority:**
1. TriggerSource coordinates (if set)
2. Business coordinates (if businessId exists)
3. Neither - No location validation

Distance constraints defined in CampaignTrigger.maxGeoDistanceInMeters. Both latitude and longitude must be provided together.
**Geocoding behavior:** Changing coords will auto-update address fields. To adjust pin position without changing address (e.g., parking entrance), set BOTH coordinates AND address fields in the same request.
    Example: 47.6062

  - `included.campaign.included.triggerSources.coordsLongitude` (number)
    Longitude. Geographic coordinates for location-based trigger validation.
**Universal Location Support:** ANY trigger type can use proximity validation (GPS_GEOFENCE, QR_CODE, NFC_TAG, API_WEBHOOK, TRANSACTION).
**Location Resolution Priority:**
1. TriggerSource coordinates (if set)
2. Business coordinates (if businessId exists)
3. Neither - No location validation

Distance constraints defined in CampaignTrigger.maxGeoDistanceInMeters. Both latitude and longitude must be provided together.
    Example: -122.3321

  - `included.campaign.included.triggerSources.streetAddress` (string)
    Street address (auto-populated from geocoding if coordinates provided)
    Example: 123 Main Street

  - `included.campaign.included.triggerSources.neighborhood` (string)
    Neighborhood/area name (e.g., "West Bay", "Pearl Qatar", "Lusail") - auto-populated from geocoding
    Example: West Bay

  - `included.campaign.included.triggerSources.district` (string)
    District/administrative area - auto-populated from geocoding
    Example: Doha Municipality

  - `included.campaign.included.triggerSources.city` (string)
    City. Auto-populated from geocoding if only coordinates provided. **Geocoding behavior:** Changing address fields will auto-update coordinates. To adjust pin without changing address, set BOTH coords AND address fields.
    Example: Doha

  - `included.campaign.included.triggerSources.postalCode` (string)
    Postal code (auto-populated from geocoding if coordinates provided)
    Example: 12345

  - `included.campaign.included.triggerSources.country` (string)
    Country (auto-populated from geocoding if coordinates provided)
    Example: Qatar

  - `included.campaign.included.triggerSources.countryCode` (string)
    ISO 3166-1 alpha-2 country code (auto-populated from geocoding)
    Example: QA

  - `included.campaign.included.triggerSources.id` (string, required)
    Unique identifier for the trigger source
    Example: source-12345

  - `included.campaign.included.triggerSources.isActive` (boolean, required)
    Whether this trigger source is currently active. Inactive sources won't trigger any flows
    Example: true

  - `included.campaign.included.triggerSources.isExhausted` (boolean, required)
    Whether this trigger source has been exhausted (agotado). Set via CQRS when claim count reaches maxUsage.

  - `included.campaign.included.triggerSources.createdAt` (object, required)
    Timestamp when the trigger source was created
    Example: 2024-01-01T12:00:00.000Z

  - `included.campaign.included.triggerSources.updatedAt` (object, required)
    Timestamp when the trigger source was last updated
    Example: 2024-01-10T12:00:00.000Z

  - `included.campaign.included.businesses` (array)
    Full business entities for all businessEngagements (via ?include=businesses)

  - `included.user` (object)

  - `included.user.id` (string, required)

  - `included.user.email` (string)

  - `included.user.identifierEmail` (string, required)
    Universal identifier email for deterministic operations. Generated from B2B inputs (email, externalId) for wallet salt generation and external integrations.
    Example: user123@user.pers.internal

  - `included.user.firstName` (string, required)
    User first name

  - `included.user.lastName` (string, required)
    User last name

  - `included.user.externalId` (string, required)
    User external id

  - `included.user.accountAddress` (string, required)
    User account address

  - `included.user.instagramAccountId` (string, required)
    Instagram account id

  - `included.user.googleAccountName` (string, required)
    Google account name

  - `included.user.customData` (object, required)
    Custom data

  - `included.user.publicProfile` (object, required)
    Public profile data

  - `included.user.isActive` (boolean, required)
    Is active

  - `included.user.currentSigningAccountId` (string)
    Current active signing account ID for external wallet operations

  - `included.user.wallets` (array, required)
    User-owned counterfactual smart contract wallets that can receive tokens

  - `included.user.wallets.id` (string, required)
    Unique identifier for the internal wallet

  - `included.user.wallets.ownerType` (string, required)
    Owner type for polymorphic ownership
    Enum: "user", "business", "tenant", "system", "external"

  - `included.user.wallets.ownerId` (string, required)
    Owner ID for polymorphic ownership
    Example: user_123

  - `included.user.wallets.walletManagementType` (string, required)
    Type of internal wallet
    Enum: "custodial", "non-custodial"

  - `included.user.wallets.address` (string, required)
    CREATE2 generated address that can receive tokens

  - `included.user.wallets.chainId` (number, required)
    Blockchain network chain identifier

  - `included.user.wallets.status` (string, required)
    Current status of the wallet
    Enum: "pending", "active", "suspended", "archived"

  - `included.user.wallets.ownerSigningAccountId` (string)
    ID of signing account that owns this internal wallet

  - `included.user.wallets.tags` (array, required)
    Tags associated with the wallet for categorization

  - `included.user.wallets.createdAt` (string, required)
    Timestamp when the wallet was created

  - `included.user.wallets.updatedAt` (string, required)
    Timestamp when the wallet was last updated

  - `included.user.createdAt` (string, required)
    Timestamp when the user was created

  - `included.user.updatedAt` (string, required)
    Timestamp when the user was last updated

  - `included.user.registrationSource` (object)
    Registration source tracking for analytics - captures channel and attribution when user was created
    Example: {"channel":"web","medium":"referral","campaign":"launch_2026"}

  - `included.user.lastActivityAt` (string)
    Last activity timestamp. Updated whenever user generates tokens (login or refresh). Tracks last time user was active (~1 hour precision).

  - `included.user.activityCount` (number)
    Total activity count. Increments on every token generation (login + refresh). Measures true user engagement.
    Example: 42

  - `included.user.included` (object)
    Included related entities. Only populated when include parameter is specified.

  - `included.user.included.statusTypes` (array)
    User status types earned based on token balances (via ?include=status)

  - `included.user.included.statusTypes.name` (string, required)
    User Status Type name

  - `included.user.included.statusTypes.description` (string)
    User Status Type description

  - `included.user.included.statusTypes.minTokenBalance` (string, required)
    User Status Type eligible Token Addresses

  - `included.user.included.statusTypes.discountPercentage` (number, required)
    User Status Type discount Rate in percentage

  - `included.user.included.statusTypes.imageUrl` (string)
    User Status Type image Url

  - `included.user.included.statusTypes.eligibleTokenAddresses` (array)
    Eligible token contract addresses for this status type
    Example: ["0x1234...","0x5678..."]

  - `included.user.included.statusTypes.tags` (array)
    Tags for categorization and filtering
    Example: ["vip","premium","gold"]

  - `included.user.included.statusTypes.order` (number)
    Explicit ordering for status hierarchy (higher = more prestigious). If not set, falls back to minTokenBalance for ordering.
    Example: 100

  - `included.user.included.statusTypes.id` (number, required)
    User Status Type id

  - `included.user.included.tokenBalances` (array)
    Token balances for user wallets (via ?include=balances)

  - `included.user.included.tokenBalances.accountAddress` (string, required)

  - `included.user.included.tokenBalances.tokenBalances` (array, required)

  - `included.user.included.tokenBalances.tokenBalances.contractAddress` (string, required)

  - `included.user.included.tokenBalances.tokenBalances.chainId` (number, required)

  - `included.user.included.tokenBalances.tokenBalances.balance` (number, required)

  - `included.user.included.tokenBalances.tokenBalances.tokenName` (string)

  - `included.user.included.tokenBalances.tokenBalances.tokenSymbol` (string)

  - `included.user.included.tokenBalances.tokenBalances.tokenType` (string, required)

  - `included.user.included.tokenBalances.tokenBalances.tokenId` (string, required)

  - `included.user.included.tokenBalances.tokenBalances.metadataUri` (string, required)

  - `included.user.included.tokenBalances.tokenBalances.metadata` (object, required)
    Token metadata (loaded from IPFS/storage when needed for filtering)

  - `included.transactions` (array)
    Included transaction entities created for this claim

  - `included.transactions.amount` (string, required)
    Transaction amount

  - `included.transactions.id` (string, required)
    Transaction id

  - `included.transactions.tokenAddress` (string, required)
    Transaction token address

  - `included.transactions.contractTokenId` (string, required)
    Transaction token contract id, this is the blockchain contract id of the token

  - `included.transactions.tokenType` (string, required)
    Transaction token type

  - `included.transactions.senderAddress` (string, required)
    Sender address

  - `included.transactions.recipientAddress` (string, required)
    Recipient address

  - `included.transactions.transactionHash` (string, required)
    Transaction hash

  - `included.transactions.type` (string, required)
    Transaction type
    Enum: "MINT", "TRANSFER", "BURN"

  - `included.transactions.triggerProcessType` (string, required)
    Trigger process type
    Enum: "PURCHASE", "SPEND", "TRANSFER", "EARN", "CAMPAIGN_USER_CLAIM", "CAMPAIGN_SYSTEM_CLAIM", "CAMPAIGN_BUSINESS_CLAIM", "REDEMPTION_SPEND", "REDEMPTION_RECEIVE", "REDEMPTION_PRICE_TOKEN_TRANSFER", "MIGRATION", "ADMIN_TRIGGERED", "BUSINESS_TRIGGERED"

  - `included.transactions.triggerProcessId` (string, required)
    Trigger process id, this is the id of the entity that triggered the transaction if applicable (e.g. CampaignUserClaim id)

  - `included.transactions.status` (string, required)
    Transaction status
    Enum: "created", "processing", "pending_signature", "pending_submission", "broadcasted", "succeeded", "failed", "cancelled", "expired"

  - `included.transactions.createdAt` (string, required)
    Transaction creation timestamp

  - `included.transactions.updatedAt` (string, required)
    Transaction last update timestamp

  - `included.transactions.tenantId` (string, required)
    Tenant ID for multi-tenant isolation

  - `included.transactions.chainId` (number, required)
    Blockchain chain ID

  - `included.transactions.senderId` (string, required)
    Sender entity ID (polymorphic reference)

  - `included.transactions.senderOwnerType` (string, required)
    Sender entity type (user, business, system etc.)
    Enum: "user", "business", "tenant", "system", "external"

  - `included.transactions.recipientId` (string, required)
    Recipient entity ID (polymorphic reference)

  - `included.transactions.recipientOwnerType` (string, required)
    Recipient entity type (user, Business, system, etc.)
    Enum: "user", "business", "tenant", "system", "external"

  - `included.transactions.message` (string, required)
    Optional message associated with the transaction, e.g. for error details

  - `included.transactions.engagedBusinessId` (string, required)
    Business commercially involved in this transaction (for stats/reporting)

  - `included.transactions.authorizedSubmitterId` (string, required)
    Entity authorized to submit this transaction (for POS flow security)

  - `included.transactions.authorizedSubmitterType` (string, required)
    Type of entity authorized to submit (USER, BUSINESS, etc.)
    Enum: "user", "business", "tenant", "system", "external"

  - `included.transactions.userCountryCode` (string, required)
    ISO 3166-1 alpha-2 country code derived from IP geolocation

  - `included.transactions.anonymizedIpAddress` (string, required)
    Anonymized IP address (last octet zeroed for privacy)

  - `included.transactions.metadataUri` (string, required)
    IPFS/storage URL for token metadata. For ERC721: unique URI per minted token. For ERC1155: shared URI per token type. Example: ipfs://Qm.../metadata.json
    Example: ipfs://QmXyz123.../metadata.json

  - `included.transactions.tokenMetadataIncrementalId` (number, required)
    Token metadata template ID - stable reference for mint/burn counting. For ERC1155: same as on-chain tokenId. For ERC721: template lookup key (preserved since on-chain ID differs).

  - `included.transactions.issuanceMode` (string)
    Economic issuance mechanism for reward transactions. TENANT_DELEGATED_MINT: master wallet mints. BUSINESS_OWNED_MINT: business owns the token contract. BUSINESS_BALANCE_TRANSFER: business transfers from own wallet balance. Null for non-reward or legacy transactions.
    Enum: "TENANT_DELEGATED_MINT", "BUSINESS_OWNED_MINT", "BUSINESS_BALANCE_TRANSFER"

  - `included.transactions.included` (object)
    Included related entities. Only populated when include parameter is specified. Contains sender, recipient, and/or engaged business entities based on requested relations.

  - `included.transactions.included.sender` (any)
    Included sender entity (User or Business)

  - `included.transactions.included.recipient` (any)
    Included recipient entity (User or Business)

