Send Return Transaction

Using the same endpoint featured in "Send Transaction," this task sends a return transaction from a POS system to SessionM. When the endpoint runs to execute a purchase, it passes a transaction request object that has a payload that contains JSON data describing the transaction itself, the items being purchased, the payments being made, and the discounts being applied.

The payload for a full or partial return contains much of the same information from the original transaction, with some important differences, including updated item and payment objects. For a comparison of the original transaction payload with the full refund payload, see Defining Request Payload for Full Return and Refund. Or, alternatively, you can consult a comparison of the original transaction payload with the partial refund payload in Defining Request Payload for Partial Return and Refund.

Once it receives the sent transaction with its payload returning a purchased item, SessionM can make the requisite adjustment for any of the outcomes that had been awarded when the item was purchased. This includes deducting points earned from either economy or campaign rules. Note that you do have the option to reinstate offer options as well - presuming that doing so is applicable to the original transaction.

This operation is an asynchronous flow. Transactions queue up as needed to mitigate bursts of activity.

Sequence Diagram

See the overall flow for this task below.

CUSTOMER CUSTOMER CLIENT MIDDLEWARE CLIENT MIDDLEWARE SESSIONM SESSIONM SEND RETURN TRANSACTION Return item Look up original transaction Remove returned item Send original transaction with modified time and items Enqueue transaction job Return success message Optional: Economy Rule Point Adjustment Deduct points earned from economy rules Optional: Campaign Outcome Point Adjustment Deduct points earned from campaign outcome Optional: Offer Reinstatement Reinstate offer Return success message

API Endpoints & Constraints

POST /api/2.0/send_transaction

If passing an external user ID to SessionM and using the "ext → internal translation pattern," an additional call to get the internal SessionM user ID is required and made.

Bear in mind the following limits:

  • Maximum number of items is 1,000; maximum number of discounts is 100.
  • Maximum number of payments is 100.
  • Maximum number of custom object elements is 1000 (drops in orders of magnitude as the object complexity and size increases.
  • Limit number of calls to the send transaction operation and make them only at the end of the transaction. However, changes and voids may be applied as needed.
  • Similarly, offer locking and validation should be at the end of the transaction and not after each new item is added or removed.
  • Return periods greater than 12 months will not be able to restore points upon returns.
  • Avoid using the user ID translation pattern when possible. These APIs are agnostic of the user ID, which is the source of truth for the customer. It is just as viable to pass an external ID and NOT need to translate when using the SOR pattern, where the external user ID is treated as the SessionM ID for internal processing. Note: This only works when there is one source of external ID. Multiple sources of user ID would require translation (normalization) to SessionM user ID.

Defining Request Payload for Full Return and Refund

The workflow for purchases and returns relies heavily on the JSON payloads that specify several different attributes. This section compares the payloads typical of both. Consider the two payloads below, one for the original purchase and one for the subsequent full refund. Each one is shown with color-coded boxes that identify key attributes in the payloads.

Original Purchase Request Payload Subsequent Full Refund Request Payload

The annotated attributes illustrate important differences in the data they specify. Consult the table below for more information and bear in mind that the information within it pertains to the sequence diagram step above called, "Send original transaction with modified time and items."

Annotation Sample Code from Original Purchase Sample Code from Full Refund Comments
Red "is_voided": false, "is_voided": true,

The original purchase payload requires the is_voided field to be set to "false", which indicates that the purchase request was made and is not voided.

The full refund payload requires the is_voided field to be set to "true", which indicates that the full refund request was made and thereby voids out the original purchase when the full refund occurs.

Yellow

"subtotal": 101.74,
"tax_total": 10.17,

"subtotal": 101.74,
"tax_total": 10.17,

The request payload for the original transaction indicates that the items were purchased for the subtotal of $101.74 - plus $10.17 in tax. The full refund payload retains the same values for these fields because the SessionM rules engine sees that is_voided equals "true" and subtracts the appropriate number of points. Duplicating these fields in the refund informs the rules engine how many points it must refund and how many points it must deduct.
Green "modified_time": "{{purchase_timestamp}}", "modified_time": "{{refund_timestamp}}", The timestamp, modified_time, is present on both the purchase transaction and the refund. The timestamp for a refund is always later than the one for the original purchase.
Blue "items": [
{
"line_id": "1",
"item_id": "Sub category 1",
"quantity": 2,
"unit_price": 30.11,
"subtotal": 60.22,
"tax_included": 0.0,
"modifies_line_id": null,
"custom_data": null
},
{
"line_id": "2",
"item_id": "Sub category 2",
"quantity": 1,
"unit_price": 41.52,
"subtotal": 41.52,
"tax_included": 0.0,
"modifies_line_id": null,
"custom_data": null }],
"items": [
{
"line_id": "1",
"item_id": "Sub category 1",
"quantity": 2,
"unit_price": 30.11,
"subtotal": 60.22,
"tax_included": 0.0,
"modifies_line_id": null,
"custom_data": null
},
{
"line_id": "2",
"item_id": "Sub category 2",
"quantity": 1,
"unit_price": 41.52,
"subtotal": 41.52,
"tax_included": 0.0,
"modifies_line_id": null,
"custom_data": null }],

With respect to the items array, the original transaction and the full refund are identical. But they are processed differently because the full refund payload has its is_voided flag set to "true."

Note that in both payloads the items array contains two objects describing a total of 3 items acquired in the transaction:

  • The first object describes 2 of the purchased items; so quantity is 2. Since the unit_price is 30.11, the subtotal for 2 items is 60.22

  • The second object describes the 3rd purchased item, so quantity is 1. Since the unit_price is 41.52, the subtotal remains 41.52 for 1 item.

Brown "payments": [{
"payment_id": "1",
"amount": 111.91,
"type": "VISA|MASTERCARD|DINERS|CASH|PAYPAL|...",
"payment_time":{{$isoTimestamp}}",
"user_id":"{{user_id}}",
"user_id_type": "SessionM_ID",
"custom_data": null}]
"payments": [{
"payment_id": "1",
"amount": 111.91,
"type": "VISA|MASTERCARD|DINERS|CASH|PAYPAL|...",
"payment_time":{{$isoTimestamp}}",
"user_id":"{{user_id}}",
"user_id_type": "SessionM_ID",
"custom_data": null}]

The payments array in both the original transaction and the full refund contains several attributes, including the amount and type of the payment being made and subsequently refunded.

Defining Request Payload for Partial Return and Refund

The workflow for purchases and returns relies heavily on the JSON payloads that specify several different attributes. This section compares the payloads typical of both. Consider the two payloads below, one for the original purchase and one for the subsequent partial refund. Each one is shown with color-coded boxes that identify key attributes in the payloads.

Original Purchase Request Payload Subsequent Partial Refund Request Payload

The annotated attributes illustrate important differences in the data they specify. Consult the table below for more information and bear in mind that the information within it pertains to the sequence diagram step above called, "Send original transaction with modified time and items."

Annotation Sample Code from Original Purchase Sample Code from Partial Refund Comments
Red "is_voided": false, "is_voided": false,

The original purchase payload requires that the is_voided field be set to "false", which indicates that the purchase request was made and is not voided.

The partial refund payload requires that the is_voided field be set to "false" as well because a partial refund request removes only part of the transaction. So, in effect, the transaction is not voided.

Yellow

"subtotal": 101.74,
"tax_total": 10.17,

"subtotal": 60.22,
"tax_total": 6.02,

The request payload for the original transaction indicates that the items were purchased for the subtotal of $101.74, plus $10.17 in tax.

But the corresponding partial refund leaves a portion of the transaction in tact, so the cost reflected in the subtotal and tax_total fields is for only 1 of the items. Only 1 of 2 items acquired in the original purchase has been reversed. As such, the partial refund shows both the subtotal (60.22) and tax_total (6.02) fields, each one reflecting a cost that is less than what is shown in the original transaction.

Green "modified_time": "{{purchase_timestamp}}", "modified_time": "{{refund_timestamp}}", The timestamp, or modified_time, for when the original transaction and the partial refund occurred. The timestamp for the refund is always later than the one for the original purchase.
Blue "items": [
{
"line_id": "1",
"item_id": "Sub category 1",
"quantity": 2,
"unit_price": 30.11,
"subtotal": 60.22,
"tax_included": 0.0,
"modifies_line_id": null,
"custom_data": null
},
{
"line_id": "2",
"item_id": "Sub category 2",
"quantity": 1,
"unit_price": 41.52,
"subtotal": 41.52,
"tax_included": 0.0,
"modifies_line_id": null,
"custom_data": null }],
"items": [
{
"line_id": "1",
"item_id": "Sub category 1",
"quantity": 2,
"unit_price": 30.11,
"subtotal": 60.22,
"tax_included": 0.0,
"modifies_line_id": null,
"custom_data": null
}]

The original transaction contains an items array that has two objects that describe a total of 3 items acquired in the transaction:

  • The first object describes 2 of the purchased items, so quantity is 2. Since the unit_price is 30.11, the subtotal for 2 items is 60.22 .

  • The second object describes the 3rd purchased item, so quantity is 1. Since the unit_price is 41.52, the subtotal remains 41.52 for 1 item.

While the partial refund does contain an items array, it no longer has one of the items purchased in the original transaction. That object and the item it represented - with line_id of "2" - has been returned and refunded. So its solitary object (with a line_id of "1") describes the same 2 items as seen for the first object in the original transaction :

  • The object describes 2 of the purchased items; so quantity is 2. Since the unit_price is 30.11, the subtotal for 2 items is 60.22

Brown "payments": [{
"payment_id": "1",
"amount": 111.91,
"type": "VISA|MASTERCARD|DINERS|CASH|PAYPAL|...",
"payment_time":{{$isoTimestamp}}",
"user_id":"{{user_id}}",
"user_id_type": "SessionM_ID",
"custom_data": null}]
"payments": [{
"payment_id": "1",
"amount": 66.24,
"type": "VISA|MASTERCARD|DINERS|CASH|PAYPAL|...",
"payment_time":{{$isoTimestamp}}",
"user_id":"{{user_id}}",
"user_id_type": "SessionM_ID",
"custom_data": null}]

The original transaction payments array contains several attributes, including the amount and type of the payment being made. However, since the partial refund returns one of the purchased items, a smaller payment is being made - a value of 66.24 as shown in the amount field.