Send Store and Forward (SAF) Transaction
POST/client/users/:correlation_id/activity/saf/v2
Sends a "finalized" activity (that is, transaction details) associated with a user where the data was stored and forwarded.
If ES Loyalty and the client POS or e-Commerce storefront lose connectivity, all finalized calls should be converted to SAF for forwarding at a later date. SAF cannot process redemptions, so redemptions will be processed once connectivity is restored. SAF transactions still qualify for rewards but the transaction date will be backdated to when the offers occurred to maintain reporting accuracy.
If a purchase made by a non-loyalty account is delayed being sent into the system with this call until after the user was registered, no points are awarded since the user was not associated with a Loyalty Account when the purchase was made.
In some cases, points can only be awarded after payment or fulfillment of the order have taken place, resulting in delayed transactions. Adding the following object to the end of the call supports a delayed transaction that requires confirmation.
"confirmation": {
"mode": "CART"
}
The response includes information about the confirmation status.
"ConfirmationDetails": {
"confirmed": true,
"mode": "CART"
}
Note: For a single members or in a household, if a redemption transaction begins, but one or more of the cards are subsequently set to a non-active state such as Suspended, Lost or Stolen, Fraud/Abuse, Cancelled, or Damaged before the redemption transaction is completed, then to prevent fraud, the redemption amount is still withdrawn from the single member or proportionally from all household members who had active cards before the redemption transaction began.
Request
For information about requests, view the documentation for the Send Finalize Transaction request.
Body
| Attribute | Definition | Format | Notes |
|---|---|---|---|
| action | Identifies purchase transaction | String | Always "PURCHASE" |
| channel | Identifies through which channel the transaction was invoked | Enum: "STORE", "POS", "WEBSITE", "APP", "PARTNER" | |
| locale | The locale of the member from the POS system. | String | Optional. Currently "en-CA" or "fr-CA". If locale is set by the POS system in the Start Session request, this overrides locale set in the member provide and as the system default. |
| reservationToken | Used for purchases that include redemption. | String | This attribute is optional. |
| transactionDate | Full date and time of the transaction. | String | Date of the Transaction (Full Date and Time) must be in an ISO-8601-compliant format, for example: 2022-01-17T13:48:59-04:00. |
| retailBanner | A store grouping or type. | String | Transactions will default if a single BU or banner exists (configuration). OAuth token controls how we process. This attribute is optional. |
| storeNumber | Used for targeting, analytics and support. | String | |
| tillNumber | Use for analytics and support. | Number | This attribute is optional. |
| employeeCode | CSR of the transaction. | Number | This attribute is optional for operations, but required for analytics. |
| loyaltyId | Unique identifier for each member. | Number | This can be captured in the Start Session. This attribute is optional. |
| externalTransactionID | Unique identifier for transaction used by the client. | String | Optional. |
| priceMatrix | Designates whether the transaction is retail or an employee purchase. | Enum: "R" or "E" | R = Retail E = Employee |
| locale | Used to change the receipt message language response for this transaction. Defaults to the client's chosen language when not present. | String | "en-CA" for english. "fr-CA" for french. |
| callId | Request identifier. | String | Can be auto-generated if none provided. Supports tracking specific calls to be captured within a specific session for analytics. (Secondary Correlation ID). This attribute is optional. |
| cart | Containing array of saleLineItems | Object | JSON Object containing array of saleLineItems. |
| saleLineItems | Information for one item in the transaction. | Array | Array of JSON Objects. |
| subCategory | Same subcategory as in Product feed. | Number | Can be blank to force system to grab subcategory from product data. This is an optional attribute. |
| sku | The product identifier. | Number | For instance, this may be scanned at the Point of Sale. |
| quantity | Measure of product amount sold. | Number | Can be partial value for unit of measure calculations where there is no directly-applicable SKU (for instance, rope sold by the foot). |
| originalSaleAmount | The Manufacturer's Suggested Retail Price for a product. | Number | Single-unit MSRP in pennies. |
| saleAmount | MSRP less the discount, the actual sale price. | Number | MSRP minus item discount in pennies. |
| storeCoupon | Store-based coupon. | Number | This is informational only, no active discounting occurs in ESL. This attribute is optional. |
| itemDiscount | Amount discounted. | Number | This attribute is optional. In pennies. |
| mnfCoupon | Manufacturer Coupon. | Number | This is informational only, no active discounting occurs in ESL. This attribute is optional. |
| promoCoupon | Flyer coupon. | Number | This is informational only, no active discounting occurs in ESL. This attribute is optional. |
| itemTax | Tax on the item. | Number | Tax on the line item in pennies. |
| finalSaleAmount | Total sale amount for a specific product, the discounted price times the quantity purchased. | Number | quantity * saleAmount |
| tags | Provides additional transaction information. | String | Required, but can be empty. |
| itemCost | Total cost for a specific product, the cost per unit times the quantity purchased. | Number | cost per unit * quantity. This attribute is optional. |
| totalSaleAmount | Total of all items sold on this transaction, including tax. | Number | Summed up, tax included, total of all saleLineItems. In pennies. |
| couponCodes | Purchase-level coupons. | String | This attribute is optional. |
| extendedData | Client keys needed for analytics at the transaction. | Object | Maximum 1KB, 1 level deep, 10 keys maximum. This is an optional attribute. |
| tender | JSON Object containing transaction tender used. | Object | Contains one or more type of tender and details of each (as required). |
| prefix | Prefix of the card identifier. | Number | Usually the BIN or first 6 numbers of the card. Used for partner-based offers. This attribute is optional. |
| idType | Type of the card identifier being passed in. | String | "TOKEN". This attribute is optional. |
| suffix | Suffix of the card identifier. | Number | Usually the last 4 digits. Used for partner-based offers. This attribute is optional. |
| amount | Total amount of the tender. | Number | Total amount of the tender that was spent using this specific card/tender. |
| loyalty | Reserved key that denotes in cents the dollars spent by exchanging for loyalty points. | Number | Used for redemption-based actions. This attribute is optional. |
| confirmation | Used to indicate delayed transaction status. | Object | See introduction to documentation for this request above for more information. |
| mode | Include source of confirmation required in the request | String: "CART" | |
| cart | Object containing array of saleLineItems | Object | Required. JSON Object containing array of saleLineItems. |
| saleLineItems | Contains details of one transaction item. | Array | Required. JSON Object containing line items. See saleLineItems Details below this table |
| subcategory | Same subcategory as in Product feed. | Number | Optional. Can be blank to force system to grab subcategory from product data. |
| sku | The product identifier scanned at POS. | Number | Required |
| quantity | Measure of product amount sold. | Number; for some clients, may include values confirmed to be as low as 0.000001 | Required. Can be partial value for unit of measure calculations where there is no directly-applicable SKU (for instance, rope sold by the foot). |
| originalSaleAmount | The Manufacturer's Suggested Retail Price for a product. | Number | Required. Single-unit MSRP in pennies. |
| subCategory | Identifier for the sub-category associated with the product. | String | |
| productName | Unique product name. | String | |
| saleAmount | MSRP less the discount, the actual sale price. | Number | Required. MSRP minus item discount in pennies. |
| storeCoupon | Store-based coupon. | Number | Optional. This is informational only, no active discounting occurs in ESL. This attribute is optional. |
| itemDiscount | Amount discounted. | Number | Optional. This attribute is optional. In pennies. |
| mnfCoupon | Manufacturer Coupon. | Number | Optional. This is informational only, no active discounting occurs in ESL. This attribute is optional. |
| promoCoupon | Flyer coupon. | Number | Optional. This is informational only, no active discounting occurs in ESL. This attribute is optional. |
| itemTax | Tax on the item. | Number | Required. Tax on the line item in pennies. |
| finalSaleAmount | Total sale amount for a specific product, the discounted price times the quantity purchased. | Number | Required. quantity * saleAmount |
| tags | To provide additional information | String | Required, but can be empty. |
| rewardTags | To provide additional information about specified rewards. | Object | Required, but can be empty. Contains offer name(s) and associated reward(s) as key:value pairs. |
| itemCost | Total cost for a specific product, the cost per unit times the quantity purchased. | Number | Optional. cost per unit * quantity. This attribute is optional. |
| couponCodes | Purchase-level coupons. | String | Optional. |
| extendedData | Client keys needed for analytics of the transaction. | Optional. Maximum 1KB, 1 level deep, 10 keys maximum. | |
| totalSaleAmount | Total of all items sold on this transaction, including tax. | Number | Required. Summed up, tax included, total of all saleLineItems. In pennies. |
| tender | JSON Object containing transaction tender used. | Object | Required. Contains one or more type of tender and details of each (as required). |
| {tender_type} | Array containing one or more objects for a particular type of tender (such as "VISA" which replaces {tender_type}). | String for tender type name, then array containing an object for each instance of that tender type. | Contains idType to amount below. Possible values for {tender_type}: "CASH", "COUPON" (flyer coupon), "REWARDS" (non-points rewards), "AMEX", "MSTCARD", "VISA", "GWCOUP", "MCOUPON" (manufacturer's coupon), "LOYALTY" (points) |
Response
To view the hierarchy, see the example Response.
| Attribute | Definition | Format | Notes |
|---|---|---|---|
| earned | Contains points earned on all applicable programs. | Object | Besides "loyalty," there may be other programs such as a partner program (and related object) with additional points awarded. |
| loyalty | Contains points earned on the loyalty program. | Object | The attributes would be the same for other programs (if any). |
| base | The number of base rewards earned on the transaction. | Number | Base points = points for any transaction based on spend. |
| bonus | The number of bonus rewards earned on the transaction. | Number | Bonus points = points for completing particular behaviour. |
| targeted | The number of points attributable to targeted offers. | Number | Targeted points = points derived from targeted offer. |
| total | The total of all points earned on the transaction. | Number | = base + bonus + targeted points |
| loyaltyID | Loyalty Card number for the session. | Number | If loyaltyId was not provided in the request, then this is the primary card number on the account |
| pointsRedeemed | The number of points redeemed. | Number | Always 0 for this type of request. To redeem points, use Send Finalize Transaction (with Redemption). |
| pointsEarnedTotal | The total of points earned after redemptions. | Number | total minus pointsRedeemed |
| offerRewards | Contains details of one or more offer rewards. | Array | |
| offerDescription | General description of offer. | String | For instance, "Spend $20 and get 500 points." |
| offerDescription2 | Additional details of offer. | String | For instance, "Offer good through March 22." |
| promotionHeadline | Headline under which offer is promoted. | String | For example: "Spend $20 and get 500 points." |
| offerCode | Unique code identifying offer. | String | |
| pointsEarned | Points earned for this offer. | Number | |
| isTargeted | Flags whether the transaction results from a targeted offer. | Boolean | |
| isDiscretionary | Flags whether the transaction is discretionary. | Boolean | |
| stacking | Used to provide data about reward groups and the winning group for rewards when one or more of the rewards are based on units. | Object | Contains rewardGroups and winningGroup |
| rewardGroups | All possible reward groups for this reward. | Array | Contains one or more reward groups |
| winningGroup | Winning reward group, the one used for this reward. | String | Contains one reward group from the array in rewardGroups |
| partnerID | Identification of a partner. | String | Used only with partner offerRewards, if relevant. |
| receiptMessage | Message to show on the receipt. | String | The message may differ depending on points earned, redeemed, both, or neither. |
| message | Details of transaction not shown to consumer. | String | Provides information about the transaction and any redemptions. |
| pointsBalance | Total number of points currently attributed to this account. | Number | Rewards balance in points. |
| redeemableBalance | Maximum currency that can currently be redeemed. | Number | An increment of a standard redemption amount. For instance, with a pointsBalance of 120000 and currency rewards of $10 per 25000 points, this value would be 40, or four increments of 10. |
| redeemablePointBalance | Maximum number of points that can currently be redeemed. | Number | An increment of a standard redemption amount. For example, with a pointsBalance of 110000, the user may be able to redeem 100000, or four increments of 25000. |
| household | Object containing information about the household to which the member belongs. | Object | Only returned if the member is a member of a household. |
| id | Unique identifier for the household. | String | |
| role | The member's role in the household. | Enum: "PRIMARY" or "SECONDARY" | |
| balance | Object containing data about the balances available to the household. | Object | |
| totalPointsBalance | The total points balance of the household. | Number | The sum of all member balances. |
| totalDollarBalance | The total dollar balance of the household. | Number | The sum of all member balances. |
| totalAvailablePointBalance | The total points available to the household. | Number | |
| totalAvailableDollarBalance | The total dollars available to the household. | Number | |
| totalRedeemablePointBalance | The total number of points that can currently be redeemed by the household members. | Number | |
| totalRedeemableDollarBalance | The total number of dollars that can currently be redeemed by the household members. | Number | |
| minRedeemPoints | The minimum number of points that can be redeemed by the household. | Number | |
| maxRedeemPoints | The maximum number of points that can be redeemed by the household. | Number | |
| minRedeemDollars | The minimum number of dollars that can be redeemed by the household. | Number | |
| maxRedeemDollars | The maximum number of dollars that can be redeemed by the household. | Number | |
| cart | Object containing array of saleLineItems | Object | Required. JSON Object containing array of saleLineItems. |
| saleLineItems | Contains details of one transaction item. | Array | Required. JSON Object containing line items. See saleLineItems Details below this table |
| subcategory | Same subcategory as in Product feed. | Number | Optional. Can be blank to force system to grab subcategory from product data. |
| sku | The product identifier scanned at POS. | Number | Required |
| quantity | Measure of product amount sold. | Number; for some clients, may include values confirmed to be as low as 0.000001 | Required. Can be partial value for unit of measure calculations where there is no directly-applicable SKU (for instance, rope sold by the foot). |
| originalSaleAmount | The Manufacturer's Suggested Retail Price for a product. | Number | Required. Single-unit MSRP in pennies. |
| subCategory | Identifier for the sub-category associated with the product. | String | |
| productName | Unique product name. | String | |
| saleAmount | MSRP less the discount, the actual sale price. | Number | Required. MSRP minus item discount in pennies. |
| storeCoupon | Store-based coupon. | Number | Optional. This is informational only, no active discounting occurs in ESL. This attribute is optional. |
| itemDiscount | Amount discounted. | Number | Optional. This attribute is optional. In pennies. |
| mnfCoupon | Manufacturer Coupon. | Number | Optional. This is informational only, no active discounting occurs in ESL. This attribute is optional. |
| promoCoupon | Flyer coupon. | Number | Optional. This is informational only, no active discounting occurs in ESL. This attribute is optional. |
| itemTax | Tax on the item. | Number | Required. Tax on the line item in pennies. |
| finalSaleAmount | Total sale amount for a specific product, the discounted price times the quantity purchased. | Number | Required. quantity * saleAmount |
| tags | To provide additional information | String | Required, but can be empty. |
| rewardTags | To provide additional information about specified rewards. | Object | Required, but can be empty. Contains offer name(s) and associated reward(s) as key:value pairs. |
| itemCost | Total cost for a specific product, the cost per unit times the quantity purchased. | Number | Optional. cost per unit * quantity. This attribute is optional. |
| couponCodes | Purchase-level coupons. | String | Optional. |
| extendedData | Client keys needed for analytics of the transaction. | Optional. Maximum 1KB, 1 level deep, 10 keys maximum. | |
| totalSaleAmount | Total of all items sold on this transaction, including tax. | Number | Required. Summed up, tax included, total of all saleLineItems. In pennies. |
| tender | JSON Object containing transaction tender used. | Object | Required. Contains one or more type of tender and details of each (as required). |
| {tender_type} | Array containing one or more objects for a particular type of tender (such as "VISA" which replaces {tender_type}). | String for tender type name, then array containing an object for each instance of that tender type. | Contains idType to amount below. Possible values for {tender_type}: "CASH", "COUPON" (flyer coupon), "REWARDS" (non-points rewards), "AMEX", "MSTCARD", "VISA", "GWCOUP", "MCOUPON" (manufacturer's coupon), "LOYALTY" (points) |
| total | Total of the sale transaction. | Object | Contains subTotal, totalSaleAmount, and taxAmount within each sale object type |
| {transaction status type} | Status of transaction. | String | For example, "final"; contains totalSaleAmount, subTotal, and taxAmount below |
| totalSaleAmount | The total amount of the sale including tax. | String | |
| subTotal | The total amount of the sale before tax. | String | |
| taxAmount | The tax generated on the sale. | String |
Error Responses
| statusCode | errorMessage | errorCode | Definition |
|---|---|---|---|
| 400 Bad Request | Session correlation ID does not exist--create it first. | INVALID_REQUEST | Must send request with an existing correlation ID |
| 400 Bad Request | Session Closed | INVALID_REQUEST | The session was closed, so this request cannot be made |
| 400 Bad Request | Session Expired | INVALID_REQUEST | The session has expired, so this request cannot be made |
| 400 Bad Request | Cart cannot contain zero-quantity line items | INVALID_REQUEST | Line items in the cart must have a quantity of 1 or more |
| 400 Bad Request | Invalid extended data: Exceeded data size limit for extended data: {dataSize} Bytes | INVALID_REQUEST | When extendedData size exceeds the size limit. See the limit on ConfigType = EXTENDED_DATA, on Platform.DataSizeLimitInKb. |
| 400 Bad Request | Invalid Extended data : Exceeded root level key limit for extended data : {numberOfKeys} keys | INVALID_REQUEST | When extendData exceeds number of attributes/keys limit. See the limit on ConfigType = ‘EXTENDED_DATA’, on Platform.TopLevelKeysLimit. |
| 400 Bad Request | Channel should be a string value. | INVALID_REQUEST | Cannot use data type other than string value for channel attribute. For example, channel attribute value cannot be a Boolean (rue, false, or null). |
| 409 Conflict | Too many simultaneous requests for the same account | INVALID_REQUEST | Reduce number of simultaneous requests |
Request
Responses
- 200
- 400
- 401
- default
200 - Store and Forward
Response Headers
Fri, 02 Oct 2020 18:59:20 GMT922keep-alived6ebe9ad-39e4-474b-a3f3-5f39e7e7bb17no-referrer1;mode=block*max-age=86400max-age=31536000vibrate 'none'; geolocation 'none'sameoriginconnect-src 'none';object-src https://*.cloudfront.net;script-src https://*.cloudfront.netTy_FPGchoAMF4Ag=no-cache, no-store, must-revalidatenosniffRoot=1-5f777887-1018d63f53d5cba41cdd578b;Sampled=0400 - Correlation ID Does Not Exist
Response Headers
Thu, 10 Jun 2021 15:55:54 GMT121keep-alive9d269ee1-f2a3-4e14-af06-5291698177eeno-referrer1;mode=block*max-age=86400max-age=31536000vibrate 'none'; geolocation 'none'sameoriginconnect-src 'none';object-src https://*.cloudfront.net;script-src https://*.cloudfront.netAt1hrGYPIAMF6Xw=no-cache, no-store, must-revalidatenosniffRoot=1-60c2360a-1ebe7f0679ec9a8b2923fd63;Sampled=0401 - Issues with Authentication
Response Headers
Thu, 10 Jun 2021 15:52:03 GMT26keep-alive33ce112b-4466-4bca-a5a6-af5b8ccdcc6aUnauthorizedExceptionAt09mFkzIAMFjnQ=200 - SAF with externalTransactionID