# Square Integration

> Point-of-sale accounting automation with Square.

- **Category:** Integrations
- HTML version: https://www.ondayzero.com/docs/guides/square
- All guides: https://www.ondayzero.com/docs/guides/index.md
- Endpoint catalog: https://www.ondayzero.com/docs/reference/index.md

---

# 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 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](/docs/guides/journal-entries), [Inventory](/docs/guides/inventory) and [Reports](/docs/guides/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

### OAuth (Recommended)

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 a `connect_url`. Redirect the merchant to that URL 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:

```
Dr  Undeposited Funds      (cash + other tenders collected)
Dr  Square Clearing        (card tenders, net of fees)
Dr  Square Processing Fees (fees for the day)
        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.

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

```
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. Send `"clear_posting_start_date": true` to remove the start date. Posting is
idempotent per location per day, so re-syncing never double-books.

## Payout & Cash Reconciliation

Card sales flow into `Square Clearing`, which is drained when the matching
Square deposit lands in your **connected bank feed**. DayZero matches the
deposit to the payout (exact amount, within a few days of the expected
arrival) and books it as:

```
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_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|false` shows which have been tied to a bank deposit |
| `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 of recent payments:

```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](/docs/guides/inventory)). Both run in the background and return immediately.

## 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 |
| `payout.sent` | Stores the payout; matched to the bank deposit when it lands |
| `refund.created` | Stores the refund; netted into the daily summary |

## 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.
