Sale

Captures a card present payment on a physical terminal in a single step, combining authorization and capture. Use this endpoint to charge a guest's card for a completed ticket at the point of sale. The terminal prompts for the card, processes the EMV transaction, and returns the approval or decline outcome.

Request Headers

HeaderRequiredDescription
AuthorizationYesBearer YOUR_ACCESS_TOKEN
Content-TypeYesapplication/json

Request Parameters

Path Parameters

ParameterTypeRequiredDescription
location_idstringYesIdentifier of the location processing the sale

Request Body Fields

FieldTypeRequiredDescription
ticketobjectYesSee ticket object below.
ticket.idstringYesThe unique identifier of the ticket.
ticket.voidbooleanNoIndicates whether the ticket has been voided.
paymentobjectYesPayment instruction for the terminal.
payment.idstringYesUnique identifier for the payment.
payment.amountintegerYesPayment amount, in cents.
payment.cashbackintegerNoEBT cashback amount, in cents.
payment.inv_numberstringNoInvoice number to associate with the payment.
user_id_externalintegerNoExternal user ID associated with the card being tokenized (if applicable).
ignoreAvsResultbooleanNoContinue processing even if AVS validation fails.
webhook_idstringYesUnique identifier for the webhook.
terminal_idstringYesUnique identifier for the POS terminal.

Object Fields

The ticket object may be sent as a compact reference (just id) or as a fully embedded structure. When embedded, it supports the fields below. All embedded fields are optional, and monetary values are expressed in minor units (cents).

ticket object

FieldTypeRequiredDescription
idstringYesThe unique identifier of the ticket.
namestringNoThe name of the ticket.
openbooleanNoIndicates whether the ticket is still open.
opened_attimestampNoThe timestamp when the ticket was opened.
closed_attimestampNoThe timestamp when the ticket was closed.
ticket_numberintegerNoThe ticket number.
totalsobjectNoTicket totals information. See ticket.totals object below.
voidbooleanNoIndicates whether the ticket has been voided.
_embeddedobjectNoEmbedded ticket resources. See ticket._embedded object below.

ticket.totals object

All values are integers in minor units (cents).

FieldTypeDescription
discountsintegerTotal ticket-level discounts, in cents.
dueintegerRemaining unpaid amount (total - paid), in cents.
exclusive_taxintegerTaxes not included in item or service charge prices, in cents.
inclusive_taxintegerTaxes included in item or service charge prices, in cents.
itemsintegerTotal cost of all items, in cents.
other_chargesintegerTotal cost of all other charges, in cents.
paidintegerTotal amount paid, in cents.
service_chargesintegerTotal service charges, in cents.
sub_totalintegerSubtotal before tax (items + other_charges - discounts), in cents.
taxintegerTotal tax, in cents.
tipsintegerTotal tips, in cents.
totalintegerFinal amount due (subtotal + service_charges + exclusive_tax), in cents.

ticket._embedded object

Container for nested ticket entities. May include ebt_type, discounts[], items[], and payments[]. Item-level entities (employee, order_type, revenue_center, table, and modifiers[]) are nested within each items[] entry.

ebt_type

FieldTypeDescription
ebt_typestringEBT type. Possible values: FOOD_STAMP, CASH_BENEFIT, VOUCHER, INQUIRY_CASH, INQUIRY_FOOD.

discounts[] (array)

FieldTypeDescription
idstringUnique identifier of the discount.
commentstringDiscount comment.
namestringDiscount name as it appears on the ticket.
valueintegerDiscount value, in cents.

items[] (array)

FieldTypeDescription
idstringUnique identifier of the item.
inclusive_taxintegerTax included in the item price, in cents.
namestringItem name.
priceintegerTotal item price including quantity, modifiers, and discounts, in cents.
quantityintegerItem quantity numerator.
sentbooleanIndicates whether the item has been sent for preparation.
sent_attimestampTime the item was sent for preparation.
splitintegerItem quantity denominator.
_embeddedobjectEmbedded item resources.

items[].employee (object)

FieldTypeDescription
check_namestringEmployee name as printed on receipts.
first_namestringEmployee first name.
idstringUnique employee identifier.
last_namestringEmployee last name.
loginstringEmployee POS login/PIN.
middle_namestringEmployee middle name.
pos_idstringEmployee ID shown in the POS.
start_datestringEmployee start date (YYYY-MM-DD).

items[].order_type (object)

FieldTypeDescription
availablebooleanWhether tickets can be opened using this order type.
idstringUnique order type identifier.
namestringOrder type name.
pos_idstringOrder type ID shown in the POS.

items[].revenue_center (object)

FieldTypeDescription
defaultbooleanIndicates whether this is the default revenue center.
idstringUnique revenue center identifier.
namestringRevenue center name.
pos_idstringRevenue center ID shown in the POS.

items[].table (object)

FieldTypeDescription
availablebooleanWhether the table is available for seating.
idstringUnique table identifier.
namestringTable name.
numberintegerTable number.
pos_idstringTable ID shown in the POS.
seatsintegerNumber of seats at the table.

payments[] (array)

FieldTypeDescription
idstringUnique payment identifier.
amountintegerPayment amount, in cents.
tender_types_idintegerTender type identifier applied to the payment.
tipintegerTip amount, in cents.
inv_numberintegerReference number for the transaction (15-character limit).

items[]._embedded.modifiers[] (array)

FieldTypeDescription
idintegerUnique modifier identifier.
namestringModifier name.
priceintegerModifier price, in cents.
quantityintegerModifier quantity.
commentstringComment attached to the modifier.

Request Example

{
  "ticket": {
    "void": false,
    "id": "rika19882"
  },
  "payment": {
    "id": "desk41231",
    "amount": 666,
    "inv_number": "INV-1024"
  },
  "user_id_external": 5488,
  "webhook_id": "7614fc1bd4saf6",
  "terminal_id": 100
}

cURL Example

curl --request POST \
  --url https://sandbox-api.softpoint.io/interface/v1/locations/YOUR_LOCATION_ID/webhook/sale \
  --header "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  --header "Content-Type: application/json" \
  --data '{
    "ticket": { "void": false, "id": "rika19882" },
    "payment": { "id": "desk41231", "amount": 666, "inv_number": "INV-1024" },
    "user_id_external": 5488,
    "webhook_id": "7614fc1bd4saf6",
    "terminal_id": 100
  }'

Success Response

An approved sale returns response: "APPROVED" together with the settled transaction details.

{
  "response": "APPROVED",
  "data": {
    "id": 7137,
    "id_external": null,
    "amount": 1081,
    "tip": 400,
    "surcharge": 0,
    "transaction_id": "28040181",
    "card_holder": "Test/Card 01",
    "reference_id": "8",
    "auth_code": "TAS547",
    "card_type": "VISA",
    "last4": "0010",
    "entry_type": "Chip",
    "customer_id_external": "inf3509263926"
  }
}

Response Fields

FieldTypeDescription
responsestringTransaction outcome. Either APPROVED or DECLINE.
dataobjectTransaction detail object.
data.idintegerSoftpoint transaction identifier.
data.id_externalstringExternal transaction reference; may be null.
data.amountintegerTotal amount charged, in minor units (cents).
data.tipintegerTip amount applied at the terminal, in minor units.
data.surchargeintegerSurcharge amount applied, in minor units.
data.transaction_idstringProcessor transaction identifier.
data.card_holderstringCardholder name; may be null.
data.reference_idstringReference identifier returned by the processor.
data.auth_codestringAuthorization code returned by the issuer.
data.card_typestringCard brand, for example VISA or AMEX.
data.last4stringLast four digits of the card number.
data.entry_typestringHow the card was read, for example Chip or Swipe.
data.customer_id_externalstringExternal customer identifier associated with the card, when present.

Error Responses

Declined Transaction

A decline is returned with HTTP 200 and response: "DECLINE". Inspect the response field rather than relying solely on the status code.

{
  "response": "DECLINE",
  "data": {
    "id": 17845,
    "id_external": "7da29929a5548",
    "amount": 0,
    "tip": 0,
    "total": 0,
    "refunded_amount": 0,
    "surcharge": 0,
    "transaction_id": "",
    "card_holder": "DI Test/Card 01",
    "reference_id": "",
    "auth_code": "",
    "card_type": "AMEX",
    "last4": "0119",
    "entry_type": "Chip",
    "status": 2
  }
}

Terminal Not Found

Returned when the supplied terminal_id does not correspond to a registered terminal.

{
  "error": {
    "code": 10107,
    "message": "The selected terminal doesn't exist.",
    "details": null
  }
}

Missing Required Parameter

Returned when a required field, such as terminal_id, is absent from the request body.

{
  "error": {
    "code": 10109,
    "message": "The request is missing one or more required parameter(s).",
    "details": {
      "terminal_id": [
        "missing_required_parameters"
      ]
    }
  }
}

Status Codes

CodeDescription
200Request processed. Inspect response for the outcome.
400Missing or invalid request parameters.
401Missing or invalid access token.
404The selected terminal does not exist.

Workflow Placement

The Sale endpoint is the terminal step in the card-present payment flow:

  1. Generate an interface access token.

  2. Register and configure the terminal.

  3. Open or reference a ticket.

  4. Submit the sale to the terminal.

  5. Reconcile the result using the returned transaction details, or issue a refund if required.

Notes

  • Amounts are expressed in minor units (cents). The returned amount reflects the final total, which may include tip and surcharge applied at the terminal and can therefore differ from the requested payment.amount.

  • A decline is reported with HTTP 200 and response: "DECLINE". Always branch on the response field.

  • The terminal interaction is asynchronous from the cardholder's perspective. Supply a webhook_id to correlate the eventual result.

  • The ticket object may be supplied either as a compact reference containing an id or as a fully embedded ticket structure. Both forms are accepted.

Common Mistakes

  • Treating an HTTP 200 response as a guaranteed approval without checking the response field.

  • Sending the amount in major units (dollars) instead of minor units (cents).

  • Omitting terminal_id, which results in error code 10109.

  • Referencing a terminal that has not been registered for the location, which results in error code 10107.

Body Params
Responses

Language
Credentials
Bearer
LoadingLoading…
Response
Click Try It! to start a request and see the response here! Or choose an example:
application/json