RewardUpdate
Description: Triggered when an existing reward is updated.
When to use: Subscribe to this event if you need to update your records when reward data changes.
Sources:
- iOS and Android Mobile SDK reward events are triggered.
Payload Structure:
{
"id": "UUID for webhook message",
"timestamp": 1778077677000,
"payload_data": {
"blink_receipt_id": "UUID - Primary Blink Receipt ID",
"update_type": "[reward|missed_earnings]",
"status": "[pending|complete]",
"reward_id": "uuid",
"reward_type": "[promo|boost|barcode_collection|base_scan|correction]",
"reward_amount": 1.00,
"promo_ids_updated": [123],
"qualified_promos": [
{
"promo_id": 123,
"title": "Name of the promotion the user's receipt qualified for",
"qualified_count": 1,
"promo_amount": 1.00,
"status": "[pending|accepted|rejected]",
"reason": "Reason for status=pending or status=rejected",
"products": [
{
"description": "Product description of the specific qualified promo",
"price": 1.00,
"quantity": 1
}
]
}
],
"client_user_id": "The client-specific user identifier"
},
"payload_type": "RewardUpdate",
"version": 1
}
RewardUpdate never sends null values — fields are either present with a value or omitted entirely.
For promo and missed earnings updates, qualified_promos contains the current full state for all qualifying promos, while promo_ids_updated contains the promo IDs whose status is first reported or changed in that specific webhook message.
Field Reference
payload_data fields
| Field | Type | Required | Nullable | Notes |
|---|---|---|---|---|
blink_receipt_id | string | Always | No | Present on every update for correlation. |
update_type | reward | missed_earnings | Always | No | |
status | pending | complete | Always | No | |
reward_id | string (uuid) | Optional | No | Omitted when absent — e.g. a missed_earnings initial update where all promos were rejected. Always present when update_type = reward. |
reward_type | promo | boost | barcode_collection | base_scan | correction | Optional | No | Only sent when update_type = reward. Always omitted for missed_earnings. correction is an out-of-band reward manually issued by Actual — see below. |
reward_amount | number | Optional | No | Sum of non-rejected promo_amounts. May be omitted for missed_earnings with no promo amount. Always the gross amount — see note below. |
promo_ids_updated | number[] | Optional | No | Only for promo rewards and missed earnings. May be an empty array. |
qualified_promos | object[] | Optional | No | Present only when there is at least one promo entry; omitted otherwise. |
client_user_id | string | Optional | No | Omitted when not provided. |
qualified_promos[] entry fields
| Field | Type | Required | Nullable | Notes |
|---|---|---|---|---|
promo_id | number | Always | No | |
title | string | Always | No | |
qualified_count | number | Always | No | 0 for rejected entries. |
promo_amount | number | Always | No | 0 for rejected entries. |
status | pending | accepted | rejected | Always | No | |
reason | string | Optional | No | Omitted for fully-accepted entries; present for pending, rejected, or partial when a reason exists. |
products | object[] | Optional | No | Omitted entirely for rejected entries. |
products[] entry fields
| Field | Type | Required | Nullable | Notes |
|---|---|---|---|---|
description | string | Always | No | May be an empty string. |
price | number | Always | No | |
quantity | number | Always | No |
Base Scan Lifecycle
The base_scan reward is tied to the receipt's own validation outcome and is no longer sent immediately upon submission.
- If the receipt resolves as accepted (via
ReceiptSummary), aRewardUpdatewithreward_type = base_scanandstatus = completeis sent. - If the receipt resolves as rejected, no
RewardUpdatefor the base scan is sent at all. - If the receipt enters pending (error review), the base scan reward is held until the review concludes and then follows the same accept/reject rule above.
Out-of-Band Corrections
Actual may manually issue a reward tied to a specific receipt at any point — for example, to credit a user outside of the normal review process. These appear as a RewardUpdate with reward_type = correction. They carry their own reward_id but share the same blink_receipt_id as the original receipt.
Contingent Coupons
Some promotions are marked as contingent, meaning they do not auto-approve after the standard 24-hour window. Instead they follow the same longer review trajectory as missed earnings — waiting on a provider decision, with an extended timeout that resolves to rejected if no decision arrives. These promos remain in pending state longer than standard promos; the existing reason codes and state machine apply.
reward_amount is always the gross amount — not adjusted by userPayoutPercentagereward_amount in every RewardUpdate payload reflects the full reward value before any client-side payout scaling is applied.
The userPayoutPercentage SDK setting (configured in BlinkEngageRewardConfig on iOS and RewardCurrency on Android) controls how much of that value is displayed to the user inside the mobile app. It is applied on-device only and has no effect on the amount sent to your webhook endpoint.
Example: If reward_amount is $1.00 and your app's userPayoutPercentage is 0.6, the user sees $0.60 in the app — but your webhook always receives $1.00.
If you use webhook amounts to credit users or reconcile rewards in your backend, apply your own payout percentage logic server-side rather than expecting the webhook to reflect the scaled amount.
