Skip to content
Get API key

API reference

Transactions API

Every sale rung up on the till, newest first. Use it for accounting syncs and data warehouses.

Deleted orders are never returned. Refunded orders are returned with totals.refund above 0 and net = total - refund. For sales as the dashboard reports them, use the daily report instead.

List transactions

GET/api-v1-transactions
Paginated
cursor

Returns till transactions, newest first by created_at, a page at a time.

A live key never sees test orders and a test key sees only them.

status and payment_method are exact matches on the stored value (lowercase, letters, digits and underscores, up to 40 characters). An unknown value matches nothing rather than failing. Payment methods include cash, qris, edc, edc_bca, card_transfer, card_transfer_bni, card_transfer_bri, card_transfer_bsi, card_transfer_mandiri, pay_later and complimentary.

Query parameters

NameTypeRequiredDescription
fromstringOptionalEarliest created_at, inclusive. ISO 8601 with offset, or YYYY-MM-DD.A bare date means 00:00 UTC that day, so pass a full timestamp with +07:00 to cut at local midnight.
tostringOptionalLatest created_at, inclusive. ISO 8601 with offset, or YYYY-MM-DD.At most 400 days after from. A bare date means 00:00 UTC that day.
location_iduuidOptionalOnly this outlet. A key pinned to one outlet is always scoped to it; another outlet’s id is 403.
statusstringOptionalExact match on the order status, for example completed.
payment_methodstringOptionalExact match on the payment method, for example qris.
cursorstringOptionalThe next_cursor from the previous page. Opaque; send it back unchanged.
limitintegerOptionalRows per page.Default 50. At least 1; values above 100 are capped at 100.

Response fields (200)

NameTypeDescription
data[]arrayTransactions on this page.
data[].numberstringThe order number printed on the receipt.
data[].statusstringThe order status.
data[].payment_statusstringThe payment status.
data[].payment_methodstringThe tender, as stored.
data[].sale_typestringThe sale type kind (dine_in, takeaway…).
data[].sale_type_namestringIts display name at the outlet.
data[].sourcestringWhere the order came from (pos…).
data[].bill_namestring | nullThe bill’s name, for example a table.
data[].totalsobjecttotal, refund, net, tax, service_charge, payment_fee and bill_discount, all integer rupiah.
data[].voided_attimestamp | nullSet when the sale was voided.
has_morebooleantrue when another page exists.
next_cursorstring | nullSend it back as cursor for the next page.
request_idstringThis request’s id, also in the x-request-id header.

Errors

Every error answers { "error": { "code", "message", "request_id" } }. Branch on code; see Errors for retrying.

HTTPCodeWhen
400validation_failedA query parameter did not parse; the message names it. Also returned when from/to span more than 400 days.
401invalid_keyThe Authorization header is missing, malformed, or the key is revoked or inactive.
402payment_requiredThe business’s plan does not include API access (Sansflow Premium). The key itself is fine.
403insufficient_scopeThe key does not carry the scope this endpoint needs, or it is pinned to a different outlet.
429rate_limitedOver the key’s per-minute limit (60 for sf_test_, 300 for sf_live_). Wait the seconds in Retry-After.
500internal_errorSomething failed on our side. Quote the request_id when you report it.
Request
curl -G "https://ewpuclvmnygoddunkyrb.supabase.co/functions/v1/api-v1-transactions" \
  -H "Authorization: Bearer $SANSFLOW_API_KEY" \
  --data-urlencode "from=2026-11-01T00:00:00+07:00" \
  --data-urlencode "to=2026-11-30T23:59:59+07:00" \
  --data-urlencode "limit=100"
Response200 OK
{
  "data": [
    {
      "id": "b1a7c9e2-4d3f-4a8b-9c61-2e5f7d8a0b13",
      "number": "ORD-20261105-3F2A",
      "status": "completed",
      "payment_status": "paid",
      "payment_method": "qris",
      "sale_type": "dine_in",
      "sale_type_name": "Dine in",
      "source": "pos",
      "location_id": "3f6c2a1e-8b4d-4c2a-9e51-7a0d2b6c9f10",
      "customer_id": null,
      "bill_name": "Meja 4",
      "totals": {
        "total": 50000,
        "refund": 0,
        "net": 50000,
        "tax": 0,
        "service_charge": 0,
        "payment_fee": 0,
        "bill_discount": 0
      },
      "is_test": false,
      "voided_at": null,
      "created_at": "2026-11-05T12:41:03.214+00:00"
    }
  ],
  "has_more": true,
  "next_cursor": "MjAyNi0xMS0wNVQxMjo0MTowMy4yMTRafGIxYTdjOWUy",
  "request_id": "5d0c7e2a-91f4-4b3e-a8c6-0f2e4b6d8a1c"
}

Example values. Run replays this response here; nothing is sent.

Retrieve a transaction

GET/api-v1-transactions/{transaction_id}

One transaction in full: line items with modifiers, every payment taken, the bill it came from, loyalty and the void reason.

Query filters are ignored here; an outlet-pinned key can only read its own outlet’s transactions.

Path parameters

NameTypeRequiredDescription
transaction_iduuidRequiredThe transaction’s id from the list.

Response fields (200)

NameTypeDescription
locationobject | null{ id, name } of the outlet. The list returns location_id instead.
billobject | nullid, number, name, table, zone, party_size, opened_at, closed_at.
totalsobjectThe list’s totals plus cash_received and change.
loyaltyobjectpoints_earned and points_redeemed.
items[]arrayTop-level lines: id, product_id, name, sku, category, variant_id, variant, quantity, unit_price, discount, line_total, modifiers, notes.
payments[]arrayEach tender: method, amount, fee, card_last4, reference, created_at.
void_reasonstring | nullWhy it was voided.

Errors

Every error answers { "error": { "code", "message", "request_id" } }. Branch on code; see Errors for retrying.

HTTPCodeWhen
400invalid_requestThe id in the path is not a UUID.
401invalid_keyThe Authorization header is missing, malformed, or the key is revoked or inactive.
402payment_requiredThe business’s plan does not include API access (Sansflow Premium). The key itself is fine.
403insufficient_scopeThe key does not carry the scope this endpoint needs, or it is pinned to a different outlet.
429rate_limitedOver the key’s per-minute limit (60 for sf_test_, 300 for sf_live_). Wait the seconds in Retry-After.
404transaction_not_foundNo such transaction for this key: another business, deleted, or on the other side of the test/live split.
404not_foundMore than one path segment after the endpoint.
500internal_errorSomething failed on our side. Quote the request_id when you report it.
Request
curl "https://ewpuclvmnygoddunkyrb.supabase.co/functions/v1/api-v1-transactions/b1a7c9e2-4d3f-4a8b-9c61-2e5f7d8a0b13" \
  -H "Authorization: Bearer $SANSFLOW_API_KEY"
Response200 OK
{
  "data": {
    "id": "b1a7c9e2-4d3f-4a8b-9c61-2e5f7d8a0b13",
    "number": "ORD-20261105-3F2A",
    "status": "completed",
    "payment_status": "paid",
    "payment_method": "qris",
    "sale_type": "dine_in",
    "sale_type_name": "Dine in",
    "source": "pos",
    "location": {
      "id": "3f6c2a1e-8b4d-4c2a-9e51-7a0d2b6c9f10",
      "name": "Main"
    },
    "customer_id": null,
    "bill": {
      "id": "4a6c8e0b-2d3f-4e5a-8b17-6c8e0a2b4c14",
      "number": "N8",
      "name": "Meja 4",
      "table": "T4",
      "zone": "Indoor",
      "party_size": 3,
      "opened_at": "2026-11-05T11:58:20+00:00",
      "closed_at": "2026-11-05T12:41:03+00:00"
    },
    "bill_name": "Meja 4",
    "totals": {
      "total": 50000,
      "refund": 0,
      "net": 50000,
      "tax": 0,
      "service_charge": 0,
      "payment_fee": 0,
      "bill_discount": 0,
      "cash_received": null,
      "change": null
    },
    "loyalty": {
      "points_earned": 0,
      "points_redeemed": 0
    },
    "items": [
      {
        "id": "6f8b0d2e-4a1c-4e3f-9b57-1d3f5b7d9e36",
        "product_id": "f1b3d5a7-9c2e-4a6b-8d14-7e3c5a9b1d68",
        "name": "Kopi Susu",
        "sku": null,
        "category": "Kopi",
        "variant_id": null,
        "variant": null,
        "quantity": 2,
        "unit_price": 25000,
        "discount": 0,
        "line_total": 50000,
        "modifiers": [],
        "notes": null
      }
    ],
    "payments": [
      {
        "method": "qris",
        "amount": 50000,
        "fee": 0,
        "card_last4": null,
        "reference": null,
        "created_at": "2026-11-05T12:41:02+00:00"
      }
    ],
    "is_test": false,
    "voided_at": null,
    "void_reason": null,
    "created_at": "2026-11-05T12:41:03.214+00:00"
  },
  "request_id": "5d0c7e2a-91f4-4b3e-a8c6-0f2e4b6d8a1c"
}

Example values. Run replays this response here; nothing is sent.

Base URL, keys and conventions: API reference overview.

Stuck? Quote the request_id from the response and write toSansflow support.Checked against API v1 on .