Skip to documentation

Rewards

Last updated: September 24, 2026.

Reward types define the custom rewards users can earn for completing your studies, such as credits they can use in your product. Workspace owners create them under Rewards → Reward types, with unit labels, whole-unit or two-decimal precision, and an optional monetary value for reporting.

After you create a reward type, its setup pane shows a copyable type ID, an example notification, and an agent prompt for implementing the connection in your product. You can reopen it from the reward type's editor using Set up in your product. Creating a type saves its definition; your server implements the actual reward.

Connect one workspace webhook endpoint and map reward.group.id to the benefit your product grants. When Palette sends participant.reward_earned, your server grants reward.amount units to user_id, once per idempotency_key. The name and unit labels can change, so use the stable ID to select the product benefit. See Webhooks for signature verification and delivery handling, and Verifying identified users for signed user IDs.

Study editors select the type under Reward type on the Rewards slide and choose an amount. Palette sends the notification after automatic qualification or manual approval. The Audience slide selects a separate user group. Built-in USD credit remains available without a custom type and also requires fulfillment in your product.

Before enabling tracked rewards, configure the workspace outbound webhook and use Verify reward-event webhook under Workspace settings → Other → Outbound event webhook. This verifies the workspace endpoint using a generic test, not your custom type's grant logic. The separate panel.invite test does not verify reward support. A test event must never grant a reward.

A study saves the type labels, precision, rate and display currency when selected. Participants keep the terms present at enrollment. Editing labels or rates does not change existing study or enrollment snapshots: explicitly reselect the reward type to adopt changes for future participants. Precision is fixed after the first study selection. Deleted types remain identifiable in historical rewards. Changing display currency clears catalogue rates; enter new rates and reselect where appropriate. Historical currencies are separate, without exchange conversion.

Reward cost means the customer's endpoint acknowledged an instruction. It does not prove receipt or redemption. Money uses the enrollment valuation. Unpriced rewards appear in units and coverage, not as free rewards. Total recorded includes Cost, In flight and Not counted, including cancelled records. Blocked obligations remain in flight. Cancelled obligations that might have reached an endpoint retain their reservation in Not counted. Acknowledged rewards counts records, not unique people. The page states the viewer's timezone, the as-of instant, and the current partial month.

Missing or unverified webhook configuration blocks existing obligations and pauses new rewarded admissions. Restoring and verifying the same destination recovers eligible obligations. An earlier attempted instruction is never automatically replayed to a different destination, even after that endpoint is verified.

Study-level CSV reports exclude acknowledged rewards by default. The explicit “Include acknowledged rewards (reconciliation)” option includes already accepted instructions; do not pay those obligations again. Pending deliveries can still reach the endpoint after any export, so reconcile their status before arranging separate payment. Reports are snapshots, not payment instructions; they grant nothing and change neither delivery nor cost. Saved exports are redacted on erasure. Each row includes acknowledged_at and report_scope (unacknowledged_only or all_eligible_including_acknowledged). API callers opt in with the JSON body {"includeAcknowledged": true} on the study reward CSV POST endpoint.

For custom groups, your handler must grant reward.group units, not infer the unit from the legacy reward.currency field. reward.amount remains a two-decimal string and reward.currency remains USD for compatibility with the event contract. For built-in USD credit these fields describe USD; custom rewards add:

"reward": {
  "type": "credit", "amount": "100.00", "currency": "USD",
  "group": { "id": "immutable-group-uuid", "name": "Study pages",
             "unit": "page", "unit_plural": "pages", "decimal_places": 0 },
  "monetary_value": { "amount": "2.00", "currency": "USD" }
}

monetary_value is reporting metadata, not an additional grant. It is null for unpriced groups. Values are rounded once to currency minor units for the webhook; analytics sums exact frozen valuations before rounding. Built-in rewards omit both new blocks. Handler retries must use the same idempotency key.