Create a new trigger source (QR code, NFC tag, webhook, geofence, etc.). Businesses create trigger sources owned by themselves; tenant admins can create shared (tenant-level) trigger sources.
Type of trigger source - HOW to claim rewards.
Available Types:
QR_CODE: Physical QR code scan. App opens camera, decodes QR, extracts triggerSourceIdNFC_TAG: NFC tag tap. App activates NFC reader, reads tag dataGPS_GEOFENCE: GPS-based geofence. App sends user coordinates for proximity validationAPI_WEBHOOK: Server-to-server webhook. External system triggers claim via APITRANSACTION: 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:
const triggerTypes = campaign.included?.triggerSources?.map(ts => ts.type);
// Based on types, show appropriate UI (camera for QR, NFC prompt, location request, etc.)Optional description explaining this trigger source
Type-specific configuration: tokenConfig (override token ID). See TriggerSourceMetadata interface.
{ "tokenConfig": { "tokenId": "1" } }
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 validityvalidityEndDate- 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" }
{ "location": "Main Lobby", "deviceId": "kiosk-001", "validityDate": "2026-04-20T11:00:00Z" }
Maximum usage limit. null=unlimited, 1=single-use (receipt), 100=limited edition. When usage reaches maxUsage, trigger becomes exhausted.
Reference to the business that owns this trigger source. Optional - can be tenant-wide trigger sources
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:
- TriggerSource coordinates (if set)
- Business coordinates (if businessId exists)
- 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.
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:
- TriggerSource coordinates (if set)
- Business coordinates (if businessId exists)
- Neither - No location validation
Distance constraints defined in CampaignTrigger.maxGeoDistanceInMeters. Both latitude and longitude must be provided together.
Street address (auto-populated from geocoding if coordinates provided)
Neighborhood/area name (e.g., "West Bay", "Pearl Qatar", "Lusail") - auto-populated from geocoding
District/administrative area - auto-populated from geocoding
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.
Postal code (auto-populated from geocoding if coordinates provided)
- Mock serverhttps://docs.pers.ninja/_mock/swagger/trigger-sources
- https://api.pers.ninja/v2https://api.pers.ninja/v2/trigger-sources
curl -i -X POST \
https://docs.pers.ninja/_mock/swagger/trigger-sources \
-H 'Authorization: Bearer <YOUR_JWT_HERE>' \
-H 'Content-Type: application/json' \
-d '{
"type": "QR_CODE",
"name": "Main Entrance QR Code",
"description": "QR code located at the main entrance for visitor check-in",
"metadata": {
"tokenConfig": {
"tokenId": "1"
}
},
"context": {
"location": "Main Lobby",
"deviceId": "kiosk-001",
"validityDate": "2026-04-20T11:00:00Z"
},
"maxUsage": 1,
"businessId": "business-uuid-123",
"coordsLatitude": 47.6062,
"coordsLongitude": -122.3321,
"streetAddress": "123 Main Street",
"neighborhood": "West Bay",
"district": "Doha Municipality",
"city": "Doha",
"postalCode": "12345",
"country": "Qatar",
"countryCode": "QA"
}'Trigger source created successfully
Type of trigger source - HOW to claim rewards.
Available Types:
QR_CODE: Physical QR code scan. App opens camera, decodes QR, extracts triggerSourceIdNFC_TAG: NFC tag tap. App activates NFC reader, reads tag dataGPS_GEOFENCE: GPS-based geofence. App sends user coordinates for proximity validationAPI_WEBHOOK: Server-to-server webhook. External system triggers claim via APITRANSACTION: 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:
const triggerTypes = campaign.included?.triggerSources?.map(ts => ts.type);
// Based on types, show appropriate UI (camera for QR, NFC prompt, location request, etc.)Optional description explaining this trigger source
Type-specific configuration: tokenConfig (override token ID). See TriggerSourceMetadata interface.
{ "tokenConfig": { "tokenId": "1" } }
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 validityvalidityEndDate- 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" }
{ "location": "Main Lobby", "deviceId": "kiosk-001", "validityDate": "2026-04-20T11:00:00Z" }
Maximum usage limit. null=unlimited, 1=single-use (receipt), 100=limited edition. Usage count calculated from claims via CQRS.
Reference to the business that owns this trigger source. Optional - can be tenant-wide trigger sources
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:
- TriggerSource coordinates (if set)
- Business coordinates (if businessId exists)
- 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.
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:
- TriggerSource coordinates (if set)
- Business coordinates (if businessId exists)
- Neither - No location validation
Distance constraints defined in CampaignTrigger.maxGeoDistanceInMeters. Both latitude and longitude must be provided together.
Street address (auto-populated from geocoding if coordinates provided)
Neighborhood/area name (e.g., "West Bay", "Pearl Qatar", "Lusail") - auto-populated from geocoding
District/administrative area - auto-populated from geocoding
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.
Postal code (auto-populated from geocoding if coordinates provided)
ISO 3166-1 alpha-2 country code (auto-populated from geocoding)
Whether this trigger source is currently active. Inactive sources won't trigger any flows
Whether this trigger source has been exhausted (agotado). Set via CQRS when claim count reaches maxUsage.
Timestamp when the trigger source was created
{ "type": "QR_CODE", "name": "Main Entrance QR Code", "description": "QR code located at the main entrance for visitor check-in", "metadata": { "tokenConfig": { … } }, "context": { "location": "Main Lobby", "deviceId": "kiosk-001", "validityDate": "2026-04-20T11:00:00Z" }, "maxUsage": null, "businessId": "business-uuid-123", "coordsLatitude": 47.6062, "coordsLongitude": -122.3321, "streetAddress": "123 Main Street", "neighborhood": "West Bay", "district": "Doha Municipality", "city": "Doha", "postalCode": "12345", "country": "Qatar", "countryCode": "QA", "id": "source-12345", "isActive": true, "isExhausted": false, "createdAt": "2024-01-01T12:00:00.000Z", "updatedAt": "2024-01-10T12:00:00.000Z" }