Skip to main content

Products

The sales product catalog (hub_invoice_products table — legacy name; semantically = billing catalog per company). Used as an optional line-item source when creating quotes or invoices (line.product_id). Scopes: sales.products.read / sales.products.write / sales.products.delete.

Endpoints

GET/api/workspace/v1/products
GET/api/workspace/v1/products/{id}
POST/api/workspace/v1/products
PATCH/api/workspace/v1/products/{id}
DELETE/api/workspace/v1/products/{id}
POST/api/workspace/v1/products/{id}/restore
POST/api/workspace/v1/products/bulk-delete

The product object

FieldTypeDescription
name*stringHuman-readable product name (required)
skustringOptional SKU / product code
descriptionstringShort description (<= 500 chars)
unitenumuur | stuk | dag | maand | km | pakket | sessie | licentie
default_pricenumberDefault unit price (excl. VAT)
cost_pricenumberCost price for margin calculations
categorystringFree-form category label
is_recurringbooleanTrue if this represents a recurring subscription
recur_intervalenumweekly | monthly | quarterly | yearly (required if is_recurring)
ledger_codestringOptional ledger / accounting code
image_urlstringHTTPS product image URL
internal_notesstringNotes visible only to workspace users
vat_ratenumberVAT percentage 0-100 (default 21)
activebooleanFalse to hide from pickers (archive flag, keeps history)
sort_orderintegerDisplay order in the picker

Create a product

curl "https://app.staffifyai.com/api/workspace/v1/products" \
  -X POST \
  -H "Authorization: Bearer sfy_wsp_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "AI Voice Agent — starter",
    "sku": "AI-VOICE-STARTER",
    "unit": "maand",
    "default_price": 499.00,
    "vat_rate": 21,
    "is_recurring": true,
    "recur_interval": "monthly",
    "category": "Subscriptions"
  }'

Archive vs delete

Two orthogonal soft states exist on every product:

  • active = false — hidden from pickers but keeps history intact and appears in list queries with ?active=false or ?active=any. No purge.
  • deleted_at — recycle bin (30-day purge countdown). Requires the separate sales.products.delete scope. Historical invoice + quote lines keep their denormalised description/price after purge, only product_id gets nullified.
# Soft-delete
curl -X DELETE "https://app.staffifyai.com/api/workspace/v1/products/42" \
  -H "Authorization: Bearer sfy_wsp_live_YOUR_KEY"

# Restore
curl -X POST "https://app.staffifyai.com/api/workspace/v1/products/42/restore" \
  -H "Authorization: Bearer sfy_wsp_live_YOUR_KEY"

# Bulk-delete (max 500 ids)
curl -X POST "https://app.staffifyai.com/api/workspace/v1/products/bulk-delete" \
  -H "Authorization: Bearer sfy_wsp_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "ids": [42, 43] }'

Webhooks

  • product.created
  • product.updated
  • product.deleted
  • product.restored
Products - Workspace API - Staffify