Skip to content
BaxPayDevelopers

Payments

Products & catalog

Create and sync a merchant product catalog for checkout, invoicing, and accounting — with barcodes, HS codes, per-store inventory, and ERP-ready exports.

Products is gated twice: the platform must have growth.products live, and the merchant must opt in under Settings → Products. Until both are true, catalog endpoints return 403.

Enable products

From the Business dashboard: Settings → Products → Enable. Multi-store inventory is optional (Settings → Multi-store). Merchants can also toggle via the dashboard JWT API PUT /business/products/feature.

Create a product

POST/productsIdempotency-Key required
curl -X POST https://sandbox-api.baxpay.com/v1/products \
  -H "Authorization: Bearer $BAXPAY_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "House blend — 250 g",
    "sku": "HB-250",
    "barcode": "3760123456789",
    "hsCode": "090121",
    "unitAmount": 12.5,
    "currency": "EUR",
    "taxRatePercent": 5.5,
    "unitOfMeasure": "EA",
    "channel": "BOTH",
    "trackInventory": true,
    "inventory": { "storeIds": "all", "quantityOnHand": 40 }
  }'
{
  "success": true,
  "data": {
    "id": "0d6fcf24-…",
    "name": "House blend — 250 g",
    "sku": "HB-250",
    "unitAmount": "12.5",
    "currency": "EUR",
    "channel": "BOTH",
    "active": true,
    "trackInventory": true,
    "imageUrl": null,
    "livemode": false
  }
}

unitAmount is the price including VAT, in decimal euros, and comes back as a decimal string. channel sets where it's sold: ONLINE, IN_STORE or BOTH.

Stock. With trackInventory: true, seed the opening stock with inventory: quantityOnHand, and storeIds as "all" or a list of location ids. Without it the product counts as always in stock.

Images. A product image is optional through the API. Square images are uploaded and attached in the Business dashboard, which then requires one.

List and update

GET/products?search=blend&channel=IN_STORE&page=1&limit=50
GET/products/{id}
PATCH/products/{id}Idempotency-Key required
curl "https://sandbox-api.baxpay.com/v1/products?search=blend&channel=BOTH" \
  -H "Authorization: Bearer $BAXPAY_API_KEY"
{
  "success": true,
  "data": { "data": [{ "id": "0d6fcf24-…", "name": "House blend — 250 g", "active": true }], "total": 1, "page": 1, "limit": 50 }
}

The list only returns active products. Archived ones are hidden.

curl -X PATCH https://sandbox-api.baxpay.com/v1/products/0d6fcf24-… \
  -H "Authorization: Bearer $BAXPAY_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{ "unitAmount": 13 }'
{ "success": true, "data": { "id": "0d6fcf24-…", "unitAmount": "13" } }

Selling catalog lines

Put catalog lines on a payment link so stock and reporting follow the sale. The link's amount is still what the customer pays:

curl -X POST https://sandbox-api.baxpay.com/v1/payment-links \
  -H "Authorization: Bearer $BAXPAY_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "description": "2 × House blend",
    "amount": 26,
    "businessWide": true,
    "items": [{ "productId": "0d6fcf24-…", "quantity": 2 }]
  }'

Shelf labels

GET/products/{id}/label
curl https://sandbox-api.baxpay.com/v1/products/0d6fcf24-…/label \
  -H "Authorization: Bearer $BAXPAY_API_KEY"
{
  "success": true,
  "data": {
    "format": "baxpay.label.v1",
    "productId": "0d6fcf24-…",
    "name": "House blend — 250 g",
    "barcodeValue": "3760123456789",
    "unitAmount": 13,
    "currency": "EUR",
    "suggestedSymbology": "EAN"
  }
}

A print-ready payload (symbology hint, price, SKU) for shelf-edge printers.

Exports

GET/products/export/catalog
GET/products/export/intrastat?from=2026-01-01&to=2026-03-31
POST/products/export/push-erpIdempotency-Key required
curl https://sandbox-api.baxpay.com/v1/products/export/catalog \
  -H "Authorization: Bearer $BAXPAY_API_KEY"
{
  "success": true,
  "data": {
    "format": "baxpay.catalog.v1",
    "products": [{ "id": "…", "name": "…", "unitAmount": 1.4, "currency": "EUR", "active": true, "inventories": [] }]
  }
}
  • Catalog: stable baxpay.catalog.v1 JSON for accounting connectors.
  • Intrastat: HS code + unit-of-measure rows, with sold quantities for the period.
  • Push to ERP: sends the catalog to every active accounting link, signed. See ERP catalog sync below.

Bulk import

Bulk onboarding uses the dashboard JWT endpoint POST /business/products/import (≤500 rows). Map CSV columns in the dashboard Products → Import tab.

ERP catalog sync

When you push the catalog (dashboard Products → Export → Push to ERP, or POST /products/export/push-erp with your API key), BaxPay delivers a snapshot to every ACTIVE accounting link with a catalog callback URL (configure under Developers → Accounting).

Request (BaxPay → your endpoint)

HeaderValue
Content-Typeapplication/json
X-BaxPay-Eventcatalog.sync
X-BaxPay-Livemodetrue or false
X-BaxPay-Formatbaxpay.catalog.v1, pennylane.products.v1, quickbooks.items.v1, or sage.products.v1
X-BaxPay-Vendorgeneric, pennylane, quickbooks, or sage
X-BaxPay-Signature-V2t=<unix seconds>,v1=<hex HMAC-SHA256 of "<t>.<raw body>"> keyed with the connection callbackSecret: verify this one
X-BaxPay-TimestampThe same t
X-BaxPay-Event-IdUnique per push; use it to deduplicate
X-BaxPay-SignatureLegacy: HMAC-SHA256 hex of the raw body only (no replay protection)

Verify X-BaxPay-Signature-V2 exactly like a webhook, with the connection's callbackSecret.

Default payload (baxpay.catalog.v1)

{
  "format": "baxpay.catalog.v1",
  "generatedAt": "2026-07-20T09:00:00.000Z",
  "livemode": true,
  "merchant": { "id": "…", "name": "Acme SA", "vatNumber": "FR12345678901" },
  "products": [
    {
      "id": "0d6fcf24-…",
      "name": "House blend — 250 g",
      "sku": "HB-250",
      "barcode": "3760123456789",
      "hsCode": "090121",
      "unitOfMeasure": "EA",
      "unitAmount": 12.5,
      "currency": "EUR",
      "taxRatePercent": 5.5,
      "channel": "BOTH",
      "active": true,
      "trackInventory": true,
      "inventories": [
        {
          "storeId": "5a8c0e3b-…",
          "storeName": "Main boutique",
          "storeCode": "MAIN",
          "quantityOnHand": 42,
          "quantityReserved": 0,
          "reorderPoint": 10
        }
      ],
      "updatedAt": "2026-07-19T14:22:00.000Z"
    }
  ]
}

Vendor-specific shapes (Pennylane, QuickBooks, Sage) are selected when provisioning the accounting link. For direct OAuth sync (no middleware), connect from the Business dashboard under Developers → Accounting — see Accounting & ERP sync.