Skip to content

Square Integration

Connect your Square POS account for automated revenue recognition, payment tracking, and payout reconciliation across all your retail locations. The /api/v1/square/* endpoints require the Commerce add-on on the business; connect, sync and disconnect calls need admin permission.

The /api/v1/square/* endpoints below work with an API token but are not part of the public API Reference — they back DayZero's own Integrations page and may change. Booked activity lands in the public Journal Entries, Inventory and Reports endpoints, which is where integrations should read from.

What Gets Synced

Data Description
Payments Rolled up into one daily sales summary per location
Refunds Netted into the daily summary as contra-revenue (Sales Refunds)
Payouts Reconciled against Square Clearing as deposits land in the bank
Tips Tracked as a liability (Tips Payable)
Sales tax Tracked as a liability (Sales Tax Payable)
Processing fees Booked as an expense, split out from revenue
Locations Multi-location support (one summary per location per day)

Connect Square

From the Integrations page in DayZero, click Connect Square. You'll be redirected to Square to authorize access.

Or via API:

bash
curl "https://api.ondayzero.com/api/v1/square/connect-url" \
  -H "Authorization: Bearer dz_your_token_here" \
  -H "x-business-id: YOUR_BUSINESS_ID"

The response includes connect_url and state. Redirect the merchant to connect_url from the same browser (the call sets a dz_oauth_square cookie that the callback requires) to begin the OAuth flow. After authorization, DayZero stores the connection and begins syncing.

Automatic Accounting

Square is point-of-sale, so DayZero does not post a journal entry per payment (a busy venue does thousands a day). Instead, payments are stored as a subledger and rolled up into one daily sales summary per location — the bookkeeping standard for POS. Once a business-local day closes, DayZero posts a single balanced entry:

plaintext
Dr  Undeposited Funds      (cash + other tenders collected)
Dr  Square Clearing        (card tenders, net of fees)
Dr  Square Processing Fees (fees for the day)
Dr  Sales Discounts        (discounts, when any)
        Cr  Sales Revenue      (net sales — excludes tax and tips)
        Cr  Sales Tax Payable  (tax collected, a liability)
        Cr  Tips Payable       (tips collected, a liability)

This keeps revenue, tax, and tips cleanly separated and splits tender so the card and cash sides reconcile independently. A cent-level imbalance is absorbed by a Square Rounding Adjustments line.

Refunds net into the same daily summary as contra-revenue:

plaintext
Dr  Sales Refunds          (amount refunded that day)
        Cr  Square Clearing    (card refunds — clawed back from a payout)
        Cr  Undeposited Funds  (cash/other refunds — returned from the drawer)

A day that only has refunds (no sales) still gets a summary so the contra-revenue is booked.

Posting configuration

Each connection has a posting_mode (default daily_summary), an optional posting_start_date, and a daily_summary_timezone / daily_summary_hour that define when a business-local "day" closes and its summary posts — critical for "what counts as today's sales". Read it with GET /api/v1/square/subledger/posting-config and change it with PATCH:

bash
curl -X PATCH "https://api.ondayzero.com/api/v1/square/subledger/posting-config" \
  -H "Authorization: Bearer dz_your_token_here" \
  -H "x-business-id: YOUR_BUSINESS_ID" \
  -H "Content-Type: application/json" \
  -d '{"daily_summary_timezone": "America/Los_Angeles", "daily_summary_hour": 4, "posting_start_date": "2026-01-01"}'

daily_summary_hour (0–23, default 5) is the local hour at which the previous day's summary posts, giving late-night sales time to settle; daily_summary_timezone is an IANA zone name and defaults to UTC. An hourly job (at :15) posts any closed day that is due. Send "clear_posting_start_date": true to remove the start date. Posting is idempotent per location per day, so re-syncing never double-books.

posting_mode can be daily_summary (default, described above), per_payout (one entry per Square payout) or per_transaction (one entry per payment, for audit or low-volume use). The GET response lists them as available_modes. Everything in this guide describes daily_summary.

Payout & Cash Reconciliation

Card sales flow into Square Clearing, which is drained when the matching Square deposit lands in your connected bank feed. After each bank sync, DayZero matches the deposit to the payout (exact amount, within 5 days of the payout's arrival date, and a bank description that looks like Square) and books it as:

plaintext
Dr  Operating Bank Account (the real bank deposit)
        Cr  Square Clearing    (drains the card side)

This uses the actual bank transaction — DayZero does not post a separate payout entry, which would double-count the deposit. Fees are recognized at sale time in the daily summary (accrual), so the deposit's net amount is exactly what clears. Cash sales flow into Undeposited Funds, drained when the operator records a bank deposit (cash reconciliation).

A connected bank feed is required for automatic card reconciliation. Without one, Square Clearing accumulates and can be reconciled manually.

Connection Status

bash
curl "https://api.ondayzero.com/api/v1/square/status" \
  -H "Authorization: Bearer dz_your_token_here" \
  -H "x-business-id: YOUR_BUSINESS_ID"

Returns connected, healthy, merchant_id, merchant_name, location_count, payment_count and last_synced_at.

Browse the Subledger

Everything DayZero pulled from Square is queryable, which is useful for tying a daily journal entry back to the payments behind it:

Endpoint Returns
GET /api/v1/square/subledger/summary Record counts (payments, refunds, payouts matched vs. unmatched, daily summaries posted vs. unposted), the Square Clearing balance and the connection's posting settings
GET /api/v1/square/subledger/daily Per-location daily summaries; filter by start_date / end_date
GET /api/v1/square/subledger/payments Individual payments; filter by location_id
GET /api/v1/square/subledger/refunds Individual refunds
GET /api/v1/square/subledger/payouts Payouts; `matched=true
GET /api/v1/square/subledger/backlink/{journal_entry_id} The Square records that produced a journal entry

These list endpoints use limit/offset paging rather than cursors.

Manual Sync

Trigger a manual sync (admin permission). It runs inline and returns payments_synced and status; it also refreshes refunds and payouts, and a failure in those two does not fail the payment sync:

bash
curl -X POST "https://api.ondayzero.com/api/v1/square/sync" \
  -H "Authorization: Bearer dz_your_token_here" \
  -H "x-business-id: YOUR_BUSINESS_ID"

POST /api/v1/square/sync-catalog queues a sync of the Square item catalog and inventory counts into DayZero's product catalog (see Inventory). The catalog sync runs in the background and returns immediately. Square catalog and inventory changes also trigger it automatically through webhooks.

Webhooks

DayZero processes the following Square webhook events in real time. Webhooks are store-only triggers — they persist data and nudge the daily rollup rather than posting per-event journal entries.

Event Action
payment.completed Stores the payment; triggers the daily rollup
payment.updated Updates the stored payment record (and nudges the rollup)
payout.sent Stores the payout; matched to the bank deposit when it lands
refund.created, refund.updated Stores the refund; netted into the daily summary
catalog.version.updated, inventory.count.updated Queues a catalog and inventory resync (bursts coalesce into one run)

Disconnect

bash
curl -X DELETE "https://api.ondayzero.com/api/v1/square/disconnect" \
  -H "Authorization: Bearer dz_your_token_here" \
  -H "x-business-id: YOUR_BUSINESS_ID"

Revokes stored credentials and removes the integration from the business.

Common errors

Status Cause Fix
403 The business does not have the Commerce add-on, or the token's user is not an admin for connect, sync and disconnect Enable the add-on, or use an admin token
400 posting_mode is not daily_summary, per_payout or per_transaction, or daily_summary_hour is outside 0-23 Use a value from available_modes
404 GET /api/v1/square/subledger/backlink/{journal_entry_id} for an entry Square did not produce Check the journal entry id