POS API Version 2.4

General API Information

The Sparkfly POS API uses standard secured HTTP requests with JSON payloads. Requests to the platform with content bodies should be JSON and have Content-Type: application/json.

The endpoint addresses (specifically, the host) listed in this document may change based on environment. Please verify with Sparkfly on the proper API host and authentication credentials for your account.

All API endpoints are authenticated using an authentication token, which can be obtained by first sending authentication credentials to the /auth endpoint.

Terminology

Throughout this document we will use terms which have significance in the Sparkfly universe.

Term Definition
Credential A unique string of text linked to one or more offers
Offer A discount with one or more rules of eligibility. For example, an offer might be "$1.00 off any beverage". The discount is $1.00, the qualifying purchase is a beverage of some kind.
Check A single check at a restaurant. Transactions with the POS API are performed at the granularity of the check. If a single table is split into multiple checks, each check is treated separately.
Transaction Synonymous with check.
Offer Code A type of credential, which refers to a Sparkfly offer.
POS Agent Our term for software running on a Point-of-Sale system, either as a part of the POS platform itself or as a plug-in or as external software. The agnet is responsible for making requests to the POS API on behalf of the POS.

API Endpoints

Localization

The display_messages field in the TransactionResponse may be localized by providing an IETF Language Tag in the TransactionRequestDetail language_override field. The responses must be configured by Sparkfly support for your account. Support may also configure default languages on a per-store basis as well as for the top level account. The Sparkfly system will respond with the first message found after searching in this order:

  1. Language specified in the Transaction Request
  2. Language configured for the store (by Site ID)
  3. Language configured for the account
  4. A configured English message for the account
  5. A Default System Message (also in English)

For a contrived example, consider a Swiss account with account-level language default set to German "de-CH", a store with French default ("fr-CH"), and a user in that store who has their personal app set to Italian ("it-CH"). A request from that user should result in an Italian response. A request from that store by a user without a language set should result in French. The only way to obtain the default German response is if neither the store has a configured language nor user/terminal requests one.

Authenticate

Endpoint

GET /auth

Description

The POS API controls access with an Identity and Key provided to registered consumers of the API. A short-lived token is generated using the Identity and Key and all subsequent API calls require the token to succeed. This endpoint provides the ability to submit an Identity and Key, and receive an authentication token in response. The token will expire after 24 hours, and thus it is a good idea to renew it once every 23 hours to avoid any failed requests. Authenticated endpoints may reject an auth token. If they reject the auth token, the integration should re-authenticate using the identity and key, then retry the request.

Request

A standard authentication request involves sending an identity and key as headers:

Request Headers

Header Description
X-Auth-Identity API identifier provided by Sparkfly
X-Auth-Key API secret provided by Sparkfly

Responses

On success, an X-Auth-Token header will be returned in the response. All other endpoints expect the X-Auth-Token header to be sent. Tokens should be refreshed every 23 hours. Tokens should be refreshed if the API rejects the X-Auth-Token.

Status Meaning
204 No Content The authentication succeeded. The X-Auth-Token header will include the authentication token. Body will be empty.
401 Unauthorized The authentication was rejected. Body will be empty.
All others Non-2xx responses should be treated as unrecoverable errors. When this occurs, the POS should instruct the user to try again.

Transaction Query

Endpoint

PUT /v2.0/transactions

Description

The Transaction Query request is used to query the Sparkfly Platform to determine the list of available offers. It informs the Sparkfly Platform of any Sparkfly identifiers entered, any transaction details so far, and expects to get back any potential offers that should be applied to the check.

Situations that generally result in this request being made are:

Regardless of the triggering event, the Transaction Query should contain all of the current transaction details, all existing applied offers, all existing applied credentials, and any new credentials being applied. The query is intended to provide Sparkfly with a full picture of the transaction at a moment in time, so that the API can respond with actions to take against the transaction.

Request

A JSON body with the current transaction details, as defined in TransactionRequest. X-Auth-Token should contain a valid authorization token.

Response

Status Meaning
200 OK The request was well-formatted and processed. The body will contain a JSON object of type TransactionResponse
401 Unauthorized The authentication token was rejected. Consider re-authenticating with the Authenticate endpoint to retrieve a new X-Auth-Token.
422 Unprocessable Entity The body sent could not be parsed.
All others Non-2xx responses should be treated as unrecoverable errors. When this occurs, the POS should instruct the user to try again.

Transaction Finalize

Endpoint

POST /v2.0/transactions

Description

The Transaction Finalize request is used to inform the Sparkfly Platform that a previously queried check has closed (finalized).

Request

A JSON body with the current transaction details, as defined in TransactionRequest. X-Auth-Token should contain a valid authorization token.

Response

Status Meaning
200 OK The request was well-formatted and processed. The transaction has been successfully closed on the Sparkfly side. The body will contain a JSON object of type TransactionResponse.
401 Unauthorized The authentication token was rejected. Consider re-authenticating with the Authenticate endpoint to retrieve a new X-Auth-Token.
422 Unprocessable Entity The body sent could not be parsed.
All others Non-2xx responses should be treated as unrecoverable errors. When this occurs, the POS should instruct the user to try again.

Transaction Void

Endpoint

POST /v2.0/voided_transactions

Description

The Transaction Void request is used to inform the Sparkfly Platform that a previously queried transaction should be voided on the Sparkfly side. This will not prevent the transaction number from being used again. Sparkfly will detach all previously applied offers from the check and make them available for use elsehere. If the check needs to be re-activated, a subsequent TransactionQuery request will executed as expected.

Request

A JSON body with the current transaction details, as defined in VoidTransactionRequest. X-Auth-Token should contain a valid authorization token.

Response

Status Meaning
200 OK The request was well-formatted and processed. Any offers associated with the pos_transaction_id have been released and are not redeemed. The body will contain a JSON object of type TransactionResponse.
401 Unauthorized The authentication token was rejected. Consider re-authenticating with the Authenticate endpoint to retrieve a new X-Auth-Token.
422 Unprocessable Entity The body sent could not be parsed.
All others Non-2xx responses should be treated as unrecoverable errors. When this occurs, the POS should instruct the user to try again.

Schema Specification

Important Notes

TransactionRequest

Field Type Description
transaction TransactionRequestDetail Contains transaction details

TransactionRequestDetail

Field Type Description
site_id string The site/store identifier(known to Sparkfly) of the location wherethe transaction is being processed.
pos_transaction_id string A unique ID for this transaction, originated by the POS.
status string The current transaction status and reason for this request. This field is legacy and has some strange definitions. Generally speaking, it should be one of the following values:
  • codeEntry — A code is being added to the check.
  • background — A change to the check warrants revalidating offers, such as items being removed or added, etc.
  • closed — The check has been closed. Typically required for Finalize Transaction calls.
occurred_at string The local date and time where the transaction is occurring. The date should be in ISO-8601 format.
business_date string The "business date" for the transaction. Expected format is "YYYY-mm-dd". For example, January 2nd, 2006 would be 2006-01-02
register_id string (Optional) The terminal ID sending the request.
operator_id string (Optional) The logged in employee ID or badge number.
till_id string (Optional) An accounting till ID, if available.
table_id string (Optional) A unique ID for the table. Only useful in table service establishments.
credentials AppliedCredential[] An array of all credentials currently applied to check, including any new credentials being applied.
offers AppliedOffer[] An array of Sparkfly offers currently applied to the check.
items TransactionItem[] An array of all transaction items currently on the check.
totals Totals The financial totals for this check. Used for calculating check-level discounts.
selected_offers SelectedOffer[] An array of selected offers. For use with staff-selected offers and queryOffers/applyOffers flows.
posagent_version string The version of the POS Agent (the POS integration or plugin built for Sparkfly)
pos_vendor string The POS vendor name.
pos_version string The version of the POS used.
member_identified boolean Specifies whether this transaction is for a pre-identified member, which may affect offer eligibility requirements.
terminal_type string The type of terminal sending the request. Valid options are instore and online. Defaults to instore.
language_override string The desired localization language for responeses, usually intended to be an IETF Language Tag, for example "en" or "fr-CA". See Localization

TransactionResponse

Field Type Description
transaction TransactionResponseDetail Contains transaction details

TransactionResponseDetail

Field Type Description
remove_offers Offer[] An array of offers to remove from the check. For example, if the POS had an offer applied in a previous request that is no longer eligibile due to an item being removed, this array will contain an element indicating the offer to remove.
errors Error[] A list of errors reported by the server. The contents of this array may contain elements even in successful cases. The intention is that the POS integration should log the contents of this array to the local logging mechanism for the integration.
display_messages DisplayMessage[] A list of messages to show the POS operator. Usually this will include messaging such as, "Code has been accepted", or "Required items not purchased". The messages may also originate from a downstream provider if the account is using one of our partner integrations.
credentials Credential[] An array containing the credentials that were sent in the request. The POS integration should inspect the valid flag for each credential, and if it is false, proceed to remove the credential from the POS.
add_offers Offer[] An array of new offers to apply to the transaction. The POS should inspect each element and apply a discount per element. The sparkfly_auth_code should be stored with the discount somehow, so that it can be sent in subsequent requests in the TransactionRequestDetail::offers[] array.
available_offers AvailableOffer[] An array of offers available for this transaction. Not to be applied, but to be displayed for selection when using the queryOffers/applyOffers flow.

VoidTransactionRequest

Field Type Description
transaction VoidTransactionRequestDetail Contains transaction details

VoidTransactionRequestDetail

Field Type Description
site_id string The site/store identifier(known to Sparkfly) of the location wherethe transaction is being processed.
pos_transaction_id string A unique ID for this transaction, originated by the POS.
occurred_at string The local date and time where the transaction is occurring. The date should be in ISO-8601 format.
business_date string The "business date" for the transaction. Expected format is "YYYY-mm-dd". For example, January 2nd, 2006 would be 2006-01-02
register_id string (Optional) The terminal ID sending the request.
operator_id string (Optional) The logged in employee ID or badge number.
till_id string (Optional) An accounting till ID, if available.
table_id string (Optional) A unique ID for the table. Only useful in table service establishments.
posagent_version string The version of the POS Agent (the POS integration or plugin built for Sparkfly)
pos_vendor string The POS vendor name.
pos_version string The version of the POS used.

Error

Field Type Description
message string The error description. This should be logged locally.

DisplayMessage

Field Type Description
message string The message description. This should be displayed to the user.
priority int The priority of this message. When processing multiple DisplayMessage objects, the messages should be displayed from least to greatest priority.
message_id string Unique identifier for the message. Provides a system-readable identifier for the message content. Useful for localization or custom message formatting on the client side.
message_content object Object containing data relevant to the message. This data, combined with the message_id can be used to construct a display-friendly message for end-users if the default message provided in the message field is not adequate for the use case.

Each display_message element will have a message_id field, which may be one of the following values:

message_id purpose default message message_content fields
SF-1000 Code has been accepted Code has been accepted credential_identifier
SF-1001 Code does not exist Code is invalid credential_identifier
SF-1002 Code already redeemed Code already redeemed credential_identifier
SF-1003 Code expired Code is expired credential_identifier
expiration_date
SF-1004 Code is locked Code is currently in use on another transaction credential_identifier
SF-1005 Only one code allowed per transaction Only one code allowed per transaction
SF-1006 Minimum purchase amount not met Offer not vaid - $X minimum required credential_identifier
minimum_purchase_amount
SF-1007 Purchase requirement not met Required items not purchased credential_identifier
SF-1008 Offer is not valid at location Offer is not valid at this location credential_identifier
SF-1009 Offer is expired Offer has expired credential_identifier
expiration_date
SF-1010 Offer is not available within time window Offer only available X (Ex: "On Weekdays", or "On Sundays", or "During Happy Hour") credential_identifier
availability
SF-1011 Offer is not available in-store Offer is not available in-store credential_identifier

For example, in the case where an offer could not be applied due to insufficient transaction total, the following JSON may be returned (remainder of response removed for brevity):

{
    ...
    "display_messages": [
        {
            "message": "Offer not vaid - $50 minimum required",
            "priority": 0,
            "message_id": "SF-1006",
            "message_content": {
                "minimum_purchase_amount": "50.00"
            }
        }
    ]
    ...
}

Offer

Field Type Description
credential_identifier string The Credential::sparkfly_identifier that this offer is a child of.
sparkfly_auth_code string The Sparkfly authorization code associated with the offer. This should be stored locally by the POS and sent in future requests referencing the Offer.
pos_offer_code string The POS-specific discount code used, or to use, for the offer. For instance, this may be the value of the unique ID of an open discount in the destination POS.
pos_offer_code_type string Helps the POS understand how to interpret the meaning of pos_offer_code. For instance, the POS may have multiple overlapping types of discounts (promos, comps, discounts, tenders), this field would contain the type of POS-specific discount to apply.
quantity string The quantity of offers to apply.
amount string The amount that should be applied.
tip string The amount that should be applied as a tip, in addition to amount, in the case where the discount type allows for tips, such as with tenders.
auth string An authorization code, as required by some POS systems to apply the discount. Usually in the case of a tender-based discount or stored-value card.
name string The name of the offer being applied. This can be shown on receipts or customer-facing check views.
qualifying_items QualifyingItem[] An array of qualifying items linked with the offer. The POS should use this field to apply the discount to specific items, and should send this information when including offers in requests.
entry_id string A unique ID within the POS system for the applied discount.

AppliedCredential

Field Type Description
sparkfly_identifier string The Sparkfly identifier to use for lookup. May be an offer code from a Sparkfly landing page, phone number, etc.
entry_method string The method of entry. (manual, magcard, barcode)
amount string (Optional) Allows for specifying a desired applied value for a credential. Useful for Gift Cards programs.
tip string (Optional) Allows for specifying a desired tip value for a credential. Useful for Gift Cards programs.

AppliedOffer

Field Type Description
credential_identifier string The Credential::sparkfly_identifier that this offer is a child of.
sparkfly_auth_code string The Sparkfly authorization code for this instance of an applied offer.
pos_offer_code string The POS-specific discount code used, or to use, for the offer. For instance, this may be the value of the unique ID of an open discount in the destination POS.
pos_offer_code_type string Helps the POS understand how to interpret the meaning of pos_offer_code. For instance, the POS may have multiple overlapping types of discounts (promos, comps, discounts, tenders), this field would contain the type of POS-specific discount to apply.
quantity string The quantity of offers applied or to apply.
amount string The amount that should be applied.
tip string The amount that should be applied as a tip, in addition to amount, in the case where the discount type allows for tips, such as with tenders.
auth string An authorization code, as required by some POS systems to apply the discount. Usually in the case of a tender-based discount or stored-value card.
name string The name of the offer being applied. This can be shown on receipts or customer-facing check views.
qualifying_items QualifyingItem[] An array of qualifying items linked with the offer. The POS should use this field to apply the discount to specific items, and should send this information when including offers in requests.
entry_id string A unique ID within the POS system for the applied discount.

AvailableOffer

Field Type Description
offer_id string A unique identifier for this offer.
name string A display-friendly name for the offer.
valid_now boolean Whether or not the offer can be applied to the current transaction.
expiration_date string (Optional) ISO-8601 format timestamp for when the offer expires.
invalid_reason string (Optional) An error message to be shown next to the offer, usually because valid_now is false

SelectedOffer

Field Type Description
offer_id string The unique identifier of the offer selected by the operator.

QualifyingItem

Field Type Description
line_number string The line_number of the transaction line item to reference.
entry_id string The entry_id of the transaction line item to reference.
qualification_type string An enum representing the type of qualification. "1" signifies the referenced item is being redeemed/discounted. "2" signifies that the referenced item is required for the discount, but is not itself being discounted.

TransactionItem

Field Type Description
line_number string The line number, either provided by the POS or generated based on the order of the item as ordered by the POS
entry_id string The POS-specific unique ID for this line item. This should be the ID of the line itself, not the ID of the menu item associated with the line
linked_entry_id string (Optional) The POS-specific unique ID of the parent line to this line. For example, in the case of linking a combo sub-item to its parent, or a modifier to its parent.
linked_line_number string (Optional) Same linkage as linked_entry_id, but using the line_number field
level string The hierarchy level for this line item, with 0 being the top level.
item_code string The POS-specific menu item ID for this line. This is the ID used to determine offer eligibility.
name string (Optional) The name, as shown on the check in the POS, of this line. May be the short, kitchen display name.
description string (Optional) The longer name, as shown on the check in the POS, of this line. May be the longer, less abbreviated name.
categories string[] (Optional) An array of strings, with each entry being a representation of the menu categories this line item's menu item belongs to.
seat string (Optional) The seat the line item is associated with. Typically only used in table service restaurants, and only if the POS provides it.
quantity string The quantity associated with this line item.
amount string The extended amount for this line item. This should be the total value of the line. (i.e. quantity * base price).
mode string Allows passing the "order state" of an item to Sparkfly. This is POS-specific and can be ignored if the situation doesn't have the concept. This is most useful in sending whether or not a line item has been sent to the kitchen and to consider it for item eligibility.
type string Allows passing a POS-specific "type" which may indicate the type of line item this is (such as "combo item", "modifier", etc.) This is POS-specific and all values are accepted.

Totals

Field Type Description
subtotal string The pre-tax total.
due string The balance due.
discount string The accumulation of all applied discounts, Sparkfly and non-Sparkfly alike
service string Gratuity or service fees.
tax string The applied tax
paid string The amount paid

Example Transactions

The following examples demonstrate some common POS workflows, and how those workflows translate to an API conversation. The first example demonstrates authentication. For the remaining examples, assume (for the sake of brevity) that authentication has been previously completed, and that an X-Auth-Token is already obtained.

Authenticating

Assuming the identity of test_account and the key of test_password provided by Sparkfly. An authentication request is sent:

GET http://posapi-staging.sparkfly.com/auth HTTP/1.1
X-Auth-Identity: test_account
X-Auth-Key: test_password
Host: posapi-staging.sparkfly.com

The request, successful, returns a 204 No Content and the X-Auth-Token header:

HTTP/1.1 204 No Content
Server: nginx/1.12.2
X-Auth-Token: abc123abc123

The X-Auth-Token is now valid, and should be used for the other endpoints.

Applying an offer, invalid credential.

In this example, the user purchased one "Diet Coke", and is attempting to use coupon "1234". A Transaction Query request is sent:

{
    "transaction": {
        "site_id": "9999999:9999",
        "register_id": "1",
        "pos_transaction_id": "1048847",
        "terminal_type": "instore",
        "operator_id": "200",
        "status": "codeEntry",
        "occurred_at": "2019-08-13T09:09:12.4580322-04:00",
        "till_id": "0",
        "credentials": [
            {
                "sparkfly_identifier": "1234",
                "entry_method": "Manual"
            }
        ],
        "items": [
            {
                "line_number": "1",
                "entry_id": "1108601",
                "level": 0,
                "item_code": "9115",
                "name": "DIET COKE",
                "description": "DIET COKE",
                "categories": [
                    "20"
                ],
                "seat": 1,
                "quantity": "1",
                "amount": "1.50"
            }
        ],
        "offers": [],
        "totals": {
            "subtotal": "1.5",
            "due": "1.61",
            "discount": "0",
            "service": "0",
            "tax": "0.11",
            "paid": "0"
        },
        "posagent_version": "1.0.0.0-DLL",
        "pos_vendor": "Aloha",
        "pos_version": "6.7.67 TS",
        "business_date": "2017-10-09",
        "table_id": "1048832"
    }
}

There are no offers with the offer code "1234", and so an "Invalid Code" error is returned:

{
    "transaction": {
        "errors": [
            {
                "message": "[200] Code is invalid"
            }
        ],
        "display_messages": [
            {
                "message": "[200] Code is invalid",
                "priority": 0
            }
        ],
        "credentials": [
            {
                "sparkfly_identifier": "1234",
                "valid": false
            }
        ]
    }
}

Note a few things:

Applying an offer, valid credential but eligibility not met.

In this example, the user purchased a "Diet Coke", and is trying to use an offer "5555" that gives a discount on "Waffles". The user has not purchased any eligible items, so the credential is returned as valid, but no offer is applied. The request sent is:

{
    "transaction": {
        "site_id": "9999999:9999",
        "register_id": "1",
        "terminal_type": "instore",
        "pos_transaction_id": "1048848",
        "operator_id": "200",
        "status": "codeEntry",
        "occurred_at": "2019-08-13T09:19:32.8143227-04:00",
        "till_id": "0",
        "credentials": [
            {
                "sparkfly_identifier": "5555",
                "entry_method": "Manual"
            }
        ],
        "items": [
            {
                "line_number": "1",
                "entry_id": "1108772",
                "level": 0,
                "item_code": "9115",
                "name": "DIET COKE",
                "description": "DIET COKE",
                "categories": [
                    "20"
                ],
                "seat": 1,
                "quantity": "1",
                "amount": "1.50"
            }
        ],
        "offers": [],
        "totals": {
            "subtotal": "1.5",
            "due": "1.61",
            "discount": "0",
            "service": "0",
            "tax": "0.11",
            "paid": "0"
        },
        "posagent_version": "1.0.0.0-DLL",
        "pos_vendor": "Aloha",
        "pos_version": "6.7.67 TS",
        "business_date": "2017-10-09",
        "table_id": "1048833"
    }
}

The server responds with a valid credential, and an error:

{
    "transaction": {
        "errors": [
            {
                "message": "Required items not purchased"
            }
        ],
        "display_messages": [
            {
                "message": "Required items not purchased",
                "priority": 0
            }
        ],
        "credentials": [
            {
                "sparkfly_identifier": "5555",
                "valid": true
            }
        ]
    }
}

Some notes:

Applying an offer, valid credential and a discount is applied, and the transaction is finalized.

This example is a more complete example, including the purchasing of an item eligible for a discount, the application of a discount, and the closing of the transaction with a Transaction Finalize request at the end.

First, the user, with a "Diet Coke" purchased, enters a valid offer code "7777", and the POS integration transmits a Transaction Query:

{
    "transaction": {
        "site_id": "9999999:9999",
        "register_id": "1",
        "terminal_type": "instore",
        "pos_transaction_id": "1048849",
        "operator_id": "200",
        "status": "codeEntry",
        "occurred_at": "2019-08-13T09:27:56.7518212-04:00",
        "till_id": "0",
        "credentials": [
            {
                "sparkfly_identifier": "7777",
                "entry_method": "Manual"
            }
        ],
        "items": [
            {
                "line_number": "1",
                "entry_id": "1108893",
                "level": 0,
                "item_code": "9115",
                "name": "DIET COKE",
                "description": "DIET COKE",
                "categories": [
                    "20"
                ],
                "seat": 1,
                "quantity": "1",
                "amount": "1.50"
            }
        ],
        "offers": [],
        "totals": {
            "subtotal": "1.5",
            "due": "1.61",
            "discount": "0",
            "service": "0",
            "tax": "0.11",
            "paid": "0"
        },
        "posagent_version": "1.0.0.0-DLL",
        "pos_vendor": "Aloha",
        "pos_version": "6.7.67 TS",
        "business_date": "2017-10-09",
        "table_id": "1048834"
    }
}

The server, noticing the presence of a "Diet Coke" and the credential "7777" responds with a valid credential, an offer to apply, and a message for the operator:

{
    "transaction": {
        "display_messages": [
            {
                "message": "Code has been accepted",
                "priority": 0
            }
        ],
        "credentials": [
            {
                "sparkfly_identifier": "7777",
                "valid": true
            }
        ],
        "add_offers": [
            {
                "credential_identifier": "7777",
                "sparkfly_auth_code": "7777:2529",
                "pos_offer_code": "1001",
                "pos_offer_code_type": "comp",
                "quantity": "1",
                "amount": "1.00",
                "name": "2529:Aloha: Comp: $1 off Diet Coke",
                "qualifying_items": [
                    {
                        "entry_id": "1108893",
                        "item_code": "9115",
                        "qualification_type": "0",
                        "amount": "1.00"
                    }
                ]
            }
        ]
    }
}

The POS sees that the credential is valid, and leaves it on the check. The POS will also apply a discount for 1.00 to the check, reducing the balance. When the customer pays for their items, a Transaction Finalize is sent to the server. This will redeem and consume the offer on the Sparkfly side. If the credential used is not reusable, the credential will no longer be valid and may not be used again. The finalize sent:

{
    "transaction": {
        "site_id": "9999999:9999",
        "register_id": "1",
        "terminal_type": "instore",
        "pos_transaction_id": "1048849",
        "operator_id": "200",
        "status": "closed",
        "occurred_at": "2019-08-13T09:33:01.7635569-04:00",
        "till_id": "0",
        "credentials": [
            {
                "sparkfly_identifier": "7777",
                "entry_method": "Manual"
            }
        ],
        "items": [
            {
                "line_number": "1",
                "entry_id": "1108893",
                "level": 0,
                "item_code": "9115",
                "name": "DIET COKE",
                "description": "DIET COKE",
                "categories": [
                    "20"
                ],
                "seat": 1,
                "quantity": "1",
                "amount": "1.50"
            }
        ],
        "offers": [
            {
                "credential_identifier": "7777",
                "sparkfly_auth_code": "7777:2529",
                "pos_offer_code": "1001",
                "pos_offer_code_type": "comp",
                "quantity": "1",
                "amount": "1.00",
                "name": "2529:Aloha: Comp: $",
                "qualifying_items": []
            }
        ],
        "totals": {
            "subtotal": "0.5",
            "due": "0",
            "discount": "1",
            "service": "0",
            "tax": "0.04",
            "paid": "10"
        },
        "posagent_version": "1.0.0.0-DLL",
        "pos_vendor": "Aloha",
        "pos_version": "6.7.67 TS",
        "business_date": "2017-10-09",
        "table_id": "1048834"
    }
}

Note that in the Finalize, the subtotal is only 0.50. This is the 1.50 from the Diet Coke reduced by the 1.00 discount we applied. We also include the currently applied discount in the offers array sent to the server. The sparkfly_auth_code is vital here, as the server uses that token to link the finalized/redeemed offer to the original credential that applied it. You can also see that the user paid by tendering 10.00, and that the balance due is 0.00. The server responds with a 200 OK and an empty transaction response:

{
    "transaction": {}
}

The offers are now redeemed and this transaction is closed with Sparkfly.

Applying an offer, valid credential and a discount is applied, but the transaction cancelled.

This example is an example of what happens when a transaction is cancelled. We will demonstrated the purchasing of an item eligible for a discount, the application of a discount, and the cancelling of the transaction with a Transaction Void request at the end.

First, the user, with a "Diet Coke" purchased, enters a valid offer code "7777", and the POS integration transmits a Transaction Query:

{
    "transaction": {
        "site_id": "9999999:9999",
        "register_id": "1",
        "terminal_type": "instore",
        "pos_transaction_id": "1048849",
        "operator_id": "200",
        "status": "codeEntry",
        "occurred_at": "2019-08-13T09:27:56.7518212-04:00",
        "till_id": "0",
        "credentials": [
            {
                "sparkfly_identifier": "7777",
                "entry_method": "Manual"
            }
        ],
        "items": [
            {
                "line_number": "1",
                "entry_id": "1108893",
                "level": 0,
                "item_code": "9115",
                "name": "DIET COKE",
                "description": "DIET COKE",
                "categories": [
                    "20"
                ],
                "seat": 1,
                "quantity": "1",
                "amount": "1.50"
            }
        ],
        "offers": [],
        "totals": {
            "subtotal": "1.5",
            "due": "1.61",
            "discount": "0",
            "service": "0",
            "tax": "0.11",
            "paid": "0"
        },
        "posagent_version": "1.0.0.0-DLL",
        "pos_vendor": "Aloha",
        "pos_version": "6.7.67 TS",
        "business_date": "2017-10-09",
        "table_id": "1048834"
    }
}

The server responds with an offer:

{
    "transaction": {
        "display_messages": [
            {
                "message": "Code has been accepted",
                "priority": 0
            }
        ],
        "credentials": [
            {
                "sparkfly_identifier": "7777",
                "valid": true
            }
        ],
        "add_offers": [
            {
                "credential_identifier": "7777",
                "sparkfly_auth_code": "7777:2529",
                "pos_offer_code": "1001",
                "pos_offer_code_type": "comp",
                "quantity": "1",
                "amount": "1.00",
                "name": "2529:Aloha: Comp: $1 off Diet Coke",
                "qualifying_items": [
                    {
                        "entry_id": "1108893",
                        "item_code": "9115",
                        "qualification_type": "0",
                        "amount": "1.00"
                    }
                ]
            }
        ]
    }
}

The offer is applied, as is seen in other exmaples. At this point the customer (or the POS operator) decides this transaction is not going to complete, and cancels it. At this point, the POS should send a Transaction Void request to Sparkfly:

{
    "transaction": {
        "site_id": "9999999:9999",
        "register_id": "1",
        "pos_transaction_id": "1048852",
        "operator_id": "200",
        "status": "background",
        "occurred_at": "0001-01-01T00:00:00",
        "credentials": [],
        "items": [],
        "offers": [],
        "totals": {},
        "posagent_version": "1.0.0.0-DLL",
        "pos_vendor": "Aloha",
        "business_date": "2017-10-09",
        "table_id": "1048837"
    }
}

The server responds with 200 OK and an empty TransactionResponse:

{
    "transaction": {}
}

All credentials and offers associated with this check (1048852 in this example), are voided and returned to the pool of available offers.

Applying an offer, valid credential and a discount is applied, order is later modified, and lastly, finalized.

This final example demonstrates the idempotent nature of the Transaction Query endpoint. The design intention of that endpoint is such that the POS integration should call it many times through the lifecycle of a transaction. For example, if a user purchases 2 items, applies a credential, then purchases 3 more items, and lastly, finalizes -- a query would be sent following the credential being applied, and again after the 3 items were purchased, and lastly, a finalize should be sent at the end. This flow allows Sparkfly to respond with changes as the contents of the check change. Let's demonstrate.

First, the user purchases a "Diet Coke", and applies a credential "EDGR". A Transaction Query is sent to the server:

{
    "transaction": {
        "site_id": "9999999:9999",
        "register_id": "1",
        "terminal_type": "instore",
        "pos_transaction_id": "1048854",
        "operator_id": "200",
        "status": "codeEntry",
        "occurred_at": "2019-08-13T10:01:14.7795385-04:00",
        "till_id": "0",
        "credentials": [
            {
                "sparkfly_identifier": "EDGR",
                "entry_method": "Manual"
            }
        ],
        "items": [
            {
                "line_number": "1",
                "entry_id": "1109682",
                "level": 0,
                "item_code": "9115",
                "name": "DIET COKE",
                "description": "DIET COKE",
                "categories": [
                    "20"
                ],
                "seat": 1,
                "quantity": "1",
                "amount": "1.50"
            }
        ],
        "offers": [],
        "totals": {
            "subtotal": "1.5",
            "due": "1.61",
            "discount": "0",
            "service": "0",
            "tax": "0.11",
            "paid": "0"
        },
        "posagent_version": "1.0.0.0-DLL",
        "pos_vendor": "Aloha",
        "pos_version": "6.7.67 TS",
        "business_date": "2017-10-09",
        "table_id": "1048838"
    }
}

The server responds with a discount on the Diet Coke:

{
    "transaction": {
        "display_messages": [
            {
                "message": "Code has been accepted",
                "priority": 0
            }
        ],
        "credentials": [
            {
                "sparkfly_identifier": "EDGR",
                "valid": true
            }
        ],
        "add_offers": [
            {
                "credential_identifier": "EDGR",
                "sparkfly_auth_code": "EDGR:2529",
                "pos_offer_code": "1001",
                "pos_offer_code_type": "comp",
                "quantity": "1",
                "amount": "1.00",
                "name": "2529:Aloha: Comp: $1 off Diet Coke",
                "qualifying_items": [
                    {
                        "entry_id": "1109682",
                        "item_code": "9115",
                        "qualification_type": "0",
                        "amount": "1.00"
                    }
                ]
            }
        ]
    }
}

The discount is applied at the POS. Next, the user adds a ROOT BEER to the order, and the POS, noting the presence of an existing credential, and a change to the check, sends another Transaction Query.

{
    "transaction": {
        "site_id": "9999999:9999",
        "register_id": "1",
        "terminal_type": "instore",
        "pos_transaction_id": "1048854",
        "operator_id": "200",
        "status": "background",
        "occurred_at": "2019-08-13T10:01:29.5839645-04:00",
        "till_id": "0",
        "credentials": [
            {
                "sparkfly_identifier": "EDGR",
                "entry_method": "Manual"
            }
        ],
        "items": [
            {
                "line_number": "1",
                "entry_id": "1109682",
                "level": 0,
                "item_code": "9115",
                "name": "DIET COKE",
                "description": "DIET COKE",
                "categories": [
                    "20"
                ],
                "seat": 1,
                "quantity": "1",
                "amount": "1.50"
            },
            {
                "line_number": "3",
                "entry_id": "1109744",
                "level": 0,
                "item_code": "9140",
                "name": "ROOT BEER",
                "description": "ROOT BEER",
                "categories": [
                    "20"
                ],
                "seat": 1,
                "quantity": "1",
                "amount": "1.50"
            }
        ],
        "offers": [
            {
                "credential_identifier": "EDGR",
                "sparkfly_auth_code": "EDGR:2529",
                "pos_offer_code": "1001",
                "pos_offer_code_type": "comp",
                "quantity": "1",
                "amount": "1.00",
                "name": "2529:Aloha: Comp: $",
                "qualifying_items": []
            }
        ],
        "totals": {
            "subtotal": "2",
            "due": "2.14",
            "discount": "0",
            "service": "0",
            "tax": "0.14",
            "paid": "0"
        },
        "posagent_version": "1.0.0.0-DLL",
        "pos_vendor": "Aloha",
        "pos_version": "6.7.67 TS",
        "business_date": "2017-10-09",
        "table_id": "1048838"
    }
}

The server inspects the request, determines that no changes need to be made (the Diet Coke offer is still valid), and sends back a response:

{
    "transaction": {
        "display_messages": [
            {
                "message": "Code has been accepted",
                "priority": 0
            }
        ],
        "credentials": [
            {
                "sparkfly_identifier": "EDGR",
                "valid": true
            }
        ]
    }
}

Finally, the user decides they no longer want a Diet Coke, and it is removed from the check. This is results in another Transaction Query being sent to Sparkfly:

{
    "transaction": {
        "site_id": "9999999:9999",
        "register_id": "1",
        "terminal_type": "instore",
        "pos_transaction_id": "1048854",
        "operator_id": "200",
        "status": "background",
        "occurred_at": "2019-08-13T10:01:29.5839645-04:00",
        "till_id": "0",
        "credentials": [
            {
                "sparkfly_identifier": "EDGR",
                "entry_method": "Manual"
            }
        ],
        "items": [
            {
                "line_number": "3",
                "entry_id": "1109744",
                "level": 0,
                "item_code": "9140",
                "name": "ROOT BEER",
                "description": "ROOT BEER",
                "categories": [
                    "20"
                ],
                "seat": 1,
                "quantity": "1",
                "amount": "1.50"
            }
        ],
        "offers": [
            {
                "credential_identifier": "EDGR",
                "sparkfly_auth_code": "EDGR:2529",
                "pos_offer_code": "1001",
                "pos_offer_code_type": "comp",
                "quantity": "1",
                "amount": "1.00",
                "name": "2529:Aloha: Comp: $",
                "qualifying_items": []
            }
        ],
        "totals": {
            "subtotal": "2",
            "due": "2.14",
            "discount": "0",
            "service": "0",
            "tax": "0.14",
            "paid": "0"
        },
        "posagent_version": "1.0.0.0-DLL",
        "pos_vendor": "Aloha",
        "pos_version": "6.7.67 TS",
        "business_date": "2017-10-09",
        "table_id": "1048838"
    }
}

The server notes the presence of an applied discount, but the eligible item (DIET COKE) is missing. The server instructs the POS to remove the offer:

{
    "transaction": {
        "errors": [
            {
                "message": "Code has been accepted"
            }
        ],
        "display_messages": [
            {
                "message": "Code has been accepted",
                "priority": 0
            }
        ],
        "credentials": [
            {
                "sparkfly_identifier": "EDGR",
                "valid": true
            }
        ],
        "remove_offers": [
            {
                "credential_identifier": "",
                "sparkfly_auth_code": "EDGR:2529",
                "pos_offer_code": "",
                "quantity": "",
                "amount": "",
                "name": "",
                "qualifying_items": null
            }
        ]
    }
}

The POS removes the offer. At this point the transaction could be finalized or voided.