Square Transaction Data and Receipt Roller Transaction Data Mapping

Square POS Integration Data Mapping Technical Details Transaction Data API

A technical explanation of the mechanism that maps transaction data obtained from the Square API into Receipt Roller's transaction data model. This is organized for developers and operations staff who want to understand the internal specification, covering the field mapping table, status code conversion, payment method normalization, resolving line item/customer/staff information, and how timezones and idempotency are handled.

This article summarizes the behavior of SquarePaymentMapper on the Receipt Roller side. For general operational steps such as "how to connect Square" or "what happens when you sync," see Square POS integration setup. For the canonical field-level model specification, see PosTransactionDto specification (field reference).

Basic structure

Square and Receipt Roller differ in the granularity of transaction data.

  • On the Square side, data is split into two: Payment (payment) and Order (order). Payment holds payment information, Order holds line item information
  • On the Receipt Roller side, payment + line items + customer + staff are consolidated into a single PosTransactionDto
  • At fetch time, Payment is the starting point, and the related Order / TeamMember / Customer are fetched additionally

Main field mapping table

Receipt Roller sideSquare sideNotes
TransactionIdPayment.idSquare's payment ID is adopted as-is. Becomes the key for idempotent upserts
ExternalTransactionIdPayment.idSame as above (kept redundantly for external reference)
TransactionDateTimePayment.created_atConverted from an ISO 8601 string to a UTC DateTime
CurrencyPayment.amount_money.currencyCurrency code. Defaults to JPY
TotalAmountPayment.amount_money.amountJPY is used as-is; other currencies are converted from smallest unit (cents) to the main unit
TaxAmountPayment.tax_money.amountSame as above
SubtotalAmountComputed valueamount - tax
DiscountAmountPayment.discount_money.amountSame as above
TipAmountPayment.tip_money.amountTip. Only if present
PaymentMethodPresence of Payment.card_detailsCreditCard if card data is present, otherwise Other (the primary tender. Breakdown is in Payments below)
Payments[]1 Payment record + card_details.cardTender breakdown. Method / Amount (total_money) / Brand (card_brand) / Last4 (last_4)
StatusPayment.statusSee the "Status mapping table" below
ReceiptNumberPayment.receipt_numberIssued by Square
ReceiptUrlPayment.receipt_urlCustomer-facing receipt URL. Kept in a structured field (previously stored in Notes, now deprecated)
ExternalIdsorder_id / location_id / customer_idCross-vendor IDs (ProviderOrderId / LocationId / ProviderCustomerId)
StaffIdPayment.team_member_idBlank if unassigned
StaffNameTeamMember.display_nameResolved via a separate TeamMembers API call
SourceFixed value "API" or "Webhook"Depends on the acquisition path
RawJsonRaw payload of Payment + OrderKept so that unmodeled fields (card fingerprint, etc.) can be recovered later. Not returned by the API
LineItemsOrder.line_items[]Resolved via a separate Orders API call. See "Line item mapping" below

Status mapping table

Square Payment.statusReceipt Roller StatusMeaning
COMPLETEDCompletedAccounting complete
CANCELEDVoidedCanceled
FAILEDVoidedFailed (not included in sales)
OtherPendingProcessing / undetermined

Currency conversion of amounts

Square's Money object handles the smallest unit differently depending on the currency.

  • JPY: 1 yen is the smallest unit. amount is adopted as-is
  • USD / EUR, etc.: 1 cent is the smallest unit. Converted to the main unit via amount / 100

The Receipt Roller side always keeps amounts in the main unit (decimal), with the currency code kept in Currency.

Line item mapping

Because Square's Payment does not include line item information, the related Order is fetched separately to expand the line items. If the Order cannot be fetched (insufficient permissions, API error, expired OAuth token, etc.), the transaction is saved without line items, and can be backfilled later on a subsequent sync.

Receipt Roller LineItemSquare Order.line_items[]Notes
ProductNamename + variation_nameIf there is a variation, formatted as "Product Name (Variation Name)"
QuantityquantityString parsed to an integer. Defaults to 1 on failure
UnitPricebase_price_money.amountCurrency conversion applied
Subtotaltotal_money.amountIf unavailable, computed as UnitPrice × Quantity
TaxRateComputed value(total_tax_money / (total_money - total_tax_money)) × 100, rounded to 1 decimal place
TaxAmounttotal_tax_money.amountTax amount at the line-item level. Kept as an amount, not just a rate
DiscountAmounttotal_discount_money.amountDiscount amount at the line-item level
CatalogObjectIdcatalog_object_idLinking ID to the Square catalog
Modifiersmodifiers[]Options/modifiers (name + total_price_money)
CategoryCurrently always blank. Resolution via the Square Catalog API is a future consideration

Extracting the customer match key

To pass data to Receipt Roller's automated delivery pipeline (CRM integration), the customer identifier on the Square side is extracted.

  • Primary key: Payment.customer_id (the customer ID in Square Customer Directory). Also kept on the transaction as ExternalIds.ProviderCustomerId
  • Fallback: Payment.card_details.card.fingerprint (a hash of the card number. Not the PAN, but a stable identifier generated by Square. Kept inside RawJson and not returned by the API)

Because a phone number or email is not included in a Square Payment, a separate API call to Customer Directory is needed to obtain them. In the current version this is omitted, since matching on the card fingerprint alone is sufficient in most cases.

Automatic refresh of the OAuth token

A Square OAuth access token expires after about 30 days. On the webhook path, right before fetching line items/staff names, the validity period of terminal.AccessToken is checked, and if it will expire within 60 seconds, it is automatically refreshed using RefreshToken (the refreshed token is then persisted to the terminal record). This prevents line-item fetch failures even at stores that have been running purely on webhooks for a long time.

Idempotency

Even if the same transaction arrives multiple times (e.g. a manual retry-sync on the Square side overlapping with a webhook), it is safely re-saved via an upsert keyed on Payment.id. No duplicate receipts are ever issued on the Receipt Roller side.

Related articles

Published: 2026-05-29 Updated: 2026-07-02