Home Integration API reference
REST API for integrations and external apps
Settings
Settings endpoints cover invoice schemes and layouts, barcode presets, notification templates, receipt printers, business settings, integration webhooks, and business locations. Unless a section says otherwise, CSV exports ignore pagination and write endpoints follow the same permission and demo-mode rules as the matching web settings screen.
Lists invoice numbering schemes that the token user can manage from Invoice settings.
| Property | Value |
|---|---|
| Method | GET |
| Path | /api/v1/integration/invoice-schemes |
| Permission | invoice_settings.access. |
| Search behavior | q requires at least 2 characters when sent. Legacy search still matches name, prefix, or numeric id. |
| CSV behavior | format=csv downloads all matching rows as UTF-8 CSV with BOM and ignores page and per_page. |
| Success response | 200 with paginated rows or a CSV download. |
| Parameter | Type | Required | Description |
|---|---|---|---|
per_page, page | integer | No | Pagination controls. per_page accepts 1 to 100 and defaults to 20. |
q, search | string | No | Text search across scheme name, prefix, and numeric id-like values. |
sort | string | No | name, scheme_type, number_type, invoice_count, or created_at. |
direction | string | No | asc or desc. |
format | string | No | json (default) or csv. |
| Field | Type | Description |
|---|---|---|
id, name | integer | string | Scheme identity and display name. |
scheme_type | string | blank or year. |
number_type | string | sequential or random. |
invoice_count, is_default | integer | boolean | Current usage counter and default flag. |
prefix_preview | string | null | Current-year preview when scheme_type = year. |
| Field | Type | Description |
|---|---|---|
data | array<object> | The current result page of invoice schemes. |
meta.current_page, meta.last_page, meta.per_page, meta.total | integer | Laravel paginator metadata. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The invoice schemes were returned successfully. | { "data": [...], "meta": { ... } } or CSV download. |
403 | The token user lacks invoice_settings.access. | { "message": string } |
422 | The query string failed validation. | Laravel validation JSON. |
Returns one invoice scheme and can flatten the same payload into a single CSV row.
| Property | Value |
|---|---|
| Method | GET |
| Path | /api/v1/integration/invoice-schemes/{id} |
| Permission | invoice_settings.access. |
| CSV behavior | format=csv streams one UTF-8 BOM row whose data_json cell matches the JSON data object. |
| Success response | 200 with one invoice-scheme object. |
| Parameter | Type | Required | Description |
|---|---|---|---|
format | string | No | json (default) or csv. CSV download name: invoice-scheme-{id}-detail-{business_id}-{timestamp}.csv. |
| Field | Type | Description |
|---|---|---|
name, prefix | string | null | Saved scheme name and optional invoice prefix. |
scheme_type, number_type | string | The numbering strategy used by this scheme. |
total_digits, start_number | integer | null | Sequential-number configuration. start_number is omitted for random schemes. |
invoice_count, is_default | integer | boolean | Current counter and whether the scheme is the business default. |
| Field | Type | Description |
|---|---|---|
data | object | The requested invoice-scheme payload. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The invoice scheme was returned successfully. | { "data": { ... } } or CSV download. |
403 | The token user lacks invoice_settings.access. | { "message": string } |
404 | The invoice scheme id does not exist for the current business. | { "message": "Not found" } |
Creates a new invoice numbering scheme and can optionally make it the default for the business.
| Property | Value |
|---|---|
| Method | POST |
| Path | /api/v1/integration/invoice-schemes |
| Permission | invoice_settings.access. |
| Default behavior | When is_default = true, the previous business default is cleared before the new scheme is marked default. |
| Write guard | Returns 403 in demo environments. |
| Success response | 201 with the created invoice-scheme object. |
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Display name for the scheme. |
scheme_type | string | Yes | blank or year. |
number_type | string | Yes | sequential or random. |
prefix | string | null | No | Optional invoice prefix. |
total_digits | integer | null | No | Optional numeric width for generated invoice numbers. |
start_number | integer | null | Conditional | Required for sequential schemes. Omit or send null for random numbering. |
is_default | boolean | No | When true, this scheme becomes the new business default. |
| Field | Type | Description |
|---|---|---|
data | object | The created invoice-scheme payload. |
| Status | When it happens | Response shape |
|---|---|---|
201 | The invoice scheme was created successfully. | { "data": { ... } } |
403 | Demo mode is active or the token user lacks invoice_settings.access. | { "message": string } |
422 | The request body failed validation. | Laravel validation JSON. |
Updates an existing invoice scheme without changing which scheme is the current default.
| Property | Value |
|---|---|
| Method | PATCH or PUT |
| Path | /api/v1/integration/invoice-schemes/{id} |
| Permission | invoice_settings.access. |
| Write rule | Uses the same field rules as create, except is_default is not accepted here. Use Set default instead. |
| Counter rule | invoice_count is read-only and is only changed when invoices are issued. |
| Success response | 200 with the updated invoice-scheme object. |
| Field | Type | Required | Description |
|---|---|---|---|
All Add invoice scheme fields except is_default | mixed | No | Send only the values that should change. |
| Field | Type | Description |
|---|---|---|
data | object | The updated invoice-scheme payload. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The invoice scheme was updated successfully. | { "data": { ... } } |
403 | Demo mode is active or the token user lacks invoice_settings.access. | { "message": string } |
404 | The invoice scheme id does not exist for the current business. | { "message": "Not found" } |
422 | The request body failed validation. | Laravel validation JSON. |
Marks one invoice scheme as default and clears the default flag from all other schemes in the same business.
| Property | Value |
|---|---|
| Method | POST |
| Path | /api/v1/integration/invoice-schemes/{id}/set-default |
| Permission | invoice_settings.access. |
| Write guard | Returns 403 in demo environments. |
| Success response | 200 with the refreshed invoice-scheme object. |
| Field | Type | Description |
|---|---|---|
data | object | The invoice scheme after the default flag is updated. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The invoice scheme became the business default. | { "data": { ... } } |
403 | Demo mode is active or the token user lacks invoice_settings.access. | { "message": string } |
404 | The invoice scheme id does not exist for the current business. | { "message": "Not found" } |
Deletes an invoice scheme that is not the active default and is not referenced by any business location.
| Property | Value |
|---|---|
| Method | DELETE |
| Path | /api/v1/integration/invoice-schemes/{id} |
| Permission | invoice_settings.access. |
| Business rule | Returns 422 when the scheme is the current default or is referenced by a location as invoice_scheme_id or sale_invoice_scheme_id. |
| Write guard | Returns 403 in demo environments. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The invoice scheme was deleted successfully. | { "message": string } |
403 | Demo mode is active or the token user lacks invoice_settings.access. | { "message": string } |
404 | The invoice scheme id does not exist for the current business. | { "message": "Not found" } |
422 | The scheme is default or is still referenced by one or more locations. | { "message": string } |
Lists printable invoice layouts exactly as they appear under Invoice settings in the web UI.
| Property | Value |
|---|---|
| Method | GET |
| Path | /api/v1/integration/invoice-layouts |
| Permission | invoice_settings.access. |
| Search behavior | q requires at least 2 characters when sent. Legacy search still matches layout name or numeric id. |
| CSV behavior | format=csv downloads all matching rows. Array and object fields are JSON-encoded in CSV cells. |
| Success response | 200 with paginated rows or a CSV download. |
| Parameter | Type | Required | Description |
|---|---|---|---|
per_page, page | integer | No | Pagination controls. per_page accepts 1 to 100 and defaults to 20. |
q, search | string | No | Text search across layout name or numeric id-like values. |
sort | string | No | name, design, is_default, or created_at. |
direction | string | No | asc or desc. |
format | string | No | json (default) or csv. |
| Field | Type | Description |
|---|---|---|
id, name, design | mixed | Layout identity and design template name. |
is_default | boolean | Whether the layout is the current business default. |
show_* flags | boolean | Print toggles copied from the web Invoice layouts form. |
module_info, common_settings | object | array | null | Structured printable settings stored with the layout. |
logo_url, letter_head_url | string | null | Resolved asset URLs when the uploaded files exist. |
| Field | Type | Description |
|---|---|---|
data | array<object> | The current result page of invoice layouts. |
meta.current_page, meta.last_page, meta.per_page, meta.total | integer | Laravel paginator metadata. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The invoice layouts were returned successfully. | { "data": [...], "meta": { ... } } or CSV download. |
403 | The token user lacks invoice_settings.access. | { "message": string } |
422 | The query string failed validation. | Laravel validation JSON. |
Returns one invoice layout, including its printable flags and uploaded asset URLs.
| Property | Value |
|---|---|
| Method | GET |
| Path | /api/v1/integration/invoice-layouts/{id} |
| Permission | invoice_settings.access. |
| CSV behavior | format=csv streams one UTF-8 BOM row whose data_json cell matches the JSON data object. |
| Success response | 200 with one invoice-layout object. |
| Parameter | Type | Required | Description |
|---|---|---|---|
format | string | No | json (default) or csv. CSV download name: invoice-layout-{id}-detail-{business_id}-{timestamp}.csv. |
| Field | Type | Description |
|---|---|---|
name, design | string | Layout name and selected print design. |
Printable labels and show_* flags | mixed | All user-configured print labels and boolean display toggles from the web form. |
module_info, table_tax_headings, product_custom_fields, contact_custom_fields, location_custom_fields, common_settings, qr_code_fields | object | array | null | Structured layout settings stored as arrays or objects. |
logo_url, letter_head_url | string | null | Resolved image URLs when uploaded assets exist. |
| Field | Type | Description |
|---|---|---|
data | object | The requested invoice-layout payload. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The invoice layout was returned successfully. | { "data": { ... } } or CSV download. |
403 | The token user lacks invoice_settings.access. | { "message": string } |
404 | The invoice layout id does not exist for the current business. | { "message": "Not found" } |
Creates a new printable invoice layout, including optional uploaded logo and letterhead images passed as data URLs.
| Property | Value |
|---|---|
| Method | POST |
| Path | /api/v1/integration/invoice-layouts |
| Permission | invoice_settings.access. |
| Content type | application/json. |
| Default behavior | When is_default = true, the previous business default is cleared before this layout is marked default. |
| Write guard | Returns 403 in demo environments. |
| Success response | 201 with the created invoice-layout object. |
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Display name for the layout. |
design | string | Yes | classic, elegant, detailed, columnize-taxes, slim, slim2, or english-arabic. |
Printable labels and show_* flags | mixed | No | Optional label overrides and boolean print toggles from the web Invoice layouts form. |
module_info, table_tax_headings, product_custom_fields, contact_custom_fields, location_custom_fields, common_settings, qr_code_fields | object | array | null | No | Structured layout settings sent as arrays or objects. |
is_default | boolean | No | When true, this layout becomes the new business default. |
logo_base64, letter_head_base64 | string | null | No | Optional image data URLs such as data:image/png;base64,.... |
| Field | Type | Description |
|---|---|---|
data | object | The created invoice-layout payload. |
| Status | When it happens | Response shape |
|---|---|---|
201 | The invoice layout was created successfully. | { "data": { ... } } |
403 | Demo mode is active or the token user lacks invoice_settings.access. | { "message": string } |
422 | The request body failed validation. | Laravel validation JSON. |
Partially updates an invoice layout while preserving any fields that are not included in the request.
| Property | Value |
|---|---|
| Method | PATCH or PUT |
| Path | /api/v1/integration/invoice-layouts/{id} |
| Permission | invoice_settings.access. |
| Write rule | Send only the fields that should change. Default selection is handled by Set default. |
| Image rule | New logo or letterhead uploads use logo_base64 and letter_head_base64 data URLs. |
| Success response | 200 with the updated invoice-layout object. |
| Field | Type | Required | Description |
|---|---|---|---|
All Add invoice layout fields except is_default | mixed | No | All update fields are optional and are applied partially. |
| Field | Type | Description |
|---|---|---|
data | object | The updated invoice-layout payload. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The invoice layout was updated successfully. | { "data": { ... } } |
403 | Demo mode is active or the token user lacks invoice_settings.access. | { "message": string } |
404 | The invoice layout id does not exist for the current business. | { "message": "Not found" } |
422 | The request body failed validation. | Laravel validation JSON. |
Marks one invoice layout as default for the business.
| Property | Value |
|---|---|
| Method | POST |
| Path | /api/v1/integration/invoice-layouts/{id}/set-default |
| Permission | invoice_settings.access. |
| Write guard | Returns 403 in demo environments. |
| Success response | 200 with the refreshed invoice-layout object. |
| Field | Type | Description |
|---|---|---|
data | object | The invoice layout after the default flag is updated. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The invoice layout became the business default. | { "data": { ... } } |
403 | Demo mode is active or the token user lacks invoice_settings.access. | { "message": string } |
404 | The invoice layout id does not exist for the current business. | { "message": "Not found" } |
Deletes an invoice layout that is neither the current default nor referenced by a business location.
| Property | Value |
|---|---|
| Method | DELETE |
| Path | /api/v1/integration/invoice-layouts/{id} |
| Permission | invoice_settings.access. |
| Business rule | Returns 422 when the layout is the current default or is referenced by a location as invoice_layout_id or sale_invoice_layout_id. |
| Write guard | Returns 403 in demo environments. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The invoice layout was deleted successfully. | { "message": string } |
403 | Demo mode is active or the token user lacks invoice_settings.access. | { "message": string } |
404 | The invoice layout id does not exist for the current business. | { "message": "Not found" } |
422 | The layout is default or is still referenced by one or more locations. | { "message": string } |
Lists saved barcode presets exactly as they appear in Barcode settings.
| Property | Value |
|---|---|
| Method | GET |
| Path | /api/v1/integration/barcode-presets |
| Permission | barcode_settings.access. |
| Search behavior | q requires at least 2 characters when sent. Legacy search still matches preset name, description, or numeric id. |
| CSV behavior | format=csv downloads all matching rows as UTF-8 CSV with BOM and ignores pagination. |
| Success response | 200 with paginated rows or a CSV download. |
| Parameter | Type | Required | Description |
|---|---|---|---|
per_page, page | integer | No | Pagination controls. per_page accepts 1 to 100 and defaults to 20. |
q, search | string | No | Text search across preset name, description, and numeric id-like values. |
sort | string | No | name, is_default, or created_at. |
direction | string | No | asc or desc. |
format | string | No | json (default) or csv. |
| Field | Type | Description |
|---|---|---|
id, name, description | mixed | Preset identity and display values. |
width, height, paper_width, paper_height | number | null | Saved label and paper dimensions. |
is_continuous, is_default | boolean | Continuous-roll behavior and default flag. |
stickers_in_one_row, stickers_in_one_sheet | integer | null | Sheet layout settings. Continuous presets force stickers_in_one_sheet = 28. |
| Field | Type | Description |
|---|---|---|
data | array<object> | The current result page of barcode presets. |
meta.current_page, meta.last_page, meta.per_page, meta.total | integer | Laravel paginator metadata. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The barcode presets were returned successfully. | { "data": [...], "meta": { ... } } or CSV download. |
403 | The token user lacks barcode_settings.access. | { "message": string } |
422 | The query string failed validation. | Laravel validation JSON. |
Returns one barcode preset and can flatten the same payload into a single CSV row.
| Property | Value |
|---|---|
| Method | GET |
| Path | /api/v1/integration/barcode-presets/{id} |
| Permission | barcode_settings.access. |
| CSV behavior | format=csv streams one UTF-8 BOM row whose data_json cell matches the JSON data object. |
| Success response | 200 with one barcode-preset object. |
| Parameter | Type | Required | Description |
|---|---|---|---|
format | string | No | json (default) or csv. CSV download name: barcode-preset-{id}-detail-{business_id}-{timestamp}.csv. |
| Field | Type | Description |
|---|---|---|
name, description | string | null | Preset label and optional description. |
| Dimension and margin fields | number | null | Width, height, paper size, and margin settings used for label rendering. |
stickers_in_one_row, stickers_in_one_sheet | integer | null | Sheet layout settings used during barcode printing. |
is_continuous, is_default | boolean | Continuous-roll behavior and default status. |
| Field | Type | Description |
|---|---|---|
data | object | The requested barcode-preset payload. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The barcode preset was returned successfully. | { "data": { ... } } or CSV download. |
403 | The token user lacks barcode_settings.access. | { "message": string } |
404 | The barcode preset id does not exist for the current business. | { "message": "Not found" } |
Creates a barcode preset that can later be reused from barcode print flows and preview endpoints.
| Property | Value |
|---|---|
| Method | POST |
| Path | /api/v1/integration/barcode-presets |
| Permission | barcode_settings.access. |
| Continuous rule | When is_continuous = true, the controller forces stickers_in_one_sheet = 28. |
| Default behavior | When is_default = true, the previous business default is cleared first. |
| Success response | 201 with the created barcode-preset object. |
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Display name for the preset. |
description | string | null | No | Optional helper text for the preset. |
width, height, paper_width, paper_height, top_margin, left_margin, row_distance, col_distance | number | null | No | Optional dimension and margin fields. |
stickers_in_one_row, stickers_in_one_sheet | integer | null | No | Optional sheet layout settings. |
is_continuous, is_default | boolean | No | Optional continuous-roll and default flags. |
| Field | Type | Description |
|---|---|---|
data | object | The created barcode-preset payload. |
| Status | When it happens | Response shape |
|---|---|---|
201 | The barcode preset was created successfully. | { "data": { ... } } |
403 | Demo mode is active or the token user lacks barcode_settings.access. | { "message": string } |
422 | The request body failed validation. | Laravel validation JSON. |
Partially updates a barcode preset and re-applies the same continuous-roll rules used by the web form.
| Property | Value |
|---|---|
| Method | PATCH or PUT |
| Path | /api/v1/integration/barcode-presets/{id} |
| Permission | barcode_settings.access. |
| Continuous rule | When is_continuous is sent, continuous presets force stickers_in_one_sheet = 28 and paper_height = 0. |
| Write mode | All update fields are optional and are merged with the current preset. |
| Success response | 200 with the updated barcode-preset object. |
| Field | Type | Required | Description |
|---|---|---|---|
| All Add barcode preset fields | mixed | No | Send only the values that should change. |
| Field | Type | Description |
|---|---|---|
data | object | The updated barcode-preset payload. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The barcode preset was updated successfully. | { "data": { ... } } |
403 | Demo mode is active or the token user lacks barcode_settings.access. | { "message": string } |
404 | The barcode preset id does not exist for the current business. | { "message": "Not found" } |
422 | The request body failed validation. | Laravel validation JSON. |
Marks one barcode preset as the business default.
| Property | Value |
|---|---|
| Method | POST |
| Path | /api/v1/integration/barcode-presets/{id}/set-default |
| Permission | barcode_settings.access. |
| Write guard | Returns 403 in demo environments. |
| Success response | 200 with the refreshed barcode-preset object. |
| Field | Type | Description |
|---|---|---|
data | object | The barcode preset after the default flag is updated. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The barcode preset became the business default. | { "data": { ... } } |
403 | Demo mode is active or the token user lacks barcode_settings.access. | { "message": string } |
404 | The barcode preset id does not exist for the current business. | { "message": "Not found" } |
Deletes a barcode preset that is not currently marked as default.
| Property | Value |
|---|---|
| Method | DELETE |
| Path | /api/v1/integration/barcode-presets/{id} |
| Permission | barcode_settings.access. |
| Business rule | Returns 422 when the preset is the current default. |
| Write guard | Returns 403 in demo environments. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The barcode preset was deleted successfully. | { "message": string } |
403 | Demo mode is active or the token user lacks barcode_settings.access. | { "message": string } |
404 | The barcode preset id does not exist for the current business. | { "message": "Not found" } |
422 | The preset is still marked as the business default. | { "message": string } |
Builds the same HTML label preview used by the Print labels screen without creating any printable transaction records.
| Property | Value |
|---|---|
| Method | POST |
| Path | /api/v1/integration/barcode-labels/preview |
| Permission | barcode_settings.access. |
| Preset rule | barcode_setting_id may reference a business preset or a global preset whose business_id is null. |
| Generation limit | The sum of all requested sticker quantities is capped at 5000, and the request may include at most 200 product rows. |
| Success response | 200 with rendered preview HTML and metadata. |
| Field | Type | Required | Description |
|---|---|---|---|
barcode_setting_id | integer | Yes | The barcode preset id to render against. |
products | array<object> | Yes | Preview rows containing variation_id, quantity, and optional price_group_id, exp_date, packing_date, and lot_number. |
print | object | null | No | Optional label overrides matching the Print labels form keys such as name, name_size, price, price_size, and price_type. |
Authorization: Bearer YOUR_ACCESS_TOKEN Content-Type: application/json Accept: application/json
| Field | Type | Description |
|---|---|---|
data.format | string | Always html for preview responses. |
data.html | string | Rendered tables and inline styles matching the web preview. |
data.meta.pages, data.meta.total_stickers | integer | Preview page count and total sticker count. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The barcode preview was generated successfully. | { "data": { "format": "html", "html": string, "meta": { ... } } } |
403 | The token user lacks barcode_settings.access. | { "message": string } |
404 | The barcode preset id does not exist or is not visible. | { "message": "Not found" } |
422 | The request body failed validation, a variation is invalid, a price group is invalid, or preview generation failed. | Laravel validation JSON or { "message": string }. |
Lists the notification-template catalog grouped the same way as the web Notification templates screen.
| Property | Value |
|---|---|
| Method | GET |
| Path | /api/v1/integration/notification-templates |
| Permission | send_notification. |
| Grouping | Templates are grouped into general, customer, and supplier buckets, plus any module-provided notification hooks. |
| CSV behavior | format=csv downloads one row per template in the same JSON order. There is no pagination. |
| Success response | 200 with grouped template arrays or a CSV download. |
| Parameter | Type | Required | Description |
|---|---|---|---|
group | string | No | general, customer, supplier, or all (default). |
format | string | No | json (default) or csv. |
| Field | Type | Description |
|---|---|---|
group, template_for, name | string | Template grouping and internal identity key. |
subject, email_body, sms_body, whatsapp_text | string | null | Saved content fields for each notification channel. |
auto_send, auto_send_sms, auto_send_wa_notif | boolean | Auto-send flags used by the template. |
cc, bcc | string | null | Saved CC and BCC addresses. |
extra_tags, id | array | integer | null | Merge-tag hints and the database id when a stored row exists. |
| Field | Type | Description |
|---|---|---|
data.general, data.customer, data.supplier | array<object> | null | Template arrays for the requested groups. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The notification-template catalog was returned successfully. | { "data": { ... } } or CSV download. |
403 | The token user lacks send_notification. | { "message": string } |
422 | The query string failed validation. | Laravel validation JSON. |
Returns one notification template by its internal template_for key.
| Property | Value |
|---|---|
| Method | GET |
| Path | /api/v1/integration/notification-templates/{template_for} |
| Permission | send_notification. |
| Identifier | template_for is the internal catalog key such as new_sale or payment_reminder. |
| CSV behavior | format=csv streams one UTF-8 BOM row with the same columns as the list endpoint. |
| Success response | 200 with one notification-template object. |
| Parameter | Type | Required | Description |
|---|---|---|---|
format | string | No | json (default) or csv. CSV download name: notification-template-{template_for}-{business_id}-{timestamp}.csv. |
| Field | Type | Description |
|---|---|---|
data | object | The requested template payload, matching the list-row shape. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The notification template was returned successfully. | { "data": { ... } } or CSV download. |
403 | The token user lacks send_notification. | { "message": string } |
404 | The requested template_for key is not present in the catalog for this business. | { "message": "Not found" } |
Saves multiple notification templates in one request using the same field names as the web bulk editor.
| Property | Value |
|---|---|
| Method | POST |
| Path | /api/v1/integration/notification-templates |
| Permission | send_notification. |
| Content type | application/json. |
| Write guard | Returns 403 in demo environments. |
| Success response | 200 with the list of template keys that were saved. |
| Field | Type | Required | Description |
|---|---|---|---|
template_data | object | Yes | Object keyed by template_for. Each nested object may contain subject, email_body, sms_body, whatsapp_text, auto_send, auto_send_sms, auto_send_wa_notif, cc, and bcc. |
| Field | Type | Description |
|---|---|---|
updated | array<string> | The list of template keys that were saved. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The notification templates were saved successfully. | { "updated": [...] } |
403 | Demo mode is active or the token user lacks send_notification. | { "message": string } |
422 | The request body failed validation or contains unknown template keys. | Laravel validation JSON. |
Partially updates a single notification template while leaving omitted fields unchanged.
| Property | Value |
|---|---|
| Method | PATCH |
| Path | /api/v1/integration/notification-templates/{template_for} |
| Permission | send_notification. |
| Write rule | Omitted fields keep their current values from NotificationTemplate::getTemplate. |
| Write guard | Returns 403 in demo environments. |
| Success response | 200 with the refreshed notification-template object. |
| Field | Type | Required | Description |
|---|---|---|---|
subject, email_body, sms_body, whatsapp_text | string | null | No | Optional content fields to update. |
auto_send, auto_send_sms, auto_send_wa_notif | boolean | No | Optional auto-send flags. |
cc, bcc | string | null | No | Optional email address fields. |
| Field | Type | Description |
|---|---|---|
data | object | The updated template payload. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The notification template was updated successfully. | { "data": { ... } } |
403 | Demo mode is active or the token user lacks send_notification. | { "message": string } |
404 | The requested template_for key is not present in the catalog for this business. | { "message": "Not found" } |
422 | The request body failed validation. | Laravel validation JSON. |
Lists receipt printers configured for the business together with connection-type metadata used by the printer settings screen.
| Property | Value |
|---|---|
| Method | GET |
| Path | /api/v1/integration/receipt-printers |
| Permission | access_printers. |
| Search behavior | q requires at least 2 characters when sent. Legacy search still matches printer name, IP, path, or numeric id. |
| CSV behavior | format=csv downloads all matching rows. JSON-only metadata stays in the normal response. |
| Success response | 200 with paginated rows plus meta.connection_types and meta.capability_profiles. |
| Parameter | Type | Required | Description |
|---|---|---|---|
per_page, page | integer | No | Pagination controls. per_page accepts 1 to 100 and defaults to 20. |
q, search | string | No | Text search across printer identity fields. |
sort | string | No | name, connection_type, capability_profile, or created_at. |
direction | string | No | asc or desc. |
format | string | No | json (default) or csv. |
| Field | Type | Description |
|---|---|---|
id, name | integer | string | Printer identity and display name. |
connection_type, connection_type_label | string | Stored connection code and human-readable label. |
capability_profile, capability_profile_label | string | Capability profile code and label. |
ip_address, port, path, char_per_line | mixed | Connection details used for printing. |
| Field | Type | Description |
|---|---|---|
data | array<object> | The current result page of receipt printers. |
meta.connection_types, meta.capability_profiles | object | Choice maps returned only on JSON responses. |
meta.current_page, meta.last_page, meta.per_page, meta.total | integer | Laravel paginator metadata. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The receipt printers were returned successfully. | { "data": [...], "meta": { ... } } or CSV download. |
403 | The token user lacks access_printers. | { "message": string } |
422 | The query string failed validation. | Laravel validation JSON. |
Returns one receipt printer together with the same connection-type metadata used by the printer settings UI.
| Property | Value |
|---|---|
| Method | GET |
| Path | /api/v1/integration/receipt-printers/{id} |
| Permission | access_printers. |
| CSV behavior | format=csv streams one row with data_json and meta_json cells matching the JSON payload. |
| Success response | 200 with one printer object and metadata maps. |
| Parameter | Type | Required | Description |
|---|---|---|---|
format | string | No | json (default) or csv. CSV download name: receipt-printer-{id}-detail-{business_id}-{timestamp}.csv. |
| Field | Type | Description |
|---|---|---|
data | object | The requested receipt-printer payload. |
meta.connection_types, meta.capability_profiles | object | Choice maps returned together with the printer record. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The receipt printer was returned successfully. | { "data": { ... }, "meta": { ... } } or CSV download. |
403 | The token user lacks access_printers. | { "message": string } |
404 | The receipt printer id does not exist for the current business. | { "message": "Not found" } |
Creates a receipt printer with the same network or local-path rules used by the web form.
| Property | Value |
|---|---|
| Method | POST |
| Path | /api/v1/integration/receipt-printers |
| Permission | access_printers. |
| Network rule | When connection_type = network, send ip_address and port. Local path is cleared. |
| Local rule | When connection_type = windows or linux, send path. IP and port are cleared. |
| Success response | 201 with the created printer object, including created_by. |
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Display name for the printer. |
connection_type | string | Yes | network, windows, or linux. |
capability_profile | string | Yes | default, simple, SP2000, TEP-200M, or P822D. |
ip_address, port | mixed | Conditional | Required for network printers. |
path | string | null | Conditional | Required for Windows and Linux printers. |
char_per_line | integer | null | No | Optional printer width hint. |
| Field | Type | Description |
|---|---|---|
data | object | The created receipt-printer payload. |
| Status | When it happens | Response shape |
|---|---|---|
201 | The receipt printer was created successfully. | { "data": { ... } } |
403 | Demo mode is active or the token user lacks access_printers. | { "message": string } |
422 | The request body failed validation. | Laravel validation JSON. |
Partially updates a receipt printer and re-applies the same connection rules after merging the new fields.
| Property | Value |
|---|---|
| Method | PATCH or PUT |
| Path | /api/v1/integration/receipt-printers/{id} |
| Permission | access_printers. |
| Write rule | All update fields are optional and are merged with the existing printer before connection rules are re-applied. |
| Success response | 200 with the updated receipt-printer object. |
| Field | Type | Required | Description |
|---|---|---|---|
| All Add receipt printer fields | mixed | No | Send only the values that should change. |
| Field | Type | Description |
|---|---|---|
data | object | The updated receipt-printer payload. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The receipt printer was updated successfully. | { "data": { ... } } |
403 | Demo mode is active or the token user lacks access_printers. | { "message": string } |
404 | The receipt printer id does not exist for the current business. | { "message": "Not found" } |
422 | The request body failed validation. | Laravel validation JSON. |
Deletes a receipt printer that is not currently referenced by any business location.
| Property | Value |
|---|---|
| Method | DELETE |
| Path | /api/v1/integration/receipt-printers/{id} |
| Permission | access_printers. |
| Business rule | Returns 422 when a location still uses the printer as printer_id. |
| Write guard | Returns 403 in demo environments. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The receipt printer was deleted successfully. | { "message": string } |
403 | Demo mode is active or the token user lacks access_printers. | { "message": string } |
404 | The receipt printer id does not exist for the current business. | { "message": "Not found" } |
422 | The printer is still assigned to one or more locations. | { "message": string } |
Returns the business settings row together with the same date-format metadata used by the web Business settings screen.
| Property | Value |
|---|---|
| Method | GET |
| Path | /api/v1/integration/business-settings |
| Permission | business_settings.access. |
| CSV behavior | format=csv streams one row with data_json and meta_json cells matching the JSON payload. |
| Sensitive-field rule | woocommerce_api_settings is never returned in the response. |
| Success response | 200 with the business-settings object and date-format metadata. |
| Field | Type | Description |
|---|---|---|
data | object | The business row with decoded JSON fields such as pos_settings, keyboard_shortcuts, and custom_labels. |
meta.date_formats | object | Allowed business date-format keys from Business::date_formats(). |
| Status | When it happens | Response shape |
|---|---|---|
200 | The business settings were returned successfully. | { "data": { ... }, "meta": { ... } } or CSV download. |
403 | The token user lacks business_settings.access. | { "message": string } |
Partially updates business settings using the same merge semantics as the web Business settings form.
| Property | Value |
|---|---|
| Method | PATCH or PUT |
| Path | /api/v1/integration/business-settings |
| Permission | business_settings.access. |
| Merge rule | pos_settings is merged with the current value and defaults. shortcuts is stored as keyboard_shortcuts. |
| Upload rule | business_logo_base64 accepts an image data URL. POS carousel images are not uploaded through this API. |
| Success response | 200 with the same response shape as GET. |
| Field | Type | Required | Description |
|---|---|---|---|
| General business fields and feature toggles | mixed | No | Includes booleans such as enable_rp, enable_tooltip, and purchase_in_diff_currency. |
pos_settings | object | No | Partial POS settings object merged with the current value. |
shortcuts | array | No | Keyboard shortcut definitions stored as keyboard_shortcuts. |
business_logo_base64 | string | null | No | Optional business logo image data URL. |
| Field | Type | Description |
|---|---|---|
data | object | The updated business-settings payload. |
meta.date_formats | object | Allowed business date-format keys. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The business settings were updated successfully. | { "data": { ... }, "meta": { ... } } |
403 | Demo mode is active or the token user lacks business_settings.access. | { "message": string } |
422 | The request body failed validation. | Laravel validation JSON. |
Lists integration webhooks configured for the business, together with the allowed event catalog used by the web settings page.
| Property | Value |
|---|---|
| Method | GET |
| Path | /api/v1/integration/webhooks |
| Permission | business_settings.access. |
| Filter support | Supports pagination plus an optional is_active boolean filter. |
| CSV behavior | format=csv downloads all matching rows. events is JSON-encoded in CSV cells. |
| Success response | 200 with paginated rows and meta.allowed_events. |
| Parameter | Type | Required | Description |
|---|---|---|---|
per_page, page | integer | No | Pagination controls. per_page accepts 1 to 100 and defaults to 20. |
is_active | boolean | No | Optional active/inactive filter. |
format | string | No | json (default) or csv. |
| Field | Type | Description |
|---|---|---|
id, url, description | mixed | Webhook identity and destination details. |
events | array<string> | The subscribed event names for this endpoint. |
is_active, secret_set | boolean | Whether the webhook is enabled and whether a signing secret is stored. |
created_by, created_at, updated_at | mixed | Audit metadata for the webhook row. |
| Field | Type | Description |
|---|---|---|
data | array<object> | The current result page of webhooks. |
meta.allowed_events | array<string> | The event names that can be subscribed on create and update. |
meta.current_page, meta.last_page, meta.per_page, meta.total | integer | Laravel paginator metadata. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The webhooks were returned successfully. | { "data": [...], "meta": { ... } } or CSV download. |
403 | The token user lacks business_settings.access. | { "message": string } |
422 | The query string failed validation. | Laravel validation JSON. |
Returns one integration webhook together with the same allowed-event metadata used by the settings page.
| Property | Value |
|---|---|
| Method | GET |
| Path | /api/v1/integration/webhooks/{id} |
| Permission | business_settings.access. |
| CSV behavior | format=csv streams one row with data_json and meta_json cells matching the JSON payload. |
| Success response | 200 with one webhook object and the allowed-event list. |
| Field | Type | Description |
|---|---|---|
data | object | The requested webhook payload. |
meta.allowed_events | array<string> | The event names that may be subscribed. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The webhook was returned successfully. | { "data": { ... }, "meta": { ... } } or CSV download. |
403 | The token user lacks business_settings.access. | { "message": string } |
404 | The webhook id does not exist for the current business. | { "message": "Not found" } |
Creates an integration webhook that can receive sale and low-stock event deliveries.
| Property | Value |
|---|---|
| Method | POST |
| Path | /api/v1/integration/webhooks |
| Permission | business_settings.access. |
| Supported events | sale.created, sale.updated, and product.stock_low. |
| Signing rule | When secret is present, deliveries include X-Webhook-Signature: sha256=<hex> over the raw JSON body. |
| Success response | 201 with the created webhook object. |
| Field | Type | Required | Description |
|---|---|---|---|
url | string | Yes | Destination URL. HTTPS is recommended. |
events | array<string> | Yes | Non-empty list of allowed event names. |
description | string | null | No | Optional human-readable description. |
secret | string | null | No | Optional signing secret with a minimum length of 8 characters. |
is_active | boolean | No | Optional active flag. Defaults to true. |
| Event | When it fires | Payload notes |
|---|---|---|
sale.created | When a final sell is saved for the first time. | Uses the same SellCreatedOrModified event pipeline as the rest of the app. |
sale.updated | When an existing final sell is modified. | Uses the same sale event pipeline as create. |
product.stock_low | When tracked quantity crosses from above the alert threshold to at or below it. | Payload includes variation_id, product_id, location_id, product_name, qty_available, and alert_quantity. |
| Field | Type | Description |
|---|---|---|
data | object | The created webhook payload. |
| Status | When it happens | Response shape |
|---|---|---|
201 | The webhook was created successfully. | { "data": { ... } } |
403 | Demo mode is active or the token user lacks business_settings.access. | { "message": string } |
422 | The request body failed validation. | Laravel validation JSON. |
Partially updates a webhook's destination, subscribed events, secret, or active state.
| Property | Value |
|---|---|
| Method | PATCH |
| Path | /api/v1/integration/webhooks/{id} |
| Permission | business_settings.access. |
| Write mode | All update fields are optional and are applied partially. |
| Success response | 200 with the updated webhook object. |
| Field | Type | Required | Description |
|---|---|---|---|
url, description, secret | string | null | No | Optional destination, description, and signing-secret updates. |
events | array<string> | No | Optional full replacement for the subscribed event list. |
is_active | boolean | No | Optional active-state update. |
| Field | Type | Description |
|---|---|---|
data | object | The updated webhook payload. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The webhook was updated successfully. | { "data": { ... } } |
403 | Demo mode is active or the token user lacks business_settings.access. | { "message": string } |
404 | The webhook id does not exist for the current business. | { "message": "Not found" } |
422 | The request body failed validation. | Laravel validation JSON. |
Deletes an integration webhook.
| Property | Value |
|---|---|
| Method | DELETE |
| Path | /api/v1/integration/webhooks/{id} |
| Permission | business_settings.access. |
| Write guard | Returns 403 in demo environments. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The webhook was deleted successfully. | { "message": string } |
403 | Demo mode is active or the token user lacks business_settings.access. | { "message": string } |
404 | The webhook id does not exist for the current business. | { "message": "Not found" } |
Queues a single webhook.test delivery so you can validate connectivity before turning a webhook on.
| Property | Value |
|---|---|
| Method | POST |
| Path | /api/v1/integration/webhooks/{id}/test |
| Permission | business_settings.access. |
| Behavior | The test run still works when the webhook itself is marked inactive. |
| Write guard | Returns 403 in demo environments. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The test delivery was queued successfully. | { "message": string } |
403 | Demo mode is active or the token user lacks business_settings.access. | { "message": string } |
404 | The webhook id does not exist for the current business. | { "message": "Not found" } |
Lists business locations visible to the token user, including receipt and invoice defaults resolved for display.
| Property | Value |
|---|---|
| Method | GET |
| Path | /api/v1/integration/business-locations |
| Permission | business_settings.access. |
| Visibility | Users with restricted location access only see permitted locations. |
| CSV behavior | format=csv downloads all matching rows and ignores pagination. |
| Success response | 200 with paginated rows or a CSV download. |
| Parameter | Type | Required | Description |
|---|---|---|---|
per_page, page | integer | No | Pagination controls. |
q, search | string | No | Search across location name, location id, city, landmark, territory/cluster names and reference_code values, and numeric id-like values. |
is_active | boolean | No | Optional active/inactive filter. |
sort | string | No | name, location_id, city, or created_at. |
direction | string | No | asc or desc. |
format | string | No | json (default) or csv. |
| Field | Type | Description |
|---|---|---|
id, name, location_id | mixed | Location identity and display values. |
territory_id, territory_reference_code, territory_name, location_cluster_id, cluster_reference_code, cluster_name | mixed | Hierarchy fields when a location is linked to a territory and/or cluster. |
territory, cluster | object | null | Compact nested objects with id, reference_code, name (cluster also includes territory_id) for integrations. |
invoice_scheme_name, invoice_layout_name, selling_price_group_name | string | null | Resolved related-setting labels. |
print_receipt_on_invoice, receipt_printer_type, printer_id, printer_name | mixed | Receipt-printing configuration returned in list rows. |
is_active | boolean | Current active state for the location. |
| Field | Type | Description |
|---|---|---|
data | array<object> | The current result page of business locations. |
meta.current_page, meta.last_page, meta.per_page, meta.total | integer | Laravel paginator metadata. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The business locations were returned successfully. | { "data": [...], "meta": { ... } } or CSV download. |
403 | The token user lacks business_settings.access. | { "message": string } |
422 | The query string failed validation. | Laravel validation JSON. |
Returns one business location with full detail, including default payment accounts and featured products when configured.
| Property | Value |
|---|---|
| Method | GET |
| Path | /api/v1/integration/business-locations/{id} |
| Permission | business_settings.access plus location visibility. |
| CSV behavior | format=csv streams one row whose data_json cell matches the JSON data object. |
| Success response | 200 with one business-location object. |
| Field | Type | Description |
|---|---|---|
data | object | The requested business-location payload, including nested fields such as default_payment_accounts and featured_products when present. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The business location was returned successfully. | { "data": { ... } } or CSV download. |
403 | The location exists but is outside the token user's permitted locations. | { "message": string } |
404 | The business location id does not exist for the current business. | { "message": "Not found" } |
Returns every territory for the business with optional reference_code (unique per business) for stable integration identifiers.
| Property | Value |
|---|---|
| Method | GET |
| Path | /api/v1/integration/territories |
| Permission | business_settings.access. |
| Success response | 200 with { "data": [ { "id", "reference_code", "name", "description", "created_at", "updated_at" } ] }. |
Returns clusters with parent territory id, name, and reference codes so callers can resolve location_cluster_id / territory_id on locations.
| Property | Value |
|---|---|
| Method | GET |
| Path | /api/v1/integration/location-clusters |
| Permission | business_settings.access. |
| Success response | 200 with { "data": [ { "id", "reference_code", "name", "description", "territory_id", "territory_name", "territory_reference_code", "created_at", "updated_at" } ] }. |
Returns the enabled payment-method keys and translated labels for one business location.
| Property | Value |
|---|---|
| Method | GET |
| Path | /api/v1/integration/business-locations/{id}/payment-types |
| Permission | No separate settings permission. The location must belong to the business and be within the token user's permitted locations. |
| CSV behavior | format=csv streams one row per payment method with the same shape as JSON data[]. |
| Success response | 200 with payment-type rows and meta.location_id. |
| Field | Type | Description |
|---|---|---|
data[] | array<object> | Rows with key and label for each enabled payment method. |
meta.location_id | integer | The resolved business-location id. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The payment types were returned successfully. | { "data": [...], "meta": { "location_id": integer } } or CSV download. |
403 | The location exists but is outside the token user's permitted locations. | { "message": string } |
404 | The business location id does not exist for the current business. | { "message": "Not found" } |
Creates a business location, auto-generates its location code when omitted, and validates the same linked settings as the web form.
| Property | Value |
|---|---|
| Method | POST |
| Path | /api/v1/integration/business-locations |
| Permission | business_settings.access. |
| Subscription rule | Returns 402 when the business is not subscribed and 422 when the location quota is exhausted. |
| Reference rule | When location_id is omitted, the controller auto-generates it and creates the matching Spatie permission location.{id}. |
| Success response | 201 with the created business-location object. |
| Field | Type | Required | Description |
|---|---|---|---|
| Core location fields | mixed | Yes | Standard location identity and address fields such as name, optional location_id, and contact details. |
territory_id, location_cluster_id | integer | null | No | Optional link to a territory and cluster belonging to the business; cluster must sit under its territory. |
invoice_scheme_id, invoice_layout_id, selling_price_group_id | integer | null | No | Optional related-setting ids that must belong to the current business. |
default_payment_accounts | object | null | No | Optional default payment-account mapping object. |
featured_products | array<integer> | null | No | Optional list of variation ids highlighted at the location. |
| Receipt settings | mixed | No | Optional receipt-printing fields such as print_receipt_on_invoice, receipt_printer_type, and printer_id. |
| Field | Type | Description |
|---|---|---|
data | object | The created business-location payload. |
| Status | When it happens | Response shape |
|---|---|---|
201 | The business location was created successfully. | { "data": { ... } } |
402 | The business subscription does not allow creating locations. | { "message": string } |
403 | Demo mode is active or the token user lacks business_settings.access. | { "message": string } |
422 | The request body failed validation or the business has reached its location quota. | Laravel validation JSON or { "message": string }. |
Partially updates a business location, including receipt-printer settings and invoice defaults.
| Property | Value |
|---|---|
| Method | PATCH |
| Path | /api/v1/integration/business-locations/{id} |
| Permission | business_settings.access. |
| Uniqueness rule | location_id must remain unique per business when it is updated. |
| Receipt rule | Receipt fields follow LocationSettingsController::updateSettings. In demo mode, sending receipt fields forces receipt_printer_type = browser. |
| Success response | 200 with the updated business-location object. |
| Field | Type | Required | Description |
|---|---|---|---|
| All Create business location fields | mixed | No | All update fields are optional and are applied partially. |
print_receipt_on_invoice, receipt_printer_type, printer_id | mixed | No | Receipt-printing settings validated against the current business and printer catalog. |
| Field | Type | Description |
|---|---|---|
data | object | The updated business-location payload. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The business location was updated successfully. | { "data": { ... } } |
403 | Demo mode is active or the token user lacks business_settings.access. | { "message": string } |
404 | The business location id does not exist for the current business. | { "message": "Not found" } |
422 | The request body failed validation. | Laravel validation JSON. |
Flips a business location between active and inactive states, mirroring the web activate/deactivate action.
| Property | Value |
|---|---|
| Method | POST |
| Path | /api/v1/integration/business-locations/{id}/toggle-active |
| Permission | business_settings.access. |
| Write guard | Returns 403 in demo environments. |
| Success response | 200 with the refreshed business-location object. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The business location active state was toggled successfully. | { "data": { ... } } |
403 | Demo mode is active or the token user lacks business_settings.access. | { "message": string } |
404 | The business location id does not exist for the current business. | { "message": "Not found" } |