Magic Receipts API
This page describes how to set up and use the Magic Receipts API
OVERVIEW:
Magic Receipts allows users to snap pictures of their grocery receipts and earn awards when their purchases contain promoted product (offers). Offers have specified restrictions such as expiration date, price minimum, store , quantity, and varietal limitations ( must match specific UPCs).
Physical receipt submissions must include a clear photo that contains the entire receipt: Store Name, Date, Product, and Sub-Totals. Receipts must be original and not previously used for another incentivized shopping program.
Upon submission, members will be informed of of success or failure. A success will initiate an Award Pending status. A failure we yield an accompanying Error Code (reason) with an option to resubmit for success or request “Manual Review” (2-3 business days processing time)
There are four possible statuses:
- AWARD_PENDING
- APPROVED
- REJECTED
- MANUAL_REVIEW
Once an offer is APPROVED, it cannot transition to another status. However, a status of the other 3 can be transitioned to a another status.
The API does only return magic receipts offers for US and CA.
CORE FUNCTIONALITY:
A successful Magic Receipts Integration will allow:
- Retrieve current available offers and metadata to display to users
- Retrieve list of supported merchants and associated available offers
- Retrieve list of categories and associated available offers
- MY List - retrieve list of offers that member has indicated as interested in.
- Receipt Upload - Send call to BitLabs with photo, offers indicated, store indicated
- Offer Upload Response
- Offer Status Changes
MAGIC RECEIPTS ENDPOINTS:
- Get access token for magic receipts endpoint requests
- OFFERS LIST: instore-offers-short
- OFFER DETAILS: instore-Offer-Details
- CATEGORIES: Get-Category-Types
- In-Store-Receipt-Validation
- In-Store-Manual-Review
- Get-Instore-Merchants
- Post Offers( My List) Endpoint
- In-Store-Manual-Review-Offer
Get access token for magic receipts
This will return an access token for a user which you need to provide in the magic receipts endpoint requests. A token is only valid for 2 hours and therefore needs to be requested again after it is no longer valid.
curl \
-X GET https://api.bitlabs.ai/v1/client/magic-receipts/access-token \
-H "X-Api-Token: $API_KEY" \
-H "X-User-Id: $API_KEY"
All other endpoint requests have to be made from https://receipts.bitlabs.ai
Generating a token, requires you to have a BitLabs account. You can create one here: https://dashboard.bitlabs.ai/
Instore Offers Short Endpoint
Description
This endpoint gets the list of offers for a logged in member
curl \
-X GET https://receipts.bitlabs.ai/api/instore-offers-short \
-H "Authorization: Bearer <token>"
Response Parameters
Param Name | Value(s) |
---|---|
status | 200 (success), 400 (failure) |
data | array[] of offers. |
Offer Fields
Name | Type | Description |
---|---|---|
addedToList | boolean | if the offer is added to the users list |
anyReceiptEligible | boolean | if the offer is an any receipt these are given special treatment as they will accept any receipt |
bannerImageUrl | string | there are several sizes for images from rectangular to square this is the rectangular ones typically used for a banner |
baseAmount | integer | this is the cashback amount in an integer format |
bonus | object | not really relevant at this time |
buyingOptions | buyingOptions Object | See additional documentation below for buyingOptions |
categoryIDs | integer[] | These are the categories that the offer is included within |
detailUrl | string | this is the url the links to the offer details view |
eligibleMediums | this is an enum[] and will contain either INSTORE or ONLINE | Out of the gate we will only offer support for the INSTORE variant |
expirationDate | a string formatted version of the expiration date | This is the date that the offer expires and is inclusive (if the end date is today then today is still valid) It will look like this expirationDate: "02/14/2024", |
imageUrl | string | Image url for the offer will often coincide with the square image url |
isIncentivized | boolean | Delineates between a high value offer or not. We have house offers that are loss leaders and this is what sets them apart. Typically we add a star to the offer to highlight it’s importance as a higher paid offer. |
isQuantitySelectionEnabled | boolean | We allow users to select the quantity or amount of line items that are on their receipt. If that quantity differs from what we parsed we will send their receipt into manual review for closer inspection. |
line1 | string | This was poorly named but you can think of this as the offer title |
line3 | string | Equally poorly named this is the actual cashback value to the user formatted as "line3": "$4", |
line4 | string | This is the string formatted cashback value in the client currency "line4": "400 SB", |
line6 | string | This is the string formatted cashback value in the client currency with “Cash Back” appended "line6": "$4 Cash Back", |
notManyLeft | boolean | Determines if there aren’t a lot of these offers left. On our O&O we show small “not many left” banner |
offerID | integer | This is the offer id |
purchaseQuantity | integer | This is the minimum required quantity a user will be required to buy to get the offer. Be forewarned a lot of this logic was moved into the buying options which defines if there are multiple goals like “buy 1” or “buy 2” |
redemptionsPerClaim | integer | this has mostly been deprecated |
restrictedToMerchants | boolean | boolean value delineating if this offer is restricted to instore merchants or if it is available at all merchants |
restrictedToMerchantsOnline | boolean | boolean value delineating if this offer is restricted to online merchants or is available at all online merchants At this time online uploads are not supported |
restrictToMerchantsCount | integer | the amount of merchants this offer is restricted to |
restrictToMerchantsShort | a dto[] { "logoUrl": "https://ucontent.prdg.io/img/instore/logos/logo-1.png?v=1694019930000", "merchantID": 1, "merchantName": "Walmart" }, | This will list a sublist of the merchants that the offer is available at with additional data like logos + name + merchantID. Expect this sublist to be variable but presume it to be set at 5. |
shortDescription | string | This is the description of the offer. Expect this to be a few words at most |
showUpTo | boolean | this determines if we should show the “Up To” description on the offer card before the payout amount. ”400 SB” vs ”Up To 400 SB” |
Buying Options Fields
Name | Type | Description |
---|---|---|
awardFormatted | string | The string formatted reward value in the clients currency "awardFormatted": "150 SB", |
cashbackAmount | double | The reward amount in dollars "cashbackAmount": 1.5, |
cashbackFormatted | string | The string formatted reward amount in dollars formatted like so: cashbackFormatted": "$1.50", |
goalDescription | string | This is the description of the goal so there might be a buy1 or a buy 2 and this is the description for it "goalDescription": "Buy 1 pack of SweeTARTS Gummies Fruity Splitz", |
payoutAmount | double | The reward amount in the clients currency "payoutAmount": 400, |
requiredQuantity | integer | This is the required amount of the product that the user is expected to purchase to meet this goal. |
requiredSpendFormatted | Expect to mostly see required quantity. This is a separate kind of goal that requires the user to spend a certain amount on an offer rather than purchase a certain number | |
useGoalDescription | boolean | Typically the goal will look something like the following: Buy any 1 eligible product were we pull in the required quantity. If this is enabled we display the description from the goal instead. In practice this is mostly not used. |
useRequiredSpend | boolean | determines if required spend is used. This is almost never enabled. |
Example Response:
{
"bonus": null,
"data": \[
{
"addedToList": true,
"anyReceiptEligible": false,
"bannerImageUrl": "<https://ucontent.prdg.io/pimages/96/96773959-73c5-4c8c-8cdc-f5178860c012.jpg">,
"baseAmount": 400,
"bonus": null,
"buyingOptions": \[
{
"awardFormatted": "150 SB",
"cashbackAmount": 1.5,
"cashbackFormatted": "$1.50",
"goalDescription": "Buy 1 pack of SweeTARTS Gummies Fruity Splitz",
"payoutAmount": 150,
"requiredQuantity": 1,
"requiredSpendFormatted": null,
"useGoalDescription": false,
"useRequiredSpend": false
},
{
"awardFormatted": "400 SB",
"cashbackAmount": 4,
"cashbackFormatted": "$4",
"goalDescription": "Buy 2 packs of SweeTARTS Gummies Fruity Splitz",
"payoutAmount": 400,
"requiredQuantity": 2,
"requiredSpendFormatted": null,
"useGoalDescription": false,
"useRequiredSpend": false
}
\],
"categoryIDs": \[
13,
18,
40,
44,
45,
8
\],
"detailUrl": "/grocery-receipts/sweetarts-gummies-fruity-splitz-coupon/7045645",
"eligibleMediums": \[
"INSTORE"
\],
"expirationDate": null,
"imageUrl": "<https://ucontent.prdg.io/pimages/b8/b829991d-14c1-406a-bacb-5925ca873518.jpg">,
"isIncentivized": true,
"isQuantitySelectionEnabled": true,
"line1": "SweeTARTS® Gummies Fruity Splitz",
"line3": "$4",
"line4": "400 SB",
"line6": "$4 Cash Back",
"notManyLeft": false,
"offerID": 7045645,
"purchaseQuantity": 1,
"redemptionsPerClaim": 0,
"restrictedToMerchants": true,
"restrictedToMerchantsOnline": false,
"restrictToMerchantsCount": 23,
"restrictToMerchantsShort": \[
{
"logoUrl": "<https://ucontent.prdg.io/img/instore/logos/logo-1.png?v=1694019930000">,
"merchantID": 1,
"merchantName": "Walmart"
},
{
"logoUrl": "<https://ucontent.prdg.io/img/instore/logos/logo-11.png?v=1694019930000">,
"merchantID": 11,
"merchantName": "Ralphs"
},
{
"logoUrl": "<https://ucontent.prdg.io/img/instore/logos/logo-14.png?v=1694019930000">,
"merchantID": 14,
"merchantName": "Smith's Food and Drug"
},
{
"logoUrl": "<https://ucontent.prdg.io/img/instore/logos/logo-2.png?v=1694019931000">,
"merchantID": 2,
"merchantName": "Kroger"
},
{
"logoUrl": "<https://ucontent.prdg.io/img/instore/logos/logo-3.png?v=1694019931000">,
"merchantID": 3,
"merchantName": "Walgreens"
}
\],
"shortDescription": "Double the Fun with SweeTARTS® Gummies Fruity Splitz!",
"showUpTo": true,
"squareImageUrl": "<https://ucontent.prdg.io/pimages/b8/b829991d-14c1-406a-bacb-5925ca873518.jpg">
}
\],
"status": 200
}
Sample Pictures Displaying The Offer List:
Instore Offer Details Endpoint
Description
This endpoint provides additional information about an offer, including its description, images, buying options, and eligibility criteria.
Endpoint
curl \
-X GET https://receipts.bitlabs.ai/api/instore-offer-details&offerID={offerId} \
-H "Authorization: Bearer <token>"
Parameters
Param Name | Value(s) |
---|---|
status | 200 (success), 400 (failure) |
data | array[] of offers. |
Offer Detail Fields
Name | Type | Description |
---|---|---|
addedToList | boolean | if the offer is added to the users list |
allowRawHtml | boolean | this is mostly internal and can be ignored |
anyReceiptEligible | boolean | if the offer is an any receipt these are given special treatment as they will accept any receipt |
awardLookBack | integer | This will mostly only ever be used with the anyReceiptEligible. This is the number of days in the past for which we will still allow the users receipt date |
bannerImageUrl | string | there are several sizes for images from rectangular to square this is the rectangular ones typically used for a banner |
barcodeScanEligible | boolean | You can ignore this for the time being. We have a feature that allows users to submit images are barcodes and use them for redemption |
baseAmount | integer | this is the cashback amount in an integer format |
bonus | object | not really relevant at this time |
buyingOptions | buyingOptions Object | See additional documentation below for buyingOptions |
cap | mostly internal for now | |
categoryIDs | integer[] | These are the categories that the offer is included within |
clippedInReceiptChallenge | boolean | This is internal and can be ignored |
conditions | string | This will display a displaimer about the offer |
detailUrl | string | this is the url the links to the offer details view |
eligibleMediums | this is an enum[] and will contain either INSTORE or ONLINE | Out of the gate we will only offer support for the INSTORE variant |
eligibleProducts | string[] | This is a string[] that contains the eligible products for this offer "eligibleProducts": [ "SweeTARTS® Gummies Fruity Splitz 5oz", "SweeTARTS® Gummies Fruity Splitz 9oz " ], |
eligibleProductsInfo | dto[] | This is an array contains additional eligible product information "eligibleProductsInfo": [ { "imageID": 263025, "imageURL": "https://ucontent.prdg.io/pimages/34/34c8eb65-272e-4508-b38c-1053aa9a06fd.PNG", "name": "SweeTARTS® Gummies Fruity Splitz 5oz", "upc": "079200074593" }, { "imageID": 263026, "imageURL": "https://ucontent.prdg.io/pimages/85/85b8b299-2ad8-4575-9543-7a9bec98264d.PNG", "name": "SweeTARTS® Gummies Fruity Splitz 9oz", "upc": "079200074562" } ], |
expirationDate | a string formatted version of the expiration date | This is the date that the offer expires and is inclusive (if the end date is today then today is still valid) It will look like this expirationDate: "02/14/2024", |
featured | boolean | Determines if this offer is “featured”. Typically featured offers show at the top of the sort list |
imageUrl | string | Image url for the offer will often coincide with the square image url |
impressionScript | string | this is internal and can be ignored |
isIncentivized | boolean | Delineates between a high value offer or not. We have house offers that are loss leaders and this is what sets them apart. Typically we add a star to the offer to highlight it’s importance as a higher paid offer. |
isQuantitySelectionEnabled | boolean | We allow users to select the quantity or amount of line items that are on their receipt. If that quantity differs from what we parsed we will send their receipt into manual review for closer inspection. |
line1 | string | This was poorly named but you can think of this as the offer title |
line2 | string | This is the product description but it is an extremely lengthy variant of it. Expect multiple sentences to a paragraph here "line2": "Tired of choosing between sweet and tart? Now you don't have to! SweeTARTS® Gummies Fruity Splitz brings you the best of both worlds in one delicious gummy. Each chewy piece is bursting with two bold, fruity flavors, one sweet and one tart, for a flavor adventure in every bite. \n\nBuy SweeTARTS® Gummies Fruity Splitz to earn!* \nMaximum Of Two Receipt Submissions Per Week For This Offer.", |
line3 | string | Equally poorly named this is the actual cashback value to the user formatted as "line3": "$4", |
line4 | string | This is the string formatted cashback value in the client currency "line4": "400 SB", |
line5 | string | You can think of this one as a very lengthy offer disclaimer "line5": "*Only purchases of the following products are eligible for SB: \nSweeTARTS® Gummies Fruity Splitz 9oz \nSweeTARTS® Gummies Fruity Splitz 5oz \n\n No other products are eligible for SB. Must purchase at least 1 of the above eligible products to earn SB. \nSB for this offer can only be earned twice per week (Sunday-Saturday), while supplies last. \nNot all products available at all eligible retailers. \nThis offer is subject to change at any time and is available in limited quantities. \nPurchase must be made between January 8, 2024 and March 8, 2024. Receipt must be uploaded by 11:30 pm Pacific Time on March 8, 2024. Purchases made outside of the listed dates are not eligible for SB. \nUploaded receipts are not eligible for SB if linked to other promotions.", |
line6 | string | This is the string formatted cashback value in the client currency with “Cash Back” appended "line6": "$4 Cash Back", |
line7 | string | Disclaimer about how many times the user is eligible to claim the offer |
longDescription | string | A longer offer description |
notManyLeft | boolean | Determines if there aren’t a lot of these offers left. On our O&O we show small “not many left” banner |
offerID | integer | This is the offer id |
pendingDays | integer | Certain new users will have their offers automatically go into award pending. This is a measure to prevent fraud. If after the pending period is up the user will be approved. It is also possible for the user to be rejected out of award pending if their receipt is fraudulent |
purchaseQuantity | integer | This is the minimum required quantity a user will be required to buy to get the offer. Be forewarned a lot of this logic was moved into the buying options which defines if there are multiple goals like “buy 1” or “buy 2” |
receiptChallengeID | integer | This is internal and can be ignored |
rectangleImageUrl | string | Image url for a rectangular image of the offer |
redemptionsPerClaim | integer | this has mostly been deprecated |
referralUrl | string | This is internal and can be ignored |
restrictedToMerchants | boolean | boolean value delineating if this offer is restricted to instore merchants or if it is available at all merchants |
restrictedToMerchantsOnline | boolean | boolean value delineating if this offer is restricted to online merchants or is available at all online merchants At this time online uploads are not supported |
restrictToMerchants | a dto[] of restricted instore merchants | The documentation for this is provided below about the instore merchant dto. It will include things like the name and logo also please note that on the -short call we provided a short list and this will include the full list. |
restrictToMerchantsCount | integer | the amount of merchants this offer is restricted to |
restrictToMerchantsOnline | a dto[] | This can be ignored as we don’t currently support online through this api |
restrictToMerchantsShort | a dto[] | This will list a sublist of the merchants that the offer is available at with additional data like logos + name + merchantID. Expect this sublist to be variable but presume it to be set at 5. Look at the restrictToMerchants documentation below |
seocontent | This is internal and can be ignored | |
seotitles | This is internal and can be ignored | |
shortDescription | string | This is the description of the offer. Expect this to be a few words at most |
showUpTo | boolean | this determines if we should show the “Up To” description on the offer card before the payout amount. ”400 SB” vs ”Up To 400 SB” |
squareImageUrl | string | A url pointing to the square image of the offer |
startDate | string | The day that the offer starts (inclusive) formatted like so "startDate": "01/08/2024", |
swagcode | string | this is internal and can be ignored |
swagcode | string | this is internal and can be ignored |
videoUrl | string | Some of these offers include videos that will pop up in a player and display on the details view. This is not a requirement and few of these offers will include it. |
Buying Options Fields
Name | Type | Description |
---|---|---|
awardFormatted | string | The string formatted reward value in the clients currency "awardFormatted": "150 SB", |
cashbackAmount | double | The reward amount in dollars "cashbackAmount": 1.5, |
cashbackFormatted | string | The string formatted reward amount in dollars formatted like so: cashbackFormatted": "$1.50", |
goalDescription | string | This is the description of the goal so there might be a buy1 or a buy 2 and this is the description for it "goalDescription": "Buy 1 pack of SweeTARTS Gummies Fruity Splitz", |
payoutAmount | double | The reward amount in the clients currency "payoutAmount": 400, |
requiredQuantity | integer | This is the required amount of the product that the user is expected to purchase to meet this goal. |
requiredSpendFormatted | Expect to mostly see required quantity. This is a separate kind of goal that requires the user to spend a certain amount on an offer rather than purchase a certain number | |
useGoalDescription | boolean | Typically the goal will look something like the following: Buy any 1 eligible product were we pull in the required quantity. If this is enabled we display the description from the goal instead. In practice this is mostly not used. |
useRequiredSpend | boolean | determines if required spend is used. This is almost never enabled. |
RestrictToMerchants Fields
Name | Type | Description |
---|---|---|
logoUrl | string | This is the logo url for the retailer |
loyaltyLinkingInfo | This is internal and can be ignored | |
mediums | this is an enum[] and will contain either INSTORE or ONLINE | Out of the gate we will only offer support for the INSTORE variant |
merchantID | integer | The internal merchants id |
merchantName | string | This is the merchants name |
orderStatus | This is internal and can be ignored | |
shopMerchantID | integer | This is internal and can be ignored |
shopMerchantUrl | string | This is internal and can be ignored |
Example Response:
{
"data": {
"addedToList": false,
"allowRawHtml": true,
"anyReceiptEligible": false,
"awardLookBack": 0,
"bannerImageUrl": "<https://ucontent.prdg.io/pimages/96/96773959-73c5-4c8c-8cdc-f5178860c012.jpg">,
"barcodeScanEligible": true,
"baseAmount": 600,
"bonus": null,
"buyingOptions": \[
{
"awardFormatted": "200 SB",
"cashbackAmount": 2,
"cashbackFormatted": "$2",
"goalDescription": "Buy 1 pack of SweeTARTS Gummies Fruity Splitz",
"payoutAmount": 200,
"requiredQuantity": 1,
"requiredSpendFormatted": null,
"useGoalDescription": false,
"useRequiredSpend": false
},
{
"awardFormatted": "600 SB",
"cashbackAmount": 6,
"cashbackFormatted": "$6",
"goalDescription": "Buy 2 packs of SweeTARTS Gummies Fruity Splitz",
"payoutAmount": 600,
"requiredQuantity": 2,
"requiredSpendFormatted": null,
"useGoalDescription": false,
"useRequiredSpend": false
}
\],
"cap": null,
"categoryIDs": \[
13,
18,
40,
44,
45,
8
\],
"clippedInReceiptChallenge": false,
"conditions": null,
"detailUrl": "/grocery-receipts/sweetarts-gummies-fruity-splitz-coupon/7045645",
"eligibleMediums": \[
"INSTORE"
\],
"eligibleProducts": \[
"SweeTARTS® Gummies Fruity Splitz 5oz",
"SweeTARTS® Gummies Fruity Splitz 9oz "
\],
"eligibleProductsInfo": \[
{
"imageID": 263025,
"imageURL": "<https://ucontent.prdg.io/pimages/34/34c8eb65-272e-4508-b38c-1053aa9a06fd.PNG">,
"name": "SweeTARTS® Gummies Fruity Splitz 5oz",
"upc": "079200074593"
},
{
"imageID": 263026,
"imageURL": "<https://ucontent.prdg.io/pimages/85/85b8b299-2ad8-4575-9543-7a9bec98264d.PNG">,
"name": "SweeTARTS® Gummies Fruity Splitz 9oz",
"upc": "079200074562"
}
\],
"expirationDate": null,
"featured": false,
"imageUrl": "<https://ucontent.prdg.io/pimages/58/5844d280-9839-4f1e-8321-46a07608fd16.jpg">,
"impressionScript": "",
"isIncentivized": true,
"isQuantitySelectionEnabled": true,
"line1": "SweeTARTS® Gummies Fruity Splitz",
"line2": "Tired of choosing between sweet and tart? Now you don't have to! SweeTARTS® Gummies Fruity Splitz brings you the best of both worlds in one delicious gummy. Each chewy piece is bursting with two bold, fruity flavors, one sweet and one tart, for a flavor adventure in every bite.<br><br>\\n\\nBuy SweeTARTS® Gummies Fruity Splitz to earn!\_<br><br>\\nMaximum Of Two Receipt Submissions Per Week For This Offer.",
"line3": "$6",
"line4": "600 SB",
"line5": "\_Only purchases of the following products are eligible for SB:<br>\\nSweeTARTS® Gummies Fruity Splitz 9oz<br>\\nSweeTARTS® Gummies Fruity Splitz 5oz<br>\\n\\n<br>No other products are eligible for SB.<br>Must purchase at least 1 of the above eligible products to earn SB.<br>\\nSB for this offer can only be earned twice per week (Sunday-Saturday), while supplies last.<br><br>\\nNot all products available at all eligible retailers. <br>\\nThis offer is subject to change at any time and is available in limited quantities.<br>\\nPurchase must be made between January 8, 2024 and March 8, 2024. Receipt must be uploaded by 11:30 pm Pacific Time on March 8, 2024. Purchases made outside of the listed dates are not eligible for SB.<br><br>\\nUploaded receipts are not eligible for SB if linked to other promotions.",
"line6": "$6 Cash Back",
"line7": "Maximum Of Two Receipt Submissions Per Week For This Offer.",
"longDescription": "Tired of choosing between sweet and tart? Now you don't have to! SweeTARTS® Gummies Fruity Splitz brings you the best of both worlds in one delicious gummy. Each chewy piece is bursting with two bold, fruity flavors, one sweet and one tart, for a flavor adventure in every bite.<br><br>\\n\\nBuy SweeTARTS® Gummies Fruity Splitz to earn!\*<br><br>\\nMaximum Of Two Receipt Submissions Per Week For This Offer.",
"notManyLeft": false,
"offerID": 7045645,
"pendingDays": 0,
"purchaseQuantity": 1,
"receiptChallengeID": 0,
"rectangleImageUrl": "<https://ucontent.prdg.io/pimages/58/5844d280-9839-4f1e-8321-46a07608fd16.jpg">,
"redemptionsPerClaim": 0,
"referralUrl": "<https://www.swagbucks.com/grocery-receipts/refer/sweetarts-gummies-fruity-splitz-coupon/7045645?erb=etcwbiomx5neojt642cibnk33xpyhi42pnl4l6i=">,
"restrictedToMerchants": true,
"restrictedToMerchantsOnline": false,
"restrictToMerchants": \[
{
"logoUrl": "<https://ucontent.prdg.io/img/instore/logos/logo-1.png?v=1694019930000">,
"loyaltyLinkingInfo": {
"bgImageURL": "<https://ucontent.prdg.io/img/instore/bg-logos/bg-logo-1.png?v=1694019929000">,
"blinkMerchantID": 11,
"loyaltyAccountMerchantID": 1,
"loyaltyLinkingEnabled": true,
"registrationLink": "<https://www.walmart.com/account/signup?vid=oaoh">,
"tutorialText1": "Curbside pick up and online orders are not currently supported.",
"tutorialText2": "Curbside pick up and online orders are not currently supported."
},
"mediums": \[
"INSTORE"
\],
"merchantID": 1,
"merchantName": "Walmart",
"orderStatus": "",
"shopMerchantID": 183,
"shopMerchantUrl": "/shop/walmart-coupons"
}
\],
"restrictToMerchantsCount": 23,
"restrictToMerchantsOnline": null,
"restrictToMerchantsShort": \[
{
"logoUrl": "<https://ucontent.prdg.io/img/instore/logos/logo-1.png?v=1694019930000">,
"loyaltyLinkingInfo": {
"bgImageURL": "<https://ucontent.prdg.io/img/instore/bg-logos/bg-logo-1.png?v=1694019929000">,
"blinkMerchantID": 11,
"loyaltyAccountMerchantID": 1,
"loyaltyLinkingEnabled": true,
"registrationLink": "<https://www.walmart.com/account/signup?vid=oaoh">,
"tutorialText1": "Curbside pick up and online orders are not currently supported.",
"tutorialText2": "Curbside pick up and online orders are not currently supported."
},
"mediums": \[
"INSTORE"
\],
"merchantID": 1,
"merchantName": "Walmart",
"orderStatus": "",
"shopMerchantID": 183,
"shopMerchantUrl": "/shop/walmart-coupons"
}
\],
"seocontent": {},
"seotitles": {},
"shortDescription": "Double the Fun with SweeTARTS® Gummies Fruity Splitz!",
"showUpTo": true,
"squareImageUrl": "<https://ucontent.prdg.io/pimages/b8/b829991d-14c1-406a-bacb-5925ca873518.jpg">,
"startDate": "01/08/2024",
"swagcode": "",
"videoUrl": ""
},
"status": 200
}
Sample Pictures Displaying The Offer Details View
Instore Category Endpoint
In-Store Categories API Endpoint
Overview
This endpoint provides a comprehensive list of in-store categories that Instore Offers are classified under. Categories are a pivotal element of offer organization and presentation:
- Offers are associated with multiple categories as defined in the Offer Server, which enables categorization for better searchability and filtering.
- Clients can retrieve offers by category, allowing them to display offers pertinent to a selected category.
- Each category has a unique name and an associated type, which correspond to specific database tables (
prodege.shm_category
andprodege.shm_category_type
respectively). - Categories may be ordered explicitly; if no order is specified, the backend will determine the order dynamically.
- Only active categories are available for display and operations; inactive categories are excluded from caching and presentation.
The API mirrors the structure and relationships of these categories as they exist in the database, ensuring that clients can retrieve up-to-date and relevant information for displaying offers to end-users. Additionally, it provides the flexibility to manage these categories through an administrative interface, where new categories can be created, existing ones can be edited or updated, and category icons can be uploaded.
HTTP Request
curl \
-X GET https://receipts.bitlabs.ai/api/instore-categories \
-H "Authorization: Bearer <token>"
Request Parameters
None required.
Response
The response will be a JSON object containing an array of categories. Each category has the following structure:
Instore Category Object Fields
Name | Type | Description |
---|---|---|
id | integer | The unique identifier for the category, automatically generated upon creation. |
typeID | integer | The type ID that corresponds to the classification of the category. |
orderNum | integer | The specific order in which the category should appear on the front end, visible only to admin views. |
name | string | The unique name of the category, displayed on the front end. |
urlPng | string | The URL to the PNG icon for the category. |
urlSvg | string | The URL to the SVG icon for the category. |
adminPrioritized | boolean | Indicates if the category is prioritized by admins and is not ordered dynamically based on member preferences. |
Instore Category Type Object Fields
Name | Type | Description |
---|---|---|
categoryTypeID | integer | Unique identifier for the type of category. |
categoryName | string | Name of the category type. |
description | string | Description of what the category type represents. |
Example Response
{
"categories": \[
{
"id": 1,
"typeID": 1,
"name": "All Deals",
"url": "<https://content.prod.img/path/to/image.png">,
"description": "Regular Colored Instore Category"
},
{
"id": 45,
"typeID": 2,
"name": "New",
"url": "<https://content.prod.img/path/to/image.png">,
"description": "Special Category that is colored on the front end"
},
// Additional categories...
\],
"categoryTypes": \[
{
"categoryTypeID": 1,
"categoryName": "Standard",
"description": "Regular Colored Instore Category"
},
{
"categoryTypeID": 2,
"categoryName": "Special Color",
"description": "Special Category that is colored on the front end"
}
// Additional category types...
\]
}
Sample Categories Display:
- When clicking on a category it makes a offers-short call to our backend that filters to only include the offers that have that specific category.
If you click on the three dots to the right of the categories, then it shows the below screen with all the categories, when clicking on one of them, it makes a call to offers-short with that categoryID
Instore Merchants Endpoint
In-Store Merchants API Endpoint
Overview
This API retrieves a curated list of merchants tied to in-store offers. It accounts for member-specific data and preferences, ensuring the merchant list is targeted and relevant. The merchants returned by this API are filtered based on the offers available, member activity, and other bespoke criteria.
Enhanced Features
- Adaptive Filtering: It leverages an advanced filtering system that accounts for the latest member activity, such as recently uploaded receipts and offers added to the member's list, to deliver a list that resonates with the user's current shopping behavior.
- Customized Sorting: Merchants are sorted by a bespoke set of criteria that elevates member favorites and popular or featured stores, ensuring that the most relevant and preferred merchants are highlighted.
- Comprehensive Merchant Data: Each merchant entry is enriched with detailed information, from offer counts and loyalty account linkage to customized tutorial texts and image URLs, providing a full spectrum of data that can enhance user experience.
Sorting Logic
The API sorts merchants with a multi-tiered logic that prioritizes:
- User-favorited merchants, ensuring personalized experiences are at the forefront.
- Merchants popular in the user's location, enhancing relevance based on geographical trends.
- Featured merchants, highlighting those with special offers or prominence on the platform.
- Alphabetical order, providing a systematic and familiar navigation through the merchant list.
HTTP Request
curl \
-X GET https://receipts.bitlabs.ai/api/instore-merchants \
-H "Authorization: Bearer <token>"
Request Parameters
medium
(String): Specifies the medium of the offers, either "online" or "instore".getUploadList
(Boolean): If true, returns only the merchants associated with offers clipped to the member's list.getRecent
(Boolean): If true, returns only the merchants where the member has uploaded receipts recently.
Response
The response is a JSON object containing an array of merchant items. Each InstoreMerchantListItem
includes:
Merchant Information Fields
Name | Type | Description |
---|---|---|
dealCount | integer | The total number of active deals or offers currently available for the merchant. |
externalID | integer | An identifier for the merchant used in external systems or databases. |
hasOfferOnMyList | boolean | Indicates whether any of the merchant's offers are saved to the user's personal list. |
isFavorite | boolean | Shows whether the merchant is marked as a favorite by the user within the platform. |
isFeatured | boolean | Whether the merchant is highlighted in a featured section of the platform. |
isLoyaltyAccountLinked | boolean | Specifies if the user has a loyalty account linked with the merchant. |
logoUrl | string | The URL to the merchant's logo image. |
loyaltyLinkingInfo | object | Details about the merchant's loyalty program offering. |
mediums | array | The types of platforms through which the merchant's offers can be accessed. |
merchantID | integer | The internal unique identifier for the merchant. |
merchantName | string | The official name of the merchant. |
orderStatus | string | The status of an order with the merchant, if applicable. |
shopMerchantID | integer | An identifier used within the shopping interface of the platform for the merchant. |
shopMerchantUrl | string | The relative URL to the merchant's section on the platform for additional offers or coupons. |
Loyalty Linking Information Fields
Name | Type | Description |
---|---|---|
loyaltyLinkingEnabled | boolean | Indicates whether loyalty account linking is enabled for the merchant. |
registrationLink | string | The URL where users can sign up for the merchant's loyalty program. |
tutorialText1 | string | Instructional text providing guidance on using the loyalty program. |
tutorialText2 | string | Additional instructional text related to the loyalty program. |
bgImageURL | string | The URL for the background image associated with the merchant for the loyalty program. |
blinkMerchantID | integer | The Blink system's identifier for the merchant, related to the loyalty program. |
loyaltyAccountMerchantID | integer | The unique identifier for the merchant within the loyalty linking system. |
Example Response
{
"data": \[
{
"merchantID": 106,
"merchantName": "7-Eleven",
"logoUrl": "<https://ucontent.prdg.io/img/instore/logos/logo-106.png?v=1694019930000">,
"mediums": \[
"INSTORE"
\],
"orderStatus": "",
"shopMerchantID": 31339,
"shopMerchantUrl": "/shop/7eleven-coupons",
"externalID": 78,
"loyaltyLinkingInfo": {
"loyaltyLinkingEnabled": false,
"registrationLink": null,
"tutorialText1": null,
"tutorialText2": null,
"blinkMerchantID": 0,
"loyaltyAccountMerchantID": 0,
"bgImageURL": null
},
"dealCount": 42,
"hasOfferOnMyList": true,
"isFeatured": false,
"isFavorite": false,
"isLoyaltyAccountLinked": false
},
{
"merchantID": 4,
"merchantName": "Costco Wholesale Corp.",
"logoUrl": "<https://ucontent.prdg.io/img/instore/logos/logo-4.png?v=1694019932000">,
"mediums": \[
"INSTORE"
\],
"orderStatus": "completed",
"shopMerchantID": 29941,
"shopMerchantUrl": "/shop/costco.com-coupons",
"externalID": 14,
"loyaltyLinkingInfo": {
"loyaltyLinkingEnabled": false,
"registrationLink": "<https://signin.costco.com/e0714dd4-784d-46d6-a278-3e29553483eb/B2C\_1A\_SSO\_WCS\_signup\_signin\_467/api/CombinedSigninAndSignup/unified?local=signup&csrf\_token=VUFvTDlyVHNsaXo1bjVMQ1FXaW83YTFhSFd6RGo0UTI3UkFwL1JlZmtMRFhWTkx1ZU1CUk5RYmlBKzQvREc5NDdtUDc3ZksxMGE5WllFNmRiMEpCd1E9PTsyMDIxLTEyLTE2VDIzOjE3OjAzLjg3OTQ2MTVaOzIrTjUwZGxoVkhtMXBQS2cyNzZiTGc9PTt7Ik9yY2hlc3RyYXRpb25TdGVwIjo0fQ==&tx=StateProperties=eyJUSUQiOiJjMDFlNDBkYS05NDljLTQ2YjAtODI2Yi01MWVhNzI5OTgzZDcifQ&p=B2C\_1A\_SSO\_WCS\_signup\_signin_467">,
"tutorialText1": null,
"tutorialText2": null,
"blinkMerchantID": 2,
"loyaltyAccountMerchantID": 4,
"bgImageURL": null
},
"dealCount": 145,
"hasOfferOnMyList": true,
"isFeatured": false,
"isFavorite": false,
"isLoyaltyAccountLinked": false
},
... additional merchants
\]
}
Sample Instore Merchants Display:
- When clicking on a merchant it makes a offers-short call to our backend that filters to only include the offers that are available at that merchant (and the category id that is already selected is passed too, only including offers from that merchant and category).
All Merchants
Shop By Merchant
This is after clicking on one merchant and seeing only offers for that merchantID and categoryID
Instore Receipt Upload Enabled
Receipt Upload Enabled Check API Endpoint
Overview
This API endpoint checks if the receipt upload feature is enabled for the Magic Receipts program and retrieves the configuration settings related to the receipt upload process.
HTTP Request
curl \
-X GET https://receipts.bitlabs.ai/?cmd=mp-instore-receipt-upload-enabled \
-H "Authorization: Bearer <token>"
Response Object
Name | Type | Description |
---|---|---|
maxManualReviewForUpload | integer | The maximum number of manual reviews that can be requested per receipt upload. This is also internal and likely won’t be used. |
maxOfferUploads | integer | The maximum number of offers that can be uploaded at one time. |
dataShareOptInBonusAmount | integer | The bonus amount awarded for opting into data sharing during the receipt upload process. This is internal and likely won’t be used. |
enabled | boolean | Indicates whether the receipt upload feature is currently enabled. |
Example Response
{
"maxManualReviewForUpload":10,
"maxOfferUploads":10,
"dataShareOptInBonusAmount":10,
"enabled":true
}
Description
The response provides the client with essential configuration settings that govern the receipt upload process:
maxManualReviewForUpload
: Clients can use this value to inform users how many items on their receipt can be reviewed manually if automatic processing does not recognize them.maxOfferUploads
: This value can be used to validate the number of offers a user is attempting to upload and to enforce limits within the client application.dataShareOptInBonusAmount
: If there is a bonus associated with opting into data sharing, this value can be displayed to the user as an incentive.enabled
: The client application can use this boolean flag to enable or disable the receipt upload functionality dynamically, without requiring an update or release.
Notes
- This endpoint should be called before attempting to upload a receipt to ensure the feature is available and to retrieve the current operational parameters.
- The provided settings should be used to set up client-side validations and to inform the user of the receipt upload process's rules and potential benefits.
Instore Receipt Upload/Validation
Receipt Upload API Endpoint
Overview
The Receipt Upload API allows members to upload their shopping receipts to claim offers listed under the Magic Receipts program. The API processes the uploaded receipt image, evaluates the eligibility for cashback, and returns the status of each claimed offer.
HTTP Request
curl \
-X POST https://receipts.bitlabs.ai/api/magic-receipts/upload-receipt \
-H "Authorization: Bearer <token>"
Request Parameters
Name | Type | Description |
---|---|---|
merchantID | integer | The ID of the merchant where the purchase was made. |
imageCount | integer | The number of receipt images attached to the upload. |
offerIDs | integer[] | An array of offer IDs that the member wants to claim. |
dataShareAdvertiserIds | integer[] | An array of advertiser IDs for data sharing purposes. |
medium | string | The medium of shopping, e.g., "INSTORE" or "ONLINE". Defaults to empty. |
receipt | string | The text representation of the receipt, if applicable. Defaults to empty. |
Form Data Parameters
Name | Type | Description |
---|---|---|
img0 | binary | The binary data of the receipt image. |
imgName0 | string | The file name of the receipt image. |
Main Response
Name | Type | Description |
---|---|---|
status | integer | The HTTP status code of the response. |
data | object | The main data object containing the details of the processed receipt. |
Data Object Fields
Name | Type | Description |
rejected | object | Contains information about any offers that were rejected during processing. |
manualReview | object | Contains information about offers that require manual review. |
confirmed | object | Contains information about the offers that were automatically awarded |
awardPending | object | Contains information about the offers that are now in an award pending state, i.e. they will be awarded in a couple of days unless CS rejects them. |
barcodeScanEligibleDeviceCodes | array | An array of device codes that are eligible for barcode scanning. |
barcodeScanEnabled | boolean | Indicates if barcode scanning is enabled for the receipt upload. |
Rejected and Manual Review Objects
Name | Type | Description |
---|---|---|
offers | array | An array of offers with their respective processing status. |
awardBonuses | array | Any bonus awards applicable to the receipt. |
unusedLineItems | array | Line items on the receipt that were not used for any offers. |
totalAwardCashback | string | The total cashback amount awarded for the receipt. |
totalAward | string | The total award points (SB) earned for the receipt. |
Offers Array Object
Name | Type | Description |
---|---|---|
maxLinesForManualReview | integer | The maximum number of lines allowed for manual review. |
offerID | integer | The ID of the offer. |
imageUrl | string | The URL of the image related to the offer. |
pendingDays | integer | The number of days the offer is pending for. |
uploadOfferID | integer | The ID of the uploaded offer. |
state | string | The processing state of the offer (e.g., "rejected"). |
award | string | The award points (SB) for the offer. |
awardCashback | string | The cashback amount for the offer. |
surveyUrl | string | The URL to a survey related to the offer, if applicable. |
shortErrorStr | string | A short description of any error encountered. |
errorStr | string | A full description of the error. |
errorCode | integer | A code representing the error encountered. |
isBarcodeScanEligible | boolean | Indicates if the offer is eligible for barcode scanning. |
offerTitle | string | The title of the offer. |
addedToList | boolean | Indicates if the offer was added to the user's list. |
isUnselectedOffer | boolean | Indicates if the offer was not originally selected by the user |
Unused Line Items Object Fields
Name | Type | Description |
---|---|---|
receiptLineID | integer | The unique identifier for the line item on the receipt. |
rsd | string | The recognized shopping description or item name extracted from the receipt. |
price | decimal | The price of the item as captured from the receipt. |
Error Handling
- The method includes comprehensive error handling, providing clear error messages and codes for various failure scenarios such as invalid merchant ID, image count, offer IDs, receipt data, and upload progress state.
- It also ensures that if a receipt upload is already in progress, it will not start another, preserving the integrity of the member's upload queue.
Sample Receipt Upload Request Display:
On the main screen there is a Submit Receipt button that allows the member to start the upload process
Clicking on that button makes a call to the merchants api above to retrieve all the merchants that a member could choose they shopped at for their receipt.
after selecting a merchant and clicking Continue a call is made to the offers-short api above with sortType=0 and merchantID=?? whatever the id of the merchant is, that will return to you all the offers relevant for this merchant that the member could upload for.
choose which offers are on your receipt and how many of them you bought for offers that have multiple goals (buying options) attached to them, i.e. buy 1 get this amount, buy 2 get this award.
After clicking Continue you’re taken to this screen that allows you to upload a file which is a picture of your receipt.
A member can attach multiple pictures to capture the entire receipt if it’s long
Then when clicking Submit Receipt we make the upload-receipt call to the api to do the validation, while we are validating we have an upload screen.
Depending on the result from the upload we display accordingly
there can be multiple reasons the offers were rejected, as can be seen here 3 different reasons: date, matching, duplicate
From there you can click Contact Customer Support to request manual review (see above API doc), or click Review Your Receipt Photos and either resubmit the same photo or choose different ones.
Instore Manual Review
In-Store Manual Review API Endpoint
Overview
This API endpoint is dedicated to handling the manual review process for members who have submitted receipts and believe certain offers should be awarded post-rejection. It provides a mechanism for members to flag specific rejected offers for further review by customer service (CS) teams, potentially leading to offer approval.
HTTP Request
curl \
-X POST https://receipts.bitlabs.ai/api/instore-manual-review \
-H "Authorization: Bearer <token>"
Request Parameters
Name | Type | Description |
---|---|---|
uploadOfferIds | array | An array of IDs representing the offers that the member requests to be reviewed manually. |
Response
The response will include a status code and may also return an array of uploadOfferIds
that have been successfully submitted for manual review.
Example Request
POST https://receipts.bitlabs.ai/api/instore-manual-review?uploadOfferIds=151012867,151012868,151012869,151012870
Example Response
{
"manualReview":\[
151012867,
151012868,
151012869,
151012870
\],
"status":200
}
Sample Manual Review Request Display:
Immediately after the upload a user gets a display with the offer they chose to upload for showing that they weren’t awarded for them, and the choice to click Contact Customer Support, which brings you to the next screen.
The user now can choose which offers they think they should have been awarded for, i.e. that they should be manually reviewed.
Then when the user clicks Send For Review is when we make the API call above using the uploadOfferIDs of these selected offers (these ids are passed back after the receipt upload call).
Then we display a message conveying that their review request has been received, or an error request if it wasn’t received.
- If upload offer IDs were sent back, that means it was received
- If no upload offer IDs were sent back, then the request didn’t work
- If an error message (noted above) was sent back then either they requested too many offers (the limit is 10), or an error happened deserializing the JSON.
Processing Logic
Upon submission, the endpoint performs the following actions:
- Validates the eligibility of the upload offers for manual review based on certain rejection statuses and the offer's manual review eligibility.
- Changes the status of eligible upload offers to
PENDING_MANUAL_REVIEW_USER_REQUESTED
. - Allows CS teams to subsequently approve or reject the offers in the admin panel.
Error Handling
- If the request fails, an error status code and message will be provided.
{"status": 400, "message", "error"}
- Common errors include:
- invalid offer IDs
- offers that are not eligible for manual review.
- Only a configurable amount of manual review submissions are allowed per upload, if it exceeds this number the error response is returned
Best Practices
It is recommended to handle the response gracefully in the UI, providing users with clear feedback on the submission's success or failure.
Updated 17 days ago