Smaregi Transaction Data and Receipt Roller Transaction Data Mapping

Smaregi POS Integration Data Mapping Technical Details Transaction Data API

Receipt Roller connects to multiple POS vendors, including Smaregi. So that transactions imported from any vendor can be handled internally through a common transaction data model (PosTransactionDto), vendor-specific fields are normalized. This article gives a technical explanation of how transaction data from the Smaregi Platform API corresponds to Receipt Roller's internal model.

This article is reference material for developers and operations staff who want to understand the internal specification of the POS integration. For the day-to-day setup steps, see Smaregi POS integration setup. For the canonical field-level model specification, see PosTransactionDto specification (field reference).

Hierarchical structure correspondence

The Smaregi Platform API has four layers: contract, store, terminal, and transaction. On the Receipt Roller side, these correspond one-to-one, by design, to four layers: business account, store, POS terminal, and transaction.

  • Contract (contractId) ↔ Receipt Roller's business account. When you install the "Receipt Roller Link" app on Smaregi, that contract is tied to a single Receipt Roller business account (SmaregiContract.OrganizationId).
  • Smaregi store (storeId) ↔ Receipt Roller store. Tied to the Receipt Roller-side POS terminal via PosTerminal.SmaregiStoreId.
  • Smaregi terminal (terminalId) ↔ Receipt Roller's POS terminal. Held in PosTerminal.SmaregiTerminalId; one Receipt Roller POS terminal corresponds to one Smaregi terminal (register).
  • Transaction (transactionHeadId) ↔ Receipt Roller's transaction. The same ID is saved as both PosTransaction.TransactionId and ExternalTransactionId.

Transaction header field mapping

The correspondence between the response from Smaregi's /pos/transactions (SmaregiTransaction) and Receipt Roller's PosTransactionDto.

Smaregi Receipt Roller Notes
transactionHeadIdTransactionId / ExternalTransactionIdThe same value is saved into two fields. Becomes the idempotent upsert key.
transactionDateTimeTransactionDateTimeThe JST string is converted to UTC before saving.
(currency)CurrencyKept fixed as JPY.
storeId(not stored directly)Already saved as PosTerminal.SmaregiStoreId at connection time. On the transaction side, replaced with PosTerminal.StoreId (the Receipt Roller store ID).
terminalId(not stored directly)Already saved as PosTerminal.SmaregiTerminalId at connection time. On the transaction side, replaced with PosTerminal.TerminalId (the Receipt Roller terminal ID).
customerId / customerCodeExternalIds.ProviderCustomerId (and passed to CRM resolution)Passed to the CRM resolution logic as a customer match key (described below), and also kept on the transaction as a cross-vendor ID.
staffIdStaffIdCarried over as-is.
staffNameStaffNameIf blank, backfilled by fetching from /pos/staffs/{staffId}.
totalTotalAmountSince Smaregi also returns numbers as strings, parsed with decimal.TryParse.
subtotalSubtotalAmountIf 0, computed from total - tax.
taxTaxAmountSame string-parsing as above.
discountDiscountAmountSame as above.
status / cancelDivisionStatusSee the status conversion table below.
receiptNumber / terminalTransactionIdReceiptNumberThe receipt number issued by the terminal.
payments[]Payments[] / PaymentMethodEach tender is fully preserved in Payments[] (supports split payments). PaymentMethod holds the primary method (described below).

Status code conversion

Smaregi's status values are returned as numeric strings. Receipt Roller normalizes these into string labels internally.

Smaregi valueMeaningReceipt Roller Status
"1"CompletedCompleted
"2"CanceledVoided
"3"RefundedRefunded
Unknown value / blank—Pending (fallback)

Depending on the specification, there are cases where status and cancelDivision are used together in a field name. Both values are checked for the determination, so as long as either one is present, classification is done correctly.

Payment method normalization

Smaregi lists each tender of a sale in payments, which it sends only when the request includes with_payments=all. Both the transaction list request and the single-transaction request include it. Each tender is kept in Payments[] with the amount it paid. The tender that paid the most is also kept in PaymentMethod for lists and filters. Each tender is read in this order, and the first rule that applies wins:

  • Cash: a method whose name contains 現金 (cash) is Cash, unless the name also contains 券 (voucher). 現金券 and 現金商品券 are vouchers.
  • Vouchers: a tender with Smaregi's 有価証券 flag (paymentSecuritiesFlag) keeps its own name, such as 商品券 or QUOカード.
  • Payment code (支払金種コード): when Smaregi sends a denominationCode, the code decides. CREDIT, STORE, UNIONPAY and CONTACTLESS are CreditCard. SUICA, ID, QUICPAY, WAON, NANACO and the other e-money codes are IC. PAYPAY, AUPAY, LINEPAY, DPAY, RAKUTENPAY and the other wallet codes are QR. DEBIT, JDEBIT, PREPAID, QUOPAY and any other code keep Smaregi's name for it, for example デビット. A coded tender is named by Smaregi's name for the code, not by the name of the app or terminal.
  • The store's own name: otherwise the name is matched against lists of e-money, wallet and card brands. Debit, prepaid, vouchers, points and house cards are not read as credit cards.
  • creditTotal: a tender that no rule above can read becomes CreditCard if the card money Smaregi reports in creditTotal accounts for it. Otherwise it keeps the store's name.

The header's cashTotal and creditTotal add only cash or card money that no listed tender accounts for, so the same money is never counted twice. If the sale's only cash tender arrives with neither the amount received nor the change, both are taken from the header (depositCash and change), so the receipt still shows お預り and お釣り. A QR or e-money tender keeps its wallet name in Brand, so the receipt prints "お支払い(QRコード決済・PayPay)" or "お支払い(電子マネー・Suica)". Store screens show only the category. PaymentMethod is Other only when the sale has no tender at all. A tender kept under the store's own name, such as 商品券, still matches the Other payment filter.

Line item mapping

Separately from the transaction header, line item data is fetched from /pos/transactions/{id}/details, converted into an array of PosTransactionLineItemDto, and serialized into LineItemsJson.

Smaregi SmaregiTransactionDetailReceipt Roller PosTransactionLineItemDtoNotes
productNameProductNameCarried over as-is.
quantityQuantityString rounded to an integer. Values of 0 or less are corrected to 1.
priceUnitPriceString parsed.
subtotalSubtotalString parsed.
taxRateTaxRateString parsed.
taxTaxAmountTax amount at the line-item level. Kept as an amount, not just a rate.
productIdCatalogObjectId / ProductIdThe catalog ID for cross-system linking.
categoryNameCategoryCarried over as-is.

ItemCount (the total number of purchased items across the whole transaction) is calculated as the sum of Quantity across line items.

Line-item-level discount amounts are planned to be mapped once the corresponding field name in Smaregi's transactionDetails has been confirmed. Until then, DiscountAmount is left as null, and the raw payload (RawJson) is retained to prevent data loss.

Retaining the raw data (RawJson)

At import time, the source raw payload of the transaction header plus line items is saved into RawJson. This is a safety measure for internal server use, so that even fields that haven't been modeled yet can be recovered later (it is not returned by the API).

Resolving customer information (CRM integration)

The customerId / customerCode obtained from Smaregi are passed to the CRM resolution service (IPosCustomerMatchService) as a customer match key, and are also kept on the transaction as the cross-vendor ID ExternalIds.ProviderCustomerId. If a match is found, the transaction is automatically linked to the corresponding Receipt Roller CRM customer profile, and used for calculating per-customer purchase history and churn-risk scores.

The main types of match keys are as follows (see the implementation's PosCustomerMatchDto).

  • Membership number (membership code) — Smaregi's customerCode, etc.
  • External customer ID — Smaregi's customerId
  • Email address / phone number — only when obtainable from Smaregi

Transactions where no match is found can still be linked later by the customer themselves via an in-store terminal QR scan.

Backfilling staff information

There are cases where the transaction header contains only staffId. In that case, /pos/staffs/{staffId} is called separately to fetch displayName, which is saved into StaffName. Even if fetching the staff name fails, the transaction import itself is not treated as a failure — it is saved with a blank name (to prevent loss of transaction data).

Distinguishing the acquisition path (Source)

Even for the same transaction, the Source field records which path it was imported through.

  • Webhook — a path pushed in real time from Smaregi
  • Sync — a manual sync path triggered when a store operator presses the "Sync with Smaregi" button
  • API — acquisition via other Platform API calls (e.g. instant fetch at QR scan time)

Even if the same transactionHeadId arrives via multiple paths, the transaction is never duplicated, since it is upserted keyed on that same ID. The Source value reflects the most recently imported path.

Timezone handling

The Smaregi Platform API returns date-times in ISO 8601 format in JST (+09:00). The Receipt Roller side always saves everything in UTC, converting to JST for display. When sending a date-time filter to the Platform API as well, UTC is converted to JST and URL-encoded before sending (so that the + sign in +09:00 is not misinterpreted as a space).

Idempotency

The transaction upsert is keyed on transactionHeadId. Even if the same transaction arrives via both a webhook and a manual sync, it ends up consolidated into a single record. UpdatedAt is updated to the most recent import time, but TransactionDateTime (the time the transaction occurred) remains unchanged.

Overview of the import pipeline

  1. A transaction occurs on the Smaregi side → a webhook is sent from Smaregi Platform to Receipt Roller
  2. Receipt Roller's webhook receiving endpoint performs custom header authentication
  3. transactionHeadIds (there can be multiple) are extracted from the payload
  4. For each ID, the transaction header + line items + staff are fetched from the Platform API
  5. Converted into PosTransactionDto by SmaregiTransactionMapper
  6. The customer match key is passed to IPosCustomerMatchService, and CRM resolution is performed
  7. Saved via PosTransactionService.UpsertAsync (duplicates are overwritten)
  8. PosTerminal.LastTransactionAt is updated (used for displaying the latest transaction via QR scan)
  9. If the customer has been identified, handed off to the automated delivery service (electronic receipt delivery)

Related articles

Published: 2026-05-28 Updated: 2026-10-13