Square Transaction Data and Receipt Roller Transaction Data Mapping
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 side | Square side | Notes |
|---|---|---|
TransactionId | Payment.id | Square's payment ID is adopted as-is. Becomes the key for idempotent upserts |
ExternalTransactionId | Payment.id | Same as above (kept redundantly for external reference) |
TransactionDateTime | Payment.created_at | Converted from an ISO 8601 string to a UTC DateTime |
Currency | Payment.amount_money.currency | Currency code. Defaults to JPY |
TotalAmount | Payment.amount_money.amount | JPY is used as-is; other currencies are converted from smallest unit (cents) to the main unit |
TaxAmount | Payment.tax_money.amount | Same as above |
SubtotalAmount | Computed value | amount - tax |
DiscountAmount | Payment.discount_money.amount | Same as above |
TipAmount | Payment.tip_money.amount | Tip. Only if present |
PaymentMethod | Presence of Payment.card_details | CreditCard if card data is present, otherwise Other (the primary tender. Breakdown is in Payments below) |
Payments[] | 1 Payment record + card_details.card | Tender breakdown. Method / Amount (total_money) / Brand (card_brand) / Last4 (last_4) |
Status | Payment.status | See the "Status mapping table" below |
ReceiptNumber | Payment.receipt_number | Issued by Square |
ReceiptUrl | Payment.receipt_url | Customer-facing receipt URL. Kept in a structured field (previously stored in Notes, now deprecated) |
ExternalIds | order_id / location_id / customer_id | Cross-vendor IDs (ProviderOrderId / LocationId / ProviderCustomerId) |
StaffId | Payment.team_member_id | Blank if unassigned |
StaffName | TeamMember.display_name | Resolved via a separate TeamMembers API call |
Source | Fixed value "API" or "Webhook" | Depends on the acquisition path |
RawJson | Raw payload of Payment + Order | Kept so that unmodeled fields (card fingerprint, etc.) can be recovered later. Not returned by the API |
LineItems | Order.line_items[] | Resolved via a separate Orders API call. See "Line item mapping" below |
Status mapping table
Square Payment.status | Receipt Roller Status | Meaning |
|---|---|---|
COMPLETED | Completed | Accounting complete |
CANCELED | Voided | Canceled |
FAILED | Voided | Failed (not included in sales) |
| Other | Pending | Processing / 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.
amountis 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 LineItem | Square Order.line_items[] | Notes |
|---|---|---|
ProductName | name + variation_name | If there is a variation, formatted as "Product Name (Variation Name)" |
Quantity | quantity | String parsed to an integer. Defaults to 1 on failure |
UnitPrice | base_price_money.amount | Currency conversion applied |
Subtotal | total_money.amount | If unavailable, computed as UnitPrice × Quantity |
TaxRate | Computed value | (total_tax_money / (total_money - total_tax_money)) × 100, rounded to 1 decimal place |
TaxAmount | total_tax_money.amount | Tax amount at the line-item level. Kept as an amount, not just a rate |
DiscountAmount | total_discount_money.amount | Discount amount at the line-item level |
CatalogObjectId | catalog_object_id | Linking ID to the Square catalog |
Modifiers | modifiers[] | Options/modifiers (name + total_price_money) |
Category | — | Currently 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 asExternalIds.ProviderCustomerId - Fallback:
Payment.card_details.card.fingerprint(a hash of the card number. Not the PAN, but a stable identifier generated by Square. Kept insideRawJsonand 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
- Square POS integration setup — connection steps
- Smaregi transaction data mapping — the Smaregi version
- PosTransactionDto specification (field reference) — details of each field
-
Staff Sync via Square IntegrationExplains how stores connected to Square POS can sync Team Member information bidirectionally with ReceiptRoller — job assignments, pay rates, assigned stores, owner permissions, and more, kept aligned with Square.
-
Two-Way Member Information Sync with Smaregi/SquareLearn how ReceiptRoller's member information syncs bidirectionally with connected POS systems like Smaregi and Square. Covers which fields sync, sync timing, conflict priority rules, new customer matching, supported POS systems, and troubleshooting.
-
Square Customer Data and Receipt Roller Customer Data MappingExplains how customers registered in Square Customer Directory are converted into Receipt Roller's customer data (CrmCustomerDto), field by field. Covers the given_name / family_name correspondence, address decomposition logic, and how reference_id is handled.
-
Connecting with POSAn overview of the POS systems that can connect with ReceiptRoller and how to connect them. Supports Square and Smaregi.
-
Square Staff Data and Receipt Roller Staff Data MappingExplains how Square Team Members are linked to Receipt Roller's staff data (StaffDto). Covers how to use manual linking, the logic for resolving who is attributed to a transaction, and the key fields in the Team Member API.