RewardUpdate Payload Samples
These are the JSON payloads a client will receive for all supported variations of the RewardUpdate webhook.
1. Reward — Promo
PVP promo reward issued after scan results are processed.
{
"id": "fc5db27e-352e-43e9-a9c3-d72dbfc88d23",
"timestamp": 1776744008387,
"payload_data": {
"blink_receipt_id": "954d737a-c813-4249-8fab-428338abecff",
"update_type": "reward",
"status": "[pending|complete]",
"client_user_id": "test_user_123",
"reward_id": "dfcd3092-3320-4605-9e29-30dd8bce8d54",
"reward_type": "promo",
"reward_amount": 4,
"promo_ids_updated": [123],
"qualified_promos": [
{
"promo_id": 123,
"title": "Save $4.00 on any ONE (1) One A Day® 110ct+",
"qualified_count": 1,
"promo_amount": 4,
"status": "[pending|accepted|rejected]",
"reason": "REASON_CODE",
"products": [
{
"description": "ONE A DAY",
"price": 5,
"quantity": 1
}
]
}
]
},
"payload_type": "RewardUpdate",
"version": 1
}
-
The top-level promo reward
payload_data.statusfollows this state machine:
-
Each individual promo follows this state machine:

Notes
- All initial promo updates will have top-level
status: pendingand this status will not change in subsequent updates until all individual promo statuses have been resolved reward_amountrepresents the total potential awardable amount at a given time - it is the sum of all promo amounts that are inacceptedorpendingstatesreward_idwill remain constant throughout all related updatespromo_ids_updatedcontains thepromo_idvalues for promos whose status is first reported or changed in this webhook messagequalified_countandpromo_amountrepresent the number of instances of that promo and the total amount for that promo, respectively, that currently, or may in the future, qualify. In the case of a partial qualification, these fields will reflect only the portion that actually qualifiedreasonwill exist only when status ispendingorrejectedproductswill exist only when status ispendingoraccepted
2. Reward — Boost
Google SSV ad reward issued.
{
"id": "1e74a91c-0b63-4158-9d4c-29fe6e1d7fff",
"timestamp": 1776483872691,
"payload_data": {
"blink_receipt_id": "d4f5a8b2-9c3e-4a1f-b7d6-2e8f0c1a3b5d",
"client_user_id": "user-abc-123",
"reward_id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
"update_type": "reward",
"reward_type": "boost",
"reward_amount": 0.25,
"status": "[pending|complete]"
},
"payload_type": "RewardUpdate",
"version": 1
}
Notes
- For hard currency apps only, boosts cannot be paid out immediately after the user completes the ad watch. In this case only, a
pendingstatus will be sent out and then upon the next valid receipt submission, the reward will be paid and a subsequent webhook with statuscompletewill be sent.
3. Reward — Barcode Collection
UGC/barcode collection task reward issued.
{
"id": "1e74a91c-0b63-4158-9d4c-29fe6e1d7fff",
"timestamp": 1776483872691,
"payload_data": {
"blink_receipt_id": "d4f5a8b2-9c3e-4a1f-b7d6-2e8f0c1a3b5d",
"client_user_id": "user-abc-123",
"reward_id": "c3d4e5f6-a7b8-9012-cdef-123456789012",
"update_type": "reward",
"reward_type": "barcode_collection",
"reward_amount": 0.50,
"status": "complete"
},
"payload_type": "RewardUpdate",
"version": 1
}
4. Reward — Base Scan
A paper receipt scan has been accepted and the base scan reward is confirmed.
{
"id": "1e74a91c-0b63-4158-9d4c-29fe6e1d7fff",
"timestamp": 1776483872691,
"payload_data": {
"blink_receipt_id": "bfcf4575-b287-4135-8236-d0eac733f3d0",
"client_user_id": "user-abc-123",
"update_type": "reward",
"status": "complete",
"reward_id": "0bd9a3ff-c79a-4d2a-9aee-0e82d895df81",
"reward_type": "base_scan",
"reward_amount": 0.5
},
"payload_type": "RewardUpdate",
"version": 1
}
Notes
- The base scan
RewardUpdateis sent only after the correspondingReceiptSummaryresolves asaccepted. If the receipt is rejected, no base scan webhook is sent. If the receipt enterspending(error review), the base scan is held until the review concludes.
5. Missed Earnings
Missed earnings request submitted and queued for processing.
{
"id": "251e0d6e-d117-4684-b047-98b6d4896b9f",
"timestamp": 1776458765539,
"payload_data": {
"blink_receipt_id": "d4f5a8b2-9c3e-4a1f-b7d6-2e8f0c1a3b5d",
"client_user_id": "user-abc-123",
"update_type": "missed_earnings",
"status": "[pending|complete]",
"reward_id": "0bd9a3ff-c79a-4d2a-9aee-0e82d895df81",
"reward_amount": 0,
"promo_ids_updated": [123],
"qualified_promos": [
{
"promo_id": 123,
"title": "Save $4.00 on any ONE (1) One A Day® 110ct+",
"qualified_count": 1,
"promo_amount": 4,
"status": "[pending|accepted|rejected]",
"reason": "REASON_CODE",
"products": [
{
"description": "ONE A DAY",
"price": 5,
"quantity": 1
}
]
}
]
},
"payload_type": "RewardUpdate",
"version": 1
}
Notes
- Similar structure and semantics to promo updates but with some notable differences:
- All amounts, promos, and products relate only to incremental earnings that have been preliminarily identified on this receipt in response to the user's corrections and/or supplementary data as part of the Missed Earnings process
- The
reward_amountstarts at 0 rather than the total potential rewardable amount as in promos, and is updated only when one or more promos are resolved asaccepted- this reflects the lower likelihood of missed earnings requests being validated - If a user's missed earnings request does not result in any preliminary incremental qualifications, the only webhook that will be sent out will have top level
status: completeand noqualified_promosarray.
6. Reward — Out-of-Band Correction
A reward manually issued by Actual, tied to an existing receipt but outside of the normal review or promo workflow.
{
"id": "7f3a2b1c-4d5e-6f7a-8b9c-0d1e2f3a4b5c",
"timestamp": 1776483999999,
"payload_data": {
"blink_receipt_id": "bfcf4575-b287-4135-8236-d0eac733f3d0",
"client_user_id": "user-abc-123",
"update_type": "reward",
"status": "complete",
"reward_id": "9ea1b2c3-d4e5-6f7a-8b9c-0d1e2f3a4b5c",
"reward_type": "correction",
"reward_amount": 1.00
},
"payload_type": "RewardUpdate",
"version": 1
}
Notes
correctionrewards are always sent withstatus = complete.- They carry their own unique
reward_idbut share theblink_receipt_idof the receipt they are associated with. - These are issued by Actual manually — no user action triggers them.
Statuses / Reason Codes
For promo and missed earnings updates, these are the possible combinations of status and reason for entries in the qualified_promos array.
| Status | Reason code | Description |
|---|---|---|
accepted | [reason key will not exist in case of full acceptance] | Fully validated |
accepted | ACCEPTED_PARTIAL | Offer was partially validated |
pending | INITIAL | Initial offer match, awaiting downstream updates. |
pending | PENDING_AUTO_REVIEW | Standard happy-path pending — pipeline still running, no risk or review flags raised. |
pending | PENDING_HOLD_PERIOD | Approved and placed in a hold. Varying subrisk levels may be either auto-approved or remain in holding period. |
pending | PENDING_MANUAL_REVIEW | Routed for human review (standard manual, fraud specialist, admin-requested). |
pending | PENDING_MISSING_INFO | Processing paused on missing data (unparsed fields, awaited OCR retry, awaited match). Not user-actionable. |
pending | PENDING_SECONDARY_REVIEW | Already-reviewed submission pulled into senior/QA tier for a second look. Decision can flip. |
pending | PENDING_USER_ACTION_SUPPORT | Support has reached out to the user (clarification or additional images); paused until they respond. |
rejected | REJECTED_DUPLICATE | Receipt or transaction already redeemed/submitted — same user, different user, or anywhere in system. |
rejected | REJECTED_EMAIL_NO_MATCH | No merchant e-receipt email matched within the expected window. |
rejected | REJECTED_FRAUD | Fraud signals — image-forensic flags (screen, edit, banned phrases), ML decision, or generic 'fraud'. |
rejected | REJECTED_MEMBER_OFFER_MAX | Per-offer redemption cap hit. |
rejected | REJECTED_OFFER_NOT_ACTIVATED | Offer wasn't activated/clipped before purchase, or wasn't on the user's list. |
rejected | REJECTED_OFFER_RULES_CHANNEL | Fulfilment channel/medium not eligible (e.g., curbside pickup, ineligible online channel). |
rejected | REJECTED_OFFER_RULES_DATE | Purchase date outside the offer window — before start, after end, or past grace period. |
rejected | REJECTED_OFFER_RULES_ITEM | Eligible product not found, or didn't meet product/quantity/UPC/return conditions. |
rejected | REJECTED_OFFER_RULES_LOCATION | Offer not available in the user's area (state, zip, region). |
rejected | REJECTED_OFFER_RULES_MERCHANT | Merchant unrecognised or ineligible for the offer. |
rejected | REJECTED_OFFER_UNAVAILABLE | Offer no longer available — expired, exhausted, capped, or removed. |
rejected | REJECTED_QUALITY | Receipt image or parsed data inadequate (blurry, incomplete, missing fields, unparseable). User can resubmit a fresh image. |
rejected | REJECTED_RATE_LIMIT | Velocity threshold hit (uploads, redemptions, or dollars in the rate-limit window). Don't expose to end customer. |
rejected | REJECTED_SYSTEM_ERROR | Internal/partner-side error or config issue. |
rejected | REJECTED_USER_BLOCK | User on the partner's blocklist (prior fraud history or other reputation signals). Don't expose to end customer. |
Field Reference
| Field | Type | Description |
|---|---|---|
version | number | Always 1 |
id | string (UUID) | Top-level ID for the webhook |
timestamp | number | Unix timestamp of the reward update in milliseconds |
payload_type | string | Always "RewardUpdate" |
payload_data.blink_receipt_id | string (UUID) | Unique receipt ID |
payload_data.client_user_id | string | The client-specific user identifier, if one was provided during registration or on a subsequent SDK request. Omitted when no value is available. |
payload_data.reward_id | string (UUID) | Unique reward identifier |
payload_data.update_type | string | "reward" or "missed_earnings" |
payload_data.reward_type | string | "promo", "boost", "barcode_collection", "base_scan", "correction" |
payload_data.reward_amount | number | Total dollar amount of the reward (see notes above for meaning in promo and missed_earnings contexts). Always the gross amount — not scaled by userPayoutPercentage. |
payload_data.status | string | "pending", "complete" |
payload_data.promo_ids_updated | number[] | Promo IDs whose status is first reported or changed in this webhook message |
payload_data.qualified_promos.promo_id | number | Identifier of this promo |
payload_data.qualified_promos.title | string | Name of the promotion the user's receipt qualified for |
payload_data.qualified_promos.qualified_count | number | Number of instances of the promo that qualified |
payload_data.qualified_promos.promo_amount | number | Dollar amount of the reward for the specific qualified promo |
payload_data.qualified_promos.status | string | "pending", "accepted", "rejected" |
payload_data.qualified_promos.reason | string | See table of reason codes above |
payload_data.qualified_promos.products.description | string | Product description of the specific qualified promo |
payload_data.qualified_promos.products.price | number | Price of the product(s) associated with the specific qualified promo |
payload_data.qualified_promos.products.quantity | number | Quantity of the product(s) associated with the specific qualified promo |
client_user_id is included in the payload only when a non-empty value was provided by the client during user registration or on a subsequent SDK request (GET /activations or POST /activations/scan_results). If no value has been set, the field is omitted entirely.