Challenge Logs
Challenge Logs are the activity events that drive challenge progress. Every time an end user performs a qualifying action — a purchase, a visit, a workout — your backend sends a Challenge Log entry. The platform aggregates these entries according to the challenge's aggregationMethod and aggregationPeriod, updating the user's Challenge Progress automatically.
Challenge Logs can only be created via the API (CREATE, GET, LIST). They cannot be updated or deleted. Once submitted, a log entry is permanent.
How it works
- User performs an action — a customer places an order, visits a store, or completes any activity your challenge tracks.
- Your backend sends a log — call
POST /schema/challenge_log/recordwith thechallengeId,ownedById,activityAt,uniqueIdentifierandactivityValue(Required whenaggregationMethodof theChallengeschema issum). - Progress updated — This aggregates the new entry into the user's
Challenge Progress, updatingcurrentProgressValueand checking milestone thresholds. - Milestone triggered — if
currentProgressValuecrosses a milestone'smilestoneTargetValue, aReward Logis created andachievedMilestone+achievedMilestoneRewardLogare set on the response. - Challenge completed — if
currentProgressValuereachescompletionTargetValue,challengeProgressStatustransitions tocompleted.
Fields
Required on create
| Field | Type | Required | Description |
|---|---|---|---|
challengeId | UUID | ✅ | ID of the challenge this log contributes to |
ownedById | UUID | ✅ (or use ownedBy) | Gamopanda member ID of the user performing the activity. Use this if the member already exists. |
activityAt | datetime | ✅ | When the activity occurred. Used to determine which aggregation period this log falls into. |
activityId | string | ✅ | Activity Id for this event — e.g. made_a_purchase, visited_website, etc |
uniqueIdentifier | string | ✅ | Unique Identifier for this event — e.g. order_id, transaction_id, review_id, etc |
Optional on create
| Field | Type | Description |
|---|---|---|
activityValue | number | The numeric value of the activity. Required when the challenge uses aggregationMethod: sum (e.g. spend amount, steps, calories). Ignored for count challenges. |
ownedBy | object | Inline member upsert payload. Use instead of ownedById to sync the member in the same request. See syncing a member inline below. |
Status
| Field | Type | Default | Description |
|---|---|---|---|
status | enum | live | draft · live · paused. Only live logs are included in aggregation. |
Extra fields returned in the response
After a log is created, the platform enriches the response with several computed fields:
| Field | Description |
|---|---|
challenge | The full joined Challenge object this log belongs to |
challengeProgress | The user's updated Challenge Progress record after this log was processed |
achievedMilestone | The Milestone record crossed by this log entry, if any. null if no milestone was reached. |
nextMilestone | The next Milestone the user is working toward, if any. null if no further milestones exist. |
achievedMilestoneRewardLog | The Reward Log issued when a milestone was crossed by this entry. null if no milestone was reached. |
These fields make the create response self-contained — your backend can read the updated progress and any earned reward in a single API call without making additional requests.
Handling achievedMilestoneRewardLog
When a milestone threshold is crossed, the platform creates a Reward Log record and returns it as achievedMilestoneRewardLog in the response. At this point the reward log exists but has no coupon code or timestamps yet — your backend is responsible for fulfilling the reward and updating the log.
Reward fulfilment workflow
- Check the response — after
POST /schema/challenge_log/record, inspectachievedMilestoneRewardLog. If it is notnull, a milestone was just crossed. - Generate a coupon — call your coupon or voucher system to issue a reward code for this user.
- Update the reward log —
PATCHthe reward log with the coupon code and timestamps:
Code
Reward log lifecycle
| Step | Fields set | Who sets it |
|---|---|---|
| Milestone crossed | milestoneId, linkedSchemaRecordId, ownedById | Platform (automatic) |
| Reward issued | couponCode, rewardIssuedAt, rewardExpiryAt | Your backend |
Syncing a member inline
Instead of managing a separate upsert call to Member before logging activity, you can pass member details directly in the ownedBy field. The platform will create or update the member record automatically as part of processing the log`.
Use ownedBy (with externalId) instead of ownedById when you want to sync the user and log activity in a single API call:
Code
The platform resolves the member by externalId, upserts their profile with any supplied fields, and uses the resulting member ID as ownedById for the log.
This is the recommended pattern when logging activity from an order or checkout webhook — you get the member sync and the activity log in one request, reducing latency and the risk of a log being submitted before the member record exists.
| Field | Type | Required | Description |
|---|---|---|---|
externalId | string | ✅ | Your system's unique identifier for this user. Used to match or create the member. |
firstName | string | ❌ | Member's first name |
lastName | string | ❌ | Member's last name |
email | ❌ | Member's email address | |
phoneNumber | phone | ❌ | Member's phone number in E.164 format — e.g. +14155552671 |
See Members for full details on member fields and the E.164 phone number format.
The uniqueIdentifier — preventing duplicates
uniqueIdentifier is your system's unique identifier for the triggering event. The platform uses it to idempotently reject duplicate submissions — if you send the same activityId for the same challengeId and ownedById twice, the second request is rejected.
Use whatever identifier uniquely describes the event in your system:
Code
Always pass a stable, unique uniqueIdentifier. If you omit it or pass a generic value, duplicate logs may inflate a user's progress.
Real-world examples
🛍️ E-commerce — sum challenge (monthly spend)
A user spends $87.50 on an order. The challenge aggregates spend with aggregationMethod: sum:
Code
Response:
Code
☕ Food & Beverage — count challenge (monthly visits)
A user's 4th café visit this month. The challenge aggregates visits with aggregationMethod: count:
Code
Response — milestone crossed:
Code
🏋️ Fitness — sum challenge (weekly steps) — challenge completed
A user's final step log pushes them over 100,000 steps, completing the weekly challenge:
Code
Response — challenge completed:
Code
Who can create challenge logs
Challenge Logs are created by your backend server. End users have no write access to this resource.
Code
Access & permissions
| Caller | Allowed operations | Notes |
|---|---|---|
| Admin | CREATE · GET · LIST | Non-editable, Cannot be deleted |
| End user | (none) | No direct access |
| Guest user | (none) | Not accessible |
Challenge Logs cannot be updated or deleted. Once submitted, a log entry is permanent. To correct a mistake, contact support.
Related resources
| Resource | Description |
|---|---|
| Challenge | The parent challenge that defines the rules for aggregation |
| Challenge Progress | The running summary of a user's progress, updated after each log |
| Milestone | Reward checkpoints that fire when currentProgressValue crosses a target |
| Reward Log | Reward entries automatically created when a milestone is crossed |
| Member | The end user (ownedById) whose progress is updated by this log |
API reference
See the API Reference for full request/response schemas and interactive examples for:
POST /schema/challenge_log/record— create a challenge logGET /schema/challenge_log/record— list challenge logsGET /schema/challenge_log/record/{id}— get a challenge log by ID