# Accounting & ERP sync

Sync your BaxPay product catalog with accounting software. Merchants connect from the Business
dashboard under <strong>Developers → Accounting</strong> — not under POS Connections.

Accounting links are **ERP** integrations. They are separate from till / pump
[Connections](https://developers.baxpay.com/connections) (`ECR`, `FORECOURT`, …). Use Accounting for catalog push/pull;
use Connections for in-store payment credentials (`bxc_…`).

## Ways to connect

| Mode | Merchant experience | Best for |
| --- | --- | --- |
| **OAuth** | Click **Connect Pennylane / QuickBooks / Sage**, log in, approve BaxPay | Direct vendor APIs |
| **Webhook** | Provide a catalog callback URL; receive signed `catalog.sync` POSTs | Middleware or custom ERP |

OAuth uses **BaxPay’s** platform app with each vendor. Merchants authorize access to *their*
company; they do not register their own OAuth client ID in BaxPay.

## Dashboard flow

1. Open **Developers → Accounting** → **Connect accounting**.
2. Pick the software (or **Custom webhook**).
3. For OAuth vendors, open the connection and click **Connect** (Pennylane, QuickBooks, or Sage).
4. After approval, use **Sync catalog** (BaxPay → ERP) or **Import from ERP** (ERP → BaxPay).
5. Or push from **Products → Export → Push to ERP** (hits webhooks and OAuth links).

> **Test vs live**
> Accounting links are scoped to the dashboard mode (test or live), same as API keys and
> Connections. Connect OAuth in the mode you intend to sync.

## Webhook delivery

When BaxPay pushes a catalog snapshot to your callback:

| Header | Value |
|--------|-------|
| `X-BaxPay-Event` | `catalog.sync` |
| `X-BaxPay-Livemode` | `true` or `false` |
| `X-BaxPay-Format` | `baxpay.catalog.v1`, `pennylane.products.v1`, `quickbooks.items.v1`, or `sage.products.v1` |
| `X-BaxPay-Vendor` | `generic`, `pennylane`, `quickbooks`, or `sage` |
| `X-BaxPay-Signature-V2` | `t=<unix seconds>,v1=<HMAC-SHA256 of "<t>.<raw body>">` with your connection `callbackSecret`: **verify this one** |
| `X-BaxPay-Timestamp`, `X-BaxPay-Event-Id` | The signing time; a unique id per push for deduplication |
| `X-BaxPay-Signature` | Legacy: HMAC-SHA256 hex of the raw body only |

Verify signatures like [webhooks](https://developers.baxpay.com/webhooks#verifying-signatures). Respond with `2xx` within
**10 seconds**.

Full payload schema: [Products → ERP catalog sync](https://developers.baxpay.com/products#erp-catalog-sync).

## With your API key

A custom webhook link, and pushing the catalog to it, also work with your `bx_` API key, so a
middleware can set itself up. Create the link as an `ERP` connection with the callback URL:

```bash
curl -X POST https://sandbox-api.baxpay.com/v1/connections \
  -H "Authorization: Bearer $BAXPAY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "systemType": "ERP",
    "label": "Custom ERP",
    "callbackUrl": "https://yourapp.com/hooks/baxpay"
  }'
```

```json
{
  "success": true,
  "data": { "connectionId": "f8a5882f-…", "credential": "bxc_…", "callbackSecret": "whsec_…" }
}
```

Keep `callbackSecret`: it signs every push. Then push the catalog to all active links:

```bash
curl -X POST https://sandbox-api.baxpay.com/v1/products/export/push-erp \
  -H "Authorization: Bearer $BAXPAY_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)"
```

```json
{
  "success": true,
  "data": {
    "pushed": 1,
    "results": [{ "connectionId": "f8a5882f-…", "label": "Custom ERP", "vendor": "generic", "format": "baxpay.catalog.v1", "ok": true }]
  }
}
```

The platform must have accounting adapters switched on; otherwise creating the link answers `403`.

## Dashboard API

OAuth links (Pennylane, QuickBooks, Sage) need a person to approve access, so they are managed with
a **dashboard login**, not an API key:

| Method | Path | Notes |
|--------|------|-------|
| `POST` | `/merchant-integrations` | Create an accounting link (`systemType: "ERP"`, `label`, `erpVendor`, optional `callbackUrl`) |
| `POST` | `/merchant-integrations/{id}/erp/oauth/start` | Begin OAuth; returns `authorizationUrl` |
| `GET` | `/integrations/erp/oauth/callback` | Vendor redirect (public) |
| `POST` | `/merchant-integrations/{id}/erp/sync` | Push catalog via the vendor API |
| `POST` | `/merchant-integrations/{id}/erp/import` | Pull products into BaxPay (upsert by SKU) |
| `GET` | `/merchant-integrations/{id}/erp/accounts` | The vendor's chart of accounts |
| `PUT` | `/merchant-integrations/{id}/erp/account-map` | Map BaxPay revenue / VAT to those accounts |
| `PUT` | `/merchant-integrations/{id}/erp/settings` | Sync options, such as automatic sync |
| `DELETE` | `/merchant-integrations/{id}/erp/oauth` | Disconnect OAuth tokens |

Scheduled OAuth sync runs about every **6 hours** unless disabled on the connection.

## Related

- [Products & catalog](https://developers.baxpay.com/products) — SKUs, inventory, export formats
- [Connections & credentials](https://developers.baxpay.com/connections) — POS tills and pumps only
- [Webhooks](https://developers.baxpay.com/webhooks) — payment and lifecycle events (separate from catalog push)
