[Skip to main content](#vessel-content)

##  [ Command line ](/support/documentation/543-hikashop-cli)

Details    Written by: jobsigen    Category: [Developer area](/support/documentation/hikashop/developer-area)     Published: 01 September 2026     Hits: 622

HikaShop can be driven from a command line, so that a shop can be managed from a terminal, a cron entry, a deployment script or a Makefile, without opening a browser. It works on both platforms, using the command line each of them already provides: the Joomla console for a Joomla site, and WP-CLI for a WordPress one.

Nothing is sent over the network. The commands run inside your own site, on the machine the site is installed on, so there is no key to create and nothing to open to the outside.

### Getting started

On Joomla the commands come from the "Console - HikaShop" plugin, installed and enabled with HikaShop. On WordPress they come with the HikaShop plugin itself and need [WP-CLI](https://wp-cli.org/). Ask for the list:

```
php cli/joomla.php list        # Joomla
wp hikashop                    # WordPress
```

Each platform spells the same command its own way, Joomla with colons and WordPress with spaces. Everything else is identical: the same arguments, the same options, the same output and the same exit codes.

```
php cli/joomla.php hikashop:product:list --limit=5
wp hikashop product list --limit=5
```

### Options every command understands

| Option | What it does |
|---|---|
| --format | `table` to read, `json` to pipe into something else, and also `pretty`, `csv`, `ids` and `count`. Listings show a table by default, single records show indented JSON. |
| --user | Which account the command acts as, given by id, user name or email address. It decides what the command may do, through the access levels of your site and of the HikaShop configuration. On WordPress this is WP-CLI's own `--user`, which behaves the same and can be set once in `wp-cli.yml`. |
| --yes | Required by the commands that remove data or act on many records at once. Without it they refuse and change nothing. |
| --live-site | Joomla only. The address of your site, needed when your configuration does not set one, so that the links the shop generates are correct. |

With no `--user` a command runs as nobody in particular. On a shop that has not restricted anything this is enough; on a shop that has restricted a kind of record to a group of users, the command is refused and says to name a user. Choosing an account also means your change log records who made the change.

### What the shell gets back

Only the data is printed to the standard output, so `--format=json` can always be piped into another program. Warnings and error messages go to the error output and never mix into it.

Answers carry the same envelope the Connector API uses: `data` is what you asked for, `meta` holds the paging of a listing, and `error` is `null` unless something went wrong. The tables below describe what is inside `data`.

The exit code says what happened, which is what a script should test:

| Code | Meaning |
|---|---|
| 0 | It worked |
| 1 | Something went wrong |
| 2 | The command was asked for wrongly, for example a missing option |
| 3 | The record does not exist |
| 4 | This account is not allowed to do that |

The commands for your products, orders, customers, categories, coupons and mass actions come through the HikaShop Connector plugin, which ships with the Business edition. The commands for the shop itself, its configuration, its caches and its database, are available in every edition. Running the cron this way needs the Essential or the Business edition, as the cron itself does.

### All commands

[product:list](#hkcli-product-list)[product:get](#hkcli-product-get)[product:create](#hkcli-product-create)[product:update](#hkcli-product-update)[product:delete](#hkcli-product-delete)[product:stock](#hkcli-product-stock)[product:price](#hkcli-product-price)[product:lowstock](#hkcli-product-lowstock)[order:list](#hkcli-order-list)[order:get](#hkcli-order-get)[order:status](#hkcli-order-status)[order:create](#hkcli-order-create)[order:addproduct](#hkcli-order-addproduct)[customer:list](#hkcli-customer-list)[customer:get](#hkcli-customer-get)[customer:create](#hkcli-customer-create)[customer:delete](#hkcli-customer-delete)[category:list](#hkcli-category-list)[category:create](#hkcli-category-create)[category:delete](#hkcli-category-delete)[discount:list](#hkcli-discount-list)[discount:create](#hkcli-discount-create)[discount:delete](#hkcli-discount-delete)[massaction:list](#hkcli-massaction-list)[massaction:run](#hkcli-massaction-run)[dbcheck](#hkcli-dbcheck)[shop:statuses](#hkcli-shop-statuses)[shop:stats](#hkcli-shop-stats)[config:get](#hkcli-config-get)[config:set](#hkcli-config-set)[cache:clean](#hkcli-cache-clean)[cron:run](#hkcli-cron-run)[log:list](#hkcli-log-list)[log:get](#hkcli-log-get)[log:clear](#hkcli-log-clear)

### Products

#### product:list

List products.

The catalogue as the backend sees it, unpublished products included, which is what makes this different from the front end. Variants are not listed on their own. A parent carries `has_variants`, and `GET /products/{id}` returns the variants themselves.

```
php cli/joomla.php hikashop:product:list [--search=<search>] [--limit=<limit>] [--start=<start>] [--category=<category>] [--ids=<ids>]
wp hikashop product list [--search=<search>] [--limit=<limit>] [--start=<start>] [--category=<category>] [--ids=<ids>]
```

| Option | Type | Description |
|---|---|---|
| --search | string | Filter on a search term |
| --limit | int | How many to return |
| --start | int | Skip this many first |
| --category | int | Only this category |
| --ids | string | Only these product ids, comma separated |

| Returns | Type | Description |
|---|---|---|
| id |  |  |
| name |  |  |
| code |  | The SKU. Unique within the shop. |
| quantity |  | `-1` when the product does not track stock, which is not the same as `0`. |
| published |  |  |
| has\_variants |  | Ask `GET /products/{id}` for the variants themselves. |
| image | string\|null | Absolute URL of the main image, or `null`. |
| price |  | `null` when the product has no price row at all. |
| currency\_id |  | A row in the shop's currency table, not an ISO code. |
| custom\_fields | object | The listing values of this product, keyed by field namekey. |

| In `meta` | Type | Description |
|---|---|---|
| start | integer | Echoes the offset used. |
| limit | integer | Echoes the page size used. |
| total | integer | Rows matching the filter, before paging. This is how you know there is another page. |
| fields | object\[\] | The custom fields shown on listings, so a client can label the values it just received. |

#### product:get

Show one product.

Everything the product editor needs in one call: the record, its prices, its images and files, its categories, its characteristics and variants, and the definitions of the custom fields that apply to it. Ask for a variant's id and you get the variant, with `parent_id` set. A parent's `variants` are listed in full, so you rarely need to.

```
php cli/joomla.php hikashop:product:get <id>
wp hikashop product get <id>
```

| Argument | Description |
|---|---|
| &lt;id&gt; required | Product id |

| Returns | Type | Description |
|---|---|---|
| id |  |  |
| name |  |  |
| code |  | The SKU. Unique within the shop. |
| description |  | The long description, as HTML. |
| description\_type |  | Which editor the description was written with. |
| published |  |  |
| quantity |  | `-1` when this product does not track stock, which is not the same as `0`. |
| msrp |  | The manufacturer's suggested price, shown struck through when the shop is configured to. |
| gtin |  | The barcode: EAN, UPC or ISBN. This is what `GET /products/lookup` matches on. |
| condition |  | New, used, refurbished. Used by the feeds rather than by the shop itself. |
| weight |  | Shipping weight, in `weight_unit`. |
| weight\_unit |  | `kg`, `g`, `lb` or `oz`. |
| width |  | In `dimension_unit`. |
| height |  | In `dimension_unit`. |
| length |  | In `dimension_unit`. |
| dimension\_unit |  | `m`, `cm`, `mm`, `ft` or `in`. |
| min\_per\_order |  | The smallest quantity a customer may order, `0` for no minimum. |
| max\_per\_order |  | The largest, `0` for no maximum. |
| sale\_start | integer\|null | Unix timestamp before which the product is not on sale. |
| sale\_end | integer\|null | Unix timestamp after which it is no longer sold. |
| page\_title |  | SEO title, empty to use the name. |
| meta\_description |  | SEO description. |
| keywords |  | SEO keywords. |
| canonical |  | A canonical URL, when this page should point at another. |
| url |  | The address of the product page on the shop. |
| alias |  | The slug used in that address. |
| access | object | Who may see the product: `mode` (`all`, `none` or `groups`) and `groups`, which are user \*\*group\*\* ids and not Joomla view levels. The two id spaces overlap and disagree, so a value that looks plausible can grant the wrong audience. |
| access.mode | string | `all`, `none`, or `groups` when it is restricted to some. |
| access.groups | integer\[\] | User group ids, meaningful only when the mode is `groups`. |
| contact |  | Whether this product is enquired about rather than bought. |
| warehouse\_id |  | The warehouse holding the stock, `0` when the shop has none. |
| type |  | `main` for a product, `variant` for one of its variants. |
| parent\_id |  | The parent product when this is a variant, `0` otherwise. |
| value\_ids | integer\[\] | For a variant, the characteristic values it stands for. |
| manufacturer\_id |  | The brand, `0` when unset. |
| manufacturer\_name | string | Its name, saving a second call. |
| tax\_id |  | The tax category, `0` when the product is untaxed. |
| tax\_name | string | Its name. |
| tax\_rate | number | The rate as a fraction, so `0.2` is twenty percent. |
| prices | object\[\] | Every price row, including the restricted ones. A product with none is not sellable. |
| prices.id |  |  |
| prices.value |  | Tax excluded, as stored. |
| prices.currency\_id |  |  |
| prices.min\_quantity |  | From how many items this row applies, which is how quantity breaks are expressed. |
| prices.access | object | Who this price is for, in the same shape as the product access. |
| prices.access.mode | string | As above. |
| prices.access.groups | integer\[\] | As above. |
| prices.users | integer\[\] | Named customers, empty for everyone. |
| prices.zone\_ids | integer\[\] | Zones this price applies in, empty for everywhere. |
| prices.start\_date | integer\|null | Unix timestamp. |
| prices.end\_date | integer\|null | Unix timestamp. |
| images | object\[\] | In the order the editor shows them; the first is the main image. |
| images.id |  |  |
| images.name |  |  |
| images.path |  | Relative to the upload folder. |
| images.url |  | Absolute, ready to display. |
| images.ordering |  |  |
| images.description |  | The alt text. |
| images.access | object | Who may see it. |
| images.access.mode | string | As above. |
| images.access.groups | integer\[\] | As above. |
| images.free\_download |  | Files only; meaningless on an image. |
| files | object\[\] | Downloadable files, in the same shape as the images. |
| files.id |  |  |
| files.name |  |  |
| files.path |  | Relative to the upload folder. |
| files.url |  | Absolute. |
| files.ordering |  |  |
| files.description |  |  |
| files.access | object | Who may download it. |
| files.free\_download |  | Whether it can be downloaded without buying the product. |
| categories | object\[\] | The categories the product is in. |
| categories.id |  |  |
| categories.name |  |  |
| bundle | object\[\] | The products this one is made of, when it is a bundle. |
| bundle.id |  |  |
| bundle.name |  |  |
| bundle.code |  |  |
| bundle.quantity |  | How many of it the bundle contains. |
| options | object\[\] | Products offered as options alongside this one. |
| options.id |  |  |
| options.name |  |  |
| options.code |  |  |
| options.quantity |  |  |
| related | object\[\] | Products shown as related. |
| related.id |  |  |
| related.name |  |  |
| related.code |  |  |
| related.quantity |  |  |
| tags | integer\[\] | CMS tag ids. |
| characteristics | object\[\] | The characteristics this product varies on. Empty when it has no variants. |
| characteristics.id | integer | The characteristic, such as Size. |
| characteristics.name | string | Its name. |
| characteristics.values | object\[\] | The values of it this product uses, such as S, M and L. |
| characteristics.values.id | integer | The value id, which is what a variant refers to. |
| characteristics.values.value | string | Its name, such as `M`. |
| variants | object\[\] | Every variant, with its own code, stock, price and images. Empty for a product that does not vary. |
| variants.id | integer | The variant is a product in its own right, and this is its id. |
| variants.code | string | Its own SKU. |
| variants.quantity | integer | Its own stock. This is the figure to change, not the parent's. |
| variants.published | boolean |  |
| variants.price | number\|null | `null` when the variant has no price of its own and the parent's applies. |
| variants.values | object\[\] | Which characteristic values this variant stands for, one per characteristic. |
| variants.values.option\_id | integer | The characteristic. |
| variants.values.option\_name | string | Its name, so the variant can be labelled without a second call. |
| variants.values.value\_id | integer | The value. |
| variants.values.value | string | Its name. |
| variants.images | object\[\] | The variant's own images, in the same shape as the product's. |
| variants.images.id | integer |  |
| variants.images.name | string |  |
| variants.images.path | string | Relative to the upload folder. |
| variants.images.url | string | Absolute. |
| variants.images.ordering | integer |  |
| fields | object\[\] | The definitions of the custom fields that apply to this product, so a client can build a form for them. |
| fields.namekey | string | The key used in `custom_fields`. |
| fields.label | string | Translated into the operator's language. |
| fields.type | string | `text`, `radio`, `singledropdown`, `file`, and the rest of HikaShop's field types. |
| fields.required | boolean | Whether the shop refuses to save the product without it. |
| fields.translatable | boolean | Whether its value can be translated, which is what the translation routes offer. |
| fields.upload\_dir | string | For a file field, where its uploads are kept. |
| fields.raw\_type | string | HikaShop's own name for the type, before it is mapped to something a client can render. |
| fields.default | string | The value used when none is given. |
| fields.options | object\[\] | The choices, for a field that has them. Empty for a free text one. |
| fields.multiple | boolean | Whether more than one choice may be selected. |
| fields.allowed\_extensions | string | For a file field, the extensions it accepts, comma separated. Empty means the shop default. |
| fields.date\_format | string | For a date field, the format it is stored in. |
| custom\_fields | object | Their values, keyed by namekey. |
| custom\_field\_files | object | For custom fields holding a file, the file behind each value. |
| sections | object\[\] | Information other plugins show on this record, each with a `key`, a `title` and `rows` (`label`, `value`, and optionally `url`, `badge` and `ref`). Empty when no plugin adds any; on a customer, core adds their paid downloads. See the guide on adding information and settings. |
| extensions | object\[\] | Settings other plugins keep on this record, in groups (`key`, `title`, `fields`), each field described like a custom field plus its current `value`. Send changes back as `extensions` with the record's save. Empty when no plugin adds any. |

#### product:create

Create a product.

Creates a product and answers with its id. Only the name is required; everything else can be set now or later with `PUT /products/{id}`. Prices, images and categories are separate calls, so a new product is not sellable until it has at least one price.

```
php cli/joomla.php hikashop:product:create --name=<name> [--code=<code>] [--quantity=<quantity>] [--published] [--description=<description>] [--categories=<categories>]
wp hikashop product create --name=<name> [--code=<code>] [--quantity=<quantity>] [--published] [--description=<description>] [--categories=<categories>]
```

| Option | Type | Description |
|---|---|---|
| --name required | string | Product name |
| --code | string | Product code, derived from the name when left out |
| --quantity | int | Stock, -1 for unlimited |
| --published | flag | Publish it |
| --description | string | Description |
| --categories | ids, comma separated | Category ids, comma separated |

| Returns | Type | Description |
|---|---|---|
| id |  |  |
| name |  |  |
| code |  | The SKU. Unique within the shop. |
| description |  | The long description, as HTML. |
| description\_type |  | Which editor the description was written with. |
| published |  |  |
| quantity |  | `-1` when this product does not track stock, which is not the same as `0`. |
| msrp |  | The manufacturer's suggested price, shown struck through when the shop is configured to. |
| gtin |  | The barcode: EAN, UPC or ISBN. This is what `GET /products/lookup` matches on. |
| condition |  | New, used, refurbished. Used by the feeds rather than by the shop itself. |
| weight |  | Shipping weight, in `weight_unit`. |
| weight\_unit |  | `kg`, `g`, `lb` or `oz`. |
| width |  | In `dimension_unit`. |
| height |  | In `dimension_unit`. |
| length |  | In `dimension_unit`. |
| dimension\_unit |  | `m`, `cm`, `mm`, `ft` or `in`. |
| min\_per\_order |  | The smallest quantity a customer may order, `0` for no minimum. |
| max\_per\_order |  | The largest, `0` for no maximum. |
| sale\_start | integer\|null | Unix timestamp before which the product is not on sale. |
| sale\_end | integer\|null | Unix timestamp after which it is no longer sold. |
| page\_title |  | SEO title, empty to use the name. |
| meta\_description |  | SEO description. |
| keywords |  | SEO keywords. |
| canonical |  | A canonical URL, when this page should point at another. |
| url |  | The address of the product page on the shop. |
| alias |  | The slug used in that address. |
| access | object | Who may see the product: `mode` (`all`, `none` or `groups`) and `groups`, which are user \*\*group\*\* ids and not Joomla view levels. The two id spaces overlap and disagree, so a value that looks plausible can grant the wrong audience. |
| access.mode | string | `all`, `none`, or `groups` when it is restricted to some. |
| access.groups | integer\[\] | User group ids, meaningful only when the mode is `groups`. |
| contact |  | Whether this product is enquired about rather than bought. |
| warehouse\_id |  | The warehouse holding the stock, `0` when the shop has none. |
| type |  | `main` for a product, `variant` for one of its variants. |
| parent\_id |  | The parent product when this is a variant, `0` otherwise. |
| value\_ids | integer\[\] | For a variant, the characteristic values it stands for. |
| manufacturer\_id |  | The brand, `0` when unset. |
| manufacturer\_name | string | Its name, saving a second call. |
| tax\_id |  | The tax category, `0` when the product is untaxed. |
| tax\_name | string | Its name. |
| tax\_rate | number | The rate as a fraction, so `0.2` is twenty percent. |
| prices | object\[\] | Every price row, including the restricted ones. A product with none is not sellable. |
| prices.id |  |  |
| prices.value |  | Tax excluded, as stored. |
| prices.currency\_id |  |  |
| prices.min\_quantity |  | From how many items this row applies, which is how quantity breaks are expressed. |
| prices.access | object | Who this price is for, in the same shape as the product access. |
| prices.access.mode | string | As above. |
| prices.access.groups | integer\[\] | As above. |
| prices.users | integer\[\] | Named customers, empty for everyone. |
| prices.zone\_ids | integer\[\] | Zones this price applies in, empty for everywhere. |
| prices.start\_date | integer\|null | Unix timestamp. |
| prices.end\_date | integer\|null | Unix timestamp. |
| images | object\[\] | In the order the editor shows them; the first is the main image. |
| images.id |  |  |
| images.name |  |  |
| images.path |  | Relative to the upload folder. |
| images.url |  | Absolute, ready to display. |
| images.ordering |  |  |
| images.description |  | The alt text. |
| images.access | object | Who may see it. |
| images.access.mode | string | As above. |
| images.access.groups | integer\[\] | As above. |
| images.free\_download |  | Files only; meaningless on an image. |
| files | object\[\] | Downloadable files, in the same shape as the images. |
| files.id |  |  |
| files.name |  |  |
| files.path |  | Relative to the upload folder. |
| files.url |  | Absolute. |
| files.ordering |  |  |
| files.description |  |  |
| files.access | object | Who may download it. |
| files.free\_download |  | Whether it can be downloaded without buying the product. |
| categories | object\[\] | The categories the product is in. |
| categories.id |  |  |
| categories.name |  |  |
| bundle | object\[\] | The products this one is made of, when it is a bundle. |
| bundle.id |  |  |
| bundle.name |  |  |
| bundle.code |  |  |
| bundle.quantity |  | How many of it the bundle contains. |
| options | object\[\] | Products offered as options alongside this one. |
| options.id |  |  |
| options.name |  |  |
| options.code |  |  |
| options.quantity |  |  |
| related | object\[\] | Products shown as related. |
| related.id |  |  |
| related.name |  |  |
| related.code |  |  |
| related.quantity |  |  |
| tags | integer\[\] | CMS tag ids. |
| characteristics | object\[\] | The characteristics this product varies on. Empty when it has no variants. |
| characteristics.id | integer | The characteristic, such as Size. |
| characteristics.name | string | Its name. |
| characteristics.values | object\[\] | The values of it this product uses, such as S, M and L. |
| characteristics.values.id | integer | The value id, which is what a variant refers to. |
| characteristics.values.value | string | Its name, such as `M`. |
| variants | object\[\] | Every variant, with its own code, stock, price and images. Empty for a product that does not vary. |
| variants.id | integer | The variant is a product in its own right, and this is its id. |
| variants.code | string | Its own SKU. |
| variants.quantity | integer | Its own stock. This is the figure to change, not the parent's. |
| variants.published | boolean |  |
| variants.price | number\|null | `null` when the variant has no price of its own and the parent's applies. |
| variants.values | object\[\] | Which characteristic values this variant stands for, one per characteristic. |
| variants.values.option\_id | integer | The characteristic. |
| variants.values.option\_name | string | Its name, so the variant can be labelled without a second call. |
| variants.values.value\_id | integer | The value. |
| variants.values.value | string | Its name. |
| variants.images | object\[\] | The variant's own images, in the same shape as the product's. |
| variants.images.id | integer |  |
| variants.images.name | string |  |
| variants.images.path | string | Relative to the upload folder. |
| variants.images.url | string | Absolute. |
| variants.images.ordering | integer |  |
| fields | object\[\] | The definitions of the custom fields that apply to this product, so a client can build a form for them. |
| fields.namekey | string | The key used in `custom_fields`. |
| fields.label | string | Translated into the operator's language. |
| fields.type | string | `text`, `radio`, `singledropdown`, `file`, and the rest of HikaShop's field types. |
| fields.required | boolean | Whether the shop refuses to save the product without it. |
| fields.translatable | boolean | Whether its value can be translated, which is what the translation routes offer. |
| fields.upload\_dir | string | For a file field, where its uploads are kept. |
| fields.raw\_type | string | HikaShop's own name for the type, before it is mapped to something a client can render. |
| fields.default | string | The value used when none is given. |
| fields.options | object\[\] | The choices, for a field that has them. Empty for a free text one. |
| fields.multiple | boolean | Whether more than one choice may be selected. |
| fields.allowed\_extensions | string | For a file field, the extensions it accepts, comma separated. Empty means the shop default. |
| fields.date\_format | string | For a date field, the format it is stored in. |
| custom\_fields | object | Their values, keyed by namekey. |
| custom\_field\_files | object | For custom fields holding a file, the file behind each value. |
| sections | object\[\] | Information other plugins show on this record, each with a `key`, a `title` and `rows` (`label`, `value`, and optionally `url`, `badge` and `ref`). Empty when no plugin adds any; on a customer, core adds their paid downloads. See the guide on adding information and settings. |
| extensions | object\[\] | Settings other plugins keep on this record, in groups (`key`, `title`, `fields`), each field described like a custom field plus its current `value`. Send changes back as `extensions` with the record's save. Empty when no plugin adds any. |

| Can also fail with | Meaning |
|---|---|
| invalid\_fields | One of your own fields was rejected by its own rules. |
| save\_failed | The shop refused to save the product. |

#### product:update

Change a product.

Changes the fields you send and leaves the rest alone, which is the opposite of the price and category calls: this one merges. Sending nothing to change is refused rather than treated as a success, so a client cannot believe it saved something it did not.

```
php cli/joomla.php hikashop:product:update <id> [--name=<name>] [--code=<code>] [--description=<description>] [--published] [--msrp=<msrp>] [--gtin=<gtin>] [--weight=<weight>] [--tax-id=<tax-id>]
wp hikashop product update <id> [--name=<name>] [--code=<code>] [--description=<description>] [--published] [--msrp=<msrp>] [--gtin=<gtin>] [--weight=<weight>] [--tax-id=<tax-id>]
```

| Argument | Description |
|---|---|
| &lt;id&gt; required | Product id |

| Option | Type | Description |
|---|---|---|
| --name | string | Product name |
| --code | string | Product code |
| --description | string | Description |
| --published | flag | Publish it |
| --msrp | float | Recommended retail price |
| --gtin | string | GTIN / barcode |
| --weight | float | Weight |
| --tax-id | int | Tax category id |

| Returns | Type | Description |
|---|---|---|
| id |  |  |
| name |  |  |
| code |  | The SKU. Unique within the shop. |
| description |  | The long description, as HTML. |
| description\_type |  | Which editor the description was written with. |
| published |  |  |
| quantity |  | `-1` when this product does not track stock, which is not the same as `0`. |
| msrp |  | The manufacturer's suggested price, shown struck through when the shop is configured to. |
| gtin |  | The barcode: EAN, UPC or ISBN. This is what `GET /products/lookup` matches on. |
| condition |  | New, used, refurbished. Used by the feeds rather than by the shop itself. |
| weight |  | Shipping weight, in `weight_unit`. |
| weight\_unit |  | `kg`, `g`, `lb` or `oz`. |
| width |  | In `dimension_unit`. |
| height |  | In `dimension_unit`. |
| length |  | In `dimension_unit`. |
| dimension\_unit |  | `m`, `cm`, `mm`, `ft` or `in`. |
| min\_per\_order |  | The smallest quantity a customer may order, `0` for no minimum. |
| max\_per\_order |  | The largest, `0` for no maximum. |
| sale\_start | integer\|null | Unix timestamp before which the product is not on sale. |
| sale\_end | integer\|null | Unix timestamp after which it is no longer sold. |
| page\_title |  | SEO title, empty to use the name. |
| meta\_description |  | SEO description. |
| keywords |  | SEO keywords. |
| canonical |  | A canonical URL, when this page should point at another. |
| url |  | The address of the product page on the shop. |
| alias |  | The slug used in that address. |
| access | object | Who may see the product: `mode` (`all`, `none` or `groups`) and `groups`, which are user \*\*group\*\* ids and not Joomla view levels. The two id spaces overlap and disagree, so a value that looks plausible can grant the wrong audience. |
| access.mode | string | `all`, `none`, or `groups` when it is restricted to some. |
| access.groups | integer\[\] | User group ids, meaningful only when the mode is `groups`. |
| contact |  | Whether this product is enquired about rather than bought. |
| warehouse\_id |  | The warehouse holding the stock, `0` when the shop has none. |
| type |  | `main` for a product, `variant` for one of its variants. |
| parent\_id |  | The parent product when this is a variant, `0` otherwise. |
| value\_ids | integer\[\] | For a variant, the characteristic values it stands for. |
| manufacturer\_id |  | The brand, `0` when unset. |
| manufacturer\_name | string | Its name, saving a second call. |
| tax\_id |  | The tax category, `0` when the product is untaxed. |
| tax\_name | string | Its name. |
| tax\_rate | number | The rate as a fraction, so `0.2` is twenty percent. |
| prices | object\[\] | Every price row, including the restricted ones. A product with none is not sellable. |
| prices.id |  |  |
| prices.value |  | Tax excluded, as stored. |
| prices.currency\_id |  |  |
| prices.min\_quantity |  | From how many items this row applies, which is how quantity breaks are expressed. |
| prices.access | object | Who this price is for, in the same shape as the product access. |
| prices.access.mode | string | As above. |
| prices.access.groups | integer\[\] | As above. |
| prices.users | integer\[\] | Named customers, empty for everyone. |
| prices.zone\_ids | integer\[\] | Zones this price applies in, empty for everywhere. |
| prices.start\_date | integer\|null | Unix timestamp. |
| prices.end\_date | integer\|null | Unix timestamp. |
| images | object\[\] | In the order the editor shows them; the first is the main image. |
| images.id |  |  |
| images.name |  |  |
| images.path |  | Relative to the upload folder. |
| images.url |  | Absolute, ready to display. |
| images.ordering |  |  |
| images.description |  | The alt text. |
| images.access | object | Who may see it. |
| images.access.mode | string | As above. |
| images.access.groups | integer\[\] | As above. |
| images.free\_download |  | Files only; meaningless on an image. |
| files | object\[\] | Downloadable files, in the same shape as the images. |
| files.id |  |  |
| files.name |  |  |
| files.path |  | Relative to the upload folder. |
| files.url |  | Absolute. |
| files.ordering |  |  |
| files.description |  |  |
| files.access | object | Who may download it. |
| files.free\_download |  | Whether it can be downloaded without buying the product. |
| categories | object\[\] | The categories the product is in. |
| categories.id |  |  |
| categories.name |  |  |
| bundle | object\[\] | The products this one is made of, when it is a bundle. |
| bundle.id |  |  |
| bundle.name |  |  |
| bundle.code |  |  |
| bundle.quantity |  | How many of it the bundle contains. |
| options | object\[\] | Products offered as options alongside this one. |
| options.id |  |  |
| options.name |  |  |
| options.code |  |  |
| options.quantity |  |  |
| related | object\[\] | Products shown as related. |
| related.id |  |  |
| related.name |  |  |
| related.code |  |  |
| related.quantity |  |  |
| tags | integer\[\] | CMS tag ids. |
| characteristics | object\[\] | The characteristics this product varies on. Empty when it has no variants. |
| characteristics.id | integer | The characteristic, such as Size. |
| characteristics.name | string | Its name. |
| characteristics.values | object\[\] | The values of it this product uses, such as S, M and L. |
| characteristics.values.id | integer | The value id, which is what a variant refers to. |
| characteristics.values.value | string | Its name, such as `M`. |
| variants | object\[\] | Every variant, with its own code, stock, price and images. Empty for a product that does not vary. |
| variants.id | integer | The variant is a product in its own right, and this is its id. |
| variants.code | string | Its own SKU. |
| variants.quantity | integer | Its own stock. This is the figure to change, not the parent's. |
| variants.published | boolean |  |
| variants.price | number\|null | `null` when the variant has no price of its own and the parent's applies. |
| variants.values | object\[\] | Which characteristic values this variant stands for, one per characteristic. |
| variants.values.option\_id | integer | The characteristic. |
| variants.values.option\_name | string | Its name, so the variant can be labelled without a second call. |
| variants.values.value\_id | integer | The value. |
| variants.values.value | string | Its name. |
| variants.images | object\[\] | The variant's own images, in the same shape as the product's. |
| variants.images.id | integer |  |
| variants.images.name | string |  |
| variants.images.path | string | Relative to the upload folder. |
| variants.images.url | string | Absolute. |
| variants.images.ordering | integer |  |
| fields | object\[\] | The definitions of the custom fields that apply to this product, so a client can build a form for them. |
| fields.namekey | string | The key used in `custom_fields`. |
| fields.label | string | Translated into the operator's language. |
| fields.type | string | `text`, `radio`, `singledropdown`, `file`, and the rest of HikaShop's field types. |
| fields.required | boolean | Whether the shop refuses to save the product without it. |
| fields.translatable | boolean | Whether its value can be translated, which is what the translation routes offer. |
| fields.upload\_dir | string | For a file field, where its uploads are kept. |
| fields.raw\_type | string | HikaShop's own name for the type, before it is mapped to something a client can render. |
| fields.default | string | The value used when none is given. |
| fields.options | object\[\] | The choices, for a field that has them. Empty for a free text one. |
| fields.multiple | boolean | Whether more than one choice may be selected. |
| fields.allowed\_extensions | string | For a file field, the extensions it accepts, comma separated. Empty means the shop default. |
| fields.date\_format | string | For a date field, the format it is stored in. |
| custom\_fields | object | Their values, keyed by namekey. |
| custom\_field\_files | object | For custom fields holding a file, the file behind each value. |
| sections | object\[\] | Information other plugins show on this record, each with a `key`, a `title` and `rows` (`label`, `value`, and optionally `url`, `badge` and `ref`). Empty when no plugin adds any; on a customer, core adds their paid downloads. See the guide on adding information and settings. |
| extensions | object\[\] | Settings other plugins keep on this record, in groups (`key`, `title`, `fields`), each field described like a custom field plus its current `value`. Send changes back as `extensions` with the record's save. Empty when no plugin adds any. |

| Can also fail with | Meaning |
|---|---|
| not\_found | No such product, or the operator may not change it. |
| invalid\_fields | One of your own fields was rejected by its own rules. |
| nothing | The body held no field this shop knows, so nothing would have been written. |
| invalid\_extensions | The product was saved, but a plugin refused some of its values: `error.details` says which, as `{ group key: { namekey: message } }`. |

#### product:delete

Delete a product and its variants.

Deletes a product and its variants. Orders that already contain it are untouched: an order line records what was sold at the time, and it does not stop meaning something because the catalogue changed.

```
php cli/joomla.php hikashop:product:delete <id> --yes
wp hikashop product delete <id> --yes
```

| Argument | Description |
|---|---|
| &lt;id&gt; required | Product id |

| Returns | Type | Description |
|---|---|---|
| id | integer | The product that was deleted. |
| deleted | boolean | True when the row is gone. |

| Can also fail with | Meaning |
|---|---|
| not\_found | No such product, or the operator may not delete it. |
| delete\_failed | The shop refused to delete it. |

#### product:stock

Set a product's stock.

Sets the tracked quantity to an absolute figure, which is what a stock take does. It is not an adjustment: send what the shelf holds, not the difference. A product with variants keeps no stock of its own, so set it on the variant instead. Asking to set it on the parent is refused rather than silently ignored.

```
php cli/joomla.php hikashop:product:stock <id> --quantity=<quantity>
wp hikashop product stock <id> --quantity=<quantity>
```

| Argument | Description |
|---|---|
| &lt;id&gt; required | Product id |

| Option | Type | Description |
|---|---|---|
| --quantity required | int | New quantity, -1 for unlimited |

| Returns | Type | Description |
|---|---|---|
| id | integer |  |
| quantity | integer | As stored, so you can confirm what was written. |

| Can also fail with | Meaning |
|---|---|
| not\_found | No such product, or the operator may not change it. |
| has\_variants | It is a parent: set the stock on one of its variants. |

#### product:price

Replace a product's price set.

Replaces the whole price set, it does not merge into it. Send every price the product should have, including the ones you are not changing; anything you leave out is deleted. That is deliberate, because a price set is a set: quantity breaks and audience restrictions only make sense against each other.

```
php cli/joomla.php hikashop:product:price <id> --value=<value> [--currency=<currency>] [--min-quantity=<min-quantity>]
wp hikashop product price <id> --value=<value> [--currency=<currency>] [--min-quantity=<min-quantity>]
```

| Argument | Description |
|---|---|
| &lt;id&gt; required | Product id |

| Option | Type | Description |
|---|---|---|
| --value required | float | The price |
| --currency | int | Currency id, the shop's own when left out |
| --min-quantity | int | Quantity this price starts at |

| Returns | Type | Description |
|---|---|---|
| id | integer |  |
| value | number | Tax excluded, as stored. |
| currency\_id | integer |  |
| min\_quantity | integer | From how many items this row applies, which is how a quantity break is expressed. |
| access | object | Which user groups the price is for. |
| access.mode | string | `all`, `none` or `groups`. |
| access.groups | integer\[\] | User group ids, not view levels. |
| users | integer\[\] | Named customers, empty for everyone. |
| zone\_ids | integer\[\] | Zones it applies in, empty for everywhere. |
| start\_date | integer\|null | Unix timestamp. |
| end\_date | integer\|null | Unix timestamp. |

| Can also fail with | Meaning |
|---|---|
| invalid\_request | No prices array was sent. |
| invalid\_price | A price in the set cannot be stored, and the message says which one and why. Nothing is saved: a set is replaced whole or not at all. |
| not\_found | No such product, or the operator may not change it. |

#### product:lowstock

List sellable products at or below a stock threshold.

Sellable items at or below a stock threshold, cheapest first to reorder. Variants are listed in their own right, since that is where the stock actually sits. Products that do not track stock are left out: they are not running out of anything.

```
php cli/joomla.php hikashop:product:lowstock [--threshold=<threshold>] [--limit=<limit>]
wp hikashop product lowstock [--threshold=<threshold>] [--limit=<limit>]
```

| Option | Type | Description |
|---|---|---|
| --threshold | int | Stock level to report at or below |
| --limit | int | How many to return |

| Returns | Type | Description |
|---|---|---|
| id |  | The parent product. |
| variant\_id |  | The variant that is low, `0` when the parent itself is. |
| name |  |  |
| code |  | The SKU of whichever record is low. |
| quantity |  | What is left. |

### Orders

#### order:list

List orders.

The orders the operator may see, newest first. It is the listing the app's order screen is built on, so it carries just enough to draw a row and no more; ask for one order when you need the rest.

```
php cli/joomla.php hikashop:order:list [--search=<search>] [--limit=<limit>] [--start=<start>] [--status=<status>]
wp hikashop order list [--search=<search>] [--limit=<limit>] [--start=<start>] [--status=<status>]
```

| Option | Type | Description |
|---|---|---|
| --search | string | Filter on a search term |
| --limit | int | How many to return |
| --start | int | Skip this many first |
| --status | string | Only this order status |

| Returns | Type | Description |
|---|---|---|
| id |  | The order id, which is what every other order route takes. |
| number |  | The order number the customer sees, which is not the id. |
| status |  | A namekey, not a label. `GET /statuses` translates it. |
| created |  | Unix timestamp. |
| total |  | What the customer owes, tax included, in the order currency. |
| currency\_id |  | The order keeps the currency it was placed in, which need not be the shop default. |
| customer | object | Enough to name the buyer in a list. |
| customer.name |  |  |
| customer.email |  |  |
| custom\_fields | object | The listing values of your own order fields, keyed by namekey. |

| In `meta` | Type | Description |
|---|---|---|
| start | integer | Echoes the offset used. |
| limit | integer | Echoes the page size used. |
| total | integer | Orders matching the filter, before paging. |
| fields | object\[\] | The definitions behind `custom_fields`. |

#### order:get

Show one order.

The whole order: its lines, its totals, its addresses, its history and your own fields. Money is in the currency the order was placed in, which is not necessarily the shop's. Do not convert it: an order is a record of what was agreed at the time.

```
php cli/joomla.php hikashop:order:get <id>
wp hikashop order get <id>
```

| Argument | Description |
|---|---|
| &lt;id&gt; required | Order id |

| Returns | Type | Description |
|---|---|---|
| fees | object | The `discount`, `shipping` and `payment` amounts, which is what `PUT /orders/{id}/fees` writes. |
| fees.discount | object | Its `amount`, its `tax`, the `tax_namekeys` behind that tax, and the coupon `code` when one was used. |
| fees.discount.amount | number | A positive figure, already subtracted from the total. |
| fees.discount.tax | number | The tax on it. |
| fees.discount.tax\_namekeys | string\[\] | Which tax rates that came from. |
| fees.discount.code | string | The coupon code, empty for a discount applied by hand. |
| fees.shipping | object | The shipping charge and what carried it. |
| fees.shipping.amount | number | Tax excluded. |
| fees.shipping.tax | number | The tax on it. |
| fees.shipping.tax\_namekeys | string\[\] | Which tax rates that came from. |
| fees.shipping.method | string | The plugin that handled it. |
| fees.shipping.method\_name | string | As the merchant named it. |
| fees.payment | object | The payment fee and what took it. |
| fees.payment.amount | number | Tax excluded. |
| fees.payment.tax | number | The tax on it. |
| fees.payment.tax\_namekeys | string\[\] | Which tax rates that came from. |
| fees.payment.method | string | The plugin that took it. |
| fees.payment.method\_name | string | As the merchant named it. |
| totals | object | The figures. See the shape below. |
| totals.total | number | What the customer owes, tax included. |
| totals.discount | number | The discount applied, as a positive figure already subtracted. |
| totals.shipping | number | The shipping charged. |
| totals.payment | number | The payment fee charged. |
| totals.tax | number | The tax within the total, not on top of it. |
| fields.namekey | string | The key its value is stored under. |
| fields.label | string | Translated into the operator's language. |
| fields.type | string | What to render: `text`, `radio`, `singledropdown`, `file`, and the rest. |
| fields.raw\_type | string | HikaShop's own name for the type. |
| fields.required | boolean | Whether the shop refuses to save without it. |
| fields.default | string | The value used when none is given. |
| fields.options | object\[\] | The choices, for a field that has them. |
| fields.options.value | string | What to send back when this choice is picked. |
| fields.options.label | string | What to show. |
| fields.options.label\_key | string | The translation key behind the label, when there is one. |
| fields.multiple | boolean | Whether more than one may be chosen. |
| fields.translatable | boolean | Whether its value can be translated. |
| fields.upload\_dir | string | For a file field, where its uploads are kept. |
| fields.allowed\_extensions | string | For a file field, the extensions it accepts. Empty means the shop default. |
| fields.date\_format | string | For a date field, the format it is stored in. |
| id |  |  |
| number |  | The number the customer sees. |
| status |  | A namekey. |
| created |  | Unix timestamp. |
| modified |  | Unix timestamp of the last change. |
| currency\_id |  | The currency the order was placed in. |
| customer | object | Who placed it. |
| customer.name |  |  |
| customer.email |  |  |
| payment\_method | string | How it was paid, as the shop names it. |
| shipping\_method | string | How it ships. |
| invoice\_number | string | Empty until an invoice has been issued. |
| invoice\_created | integer\|null | Unix timestamp of the invoice. |
| items | object\[\] | The lines: `id`, `name`, `code`, `quantity`, `price`, `tax` and whether the line can still be edited. |
| items.id | integer | The line id, which is what `PUT /orders/{id}/products/{lineId}` takes. It is not the product id. |
| items.name | string | The product as it was named when ordered, which may since have changed. |
| items.code | string | Its SKU at the time. |
| items.quantity | integer |  |
| items.price | number | Unit price, tax excluded, as agreed at the time. |
| items.tax | number | Tax on the line. |
| items.editable | boolean | False once the line can no longer be changed, for instance on a shipped order. |
| billing\_address | object\|null | The address as it was at the time, `null` when there is none. It is a copy, not a pointer at the customer's current address. |
| shipping\_address | object\|null | The same, for delivery. |
| shipping\_address\_override | boolean | Whether the delivery address was set apart from the billing one. |
| history | object\[\] | What has happened to the order, oldest first. |
| history.status |  | The namekey it moved to. |
| history.created |  | Unix timestamp. |
| history.type |  | What caused it: a payment notification, an operator, the shop itself. |
| history.reason |  | The note recorded with the change, when there was one. |
| history.notified | boolean | Whether the customer was emailed about it. |
| fields | object\[\] | The definitions of your own order fields. |
| custom\_fields | object | Their values, keyed by namekey. |
| custom\_field\_files | object | For a field holding a file, the file behind the value. |
| tax\_rates | object\[\] | The rates that made up the tax, each with its namekey and rate, so a total can be explained rather than only shown. |
| tax\_rates.namekey | string | The tax rate as the shop names it. |
| tax\_rates.rate | number | As a fraction, so `0.1` is ten percent. |
| sections | object\[\] | Information other plugins show on this record, each with a `key`, a `title` and `rows` (`label`, `value`, and optionally `url`, `badge` and `ref`). Empty when no plugin adds any; on a customer, core adds their paid downloads. See the guide on adding information and settings. |
| extensions | object\[\] | Settings other plugins keep on this record, in groups (`key`, `title`, `fields`), each field described like a custom field plus its current `value`. Send changes back as `extensions` with the record's save. Empty when no plugin adds any. |

#### order:status

Change an order's status.

Moves the order and, when asked, sends the customer the same notification the backend would have sent. This calls the same code the backend does, so stock, invoices and every plugin listening on a status change behave exactly as they do there. It is not a database update.

```
php cli/joomla.php hikashop:order:status <id> <status> [--notify] [--reason=<reason>]
wp hikashop order status <id> <status> [--notify] [--reason=<reason>]
```

| Argument | Description |
|---|---|
| &lt;id&gt; required | Order id |
| &lt;status&gt; required | Status namekey, e.g. confirmed or shipped |

| Option | Type | Description |
|---|---|---|
| --notify | flag | Email the customer about the change |
| --reason | string | Note stored with the change |

| Returns | Type | Description |
|---|---|---|
| id | integer | The order id. |
| status |  | The namekey the order now has. |
| changed |  | False when the order already had that status. |
| notified | boolean | Whether the customer was actually emailed, which can be false even when you asked, if the status has no notification configured. |

| Can also fail with | Meaning |
|---|---|
| invalid\_status | No such status namekey on this shop. |
| not\_found | No such order, or the operator may not see it. |
| save\_failed | The order could not be saved. |

#### order:create

Create an empty order for a customer.

Creates an empty order for a customer, to be filled in with lines, fees and an address. Give it either an existing `user_id` or a `guest` with at least an email address, which is how an order gets taken over the telephone from somebody who has never bought before.

```
php cli/joomla.php hikashop:order:create [--customer=<customer>] [--guest]
wp hikashop order create [--customer=<customer>] [--guest]
```

| Option | Type | Description |
|---|---|---|
| --customer | int | HikaShop customer id |
| --guest | flag | Create it for a guest instead |

| Returns | Type | Description |
|---|---|---|
| id | integer | The order that was created, to add lines to. |

| Can also fail with | Meaning |
|---|---|
| no\_customer | Neither a user\_id nor a usable guest was given. |
| save\_failed | The order could not be created. |

#### order:addproduct

Add a product line to an order.

Adds a product to an existing order and re-totals it. Send a `price` only to override what the shop would charge; leave it out and the order's own pricing applies, which is what `GET /orders/{id}/products/precompute` shows you beforehand.

```
php cli/joomla.php hikashop:order:addproduct <id> --product=<product> [--quantity=<quantity>] [--price=<price>]
wp hikashop order addproduct <id> --product=<product> [--quantity=<quantity>] [--price=<price>]
```

| Argument | Description |
|---|---|
| &lt;id&gt; required | Order id |

| Option | Type | Description |
|---|---|---|
| --product required | int | Product id |
| --quantity | int | How many |
| --price | float | Unit price, the product's own when left out |

| Returns | Type | Description |
|---|---|---|
| totals | object | The order totalled, so a client need not compute it and disagree with the shop. |
| totals.total | number | What the customer owes, tax included. |
| totals.discount | number | The discount applied, as a positive figure already subtracted. |
| totals.shipping | number | The shipping charged. |
| totals.payment | number | The payment fee charged. |
| totals.tax | number | The tax within the total, not on top of it. |
| items.id | integer | The line id, which is what the line routes take. It is not the product id. |
| items.name | string | The product as it was named when ordered. |
| items.code | string | Its SKU at the time. |
| items.quantity | integer |  |
| items.price | number | Unit price, tax excluded, as agreed at the time. |
| items.tax | number | Tax on the line. |
| items.editable | boolean | False once the line can no longer be changed. |
| id | integer | The order. |
| items | object\[\] | The lines as they now stand, in the same shape as on the order. |

| Can also fail with | Meaning |
|---|---|
| not\_found | No such order or product, or the operator may not change the order. |
| save\_failed | The order could not be saved. |

### Customers

#### customer:list

List customers.

The customers the operator may see, with enough to recognise one and to know whether they have bought anything. Guests are included. A shop that lets people order without an account still has a row for each of them, and `type` is how you tell the two apart.

```
php cli/joomla.php hikashop:customer:list [--search=<search>] [--limit=<limit>] [--start=<start>]
wp hikashop customer list [--search=<search>] [--limit=<limit>] [--start=<start>]
```

| Option | Type | Description |
|---|---|---|
| --search | string | Filter on a search term |
| --limit | int | How many to return |
| --start | int | Skip this many first |

| Returns | Type | Description |
|---|---|---|
| id |  | The HikaShop customer id, which is not the CMS user id. |
| name |  | The account name, or for a guest the name on their default address, since a guest has no account to take one from. |
| email |  |  |
| type |  | `registered` for an account, `guest` for someone who ordered without one. |
| created |  | Unix timestamp of the first time the shop saw them. |
| order\_count |  | How many orders they have placed, so a list can be sorted by worth without a second call. |

| In `meta` | Type | Description |
|---|---|---|
| start | integer | Echoes the offset used. |
| limit | integer | Echoes the page size used. |
| total | integer | Customers matching the filter, before paging. |

#### customer:get

Show one customer.

A customer with their addresses, their orders, which groups they are in and your own customer fields. `can_edit_account` and `groups_editable` are worth reading before drawing a form: they say whether this operator may change this particular account at all, so a client can leave the controls out rather than offer something that will be refused. A customer can have many addresses and one default of each kind.

```
php cli/joomla.php hikashop:customer:get <id>
wp hikashop customer get <id>
```

| Argument | Description |
|---|---|
| &lt;id&gt; required | Customer id |

| Returns | Type | Description |
|---|---|---|
| id | integer | The HikaShop customer id, which is what every customer route takes. |
| cms\_id | integer | The Joomla or WordPress user id, `0` for a guest with no account. |
| name | string |  |
| email | string |  |
| username | string | The login, empty for a guest. |
| type | string | `registered` or `guest`. |
| blocked | boolean | Whether the CMS account is disabled. |
| can\_edit\_account | boolean | Whether this operator may change the login and password of this particular account. False for an account above their own level, which is how a super user is protected from staff. |
| groups\_editable | boolean | Whether this operator may change which groups the customer is in. |
| groups | object\[\] | The groups they are in. |
| groups.id | integer |  |
| groups.title | string |  |
| available\_groups | object\[\] | Every group, with whether this operator may put the customer into it, so a picker can grey out the rest rather than offering a refusal. |
| available\_groups.id | integer |  |
| available\_groups.title | string |  |
| available\_groups.assignable | boolean | False for a group this operator may not grant. |
| created | integer | Unix timestamp of the first time the shop saw them. |
| addresses | object\[\] | Their addresses, defaults first. |
| addresses.id | integer |  |
| addresses.types | string\[\] | Which of `billing` and `shipping` it is used for. |
| addresses.name | string |  |
| addresses.company | string |  |
| addresses.street | string |  |
| addresses.city | string |  |
| addresses.post\_code | string |  |
| addresses.telephone | string |  |
| addresses.default | boolean | Whether it is the default for one of its types. |
| addresses.formatted | object | The address laid out the way this shop lays addresses out, which depends on its address format setting. |
| addresses.formatted.text | string | Several lines, for an invoice or a label. |
| addresses.formatted.one\_line | string | One line, for a list. |
| orders | object\[\] | Their orders, newest first, enough to list them. |
| orders.id | integer |  |
| orders.number | string | The number the customer sees. |
| orders.status | string | A namekey. |
| orders.created | integer | Unix timestamp. |
| orders.total | number | Tax included, in the order currency. |
| orders.currency\_id | integer | That currency. |
| fields | object\[\] | The definitions of your own customer fields. |
| custom\_fields | object | Their values, keyed by namekey. |
| custom\_field\_files | object | For a field holding a file, the file behind the value. |
| sections | object\[\] | Information other plugins show on this record, each with a `key`, a `title` and `rows` (`label`, `value`, and optionally `url`, `badge` and `ref`). Empty when no plugin adds any; on a customer, core adds their paid downloads. See the guide on adding information and settings. |
| extensions | object\[\] | Settings other plugins keep on this record, in groups (`key`, `title`, `fields`), each field described like a custom field plus its current `value`. Send changes back as `extensions` with the record's save. Empty when no plugin adds any. |

| Can also fail with | Meaning |
|---|---|
| not\_found | No such customer, or the operator may not see them. |

#### customer:create

Create a customer.

Creates a customer from an email address and a name, as a guest: no account, no password, nothing for them to log in with. `POST /customers/{id}/account` turns one into a registered customer afterwards.

```
php cli/joomla.php hikashop:customer:create --email=<email> [--name=<name>]
wp hikashop customer create --email=<email> [--name=<name>]
```

| Option | Type | Description |
|---|---|---|
| --email required | string | Email address |
| --name | string | Full name |

| Returns | Type | Description |
|---|---|---|
| id | integer | The customer that was created. |

| Can also fail with | Meaning |
|---|---|
| email\_taken | Another customer already has that address. |
| save\_failed | The shop refused to save it. |

#### customer:delete

Delete a customer.

Removes a customer and their addresses. A customer with orders is refused, which is what the backend does too: delete their orders first, and then the customer.

```
php cli/joomla.php hikashop:customer:delete <id> --yes
wp hikashop customer delete <id> --yes
```

| Argument | Description |
|---|---|
| &lt;id&gt; required | Customer id |

| Returns | Type | Description |
|---|---|---|
| deleted | boolean | True when the row is gone. |

| Can also fail with | Meaning |
|---|---|
| not\_found | No such customer, or the operator may not delete them. |
| has\_orders | They have orders. Delete those first. |
| delete\_failed | The shop refused to delete the row. |

### Categories

#### category:list

List product categories.

One level of the category tree at a time, unpublished categories included, which is what makes this a management view rather than a shop one. Pass a `parent_id` to walk down. `has_children` tells you whether there is anything below without asking, so a tree can be drawn lazily. HikaShop keeps its manufacturers and its tax categories in the same table as the product categories, told apart by their root. Ask for the tree you want.

```
php cli/joomla.php hikashop:category:list
wp hikashop category list
```

| Returns | Type | Description |
|---|---|---|
| id |  |  |
| name |  |  |
| parent\_id |  | Its parent, so a flat answer can be rebuilt into a tree. |
| published |  |  |
| has\_children |  | Whether anything sits below it. |
| image | string\|null | Absolute URL of its image, `null` when it has none. |

| In `meta` | Type | Description |
|---|---|---|
| total | integer | Categories matching, before paging. |
| start | integer | Echoes the offset used. |
| limit | integer | Echoes the page size used. |

#### category:create

Create a product category.

Creates a category under another, or at the top of the product tree when no parent is given.

```
php cli/joomla.php hikashop:category:create --name=<name>
wp hikashop category create --name=<name>
```

| Option | Type | Description |
|---|---|---|
| --name required | string | Category name |

| Returns | Type | Description |
|---|---|---|
| id | integer | The category that was created. |
| name | string |  |
| parent\_id | integer | Where it sits. |
| published | boolean |  |

| Can also fail with | Meaning |
|---|---|
| invalid\_fields | One of your own fields was rejected by its own rules. |
| save\_failed | The shop refused to save it. |

#### category:delete

Delete a product category.

Deletes a category. The products in it are not deleted; they simply stop being in it, and a product left in no category at all disappears from the shop's listings.

```
php cli/joomla.php hikashop:category:delete <id> --yes
wp hikashop category delete <id> --yes
```

| Argument | Description |
|---|---|
| &lt;id&gt; required | Category id |

| Returns | Type | Description |
|---|---|---|
| id | integer | The category that was deleted. |
| deleted | boolean | True when the row is gone. |

| Can also fail with | Meaning |
|---|---|
| not\_found | No such category, or the operator may not delete it. |

### Coupons and discounts

#### discount:list

List coupons and discounts.

Both kinds of reduction live in one table and are told apart by `type`: a \*\*discount\*\* applies by itself when its conditions are met, a \*\*coupon\*\* waits for its code to be entered. The restriction fields are the interesting part, and they are all lists of ids: which products, which categories, which zones, which customers, and the same again for exclusions. An empty list means no restriction of that kind rather than none allowed.

```
php cli/joomla.php hikashop:discount:list [--limit=<limit>] [--start=<start>]
wp hikashop discount list [--limit=<limit>] [--start=<start>]
```

| Option | Type | Description |
|---|---|---|
| --limit | int | How many to return |
| --start | int | Skip this many first |

| Returns | Type | Description |
|---|---|---|
| id | integer |  |
| type | string | `discount` applies by itself, `coupon` waits for its code. |
| code | string | What the customer types. Empty on a discount. |
| kind | string | Whether the value is a percentage or a fixed amount. |
| value | number | The reduction, read according to `kind`. |
| currency\_id | integer | The currency a fixed amount is in. |
| published | boolean |  |
| start | integer\|null | Unix timestamp before which it does not apply. |
| end | integer\|null | Unix timestamp after which it expires. |
| minimum\_order | number | Order total below which it does not apply, `0` for none. |
| maximum\_order | number | Order total above which it stops applying, `0` for none. |
| quota | integer | How many times it may be used in total, `0` for no limit. |
| quota\_per\_user | integer | How many times one customer may use it, `0` for no limit. |
| used\_times | integer | How many times it already has been. |
| tax\_included | boolean | Whether the value is understood as tax included. |
| tax\_id | integer | The tax category of the reduction itself. |
| shipping\_percent | number | A reduction on the shipping rather than on the goods. |
| minimum\_products | integer | Fewest items in the cart for it to apply. |
| maximum\_products | integer | Most items for it to still apply. |
| product\_ids | integer\[\] | Restricted to these products. Empty means all of them. |
| exclude\_product\_ids | integer\[\] | Never applies to these. |
| category\_ids | integer\[\] | Restricted to these categories. |
| category\_childs | boolean | Whether those categories include their sub-categories. |
| exclude\_category\_ids | integer\[\] | Never applies in these categories. |
| exclude\_category\_childs | boolean | Whether those exclusions include sub-categories. |
| zone\_ids | integer\[\] | Restricted to these zones. |
| user\_ids | integer\[\] | Restricted to these customers. |
| access | object | Who this is for. |
| exclude\_access | object | Who this is for. |
| auto\_load | boolean | For a coupon, whether the shop applies it without the customer typing it. |
| product\_only | boolean | Whether it reduces only the goods and leaves the fees alone. |
| discounted\_products | integer | How many products in the cart it applied to, on a discount that has been used. |
| access.mode | string | `all`, `none`, or `groups` when it is restricted to some. |
| access.groups | integer\[\] | User \*\*group\*\* ids, and not Joomla view levels. The two id spaces overlap and disagree, so a value that looks plausible can grant the wrong audience. |
| exclude\_access.mode | string | `all`, `none`, or `groups` when it is restricted to some. |
| exclude\_access.groups | integer\[\] | User \*\*group\*\* ids, and not Joomla view levels. The two id spaces overlap and disagree, so a value that looks plausible can grant the wrong audience. |

| In `meta` | Type | Description |
|---|---|---|
| start | integer | Echoes the offset used. |
| limit | integer | Echoes the page size used. |
| total | integer | Rows matching the filter, before paging. |

#### discount:create

Create a coupon or a discount.

Creates a reduction and answers with it as the shop stored it. `type` decides which kind it is: a `coupon` needs a `code`, a `discount` applies by itself. Either way `value` is required, read according to `kind`.

```
php cli/joomla.php hikashop:discount:create [--code=<code>] --value=<value> [--kind=<kind>] [--type=<type>] [--published]
wp hikashop discount create [--code=<code>] --value=<value> [--kind=<kind>] [--type=<type>] [--published]
```

| Option | Type | Description |
|---|---|---|
| --code | string | Coupon code |
| --value required | float | Amount or percentage |
| --kind | string | percent or flat |
| --type | string | coupon or discount |
| --published | flag | Publish it |

| Returns | Type | Description |
|---|---|---|
| id | integer |  |
| type | string | `discount` applies by itself, `coupon` waits for its code. |
| code | string | What the customer types. Empty on a discount. |
| kind | string | Whether the value is a percentage or a fixed amount. |
| value | number | The reduction, read according to `kind`. |
| currency\_id | integer | The currency a fixed amount is in. |
| published | boolean |  |
| start | integer\|null | Unix timestamp before which it does not apply. |
| end | integer\|null | Unix timestamp after which it expires. |
| minimum\_order | number | Order total below which it does not apply, `0` for none. |
| maximum\_order | number | Order total above which it stops applying, `0` for none. |
| quota | integer | How many times it may be used in total, `0` for no limit. |
| quota\_per\_user | integer | How many times one customer may use it, `0` for no limit. |
| used\_times | integer | How many times it already has been. |
| tax\_included | boolean | Whether the value is understood as tax included. |
| tax\_id | integer | The tax category of the reduction itself. |
| shipping\_percent | number | A reduction on the shipping rather than on the goods. |
| minimum\_products | integer | Fewest items in the cart for it to apply. |
| maximum\_products | integer | Most items for it to still apply. |
| product\_ids | integer\[\] | Restricted to these products. Empty means all of them. |
| exclude\_product\_ids | integer\[\] | Never applies to these. |
| category\_ids | integer\[\] | Restricted to these categories. |
| category\_childs | boolean | Whether those categories include their sub-categories. |
| exclude\_category\_ids | integer\[\] | Never applies in these categories. |
| exclude\_category\_childs | boolean | Whether those exclusions include sub-categories. |
| zone\_ids | integer\[\] | Restricted to these zones. |
| user\_ids | integer\[\] | Restricted to these customers. |
| access | object | Who this is for. |
| exclude\_access | object | Who this is for. |
| auto\_load | boolean | For a coupon, whether the shop applies it without the customer typing it. |
| product\_only | boolean | Whether it reduces only the goods and leaves the fees alone. |
| discounted\_products | integer | How many products in the cart it applied to, on a discount that has been used. |
| access.mode | string | `all`, `none`, or `groups` when it is restricted to some. |
| access.groups | integer\[\] | User \*\*group\*\* ids, and not Joomla view levels. The two id spaces overlap and disagree, so a value that looks plausible can grant the wrong audience. |
| exclude\_access.mode | string | `all`, `none`, or `groups` when it is restricted to some. |
| exclude\_access.groups | integer\[\] | User \*\*group\*\* ids, and not Joomla view levels. The two id spaces overlap and disagree, so a value that looks plausible can grant the wrong audience. |

| Can also fail with | Meaning |
|---|---|
| code\_required | A coupon needs a code. |
| code\_taken | Another coupon already uses that code. |
| value\_required | A reduction needs a value. |
| not\_found | Not reachable when creating: the same handler serves the update, where it means no such discount. |
| save\_failed | The shop refused to save it. |

#### discount:delete

Delete a coupon or discount.

Deletes a reduction. Orders that already used it keep the amount they were given: the discount on an order is a figure, not a pointer at this row.

```
php cli/joomla.php hikashop:discount:delete <id> --yes
wp hikashop discount delete <id> --yes
```

| Argument | Description |
|---|---|
| &lt;id&gt; required | Discount id |

| Returns | Type | Description |
|---|---|---|
| deleted | boolean | True when the row is gone. |

| Can also fail with | Meaning |
|---|---|
| not\_found | No such discount, or the operator may not delete it. |

### Mass actions

#### massaction:list

List the shop's own bulk operations.

The mass actions the merchant has configured for a listing, so a client can offer the merchant's own bulk operations rather than a fixed set of its own. Whatever they built in the backend appears here, and running one is `POST /massactions/{id}`.

```
php cli/joomla.php hikashop:massaction:list [--table=<table>]
wp hikashop massaction list [--table=<table>]
```

| Option | Type | Description |
|---|---|---|
| --table | string | Which listing, e.g. product or order |

| Returns | Type | Description |
|---|---|---|
| id |  | What to run. |
| name |  | As the merchant named it. |
| description |  | Their own note about what it does, when they wrote one. |
| table |  | The listing it belongs to. |
| restricted | boolean | Whether it may only run on a selection rather than on everything matching a filter. |

| Can also fail with | Meaning |
|---|---|
| invalid\_request | The table is not one the shop has mass actions for. |
| forbidden | The operator may not view that kind of record. |

#### massaction:run

Run a bulk operation over a selection.

Runs one of the merchant's own bulk operations over a selection. It runs the same code the backend runs, so whatever the action does there it does here, including whatever a third-party plugin added to it. Give it the ids to work on.

```
php cli/joomla.php hikashop:massaction:run <id> --ids=<ids> --yes
wp hikashop massaction run <id> --ids=<ids> --yes
```

| Argument | Description |
|---|---|
| &lt;id&gt; required | Mass action id |

| Option | Type | Description |
|---|---|---|
| --ids required | ids, comma separated | Record ids to act on, comma separated |

| Returns | Type | Description |
|---|---|---|
| ok | boolean | Whether the action reported success. |
| count | integer | How many records it worked on. |
| report | string | Whatever the action had to say, ready to show. Its wording is the action's own. |

| Can also fail with | Meaning |
|---|---|
| invalid\_request | No ids were sent, or the action is not one this shop has. |
| forbidden | The operator may not work on that kind of record. |

### The shop itself

#### dbcheck

Bring the database schema up to date, what you want after restoring a dump. Runs inside the site itself and needs no plugin beyond HikaShop.

```
php cli/joomla.php hikashop:dbcheck
wp hikashop dbcheck
```

| Returns | Type | Description |
|---|---|---|
| checked | boolean | Always true once the check has run. |
| report | string\[\] | What it changed, one line per change. Empty when the schema was already correct. |

#### shop:statuses

List the shop's order statuses.

Every published order status, in the order the backend shows them. A shop invents its own, so this list is not a fixed set and should never be hard coded. The `namekey` is the identifier to send to `POST /orders/{id}/status`; the `name` is for a person to read.

```
php cli/joomla.php hikashop:shop:statuses
wp hikashop shop statuses
```

| Returns | Type | Description |
|---|---|---|
| namekey |  | The identifier. This is what you send when changing an order. |
| name |  | Translated into the operator's language, ready to display. |
| label\_key |  | The translation key behind that name, if you would rather translate it yourself. |
| color |  | The colour the backend uses for this status, empty when none is set. |

#### shop:stats

Show the dashboard totals.

Revenue, orders, average basket and new customers over a period, the same figures again for the period before it so a change can be shown, the series behind them, and the best sellers. Only orders the shop counts as sold are included, so a cancelled order does not inflate a total. Amounts are in the shop's own currency.

```
php cli/joomla.php hikashop:shop:stats [--range=<range>]
wp hikashop shop stats [--range=<range>]
```

| Option | Type | Description |
|---|---|---|
| --range | string | day, week, month or year |

| Returns | Type | Description |
|---|---|---|
| range | string | The period the figures cover. |
| currency\_id | integer | The shop's currency, which every amount here is in. |
| totals | object | The four headline figures. |
| totals.revenue | number | Taken in the period. |
| totals.orders | integer | How many were placed. |
| totals.average\_order | number | Revenue divided by orders. |
| totals.customers | integer | New customers in the period. |
| previous | object | The same four figures for the preceding period of the same length, for a comparison. |
| previous.revenue | number | Taken in the preceding period. |
| previous.orders | integer | Placed in it. |
| previous.average\_order | number | Its average basket. |
| previous.customers | integer | New customers in it. |
| series\_granularity | string | Whether the series is by day, week, month or year, which follows from the range. |
| revenue\_series | object\[\] | One point per interval, for a chart. |
| revenue\_series.date | string | The interval, as a date. |
| revenue\_series.revenue | number | Taken in it. |
| top\_products | object\[\] | The best sellers of the period. |
| top\_products.name | string |  |
| top\_products.quantity | integer | How many were sold. |

### Configuration

#### config:get

Read one configuration value. Runs inside the site itself and needs no plugin beyond HikaShop.

```
php cli/joomla.php hikashop:config:get <key>
wp hikashop config get <key>
```

| Argument | Description |
|---|---|
| &lt;key&gt; required | Configuration key, e.g. main\_currency |

| Returns | Type | Description |
|---|---|---|
| key | string | The key that was read. |
| value | mixed | Its value, as the shop stores it. |

| Can also fail with | Meaning |
|---|---|
| not\_found | No configuration key of that name. |

#### config:set

Change one configuration value. Runs inside the site itself and needs no plugin beyond HikaShop.

```
php cli/joomla.php hikashop:config:set <key> <value>
wp hikashop config set <key> <value>
```

| Argument | Description |
|---|---|
| &lt;key&gt; required | Configuration key |
| &lt;value&gt; required | New value |

| Returns | Type | Description |
|---|---|---|
| key | string | The key that was changed. |
| was | mixed | The value before the change, so a script can put it back. |
| now | mixed | The value after it. |

| Can also fail with | Meaning |
|---|---|
| not\_found | No configuration key of that name. This changes existing keys, it does not invent them. |
| save\_failed | The configuration could not be written. |

### Caches

#### cache:clean

Empty the shop's caches. Runs inside the site itself and needs no plugin beyond HikaShop.

```
php cli/joomla.php hikashop:cache:clean
wp hikashop cache clean
```

| Returns | Type | Description |
|---|---|---|
| cleaned | string\[\] | Which caches were emptied: the shop's own plugin cache, and the platform's. |

### Cron

#### cron:run

Run the scheduled tasks the shop would run on a page hit. Runs inside the site itself and needs no plugin beyond HikaShop.

```
php cli/joomla.php hikashop:cron:run
wp hikashop cron run
```

| Returns | Type | Description |
|---|---|---|
| launched | boolean | False when the cron was not due to run yet. |
| messages | string\[\] | The summary the cron would otherwise have emailed. |
| details | string\[\] | The detail lines behind that summary. |

| Can also fail with | Meaning |
|---|---|
| cron\_disabled | The cron is turned off in the shop configuration. |

### Log

#### log:list

List the entries of the HikaShop log, newest first. Runs inside the site itself and needs no plugin beyond HikaShop.

```
php cli/joomla.php hikashop:log:list [--source=<source>] [--type=<type>] [--level=<level>] [--order=<order>] [--request=<request>] [--since=<since>] [--until=<until>] [--search=<search>] [--limit=<limit>] [--start=<start>]
wp hikashop log list [--source=<source>] [--type=<type>] [--level=<level>] [--order=<order>] [--request=<request>] [--since=<since>] [--until=<until>] [--search=<search>] [--limit=<limit>] [--start=<start>]
```

| Option | Type | Description |
|---|---|---|
| --source | string | Only this source: a plugin name such as paypal, or a part of HikaShop such as mail |
| --type | string | Only this type: payment, shipping, plugin or core |
| --level | string | This level and the worse ones: debug, info, warning or error |
| --order | int | Only the entries about this order id |
| --request | string | Only the entries written by this request |
| --since | string | From this date, e.g. 2026-10-01 or "2 hours ago" |
| --until | string | Up to this date; a bare day is included |
| --search | string | Text in the message, the data, the source, the address or the IP |
| --limit | int | How many to return |
| --start | int | Skip this many first |

| Returns | Type | Description |
|---|---|---|
| id | int | Entry id. |
| created | int | When it was written, as a Unix timestamp. |
| level | string | debug, info, warning or error. |
| source | string | What wrote it: a plugin name, or a part of HikaShop. |
| type | string | payment, shipping, plugin or core. |
| message | string | The text of the entry, or the beginning of its data. |
| order\_id | int | The order it is about, 0 when none. |
| user\_id | int | The user logged in when it was written, 0 for a guest or a server call. |
| ip | string | IP address of the request. |
| url | string | Address of the request, secrets masked. |
| request | string | Id shared by the entries one request wrote. |
| data\_size | int | Size in bytes of the data the entry holds beyond its message. |

| In `meta` | Type | Description |
|---|---|---|
| total | int | How many entries match, on every page. |

#### log:get

Show one entry of the HikaShop log with its data. Runs inside the site itself and needs no plugin beyond HikaShop.

```
php cli/joomla.php hikashop:log:get <id>
wp hikashop log get <id>
```

| Argument | Description |
|---|---|
| &lt;id&gt; required | Log entry id |

| Returns | Type | Description |
|---|---|---|
| id | int | Entry id. |
| created | int | When it was written, as a Unix timestamp. |
| level | string | debug, info, warning or error. |
| source | string | What wrote it: a plugin name, or a part of HikaShop. |
| type | string | payment, shipping, plugin or core. |
| message | string | The text of the entry, or the beginning of its data. |
| order\_id | int | The order it is about, 0 when none. |
| user\_id | int | The user logged in when it was written, 0 for a guest or a server call. |
| ip | string | IP address of the request. |
| url | string | Address of the request, secrets masked. |
| request | string | Id shared by the entries one request wrote. |
| data\_size | int | Size in bytes of the data the entry holds beyond its message. |
| data | mixed | What the entry holds beyond its message: decoded JSON when it was an array or object, text otherwise. Secrets were masked when it was written. |

| Can also fail with | Meaning |
|---|---|
| not\_found | No log entry with that id. |

#### log:clear

Delete the entries of the HikaShop log that match the filters. Runs inside the site itself and needs no plugin beyond HikaShop.

```
php cli/joomla.php hikashop:log:clear [--source=<source>] [--type=<type>] [--level=<level>] [--order=<order>] [--request=<request>] [--since=<since>] [--until=<until>] [--search=<search>] [--all] --yes
wp hikashop log clear [--source=<source>] [--type=<type>] [--level=<level>] [--order=<order>] [--request=<request>] [--since=<since>] [--until=<until>] [--search=<search>] [--all] --yes
```

| Option | Type | Description |
|---|---|---|
| --source | string | Only this source: a plugin name such as paypal, or a part of HikaShop such as mail |
| --type | string | Only this type: payment, shipping, plugin or core |
| --level | string | This level and the worse ones: debug, info, warning or error |
| --order | int | Only the entries about this order id |
| --request | string | Only the entries written by this request |
| --since | string | From this date, e.g. 2026-10-01 or "2 hours ago" |
| --until | string | Up to this date; a bare day is included |
| --search | string | Text in the message, the data, the source, the address or the IP |
| --all | flag | Delete every entry; needed when no filter is given |

| Returns | Type | Description |
|---|---|---|
| deleted | int | How many entries were deleted. |

| Can also fail with | Meaning |
|---|---|
| no\_filter | No filter was given and --all was not: nothing is deleted by accident. |

### Anything the named commands do not cover

Everything the HikaShop Connector API can do is reachable from the command line as well, with the same paths and the same content the [Connector API](/support/documentation?alias=hikashop-connector-api)page documents, through a single command:

```
php cli/joomla.php hikashop:api GET products --query="limit=5&search=shirt"
php cli/joomla.php hikashop:api PUT products/12 --data='{"name":"New name"}'
wp hikashop api POST orders/44/status --data='{"status":"shipped"}'
```

The body can also be read from a file, or from the output of another program, with `--data-file=<file>` or `--data-file=-` for the standard input.

### Examples

```
# The products lowest on stock
php cli/joomla.php hikashop:product:lowstock --threshold=3

# Every order id waiting to be confirmed, one per line, for a script to loop over
wp hikashop order list --status=created --format=ids

# Create a product and give it a price
php cli/joomla.php hikashop:product:create --name="Blue mug" --code=MUG-BLUE --quantity=40 --published
php cli/joomla.php hikashop:product:price 812 --value=12.50

# Mark an order shipped and tell the customer
wp hikashop order status 44 shipped --notify

# After restoring a backup
php cli/joomla.php hikashop:dbcheck
```

### Running it from a cron

The scheduled tasks of your shop can be run from your server's own scheduler, which is more reliable than waiting for a visitor to open a page:

```
0 * * * * cd /path/to/your/site && php cli/joomla.php hikashop:cron:run --live-site=https://www.example.com

0 * * * * wp --path=/path/to/your/site hikashop cron run
```

The older `cli/hikashop_cron.php` script still works and does the same thing, so a cron entry that already uses it does not need changing.

##  [ Connector API ](/support/documentation/542-hikashop-connector-api)

Details    Written by: jobsigen    Category: [Developer area](/support/documentation/hikashop/developer-area)     Published: 01 September 2026     Hits: 826

# HikaShop Connector API

https://your-shop.tld/hikashop-api/v1   Version  6.7.0  (current)    [YAML](https://www.hikashop.com/images/doc/hk/api/connector-api-6.7.0.yaml "OpenAPI 3.1, YAML") [JSON](https://www.hikashop.com/images/doc/hk/api/connector-api-6.7.0.json "OpenAPI 3.1, JSON") [MARKDOWN](https://www.hikashop.com/images/doc/hk/api/connector-api-6.7.0.md "One flat file, for an assistant")

## Overview

The connector plugin ships inside HikaShop Business and answers JSON over HTTPS. The mobile application is one client of it; anything it does, your own code can do.

Every response carries the same envelope, `{"data": …, "meta": …, "error": null}`, and every route except `POST /pair` carries a device token as `Authorization: Bearer <token>`. A token holds the scopes `read` and optionally `write`, and the operator it is bound to keeps their own access levels, so a device may hold `write` and still be refused an order its operator cannot see.

The base path is a plugin parameter and a shop can move it. Nothing else here changes between shops.

```
{
  <span class="k">"data"</span>: { … },
  <span class="k">"meta"</span>: <span class="n">null</span>,
  <span class="k">"error"</span>: <span class="n">null</span>
}
```

## Pairing a device

A client never sees the merchant's password. It is given a **pairing code** instead, generated in **System &gt; App Devices** of the backend, and exchanges it once for a token of its own.

The code is nine characters, lives five minutes, may be tried five times before it dies, and can only be spent once. `POST /pair` is rate limited to thirty attempts per minute per address, which is the only route that answers without a token.

What comes back is the token, the scopes the code granted, and the id of the device row. The token is shown once and stored only as a SHA-256 hash, so a device that loses it pairs again rather than recovering it. Revoking a device is deleting its row in that same screen, and every token it held stops working at once.

```
curl -X POST "$SHOP/hikashop-api/v1/pair" \
  -H "Content-Type: application/json" \
  -d '{ "code": "K7QM-2F84", "device_name": "Counter tablet" }'

# then, for everything else
curl "$SHOP/hikashop-api/v1/products" \
  -H "Authorization: Bearer $TOKEN"
```

## Scopes and access levels

Two separate checks run on every request, and the narrower one wins.

The **scope** is what the device may do at all: `read`, and `write` if the pairing code granted it. A device without `write` is refused every route that changes anything, whoever holds it.

The **access levels** are the shop's own, belonging to the operator the device is bound to. They decide which records that person may see and change, exactly as they do in the backend. So a device holding `write` can still be refused an order, and a device holding only `read` sees a smaller catalogue than another one.

This is why an integration should be given its own device rather than borrowing one: revoke it and nothing else is disturbed, and its operator's access levels are the ceiling on what it can reach.

```
{
  "data": null,
  "error": {
    "code": "forbidden",
    "message": "This device does not have the required scope."
  }
}
```

## The envelope, errors and paging

Every JSON answer has the same three keys. `data` is the payload, `meta` carries paging and other context when there is any and is `null` otherwise, and `error` is `null` on success.

On failure `data` is `null` and `error` holds a stable `code` and a human `message`. Read the code, not the message: the message is written for a person and may be translated or reworded, the code is what your own logic should branch on.

Listings page with `start` and `limit` in the query, and answer with `start`, `limit` and `total` in the envelope's `meta`. `total` counts the rows matching the filter before paging, so it is how you know there is another page. `limit` is capped, usually at a hundred, and asking for more silently gets you the cap rather than an error.

One thing to note about a listing: `data` is the list itself, not an object wrapping it. The paging lives in `meta`.

### Codes every route can return

CodeHTTPMeans

invalid\_request400A required field is missing or malformed.

unauthorized401No token, or a token that is unknown, revoked or unpublished.

forbidden403The device lacks the scope, or the operator lacks the access level.

not\_found404No such record, or no such route. Also returned when the operator may not see the record, so that it cannot be probed for.

too\_many\_requests429Rate limited. Only /pair does this.

```
{
  "data": [ … ],
  "meta": { "start": 0, "limit": 20, "total": 307 },
  "error": null
}
```

## Calling it from a browser

The API answers cross-origin requests, because the application is a web application as well as a phone one. `Access-Control-Allow-Origin` is `*`, the allowed methods are GET, POST, PUT, DELETE and OPTIONS, and the allowed headers are `Authorization`, `Content-Type` and `X-Hikashop-Token`. A preflight is answered immediately and may be cached for a day.

`*` with a bearer token is deliberate and safe in the way cookies would not be: nothing is sent automatically by the browser, so a page on another origin can only call this API if it already holds a token, and a token is only ever obtained by pairing.

Send the token in the `Authorization` header. Never put it in the query string, where it would be written to every access log between you and the shop.

```
OPTIONS /hikashop-api/v1/products

Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Headers: Authorization, Content-Type, X-Hikashop-Token
Access-Control-Max-Age: 86400
```

## Adding information and settings to customers, orders and products

Since 6.7.0, a plugin can add to the records the connector already serves, rather than serving a path of its own: something to **show** on a customer, an order or a product, and settings to **edit** there. A client draws both without knowing the plugin exists, so an add-on reaches the mobile application, a helpdesk or your own code with no work on their side.

The detail of a customer, an order or a product carries two lists, empty when no plugin answers:

\- `sections`, information to display. A section has a `key` (namespace it with your plugin's name), a `title` and `rows`. A row has a `label` and a `value` already formatted for display (the shop knows the currency, the date format and the language; the client does not), and optionally a `url`, a `badge` (`text` and a `tone`: `neutral`, `success`, `warning` or `danger`) and a `ref` to another record (`type` `customer`, `order` or `product`, and its `id`). - `extensions`, groups of settings. A group has a `key`, a `title` and `fields`, each described like the shop's own custom fields (`namekey`, `type`, `label`, `required`, `options`...) plus its current `value`, a string. The types are `text`, `textarea`, `number`, `email`, `url`, `boolean`, `singledropdown`, `multipledropdown`, `radio`, `checkbox`, `date`, `datetime` and `wysiwyg`; anything else is dropped, so a plugin cannot hand a client something it cannot draw. A client that does not know a type shows a text input, which is why `boolean` also carries yes/no options. A field may be `readonly`.

To save, send `extensions` with the record's usual save (`PUT /customers/{id}`, `PUT /products/{id}`, `PUT /orders/{id}/fields`) as `{ "group key": { "namekey": "value" } }`. The record's own fields are saved first, then each group, and each plugin only receives its own group's values, for the fields it declared. A plugin refusing a value answers per field, and the route returns `invalid_extensions` with those messages in `error.details`, keyed by group and then field.

Three events, each given one object by reference: `onConnectorElementSections` and `onConnectorElementForm` carry `type`, `id` and `device`, and your plugin appends to `sections` or `groups`; `onConnectorElementSave` also carries `group` and `values`, and your plugin fills `errors` (namekey =&gt; message) when it refuses something. Check `type` first: every plugin hears every record.

```
public function onConnectorElementSections(&$ctx) {
    if ($ctx->type !== 'product' || !$this->isAuction($ctx->id))
        return;
    $ctx->sections[] = array('key' => 'auction.bids', 'title' => 'Bids', 'rows' => array(
        array('label' => 'Highest bid', 'value' => '120.00 EUR'),
        array('label' => 'Ends', 'value' => '3 October 2026 18:00',
            'badge' => array('text' => 'ending soon', 'tone' => 'warning')),
    ));
}

public function onConnectorElementForm(&$ctx) {
    if ($ctx->type !== 'product')
        return;
    $ctx->groups[] = array('key' => 'auction', 'title' => 'Auction', 'fields' => array(
        array('namekey' => 'auction_end', 'type' => 'datetime', 'label' => 'Ends',
            'required' => true, 'value' => $this->endOf($ctx->id)),
        array('namekey' => 'auction_reserve', 'type' => 'number', 'label' => 'Reserve price',
            'value' => $this->reserveOf($ctx->id)),
    ));
}

public function onConnectorElementSave(&$ctx) {
    if ($ctx->type !== 'product' || $ctx->group !== 'auction')
        return;
    if (isset($ctx->values['auction_reserve']) && $ctx->values['auction_reserve'] < 0)
        $ctx->errors['auction_reserve'] = 'The reserve cannot be negative.';
    else
        $this->store($ctx->id, $ctx->values);
}
```

## Adding your own routes

A HikaShop plugin can serve paths of its own through the same base path, the same envelope and the same authentication, by listening to three events.

`onConnectorBeforeRoute` fires before any matching, so it can intercept a path the connector also serves. `onConnectorRoute` fires only when nothing matched, which is where a new path belongs. `onConnectorBeforeResponse` fires just before the JSON is written, for adding a field to an answer somebody else built.

The listener receives one object by reference, carrying `path` (the part after the base path), `method`, `base_path`, `response`, and `handled`. Authenticate with `requireScope()` exactly as the connector's own routes do, answer through `$ctx->response`, and set `$ctx->handled = true` so the router stops rather than falling through to its 404.

```
public function onConnectorRoute(&$ctx) {
    if ($ctx->path !== 'warehouse/stock' || $ctx->method !== 'GET')
        return;

    $device = HikashopConnectorAuth::requireScope($ctx->response, 'read');
    if ($device === null)
        return;          // it has already answered 401 or 403

    $ctx->response->data(array('pallets' => $this->countPallets()));
    $ctx->handled = true;
}
```

## What this shop is

GET /site read since 6.6.0

The first call a client makes. It says what it has connected to, who it is connected as, and what that operator is allowed to do, which is enough to draw an interface without asking for anything it will only be refused.

Nothing here changes often. Cache it, and use `GET /version` to know when to look again.

### Response expand all

FieldTypeDescription

appstringAlways `hikashop-connector`. A cheap way to be sure you are talking to this API and not to something else answering on that path.

api\_versionstringSemver of the API itself, not of HikaShop. A minor bump adds fields or routes, a major one breaks something.

site\_namestringWhat the site calls itself, which is what a merchant recognises the shop by.

hikashop\_versionstring\|nullThe HikaShop release running there.

cmsobjectWhat it is running on.nameboolean`joomla` or `wordpress`.

versionstring\|nullThe CMS release.

editionstring`starter`, `essential` or `business`. This API only answers on Business, so in practice it is `business` unless the licence has lapsed.

logostringThe shop's logo as an absolute URL, empty when none is set. The same setting the invoices use.

currencyobjectThe shop's money.defaultintegerThe currency id, a row in the shop's own table, not an ISO code.

price\_with\_taxbooleanWhether prices are shown to customers with tax included. Display only: the prices in this API are as stored.

operatorobjectThe user the device is bound to.idinteger`0` when the device is bound to nobody, which is a device paired without an operator.

namestring\|nullTheir display name.

rolestring`admin` when they may manage the component, `staff` otherwise.

scopesstring\[\]What this device may do: `read`, and `write` when it was granted.

permissionsobjectWhat the operator's access levels allow, keyed by resource (`product`, `order`, `category`, `discount`, `user`, `zone`, `characteristic`, `massaction`, `dashboard`), each with `view`, `manage` and `delete`. Use it to leave controls out rather than showing a screen full of refusals. Its keys are the resources this HikaShop knows about, so an add-on can add one.

capabilitiesobjectWhat this shop can do beyond the basics.posbooleanReserved for the point of sale, false for now.

pushbooleanReserved for push notifications, false for now.

multivendorbooleanWhether HikaMarket is installed.

```
curl "$SHOP/hikashop-api/v1/site" \
  -H "Authorization: Bearer $TOKEN"
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"app"</span>: <span class="s">"hikashop-connector"</span>,
        <span class="k">"api_version"</span>: <span class="s">"1.0.0"</span>,
        <span class="k">"site_name"</span>: <span class="s">"HikaShop Test"</span>,
        <span class="k">"hikashop_version"</span>: <span class="s">"6.6.0"</span>,
        <span class="k">"cms"</span>: {
            <span class="k">"name"</span>: <span class="s">"joomla"</span>,
            <span class="k">"version"</span>: <span class="s">"6.1.1"</span>
        },
        <span class="k">"edition"</span>: <span class="s">"essential"</span>,
        <span class="k">"logo"</span>: <span class="s">""</span>,
        <span class="k">"currency"</span>: {
            <span class="k">"default"</span>: <span class="n">1</span>
        },
        <span class="k">"price_with_tax"</span>: <span class="n">true</span>,
        <span class="k">"operator"</span>: {
            <span class="k">"id"</span>: <span class="n">0</span>,
            <span class="k">"name"</span>: <span class="n">null</span>,
            <span class="k">"role"</span>: <span class="s">"staff"</span>
        },
        <span class="k">"scopes"</span>: [
            "read",
            "write"
        ],
        <span class="k">"permissions"</span>: {
            <span class="k">"category"</span>: {
                <span class="k">"view"</span>: <span class="n">true</span>,
                <span class="k">"manage"</span>: <span class="n">true</span>,
                <span class="k">"delete"</span>: <span class="n">true</span>
            },
            <span class="k">"characteristic"</span>: {
                <span class="k">"view"</span>: <span class="n">true</span>,
                <span class="k">"manage"</span>: <span class="n">true</span>,
                <span class="k">"delete"</span>: <span class="n">true</span>
            },
            <span class="k">"product"</span>: {
                <span class="k">"view"</span>: <span class="n">true</span>,
                <span class="k">"manage"</span>: <span class="n">true</span>,
                <span class="k">"delete"</span>: <span class="n">true</span>
            },
            <span class="k">"order"</span>: {
                <span class="k">"view"</span>: <span class="n">true</span>,
                <span class="k">"manage"</span>: <span class="n">true</span>,
                <span class="k">"delete"</span>: <span class="n">true</span>
            },
            <span class="k">"discount"</span>: {
                <span class="k">"view"</span>: <span class="n">true</span>,
                <span class="k">"manage"</span>: <span class="n">true</span>,
                <span class="k">"delete"</span>: <span class="n">true</span>
            },
            <span class="k">"user"</span>: {
                <span class="k">"view"</span>: <span class="n">true</span>,
                <span class="k">"manage"</span>: <span class="n">true</span>,
                <span class="k">"delete"</span>: <span class="n">true</span>
            },
            <span class="k">"zone"</span>: {
                <span class="k">"view"</span>: <span class="n">true</span>,
                <span class="k">"manage"</span>: <span class="n">true</span>,
                <span class="k">"delete"</span>: <span class="n">true</span>
            },
            <span class="k">"dashboard"</span>: {
                <span class="k">"view"</span>: <span class="n">true</span>,
                <span class="k">"manage"</span>: <span class="n">true</span>,
                <span class="k">"delete"</span>: <span class="n">true</span>
            },
            <span class="k">"massaction"</span>: {
                <span class="k">"view"</span>: <span class="n">true</span>,
                <span class="k">"manage"</span>: <span class="n">true</span>,
                <span class="k">"delete"</span>: <span class="n">true</span>
            }
        },
        <span class="k">"capabilities"</span>: {
            <span class="k">"pos"</span>: <span class="n">false</span>,
            <span class="k">"push"</span>: <span class="n">false</span>,
            <span class="k">"multivendor"</span>: <span class="n">false</span>
        }
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## The settings that decide how prices read

GET /settings read since 6.6.0

The handful of configuration flags a client needs in order to show the same figures the shop's own pages show. They are read only here; they are changed in the backend.

### Response expand all

FieldTypeDescription

product\_contactbooleanWhether products can be enquired about rather than bought.

product\_waitlistbooleanWhether customers can join a waiting list for something out of stock.

price\_with\_taxbooleanShow prices with tax included.

floating\_tax\_pricesbooleanWhether the tax shown depends on the customer, which means a price cannot be cached across customers.

show\_original\_pricebooleanShow the price before a discount alongside the discounted one.

round\_calculationsintegerWhen rounding happens during a calculation. Match it or your totals will differ from the shop by a cent.

```
curl "$SHOP/hikashop-api/v1/settings" \
  -H "Authorization: Bearer $TOKEN"
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"product_contact"</span>: <span class="n">false</span>,
        <span class="k">"product_waitlist"</span>: <span class="n">false</span>,
        <span class="k">"price_with_tax"</span>: <span class="n">true</span>,
        <span class="k">"floating_tax_prices"</span>: <span class="n">false</span>,
        <span class="k">"show_original_price"</span>: <span class="n">false</span>,
        <span class="k">"round_calculations"</span>: <span class="n">0</span>
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## Change tokens for the cacheable resources

GET /version read since 6.6.0

Three opaque tokens, one for each resource worth caching. A token changes when its resource does, so a client keeps the copy it has until the token moves.

Compare them, do not read them. They are strings today and their meaning is deliberately not part of this contract.

This is what makes a dictionary of several thousand strings affordable: fetch it once, ask this cheap route afterwards.

### Response expand all

FieldTypeDescription

i18nstringMoves when the shop's translations change.

statusesstringMoves when an order status is added, renamed or unpublished.

languagesstringMoves when the shop's languages change.

```
curl "$SHOP/hikashop-api/v1/version" \
  -H "Authorization: Bearer $TOKEN"
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"i18n"</span>: <span class="s">"1790620910"</span>,
        <span class="k">"statuses"</span>: <span class="s">"1834471105"</span>,
        <span class="k">"languages"</span>: <span class="s">"1820052638"</span>
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## The shop's order statuses

GET /statuses read since 6.6.0

Every published order status, in the order the backend shows them. A shop invents its own, so this list is not a fixed set and should never be hard coded.

The `namekey` is the identifier to send to `POST /orders/{id}/status`; the `name` is for a person to read.

### Response a list expand all

FieldTypeDescription

namekeystringThe identifier. This is what you send when changing an order.

namestringTranslated into the operator's language, ready to display.

label\_keystringThe translation key behind that name, if you would rather translate it yourself.

colorstringThe colour the backend uses for this status, empty when none is set.

```
curl "$SHOP/hikashop-api/v1/statuses" \
  -H "Authorization: Bearer $TOKEN"
```

```
{
    <span class="k">"data"</span>: [
        {
            <span class="k">"namekey"</span>: <span class="s">"created"</span>,
            <span class="k">"name"</span>: <span class="s">"created"</span>,
            <span class="k">"label_key"</span>: <span class="s">"ORDER_STATUS_CREATED"</span>,
            <span class="k">"color"</span>: <span class="s">""</span>
        },
        {
            <span class="k">"namekey"</span>: <span class="s">"confirmed"</span>,
            <span class="k">"name"</span>: <span class="s">"confirmed"</span>,
            <span class="k">"label_key"</span>: <span class="s">"ORDER_STATUS_CONFIRMED"</span>,
            <span class="k">"color"</span>: <span class="s">""</span>
        },
        {
            <span class="k">"namekey"</span>: <span class="s">"cancelled"</span>,
            <span class="k">"name"</span>: <span class="s">"cancelled"</span>,
            <span class="k">"label_key"</span>: <span class="s">"ORDER_STATUS_CANCELLED"</span>,
            <span class="k">"color"</span>: <span class="s">""</span>
        },
        {
            <span class="k">"namekey"</span>: <span class="s">"refunded"</span>,
            <span class="k">"name"</span>: <span class="s">"refunded"</span>,
            <span class="k">"label_key"</span>: <span class="s">"ORDER_STATUS_REFUNDED"</span>,
            <span class="k">"color"</span>: <span class="s">""</span>
        },
        "… 4 more, trimmed for the example"
    ],
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## HikaShop's own translation of a locale

GET /i18n read since 6.6.0

The shop's translation dictionary for one locale, so that a client can name things exactly as the merchant's own site names them, including whatever they have overridden.

It is large. Cache it against the `i18n` token from `GET /version` rather than fetching it again.

### Query

ParameterTypeDescription

localestringA HikaShop language tag such as `en-GB`. Falls back to the site language when it is not installed.

### Response expand all

FieldTypeDescription

localestringThe locale actually served, which may not be the one asked for.

stringsobjectTranslation key to translated text. Thousands of keys, and a shop can add or override any of them, so there is no list to give.

```
curl "$SHOP/hikashop-api/v1/i{id}n?locale=en-GB" \
  -H "Authorization: Bearer $TOKEN"
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"locale"</span>: <span class="s">"en-GB"</span>,
        <span class="k">"strings"</span>: {
            <span class="k">"PRICE_BEGINNING"</span>: <span class="s">""</span>,
            <span class="k">"PRICE_BEFORE_ORIG"</span>: <span class="s">" ("</span>,
            <span class="k">"PRICE_AFTER_ORIG"</span>: <span class="s">") "</span>,
            <span class="k">"PRICE_DISCOUNT_START"</span>: <span class="s">""</span>,
            <span class="k">"PRICE_DISCOUNT_END"</span>: <span class="s">""</span>,
            <span class="k">"PRICE_BEFORE_TAX"</span>: <span class="s">" ("</span>,
            <span class="k">"PRICE_AFTER_TAX"</span>: <span class="s">" excl VAT) "</span>,
            <span class="k">"PRICE_END"</span>: <span class="s">""</span>,
            <span class="k">"FREE_PRICE"</span>: <span class="s">"Free"</span>,
            <span class="k">"PRICE_SEPARATOR"</span>: <span class="s">"<br/>"</span>,
            <span class="k">"PER_UNIT_AT_LEAST_X_BOUGHT"</span>: <span class="s">" per unit for buying at least %s"</span>,
            <span class="k">"PER_UNIT"</span>: <span class="s">" each"</span>,
            <span class="k">"ITEM_NOT_SOLD_ANYMORE"</span>: <span class="s">"Item not sold anymore"</span>,
            <span class="k">"ITEM_SOLD_ON_DATE"</span>: <span class="s">"This item will be sold starting on %s"</span>,
            <span class="k">"ADD_TO_CART"</span>: <span class="s">"Add to cart"</span>,
            <span class="k">"NO_STOCK"</span>: <span class="s">"No stock"</span>,
            <span class="k">"X_ITEMS_IN_STOCK"</span>: <span class="s">"%s items in stock"</span>,
            <span class="k">"SPECIFICATIONS"</span>: <span class="s">"Specifications"</span>,
            <span class="k">"REFRESH_INFORMATION"</span>: <span class="s">"Refresh information"</span>,
            <span class="k">"NO_VALUES_FOUND"</span>: <span class="s">"No values found"</span>,
            <span class="k">"PRODUCT"</span>: <span class="s">"Product"</span>,
            <span class="k">"CART_PRODUCT_NAME"</span>: <span class="s">"Name"</span>,
            <span class="k">"CART_PRODUCT_QUANTITY"</span>: <span class="s">"Qty"</span>,
            <span class="k">"CART_PRODUCT_PRICE"</span>: <span class="s">"Price"</span>,
            <span class="k">"CART_PRODUCT_UNIT_PRICE"</span>: <span class="s">"Unit price"</span>,
            <span class="k">"CART_PRODUCT_TOTAL_PRICE"</span>: <span class="s">"Total price"</span>,
            <span class="k">"CART_EMPTY"</span>: <span class="s">"The cart is empty"</span>,
            <span class="k">"HIKASHOP_TOTAL"</span>: <span class="s">"Total"</span>,
            <span class="k">"HIKASHOP_FINAL_TOTAL"</span>: <span class="s">"Final total"</span>,
            <span class="k">"PROCEED_TO_CHECKOUT"</span>: <span class="s">"Proceed to checkout"</span>,
            <span class="k">"REFRESH_CART"</span>: <span class="s">"Refresh cart"</span>,
            <span class="k">"PRODUCT_NOT_AVAILABLE"</span>: <span class="s">"The product %s is not available"</span>,
            <span class="k">"NOT_ENOUGH_STOCK_FOR_PRODUCT"</span>: <span class="s">"There is not enough stock for the product %s"</span>,
            <span class="k">"PRODUCT_NOT_YET_ON_SALE"</span>: <span class="s">"The product %s is not yet on sale"</span>,
            <span class="k">"PRODUCT_NOT_SOLD_ANYMORE"</span>: <span class="s">"The product %s is no longer on sale"</span>,
            <span class="k">"PRODUCT_SUCCESSFULLY_ADDED_TO_CART"</span>: <span class="s">"Product successfully added to the cart"</span>,
            <span class="k">"HIKASHOP_CHECKOUT_CART"</span>: <span class="s">"Cart"</span>,
            <span class="k">"HIKASHOP_CHECKOUT_CONFIRM"</span>: <span class="s">"Confirm"</span>,
            <span class="k">"HIKASHOP_CHECKOUT_STATUS"</span>: <span class="s">"Status"</span>,
            <span class="k">"HIKASHOP_CHECKOUT_SHIPPING"</span>: <span class="s">"Shipping"</span>,
            <span class="k">"HIKASHOP_CHECKOUT_PAYMENT"</span>: <span class="s">"Payment"</span>,
            <span class="k">"HIKASHOP_CHECKOUT_END"</span>: <span class="s">"End"</span>,
            <span class="k">"HIKASHOP_CHECKOUT_COUPON"</span>: <span class="s">"Coupon"</span>,
            <span class="k">"HIKASHOP_CHECKOUT_LOGIN"</span>: <span class="s">"Login"</span>,
            <span class="k">"HIKASHOP_CHECKOUT_ADDRESS"</span>: <span class="s">"Address"</span>,
            <span class="k">"NEXT"</span>: <span class="s">"Next"</span>,
            <span class="k">"CONTINUE_SHOPPING"</span>: <span class="s">"Continue shopping"</span>,
            <span class="k">"THANK_YOU_FOR_PURCHASE"</span>: <span class="s">"Thank you for your purchase."</span>,
            <span class="k">"ORDER_IS_COMPLETE"</span>: <span class="s">"Your order is now complete."</span>,
            <span class="k">"CURRENCY_NOT_ACCEPTED_FOR_PAYMENT"</span>: <span class="s">"The currency you selected is not accepted for payments"</span>,
            <span class="k">"PLEASE_ACCEPT_TERMS_BEFORE_FINISHING_ORDER"</span>: <span class="s">"Please accept the Terms and Conditions before proceeding"</span>,
            <span class="k">"PLEASE_ACCEPT_TERMS"</span>: <span class="s">"Please accept the Terms and Conditions before proceeding"</span>,
            <span class="k">"ADDITIONAL_INFORMATION"</span>: <span class="s">"Additional information"</span>,
            <span class="k">"LOGIN_OR_REGISTER_ACCOUNT"</span>: <span class="s">"Login or create a new account"</span>,
            <span class="k">"REGISTRATION_NOT_ALLOWED"</span>: <span class="s">"Registration not allowed"</span>,
            <span class="k">"WHEN_CLICKING_ACTIVATION"</span>: <span class="s">"Upon clicking on the activation link, your account will be activated and you will be able to continue your order"</span>,
            <span class="k">"PASSWORDS_DO_NOT_MATCH"</span>: <span class="s">"Passwords do not match"</span>,
            <span class="k">"VALID_EMAIL"</span>: <span class="s">"Please enter a valid e-mail address"</span>,
            <span class="k">"CREATE_OR_SELECT_ADDRESS"</span>: <span class="s">"Please create or select an address"</span>,
            <span class="k">"SAME_AS_BILLING"</span>: <span class="s">"Use the same address as for billing"</span>,
            <span class="k">"…"</span>: <span class="s">"4831 more keys, trimmed for the example"</span>
        }
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## The shop's languages

GET /languages read since 6.6.0

Which languages the shop publishes, and whether content translation is switched on at all.

When `enabled` is false the shop is single-language and the translation routes have nothing to do. The default language is marked and comes last, because it is the one already being edited on the main form rather than a translation of it.

### Response expand all

FieldTypeDescription

enabledbooleanWhether this shop translates its content. False on a single-language site.

languagesobject\[\]The published languages.idintegerThe language id in the shop's table.

codestringThe tag, such as `fr-FR`.

shortcodestringThe lower-case underscored form, such as `fr_fr`, which is what the translation tables key on.

site\_defaultbooleanTrue for the language the shop is written in. Its text is the original, not a translation.

```
curl "$SHOP/hikashop-api/v1/languages" \
  -H "Authorization: Bearer $TOKEN"
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"enabled"</span>: <span class="n">true</span>,
        <span class="k">"languages"</span>: [
            {
                <span class="k">"id"</span>: <span class="n">2</span>,
                <span class="k">"code"</span>: <span class="s">"fr-FR"</span>,
                <span class="k">"shortcode"</span>: <span class="s">"fr_fr"</span>,
                <span class="k">"site_default"</span>: <span class="n">false</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">1</span>,
                <span class="k">"code"</span>: <span class="s">"en-GB"</span>,
                <span class="k">"shortcode"</span>: <span class="s">"en_gb"</span>,
                <span class="k">"site_default"</span>: <span class="n">true</span>
            }
        ]
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## Read one product

GET /products/**{id}** read since 6.6.0

Everything the product editor needs in one call: the record, its prices, its images and files, its categories, its characteristics and variants, and the definitions of the custom fields that apply to it.

Ask for a variant's id and you get the variant, with `parent_id` set. A parent's `variants` are listed in full, so you rarely need to.

### Path

ParameterTypeDescription

idrequiredintegerA parent product or a variant.

### Response expand all

FieldTypeDescription

idinteger

namestring

codestringThe SKU. Unique within the shop.

descriptionstringThe long description, as HTML.

description\_typestringWhich editor the description was written with.

publishedboolean

quantityinteger`-1` when this product does not track stock, which is not the same as `0`.

msrpnumberThe manufacturer's suggested price, shown struck through when the shop is configured to.

gtinstringThe barcode: EAN, UPC or ISBN. This is what `GET /products/lookup` matches on.

conditionstringNew, used, refurbished. Used by the feeds rather than by the shop itself.

weightnumberShipping weight, in `weight_unit`.

weight\_unitstring`kg`, `g`, `lb` or `oz`.

widthnumberIn `dimension_unit`.

heightnumberIn `dimension_unit`.

lengthnumberIn `dimension_unit`.

dimension\_unitstring`m`, `cm`, `mm`, `ft` or `in`.

min\_per\_orderintegerThe smallest quantity a customer may order, `0` for no minimum.

max\_per\_orderintegerThe largest, `0` for no maximum.

sale\_startinteger\|nullUnix timestamp before which the product is not on sale.

sale\_endinteger\|nullUnix timestamp after which it is no longer sold.

page\_titlestringSEO title, empty to use the name.

meta\_descriptionstringSEO description.

keywordsstringSEO keywords.

canonicalstringA canonical URL, when this page should point at another.

urlstringThe address of the product page on the shop.

aliasstringThe slug used in that address.

accessobjectWho may see the product: `mode` (`all`, `none` or `groups`) and `groups`, which are user \*\*group\*\* ids and not Joomla view levels. The two id spaces overlap and disagree, so a value that looks plausible can grant the wrong audience.modestring`all`, `none`, or `groups` when it is restricted to some.

groupsinteger\[\]User group ids, meaningful only when the mode is `groups`.

contactbooleanWhether this product is enquired about rather than bought.

warehouse\_idintegerThe warehouse holding the stock, `0` when the shop has none.

typestring`main` for a product, `variant` for one of its variants.

parent\_idintegerThe parent product when this is a variant, `0` otherwise.

value\_idsinteger\[\]For a variant, the characteristic values it stands for.

manufacturer\_idintegerThe brand, `0` when unset.

manufacturer\_namestringIts name, saving a second call.

tax\_idintegerThe tax category, `0` when the product is untaxed.

tax\_namestringIts name.

tax\_ratenumberThe rate as a fraction, so `0.2` is twenty percent.

pricesobject\[\]Every price row, including the restricted ones. A product with none is not sellable.idinteger

valuenumberTax excluded, as stored.

currency\_idinteger

min\_quantityintegerFrom how many items this row applies, which is how quantity breaks are expressed.

accessobjectWho this price is for, in the same shape as the product access.modestringAs above.

groupsinteger\[\]As above.

usersinteger\[\]Named customers, empty for everyone.

zone\_idsinteger\[\]Zones this price applies in, empty for everywhere.

start\_dateinteger\|nullUnix timestamp.

end\_dateinteger\|nullUnix timestamp.

imagesobject\[\]In the order the editor shows them; the first is the main image.idinteger

namestring

pathstringRelative to the upload folder.

urlstringAbsolute, ready to display.

orderinginteger

descriptionstringThe alt text.

accessobjectWho may see it.modestringAs above.

groupsinteger\[\]As above.

free\_downloadbooleanFiles only; meaningless on an image.

filesobject\[\]Downloadable files, in the same shape as the images.idinteger

namestring

pathstringRelative to the upload folder.

urlstringAbsolute.

orderinginteger

descriptionstring

accessobjectWho may download it.

free\_downloadbooleanWhether it can be downloaded without buying the product.

categoriesobject\[\]The categories the product is in.idinteger

namestring

bundleobject\[\]The products this one is made of, when it is a bundle.idinteger

namestring

codestring

quantityintegerHow many of it the bundle contains.

optionsobject\[\]Products offered as options alongside this one.idinteger

namestring

codestring

quantityinteger

relatedobject\[\]Products shown as related.idinteger

namestring

codestring

quantityinteger

tagsinteger\[\]CMS tag ids.

characteristicsobject\[\]The characteristics this product varies on. Empty when it has no variants.idintegerThe characteristic, such as Size.

namestringIts name.

valuesobject\[\]The values of it this product uses, such as S, M and L.idintegerThe value id, which is what a variant refers to.

valuestringIts name, such as `M`.

variantsobject\[\]Every variant, with its own code, stock, price and images. Empty for a product that does not vary.idintegerThe variant is a product in its own right, and this is its id.

codestringIts own SKU.

quantityintegerIts own stock. This is the figure to change, not the parent's.

publishedboolean

pricenumber\|null`null` when the variant has no price of its own and the parent's applies.

valuesobject\[\]Which characteristic values this variant stands for, one per characteristic.option\_idintegerThe characteristic.

option\_namestringIts name, so the variant can be labelled without a second call.

value\_idintegerThe value.

valuestringIts name.

imagesobject\[\]The variant's own images, in the same shape as the product's.idinteger

namestring

pathstringRelative to the upload folder.

urlstringAbsolute.

orderinginteger

fieldsobject\[\]The definitions of the custom fields that apply to this product, so a client can build a form for them.namekeystringThe key used in `custom_fields`.

typestring`text`, `radio`, `singledropdown`, `file`, and the rest of HikaShop's field types.

raw\_typestringHikaShop's own name for the type, before it is mapped to something a client can render.

labelstringTranslated into the operator's language.

defaultstringThe value used when none is given.

requiredbooleanWhether the shop refuses to save the product without it.

optionsobject\[\]The choices, for a field that has them. Empty for a free text one.

multiplebooleanWhether more than one choice may be selected.

translatablebooleanWhether its value can be translated, which is what the translation routes offer.

upload\_dirstringFor a file field, where its uploads are kept.

allowed\_extensionsstringFor a file field, the extensions it accepts, comma separated. Empty means the shop default.

date\_formatstringFor a date field, the format it is stored in.

custom\_fieldsobjectTheir values, keyed by namekey. The keys are whatever this shop has configured; `fields` in the same response says what they are.

custom\_field\_filesobjectFor custom fields holding a file, the file behind each value. Keyed the same way.

sectionsobject\[\]Information other plugins show on this record, each with a `key`, a `title` and `rows` (`label`, `value`, and optionally `url`, `badge` and `ref`). Empty when no plugin adds any; on a customer, core adds their paid downloads. See the guide on adding information and settings.

extensionsobject\[\]Settings other plugins keep on this record, in groups (`key`, `title`, `fields`), each field described like a custom field plus its current `value`. Send changes back as `extensions` with the record's save. Empty when no plugin adds any.

```
curl "$SHOP/hikashop-api/v1/products/{id}" \
  -H "Authorization: Bearer $TOKEN"
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"id"</span>: <span class="n">8661</span>,
        <span class="k">"name"</span>: <span class="s">"Full-Grain Sneakers"</span>,
        <span class="k">"code"</span>: <span class="s">"DEMO-0023"</span>,
        <span class="k">"description"</span>: <span class="s">"Our best-selling sneakers. Back in stock, and worth the wait."</span>,
        <span class="k">"description_type"</span>: <span class="s">""</span>,
        <span class="k">"published"</span>: <span class="n">true</span>,
        <span class="k">"quantity"</span>: <span class="n">0</span>,
        <span class="k">"msrp"</span>: <span class="n">0</span>,
        <span class="k">"gtin"</span>: <span class="s">""</span>,
        <span class="k">"condition"</span>: <span class="s">""</span>,
        <span class="k">"weight"</span>: <span class="n">0.213</span>,
        <span class="k">"weight_unit"</span>: <span class="s">"kg"</span>,
        <span class="k">"width"</span>: <span class="n">0</span>,
        <span class="k">"height"</span>: <span class="n">0</span>,
        <span class="k">"length"</span>: <span class="n">0</span>,
        <span class="k">"dimension_unit"</span>: <span class="s">"m"</span>,
        <span class="k">"min_per_order"</span>: <span class="n">0</span>,
        <span class="k">"max_per_order"</span>: <span class="n">0</span>,
        <span class="k">"sale_start"</span>: <span class="n">0</span>,
        <span class="k">"sale_end"</span>: <span class="n">0</span>,
        <span class="k">"page_title"</span>: <span class="s">""</span>,
        <span class="k">"meta_description"</span>: <span class="s">""</span>,
        <span class="k">"keywords"</span>: <span class="s">""</span>,
        <span class="k">"canonical"</span>: <span class="s">""</span>,
        <span class="k">"url"</span>: <span class="s">""</span>,
        <span class="k">"alias"</span>: <span class="s">""</span>,
        <span class="k">"access"</span>: {
            <span class="k">"mode"</span>: <span class="s">"all"</span>,
            <span class="k">"groups"</span>: []
        },
        <span class="k">"contact"</span>: <span class="n">false</span>,
        <span class="k">"warehouse_id"</span>: <span class="n">0</span>,
        <span class="k">"type"</span>: <span class="s">"main"</span>,
        <span class="k">"parent_id"</span>: <span class="n">0</span>,
        <span class="k">"value_ids"</span>: [],
        <span class="k">"manufacturer_id"</span>: <span class="n">0</span>,
        <span class="k">"manufacturer_name"</span>: <span class="s">""</span>,
        <span class="k">"tax_id"</span>: <span class="n">0</span>,
        <span class="k">"tax_name"</span>: <span class="s">""</span>,
        <span class="k">"tax_rate"</span>: <span class="n">0</span>,
        <span class="k">"prices"</span>: [
            {
                <span class="k">"id"</span>: <span class="n">4652</span>,
                <span class="k">"value"</span>: <span class="n">308.3</span>,
                <span class="k">"currency_id"</span>: <span class="n">1</span>,
                <span class="k">"min_quantity"</span>: <span class="n">0</span>,
                <span class="k">"access"</span>: {
                    <span class="k">"mode"</span>: <span class="s">"all"</span>,
                    <span class="k">"groups"</span>: []
                },
                <span class="k">"users"</span>: [],
                <span class="k">"zone_ids"</span>: [],
                <span class="k">"start_date"</span>: <span class="n">0</span>,
                <span class="k">"end_date"</span>: <span class="n">0</span>
            }
        ],
        <span class="k">"images"</span>: [
            {
                <span class="k">"id"</span>: <span class="n">7791</span>,
                <span class="k">"name"</span>: <span class="s">"Full-Grain Sneakers"</span>,
                <span class="k">"path"</span>: <span class="s">"demo-0023.png"</span>,
                <span class="k">"url"</span>: <span class="s">"http://localhost:<span class="n">8080</span>/joomla6_ext/images/com_hikashop/upload/demo-0023.png"</span>,
                <span class="k">"ordering"</span>: <span class="n">1</span>,
                <span class="k">"description"</span>: <span class="s">""</span>,
                <span class="k">"access"</span>: {
                    <span class="k">"mode"</span>: <span class="s">"all"</span>,
                    <span class="k">"groups"</span>: []
                },
                <span class="k">"free_download"</span>: <span class="n">false</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">7792</span>,
                <span class="k">"name"</span>: <span class="s">"Full-Grain Sneakers"</span>,
                <span class="k">"path"</span>: <span class="s">"demo-0023-2.png"</span>,
                <span class="k">"url"</span>: <span class="s">"http://localhost:<span class="n">8080</span>/joomla6_ext/images/com_hikashop/upload/demo-0023-2.png"</span>,
                <span class="k">"ordering"</span>: <span class="n">2</span>,
                <span class="k">"description"</span>: <span class="s">""</span>,
                <span class="k">"access"</span>: {
                    <span class="k">"mode"</span>: <span class="s">"all"</span>,
                    <span class="k">"groups"</span>: []
                },
                <span class="k">"free_download"</span>: <span class="n">false</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">7793</span>,
                <span class="k">"name"</span>: <span class="s">"Full-Grain Sneakers"</span>,
                <span class="k">"path"</span>: <span class="s">"demo-0023-3.png"</span>,
                <span class="k">"url"</span>: <span class="s">"http://localhost:<span class="n">8080</span>/joomla6_ext/images/com_hikashop/upload/demo-0023-3.png"</span>,
                <span class="k">"ordering"</span>: <span class="n">3</span>,
                <span class="k">"description"</span>: <span class="s">""</span>,
                <span class="k">"access"</span>: {
                    <span class="k">"mode"</span>: <span class="s">"all"</span>,
                    <span class="k">"groups"</span>: []
                },
                <span class="k">"free_download"</span>: <span class="n">false</span>
            }
        ],
        <span class="k">"files"</span>: [],
        <span class="k">"categories"</span>: [
            {
                <span class="k">"id"</span>: <span class="n">238</span>,
                <span class="k">"name"</span>: <span class="s">"Shoes"</span>
            }
        ],
        <span class="k">"bundle"</span>: [],
        <span class="k">"options"</span>: [],
        <span class="k">"related"</span>: [],
        <span class="k">"tags"</span>: [],
        <span class="k">"characteristics"</span>: [
            {
                <span class="k">"id"</span>: <span class="n">8</span>,
                <span class="k">"name"</span>: <span class="s">"Size"</span>,
                <span class="k">"values"</span>: [
                    {
                        <span class="k">"id"</span>: <span class="n">9</span>,
                        <span class="k">"value"</span>: <span class="s">"S"</span>
                    },
                    {
                        <span class="k">"id"</span>: <span class="n">10</span>,
                        <span class="k">"value"</span>: <span class="s">"L"</span>
                    },
                    {
                        <span class="k">"id"</span>: <span class="n">21</span>,
                        <span class="k">"value"</span>: <span class="s">"M"</span>
                    },
                    {
                        <span class="k">"id"</span>: <span class="n">35</span>,
                        <span class="k">"value"</span>: <span class="s">"XS"</span>
                    },
                    "… 1 more, trimmed for the example"
                ]
            }
        ],
        <span class="k">"variants"</span>: [
            {
                <span class="k">"id"</span>: <span class="n">8662</span>,
                <span class="k">"code"</span>: <span class="s">"DEMO-0023-XS"</span>,
                <span class="k">"quantity"</span>: <span class="n">1</span>,
                <span class="k">"published"</span>: <span class="n">true</span>,
                <span class="k">"price"</span>: <span class="n">null</span>,
                <span class="k">"values"</span>: [
                    {
                        <span class="k">"option_id"</span>: <span class="n">8</span>,
                        <span class="k">"option_name"</span>: <span class="s">"Size"</span>,
                        <span class="k">"value_id"</span>: <span class="n">35</span>,
                        <span class="k">"value"</span>: <span class="s">"XS"</span>
                    }
                ],
                <span class="k">"images"</span>: [
                    {
                        <span class="k">"id"</span>: <span class="n">7794</span>,
                        <span class="k">"name"</span>: <span class="s">"Full-Grain Sneakers — XS"</span>,
                        <span class="k">"path"</span>: <span class="s">"demo-0023-xs.png"</span>,
                        <span class="k">"url"</span>: <span class="s">"http://localhost:<span class="n">8080</span>/joomla6_ext/images/com_hikashop/upload/demo-0023-xs.png"</span>,
                        <span class="k">"ordering"</span>: <span class="n">1</span>
                    }
                ]
            },
            {
                <span class="k">"id"</span>: <span class="n">8663</span>,
                <span class="k">"code"</span>: <span class="s">"DEMO-0023-S"</span>,
                <span class="k">"quantity"</span>: <span class="n">23</span>,
                <span class="k">"published"</span>: <span class="n">true</span>,
                <span class="k">"price"</span>: <span class="n">null</span>,
                <span class="k">"values"</span>: [
                    {
                        <span class="k">"option_id"</span>: <span class="n">8</span>,
                        <span class="k">"option_name"</span>: <span class="s">"Size"</span>,
                        <span class="k">"value_id"</span>: <span class="n">9</span>,
                        <span class="k">"value"</span>: <span class="s">"S"</span>
                    }
                ],
                <span class="k">"images"</span>: [
                    {
                        <span class="k">"id"</span>: <span class="n">7795</span>,
                        <span class="k">"name"</span>: <span class="s">"Full-Grain Sneakers — S"</span>,
                        <span class="k">"path"</span>: <span class="s">"demo-0023-s.png"</span>,
                        <span class="k">"url"</span>: <span class="s">"http://localhost:<span class="n">8080</span>/joomla6_ext/images/com_hikashop/upload/demo-0023-s.png"</span>,
                        <span class="k">"ordering"</span>: <span class="n">1</span>
                    }
                ]
            },
            {
                <span class="k">"id"</span>: <span class="n">8664</span>,
                <span class="k">"code"</span>: <span class="s">"DEMO-0023-M"</span>,
                <span class="k">"quantity"</span>: <span class="n">40</span>,
                <span class="k">"published"</span>: <span class="n">true</span>,
                <span class="k">"price"</span>: <span class="n">null</span>,
                <span class="k">"values"</span>: [
                    {
                        <span class="k">"option_id"</span>: <span class="n">8</span>,
                        <span class="k">"option_name"</span>: <span class="s">"Size"</span>,
                        <span class="k">"value_id"</span>: <span class="n">21</span>,
                        <span class="k">"value"</span>: <span class="s">"M"</span>
                    }
                ],
                <span class="k">"images"</span>: [
                    {
                        <span class="k">"id"</span>: <span class="n">7796</span>,
                        <span class="k">"name"</span>: <span class="s">"Full-Grain Sneakers — M"</span>,
                        <span class="k">"path"</span>: <span class="s">"demo-0023-m.png"</span>,
                        <span class="k">"url"</span>: <span class="s">"http://localhost:<span class="n">8080</span>/joomla6_ext/images/com_hikashop/upload/demo-0023-m.png"</span>,
                        <span class="k">"ordering"</span>: <span class="n">1</span>
                    }
                ]
            },
            {
                <span class="k">"id"</span>: <span class="n">8665</span>,
                <span class="k">"code"</span>: <span class="s">"DEMO-0023-L"</span>,
                <span class="k">"quantity"</span>: <span class="n">38</span>,
                <span class="k">"published"</span>: <span class="n">true</span>,
                <span class="k">"price"</span>: <span class="n">null</span>,
                <span class="k">"values"</span>: [
                    {
                        <span class="k">"option_id"</span>: <span class="n">8</span>,
                        <span class="k">"option_name"</span>: <span class="s">"Size"</span>,
                        <span class="k">"value_id"</span>: <span class="n">10</span>,
                        <span class="k">"value"</span>: <span class="s">"L"</span>
                    }
                ],
                <span class="k">"images"</span>: [
                    {
                        <span class="k">"id"</span>: <span class="n">7797</span>,
                        <span class="k">"name"</span>: <span class="s">"Full-Grain Sneakers — L"</span>,
                        <span class="k">"path"</span>: <span class="s">"demo-0023-l.png"</span>,
                        <span class="k">"url"</span>: <span class="s">"http://localhost:<span class="n">8080</span>/joomla6_ext/images/com_hikashop/upload/demo-0023-l.png"</span>,
                        <span class="k">"ordering"</span>: <span class="n">1</span>
                    }
                ]
            },
            "… 1 more, trimmed for the example"
        ],
        <span class="k">"fields"</span>: [
            {
                <span class="k">"namekey"</span>: <span class="s">"test_ajax_image"</span>,
                <span class="k">"type"</span>: <span class="s">"ajaximage"</span>,
                <span class="k">"raw_type"</span>: <span class="s">"ajaximage"</span>,
                <span class="k">"label"</span>: <span class="s">"Test Ajax Image"</span>,
                <span class="k">"default"</span>: <span class="s">""</span>,
                <span class="k">"required"</span>: <span class="n">false</span>,
                <span class="k">"options"</span>: [],
                <span class="k">"multiple"</span>: <span class="n">false</span>,
                <span class="k">"translatable"</span>: <span class="n">false</span>,
                <span class="k">"upload_dir"</span>: <span class="s">""</span>,
                <span class="k">"allowed_extensions"</span>: <span class="s">""</span>,
                <span class="k">"date_format"</span>: <span class="s">"%Y-%m-%d"</span>
            },
            {
                <span class="k">"namekey"</span>: <span class="s">"product_gtin"</span>,
                <span class="k">"type"</span>: <span class="s">"text"</span>,
                <span class="k">"raw_type"</span>: <span class="s">"text"</span>,
                <span class="k">"label"</span>: <span class="s">"GTIN"</span>,
                <span class="k">"default"</span>: <span class="s">""</span>,
                <span class="k">"required"</span>: <span class="n">false</span>,
                <span class="k">"options"</span>: [],
                <span class="k">"multiple"</span>: <span class="n">false</span>,
                <span class="k">"translatable"</span>: <span class="n">false</span>,
                <span class="k">"upload_dir"</span>: <span class="s">""</span>,
                <span class="k">"allowed_extensions"</span>: <span class="s">""</span>,
                <span class="k">"date_format"</span>: <span class="s">""</span>
            }
        ],
        <span class="k">"custom_fields"</span>: {
            <span class="k">"test_ajax_image"</span>: <span class="n">null</span>,
            <span class="k">"product_gtin"</span>: <span class="n">null</span>
        },
        <span class="k">"custom_field_files"</span>: {
            <span class="k">"test_ajax_image"</span>: []
        },
        <span class="k">"sections"</span>: [],
        <span class="k">"extensions"</span>: []
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## Resolve a scanned barcode

GET /products/lookup read since 6.6.0

One product from one barcode, for a scanner. It matches the product code and the GTIN, and it looks at variants as well as parents, because the thing with a barcode on it is usually the variant.

Exactly one product comes back, or `not_found`. It is deliberately not a search: a scanner needs an answer, not a list.

### Query

ParameterTypeDescription

barcoderequiredstringWhat the scanner read. Matched against the product code and the GTIN.

### Response expand all

FieldTypeDescription

idintegerThe product to open. For a variant, this is its parent.

variant\_idintegerThe variant that was scanned, `0` when the barcode belonged to the parent.

namestring

codestringThe SKU that matched.

gtinstringThe barcode held on the record, which may differ in leading zeros from what was scanned.

quantityintegerThe stock of whichever record matched, so a stock take needs no second call.

### Errors

CodeHTTPMeans

missing\_barcode400No barcode was given.

not\_found404Nothing in the shop carries that code.

```
curl "$SHOP/hikashop-api/v1/products/lookup?barcode=TEST{id}" \
  -H "Authorization: Bearer $TOKEN"
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"id"</span>: <span class="n">1</span>,
        <span class="k">"variant_id"</span>: <span class="n">0</span>,
        <span class="k">"name"</span>: <span class="s">"Test Product (Vendor 2)"</span>,
        <span class="k">"code"</span>: <span class="s">"TEST001"</span>,
        <span class="k">"gtin"</span>: <span class="s">""</span>,
        <span class="k">"quantity"</span>: <span class="n">-1</span>
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## Products running out

GET /products/low-stock read since 6.6.0

Sellable items at or below a stock threshold, cheapest first to reorder. Variants are listed in their own right, since that is where the stock actually sits.

Products that do not track stock are left out: they are not running out of anything.

### Query

ParameterTypeDescription

thresholdintegerAt or below which a product counts as low. Defaults to `5`.

limitintegerDefaults to `20`, capped at `100`.

### Response a list expand all

FieldTypeDescription

idintegerThe parent product.

variant\_idintegerThe variant that is low, `0` when the parent itself is.

namestring

codestringThe SKU of whichever record is low.

quantityintegerWhat is left.

```
curl "$SHOP/hikashop-api/v1/products/low-stock?threshold={id}&limit=3" \
  -H "Authorization: Bearer $TOKEN"
```

```
{
    <span class="k">"data"</span>: [
        {
            <span class="k">"id"</span>: <span class="n">8657</span>,
            <span class="k">"variant_id"</span>: <span class="n">0</span>,
            <span class="k">"name"</span>: <span class="s">"Botanical Shampoo Bottle — 500 ml"</span>,
            <span class="k">"code"</span>: <span class="s">"DEMO-0019"</span>,
            <span class="k">"quantity"</span>: <span class="n">0</span>
        },
        {
            <span class="k">"id"</span>: <span class="n">8896</span>,
            <span class="k">"variant_id"</span>: <span class="n">0</span>,
            <span class="k">"name"</span>: <span class="s">"Brass Colored Pencils — 12"</span>,
            <span class="k">"code"</span>: <span class="s">"DEMO-0193"</span>,
            <span class="k">"quantity"</span>: <span class="n">0</span>
        },
        {
            <span class="k">"id"</span>: <span class="n">9007</span>,
            <span class="k">"variant_id"</span>: <span class="n">0</span>,
            <span class="k">"name"</span>: <span class="s">"Brass Colored Pencils — 36"</span>,
            <span class="k">"code"</span>: <span class="s">"DEMO-0279"</span>,
            <span class="k">"quantity"</span>: <span class="n">0</span>
        }
    ],
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## Set a product's stock

POST /products/**{id}**/stock write since 6.6.0

Sets the tracked quantity to an absolute figure, which is what a stock take does. It is not an adjustment: send what the shelf holds, not the difference.

A product with variants keeps no stock of its own, so set it on the variant instead. Asking to set it on the parent is refused rather than silently ignored.

### Path

ParameterTypeDescription

idrequiredintegerThe product or variant to set.

### Body

FieldTypeDescription

quantityrequiredintegerThe new absolute quantity. `-1` turns stock tracking off for this product.

### Response expand all

FieldTypeDescription

idinteger

quantityintegerAs stored, so you can confirm what was written.

### Errors

CodeHTTPMeans

not\_found404No such product, or the operator may not change it.

has\_variants409It is a parent: set the stock on one of its variants.

```
curl -X POST "$SHOP/hikashop-api/v1/products/2/stock" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "quantity": 42
}'
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"id"</span>: <span class="n">2</span>,
        <span class="k">"quantity"</span>: <span class="n">42</span>
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## List customers

GET /customers read since 6.6.0

The customers the operator may see, with enough to recognise one and to know whether they have bought anything.

Guests are included. A shop that lets people order without an account still has a row for each of them, and `type` is how you tell the two apart.

### Query

ParameterTypeDescription

startintegerOffset. Defaults to `0`.

limitintegerDefaults to `20`, capped at `100`.

searchstringMatches the email address, the account name and login, and the first name and surname on any of their addresses, including the two together, so `John Doe` finds a guest who has never had an account.

emailstringThe exact email address, ignoring case: one customer or none. For a client that knows who it is looking for, such as a helpdesk matching a message to its sender, where `search` would also find `<joomla-hidden-mail base="" first="YW5uZQ==" is-email="1" is-link="1" last="c2hvcC5jb20=" text="YW5uZUBzaG9wLmNvbQ==">This email address is being protected from spambots. You need JavaScript enabled to view it.</joomla-hidden-mail>` for `<joomla-hidden-mail base="" first="YW5u" is-email="1" is-link="1" last="c2hvcC5jb20=" text="YW5uQHNob3AuY29t">This email address is being protected from spambots. You need JavaScript enabled to view it.</joomla-hidden-mail>`.

### Response a list expand all

FieldTypeDescription

idintegerThe HikaShop customer id, which is not the CMS user id.

namestringThe account name, or for a guest the name on their default address, since a guest has no account to take one from.

emailstring

typestring`registered` for an account, `guest` for someone who ordered without one.

createdintegerUnix timestamp of the first time the shop saw them.

order\_countintegerHow many orders they have placed, so a list can be sorted by worth without a second call.

### Envelope meta

FieldTypeDescription

startintegerEchoes the offset used.

limitintegerEchoes the page size used.

totalintegerCustomers matching the filter, before paging.

```
curl "$SHOP/hikashop-api/v1/customers?limit=2" \
  -H "Authorization: Bearer $TOKEN"
```

```
{
    <span class="k">"data"</span>: [
        {
            <span class="k">"id"</span>: <span class="n">5424</span>,
            <span class="k">"name"</span>: <span class="s">"Alex Marchand"</span>,
            <span class="k">"email"</span>: <span class="s">"<joomla-hidden-mail base="" first="YnV5ZXI=" is-email="1" is-link="1" last="ZXhhbXBsZS50ZXN0" text="YnV5ZXJAZXhhbXBsZS50ZXN0">This email address is being protected from spambots. You need JavaScript enabled to view it.</joomla-hidden-mail>"</span>,
            <span class="k">"type"</span>: <span class="s">"guest"</span>,
            <span class="k">"created"</span>: <span class="n">1790620906</span>,
            <span class="k">"order_count"</span>: <span class="n">0</span>
        },
        {
            <span class="k">"id"</span>: <span class="n">5412</span>,
            <span class="k">"name"</span>: <span class="s">""</span>,
            <span class="k">"email"</span>: <span class="s">"<joomla-hidden-mail base="" first="YnV5ZXI=" is-email="1" is-link="1" last="ZXhhbXBsZS50ZXN0" text="YnV5ZXJAZXhhbXBsZS50ZXN0">This email address is being protected from spambots. You need JavaScript enabled to view it.</joomla-hidden-mail>"</span>,
            <span class="k">"type"</span>: <span class="s">"guest"</span>,
            <span class="k">"created"</span>: <span class="n">1789923608</span>,
            <span class="k">"order_count"</span>: <span class="n">0</span>
        }
    ],
    <span class="k">"meta"</span>: {
        <span class="k">"start"</span>: <span class="n">0</span>,
        <span class="k">"limit"</span>: <span class="n">2</span>,
        <span class="k">"total"</span>: <span class="n">384</span>
    },
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## List discounts and coupons

GET /discounts read since 6.6.0

Both kinds of reduction live in one table and are told apart by `type`: a **discount** applies by itself when its conditions are met, a **coupon** waits for its code to be entered.

The restriction fields are the interesting part, and they are all lists of ids: which products, which categories, which zones, which customers, and the same again for exclusions. An empty list means no restriction of that kind rather than none allowed.

### Query

ParameterTypeDescription

startintegerOffset. Defaults to `0`.

limitintegerDefaults to `20`, capped at `100`.

typestring`discount` or `coupon`, to list one kind.

searchstringMatches the code.

### Response a list expand all

FieldTypeDescription

idinteger

typestring`discount` applies by itself, `coupon` waits for its code.

codestringWhat the customer types. Empty on a discount.

kindstringWhether the value is a percentage or a fixed amount.

valuenumberThe reduction, read according to `kind`.

currency\_idintegerThe currency a fixed amount is in.

publishedboolean

startinteger\|nullUnix timestamp before which it does not apply.

endinteger\|nullUnix timestamp after which it expires.

minimum\_ordernumberOrder total below which it does not apply, `0` for none.

maximum\_ordernumberOrder total above which it stops applying, `0` for none.

quotaintegerHow many times it may be used in total, `0` for no limit.

quota\_per\_userintegerHow many times one customer may use it, `0` for no limit.

used\_timesintegerHow many times it already has been.

tax\_includedbooleanWhether the value is understood as tax included.

tax\_idintegerThe tax category of the reduction itself.

shipping\_percentnumberA reduction on the shipping rather than on the goods.

minimum\_productsintegerFewest items in the cart for it to apply.

maximum\_productsintegerMost items for it to still apply.

product\_idsinteger\[\]Restricted to these products. Empty means all of them.

exclude\_product\_idsinteger\[\]Never applies to these.

category\_idsinteger\[\]Restricted to these categories.

category\_childsbooleanWhether those categories include their sub-categories.

exclude\_category\_idsinteger\[\]Never applies in these categories.

exclude\_category\_childsbooleanWhether those exclusions include sub-categories.

zone\_idsinteger\[\]Restricted to these zones.

user\_idsinteger\[\]Restricted to these customers.

accessobjectWhich user groups it is for, in the usual `mode` and `groups` shape.modestring`all`, `none`, or `groups` when it is restricted to some.

groupsinteger\[\]User \*\*group\*\* ids, and not Joomla view levels. The two id spaces overlap and disagree, so a value that looks plausible can grant the wrong audience.

exclude\_accessobjectWhich user groups it is never for.modestring`all`, `none`, or `groups` when it is restricted to some.

groupsinteger\[\]User \*\*group\*\* ids, and not Joomla view levels. The two id spaces overlap and disagree, so a value that looks plausible can grant the wrong audience.

auto\_loadbooleanFor a coupon, whether the shop applies it without the customer typing it.

product\_onlybooleanWhether it reduces only the goods and leaves the fees alone.

discounted\_productsintegerHow many products in the cart it applied to, on a discount that has been used.

### Envelope meta

FieldTypeDescription

startintegerEchoes the offset used.

limitintegerEchoes the page size used.

totalintegerRows matching the filter, before paging.

```
curl "$SHOP/hikashop-api/v1/discounts?limit=2" \
  -H "Authorization: Bearer $TOKEN"
```

```
{
    <span class="k">"data"</span>: [
        {
            <span class="k">"id"</span>: <span class="n">435</span>,
            <span class="k">"type"</span>: <span class="s">"discount"</span>,
            <span class="k">"code"</span>: <span class="s">"auto-2"</span>,
            <span class="k">"kind"</span>: <span class="s">"percent"</span>,
            <span class="k">"value"</span>: <span class="n">9</span>,
            <span class="k">"currency_id"</span>: <span class="n">0</span>,
            <span class="k">"published"</span>: <span class="n">true</span>,
            <span class="k">"start"</span>: <span class="n">0</span>,
            <span class="k">"end"</span>: <span class="n">0</span>,
            <span class="k">"minimum_order"</span>: <span class="n">0</span>,
            <span class="k">"maximum_order"</span>: <span class="n">0</span>,
            <span class="k">"quota"</span>: <span class="n">0</span>,
            <span class="k">"quota_per_user"</span>: <span class="n">0</span>,
            <span class="k">"used_times"</span>: <span class="n">5</span>,
            <span class="k">"tax_included"</span>: <span class="n">false</span>,
            <span class="k">"tax_id"</span>: <span class="n">0</span>,
            <span class="k">"shipping_percent"</span>: <span class="n">0</span>,
            <span class="k">"minimum_products"</span>: <span class="n">0</span>,
            <span class="k">"maximum_products"</span>: <span class="n">0</span>,
            <span class="k">"product_ids"</span>: [],
            <span class="k">"exclude_product_ids"</span>: [],
            <span class="k">"category_ids"</span>: [],
            <span class="k">"category_childs"</span>: <span class="n">false</span>,
            <span class="k">"exclude_category_ids"</span>: [],
            <span class="k">"exclude_category_childs"</span>: <span class="n">false</span>,
            <span class="k">"zone_ids"</span>: [],
            <span class="k">"user_ids"</span>: [],
            <span class="k">"access"</span>: {
                <span class="k">"mode"</span>: <span class="s">"all"</span>,
                <span class="k">"groups"</span>: []
            },
            <span class="k">"exclude_access"</span>: {
                <span class="k">"mode"</span>: <span class="s">"none"</span>,
                <span class="k">"groups"</span>: []
            },
            <span class="k">"auto_load"</span>: <span class="n">false</span>,
            <span class="k">"product_only"</span>: <span class="n">false</span>,
            <span class="k">"discounted_products"</span>: <span class="n">0</span>
        },
        {
            <span class="k">"id"</span>: <span class="n">434</span>,
            <span class="k">"type"</span>: <span class="s">"coupon"</span>,
            <span class="k">"code"</span>: <span class="s">"E2E1786215747620"</span>,
            <span class="k">"kind"</span>: <span class="s">"percent"</span>,
            <span class="k">"value"</span>: <span class="n">12</span>,
            <span class="k">"currency_id"</span>: <span class="n">0</span>,
            <span class="k">"published"</span>: <span class="n">true</span>,
            <span class="k">"start"</span>: <span class="n">0</span>,
            <span class="k">"end"</span>: <span class="n">0</span>,
            <span class="k">"minimum_order"</span>: <span class="n">0</span>,
            <span class="k">"maximum_order"</span>: <span class="n">0</span>,
            <span class="k">"quota"</span>: <span class="n">0</span>,
            <span class="k">"quota_per_user"</span>: <span class="n">0</span>,
            <span class="k">"used_times"</span>: <span class="n">0</span>,
            <span class="k">"tax_included"</span>: <span class="n">false</span>,
            <span class="k">"tax_id"</span>: <span class="n">0</span>,
            <span class="k">"shipping_percent"</span>: <span class="n">0</span>,
            <span class="k">"minimum_products"</span>: <span class="n">0</span>,
            <span class="k">"maximum_products"</span>: <span class="n">0</span>,
            <span class="k">"product_ids"</span>: [],
            <span class="k">"exclude_product_ids"</span>: [],
            <span class="k">"category_ids"</span>: [],
            <span class="k">"category_childs"</span>: <span class="n">false</span>,
            <span class="k">"exclude_category_ids"</span>: [],
            <span class="k">"exclude_category_childs"</span>: <span class="n">false</span>,
            <span class="k">"zone_ids"</span>: [],
            <span class="k">"user_ids"</span>: [],
            <span class="k">"access"</span>: {
                <span class="k">"mode"</span>: <span class="s">"all"</span>,
                <span class="k">"groups"</span>: []
            },
            <span class="k">"exclude_access"</span>: {
                <span class="k">"mode"</span>: <span class="s">"none"</span>,
                <span class="k">"groups"</span>: []
            },
            <span class="k">"auto_load"</span>: <span class="n">false</span>,
            <span class="k">"product_only"</span>: <span class="n">false</span>,
            <span class="k">"discounted_products"</span>: <span class="n">0</span>
        }
    ],
    <span class="k">"meta"</span>: {
        <span class="k">"start"</span>: <span class="n">0</span>,
        <span class="k">"limit"</span>: <span class="n">2</span>,
        <span class="k">"total"</span>: <span class="n">5</span>
    },
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## The category tree

GET /categories read since 6.6.0

One level of the category tree at a time, unpublished categories included, which is what makes this a management view rather than a shop one.

Pass a `parent_id` to walk down. `has_children` tells you whether there is anything below without asking, so a tree can be drawn lazily.

HikaShop keeps its manufacturers and its tax categories in the same table as the product categories, told apart by their root. Ask for the tree you want.

### Query

ParameterTypeDescription

parent\_idintegerWhose children to list. Omit for the top level.

startintegerOffset. Defaults to `0`.

limitintegerDefaults to `20`, capped at `100`.

searchstringMatches the name, across the whole tree rather than one level.

### Response a list expand all

FieldTypeDescription

idinteger

namestring

parent\_idintegerIts parent, so a flat answer can be rebuilt into a tree.

publishedboolean

has\_childrenbooleanWhether anything sits below it.

imagestring\|nullAbsolute URL of its image, `null` when it has none.

### Envelope meta

FieldTypeDescription

totalintegerCategories matching, before paging.

startintegerEchoes the offset used.

limitintegerEchoes the page size used.

```
curl "$SHOP/hikashop-api/v1/categories?limit=3" \
  -H "Authorization: Bearer $TOKEN"
```

```
{
    <span class="k">"data"</span>: [
        {
            <span class="k">"id"</span>: <span class="n">17</span>,
            <span class="k">"name"</span>: <span class="s">"Unrelated Cat"</span>,
            <span class="k">"parent_id"</span>: <span class="n">2</span>,
            <span class="k">"published"</span>: <span class="n">true</span>,
            <span class="k">"has_children"</span>: <span class="n">false</span>,
            <span class="k">"image"</span>: <span class="s">""</span>
        },
        {
            <span class="k">"id"</span>: <span class="n">18</span>,
            <span class="k">"name"</span>: <span class="s">"StoreLinkr Cat"</span>,
            <span class="k">"parent_id"</span>: <span class="n">2</span>,
            <span class="k">"published"</span>: <span class="n">true</span>,
            <span class="k">"has_children"</span>: <span class="n">true</span>,
            <span class="k">"image"</span>: <span class="s">""</span>
        },
        {
            <span class="k">"id"</span>: <span class="n">20</span>,
            <span class="k">"name"</span>: <span class="s">"Via Ajax Cat"</span>,
            <span class="k">"parent_id"</span>: <span class="n">2</span>,
            <span class="k">"published"</span>: <span class="n">true</span>,
            <span class="k">"has_children"</span>: <span class="n">false</span>,
            <span class="k">"image"</span>: <span class="s">""</span>
        }
    ],
    <span class="k">"meta"</span>: {
        <span class="k">"total"</span>: <span class="n">20</span>,
        <span class="k">"start"</span>: <span class="n">0</span>,
        <span class="k">"limit"</span>: <span class="n">3</span>
    },
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## Read one category

GET /categories/**{id}** read since 6.6.0

A category with its description, its image, who may see it, and your own category fields.

### Path

ParameterTypeDescription

idrequiredintegerThe category id.

### Response expand all

FieldTypeDescription

fieldsobject\[\]The definitions of your own category fields.

idinteger

namestring

parent\_idintegerIts parent.

typestringWhich tree it belongs to: `product`, `manufacturer`, `tax`, and so on.

descriptionstringThe long description, as HTML.

meta\_descriptionstringSEO description.

publishedboolean

accessobjectWho may see it.modestring`all`, `none`, or `groups` when it is restricted to some.

groupsinteger\[\]User \*\*group\*\* ids, and not Joomla view levels. The two id spaces overlap and disagree, so a value that looks plausible can grant the wrong audience.

imagestring\|nullAbsolute URL of its image, `null` when it has none.

custom\_fieldsobjectTheir values, keyed by namekey. The keys depend on the shop; `fields` says what they are.

custom\_field\_filesobjectFor a field holding a file, the file behind the value. Keyed the same way.

```
curl "$SHOP/hikashop-api/v1/categories/2" \
  -H "Authorization: Bearer $TOKEN"
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"fields"</span>: [],
        <span class="k">"id"</span>: <span class="n">2</span>,
        <span class="k">"name"</span>: <span class="s">"product category"</span>,
        <span class="k">"parent_id"</span>: <span class="n">1</span>,
        <span class="k">"type"</span>: <span class="s">"product"</span>,
        <span class="k">"description"</span>: <span class="s">""</span>,
        <span class="k">"meta_description"</span>: <span class="s">""</span>,
        <span class="k">"published"</span>: <span class="n">true</span>,
        <span class="k">"access"</span>: {
            <span class="k">"mode"</span>: <span class="s">"all"</span>,
            <span class="k">"groups"</span>: []
        },
        <span class="k">"image"</span>: <span class="s">""</span>,
        <span class="k">"custom_fields"</span>: [],
        <span class="k">"custom_field_files"</span>: []
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## The shop's own bulk operations

GET /massactions read since 6.6.0

The mass actions the merchant has configured for a listing, so a client can offer the merchant's own bulk operations rather than a fixed set of its own.

Whatever they built in the backend appears here, and running one is `POST /massactions/{id}`.

### Query

ParameterTypeDescription

tablerequiredstringWhich listing: `product`, `order`, `user`, `category`, `address`.

### Response a list expand all

FieldTypeDescription

idintegerWhat to run.

namestringAs the merchant named it.

descriptionstringTheir own note about what it does, when they wrote one.

tablestringThe listing it belongs to.

restrictedbooleanWhether it may only run on a selection rather than on everything matching a filter.

### Errors

CodeHTTPMeans

invalid\_request400The table is not one the shop has mass actions for.

forbidden403The operator may not view that kind of record.

```
curl "$SHOP/hikashop-api/v1/massactions?table=product" \
  -H "Authorization: Bearer $TOKEN"
```

```
{
    <span class="k">"data"</span>: [
        {
            <span class="k">"id"</span>: <span class="n">2</span>,
            <span class="k">"name"</span>: <span class="s">"Unpublish selected"</span>,
            <span class="k">"description"</span>: <span class="s">"Takes the chosen products off sale."</span>,
            <span class="k">"table"</span>: <span class="s">"product"</span>,
            <span class="k">"restricted"</span>: <span class="n">false</span>
        }
    ],
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## Browse the upload folder

GET /media/browse read since 6.6.0

Folders and images inside the shop's upload folder, so an existing image can be picked instead of uploaded again.

Paths are relative to that folder and never escape it: a path pointing outside is refused rather than resolved.

### Query

ParameterTypeDescription

folderstringWhich folder to list, relative to the upload folder. Omit for its root.

offsetintegerOffset into the images, for a folder with many.

### Response expand all

FieldTypeDescription

folderstringThe folder being listed.

parentstringThe folder above, for walking back up.

has\_parentbooleanFalse at the root, where there is nothing above.

foldersobject\[\]The folders inside it.

imagesobject\[\]The images inside it.namestringThe file name.

pathstringRelative to the upload folder, which is what a product image stores.

urlstringAbsolute, ready to display.

totalintegerHow many images the folder holds in all.

offsetintegerEchoes the offset used.

### Errors

CodeHTTPMeans

not\_found404No such folder, or a path that tried to leave the upload folder.

```
curl "$SHOP/hikashop-api/v1/media/browse" \
  -H "Authorization: Bearer $TOKEN"
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"folder"</span>: <span class="s">""</span>,
        <span class="k">"parent"</span>: <span class="s">""</span>,
        <span class="k">"has_parent"</span>: <span class="n">false</span>,
        <span class="k">"folders"</span>: [],
        <span class="k">"images"</span>: [
            {
                <span class="k">"name"</span>: <span class="s">"demo-0001.png"</span>,
                <span class="k">"path"</span>: <span class="s">"demo-0001.png"</span>,
                <span class="k">"url"</span>: <span class="s">"http://localhost:<span class="n">8080</span>/joomla6_ext/images/com_hikashop/upload/demo-0001.png"</span>
            },
            {
                <span class="k">"name"</span>: <span class="s">"demo-0002-2.png"</span>,
                <span class="k">"path"</span>: <span class="s">"demo-0002-2.png"</span>,
                <span class="k">"url"</span>: <span class="s">"http://localhost:<span class="n">8080</span>/joomla6_ext/images/com_hikashop/upload/demo-0002-2.png"</span>
            },
            {
                <span class="k">"name"</span>: <span class="s">"demo-0002.png"</span>,
                <span class="k">"path"</span>: <span class="s">"demo-0002.png"</span>,
                <span class="k">"url"</span>: <span class="s">"http://localhost:<span class="n">8080</span>/joomla6_ext/images/com_hikashop/upload/demo-0002.png"</span>
            },
            {
                <span class="k">"name"</span>: <span class="s">"demo-0003.png"</span>,
                <span class="k">"path"</span>: <span class="s">"demo-0003.png"</span>,
                <span class="k">"url"</span>: <span class="s">"http://localhost:<span class="n">8080</span>/joomla6_ext/images/com_hikashop/upload/demo-0003.png"</span>
            },
            "… 583 more, trimmed for the example"
        ],
        <span class="k">"total"</span>: <span class="n">587</span>,
        <span class="k">"offset"</span>: <span class="n">0</span>
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## Search countries, states and zones

GET /zones read since 6.6.0

The shop's zones, which are its countries, its states and any grouping the merchant made of them. Meant for filling a picker: search for a name, or resolve ids you already hold.

An address stores a zone by its namekey rather than its id, which is why both come back.

### Query

ParameterTypeDescription

searchstringMatches the name.

idsstringComma separated zone ids, to resolve a known set.

typestringRestrict to `country`, `state` or a zone group.

### Response a list expand all

FieldTypeDescription

idinteger

namekeystringWhat an address stores, such as `FRA` or `US-CA`.

namestringTranslated where the shop has a translation for it.

typestring`country`, `state`, or the kind of grouping it is.

```
curl "$SHOP/hikashop-api/v1/zones?search=fra" \
  -H "Authorization: Bearer $TOKEN"
```

```
{
    <span class="k">"data"</span>: [
        {
            <span class="k">"id"</span>: <span class="n">73</span>,
            <span class="k">"namekey"</span>: <span class="s">"country_France_73"</span>,
            <span class="k">"name"</span>: <span class="s">"France"</span>,
            <span class="k">"type"</span>: <span class="s">"country"</span>
        },
        {
            <span class="k">"id"</span>: <span class="n">2195</span>,
            <span class="k">"namekey"</span>: <span class="s">"state_Al_Jufrah_2195"</span>,
            <span class="k">"name"</span>: <span class="s">"Al Jufrah"</span>,
            <span class="k">"type"</span>: <span class="s">"state"</span>
        },
        {
            <span class="k">"id"</span>: <span class="n">2196</span>,
            <span class="k">"namekey"</span>: <span class="s">"state_Al_Kufrah_2196"</span>,
            <span class="k">"name"</span>: <span class="s">"Al Kufrah"</span>,
            <span class="k">"type"</span>: <span class="s">"state"</span>
        },
        {
            <span class="k">"id"</span>: <span class="n">1631</span>,
            <span class="k">"namekey"</span>: <span class="s">"state_Francisco_Moraz__n_1631"</span>,
            <span class="k">"name"</span>: <span class="s">"Francisco Morazán"</span>,
            <span class="k">"type"</span>: <span class="s">"state"</span>
        },
        "… 4 more, trimmed for the example"
    ],
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## Search customers for a picker

GET /users read since 6.6.0

A short list of customers matching a search, for the pickers that restrict a price or a discount to named people. `GET /customers` is the listing to use for anything else.

### Query

ParameterTypeDescription

searchstringMatches the name and the email address.

idsstringComma separated ids, to resolve a known set.

### Response a list expand all

FieldTypeDescription

idintegerThe customer id, which is what a restriction stores.

namestring

emailstringEnough to tell two people of the same name apart.

```
curl "$SHOP/hikashop-api/v1/users?search=a" \
  -H "Authorization: Bearer $TOKEN"
```

```
{
    <span class="k">"data"</span>: [
        {
            <span class="k">"id"</span>: <span class="n">5424</span>,
            <span class="k">"name"</span>: <span class="s">""</span>,
            <span class="k">"email"</span>: <span class="s">"<joomla-hidden-mail base="" first="YnV5ZXI=" is-email="1" is-link="1" last="ZXhhbXBsZS50ZXN0" text="YnV5ZXJAZXhhbXBsZS50ZXN0">This email address is being protected from spambots. You need JavaScript enabled to view it.</joomla-hidden-mail>"</span>
        },
        {
            <span class="k">"id"</span>: <span class="n">20</span>,
            <span class="k">"name"</span>: <span class="s">""</span>,
            <span class="k">"email"</span>: <span class="s">"<joomla-hidden-mail base="" first="YnV5ZXI=" is-email="1" is-link="1" last="ZXhhbXBsZS50ZXN0" text="YnV5ZXJAZXhhbXBsZS50ZXN0">This email address is being protected from spambots. You need JavaScript enabled to view it.</joomla-hidden-mail>"</span>
        },
        {
            <span class="k">"id"</span>: <span class="n">4939</span>,
            <span class="k">"name"</span>: <span class="s">""</span>,
            <span class="k">"email"</span>: <span class="s">"<joomla-hidden-mail base="" first="YnV5ZXI=" is-email="1" is-link="1" last="ZXhhbXBsZS50ZXN0" text="YnV5ZXJAZXhhbXBsZS50ZXN0">This email address is being protected from spambots. You need JavaScript enabled to view it.</joomla-hidden-mail>"</span>
        },
        {
            <span class="k">"id"</span>: <span class="n">4940</span>,
            <span class="k">"name"</span>: <span class="s">""</span>,
            <span class="k">"email"</span>: <span class="s">"<joomla-hidden-mail base="" first="YnV5ZXI=" is-email="1" is-link="1" last="ZXhhbXBsZS50ZXN0" text="YnV5ZXJAZXhhbXBsZS50ZXN0">This email address is being protected from spambots. You need JavaScript enabled to view it.</joomla-hidden-mail>"</span>
        },
        "… 26 more, trimmed for the example"
    ],
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## Reference data for the product editor

GET /products/meta read since 6.6.0

Everything a product form needs to offer choices: the currencies with their formatting, the tax categories, the characteristics and their values, the units, the field definitions, the warehouses and the tags.

One call rather than eight, and it changes rarely, so cache it.

### Response expand all

FieldTypeDescription

currenciesobject\[\]Every published currency, with enough to format an amount the way the shop does.idintegerWhat a price stores.

codestringThe ISO code, such as `EUR`.

symbolstring

namestring

decimalsintegerHow many decimal places to show.

decimal\_sepstringThe decimal separator.

thousands\_sepstringThe thousands separator.

symbol\_beforebooleanWhether the symbol goes before the figure.

spacebooleanWhether a space separates the symbol from the figure.

rounding\_incrementnumberWhat amounts are rounded to, for a currency without small coins.

main\_currency\_idintegerThe shop's own currency.

tax\_categoriesobject\[\]The tax categories a product can be put in.idintegerWhat `tax_id` on a product stores.

namestring

parent\_idintegerThey live in the category tree, so they have a parent like anything else there.

characteristicsobject\[\]Every characteristic in the shop, with its values, for building variants.idinteger

namestring

valuesobject\[\]Its values.idintegerWhat a variant refers to.

valuestringIts name, such as `M`.

weight\_unitsstring\[\]The weight units the shop accepts, such as `kg`.

dimension\_unitsstring\[\]The dimension units the shop accepts, such as `m`.

product\_fieldsobject\[\]The definitions of your own product fields.namekeystringThe key its value is stored under.

typestringWhat to render: `text`, `radio`, `singledropdown`, `file`, and the rest.

raw\_typestringHikaShop's own name for the type.

labelstringTranslated into the operator's language.

defaultstringThe value used when none is given.

requiredbooleanWhether the shop refuses to save without it.

optionsobject\[\]The choices, for a field that has them.valuestringWhat to send back when this choice is picked.

labelstringWhat to show.

label\_keystringThe translation key behind the label, when there is one.

multiplebooleanWhether more than one may be chosen.

translatablebooleanWhether its value can be translated.

upload\_dirstringFor a file field, where its uploads are kept.

allowed\_extensionsstringFor a file field, the extensions it accepts. Empty means the shop default.

date\_formatstringFor a date field, the format it is stored in.

category\_fieldsobject\[\]The definitions of your own category fields.namekeystringThe key its value is stored under.

labelstringTranslated into the operator's language.

typestringWhat to render: `text`, `radio`, `singledropdown`, `file`, and the rest.

raw\_typestringHikaShop's own name for the type.

requiredbooleanWhether the shop refuses to save without it.

defaultstringThe value used when none is given.

optionsobject\[\]The choices, for a field that has them.valuestringWhat to send back when this choice is picked.

labelstringWhat to show.

label\_keystringThe translation key behind the label, when there is one.

multiplebooleanWhether more than one may be chosen.

translatablebooleanWhether its value can be translated.

upload\_dirstringFor a file field, where its uploads are kept.

allowed\_extensionsstringFor a file field, the extensions it accepts. Empty means the shop default.

date\_formatstringFor a date field, the format it is stored in.

bundle\_supportedbooleanWhether this edition can sell bundles.

warehousesobject\[\]The warehouses stock can be held in. Empty when the shop has none.idintegerWhat `warehouse_id` on a product stores.

namestring

tagsobject\[\]The CMS tags a product can carry.idinteger

namestring

parent\_idintegerTags are a tree in both Joomla and WordPress.

```
curl "$SHOP/hikashop-api/v1/products/meta" \
  -H "Authorization: Bearer $TOKEN"
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"currencies"</span>: [
            {
                <span class="k">"id"</span>: <span class="n">1</span>,
                <span class="k">"code"</span>: <span class="s">"EUR"</span>,
                <span class="k">"symbol"</span>: <span class="s">"€"</span>,
                <span class="k">"name"</span>: <span class="s">"Euro"</span>,
                <span class="k">"decimals"</span>: <span class="n">2</span>,
                <span class="k">"decimal_sep"</span>: <span class="s">","</span>,
                <span class="k">"thousands_sep"</span>: <span class="s">"."</span>,
                <span class="k">"symbol_before"</span>: <span class="n">false</span>,
                <span class="k">"space"</span>: <span class="n">true</span>,
                <span class="k">"rounding_increment"</span>: <span class="n">0</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">2</span>,
                <span class="k">"code"</span>: <span class="s">"USD"</span>,
                <span class="k">"symbol"</span>: <span class="s">"$"</span>,
                <span class="k">"name"</span>: <span class="s">"United States dollar"</span>,
                <span class="k">"decimals"</span>: <span class="n">2</span>,
                <span class="k">"decimal_sep"</span>: <span class="s">"."</span>,
                <span class="k">"thousands_sep"</span>: <span class="s">","</span>,
                <span class="k">"symbol_before"</span>: <span class="n">true</span>,
                <span class="k">"space"</span>: <span class="n">false</span>,
                <span class="k">"rounding_increment"</span>: <span class="n">0</span>
            }
        ],
        <span class="k">"main_currency_id"</span>: <span class="n">1</span>,
        <span class="k">"tax_categories"</span>: [
            {
                <span class="k">"id"</span>: <span class="n">11</span>,
                <span class="k">"name"</span>: <span class="s">"Default tax category"</span>,
                <span class="k">"parent_id"</span>: <span class="n">3</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">3</span>,
                <span class="k">"name"</span>: <span class="s">"taxation category"</span>,
                <span class="k">"parent_id"</span>: <span class="n">1</span>
            }
        ],
        <span class="k">"characteristics"</span>: [
            {
                <span class="k">"id"</span>: <span class="n">1</span>,
                <span class="k">"name"</span>: <span class="s">"Vendor"</span>,
                <span class="k">"values"</span>: []
            },
            {
                <span class="k">"id"</span>: <span class="n">5</span>,
                <span class="k">"name"</span>: <span class="s">"Color"</span>,
                <span class="k">"values"</span>: [
                    {
                        <span class="k">"id"</span>: <span class="n">6</span>,
                        <span class="k">"value"</span>: <span class="s">"Red"</span>
                    },
                    {
                        <span class="k">"id"</span>: <span class="n">7</span>,
                        <span class="k">"value"</span>: <span class="s">"Blue"</span>
                    }
                ]
            },
            {
                <span class="k">"id"</span>: <span class="n">8</span>,
                <span class="k">"name"</span>: <span class="s">"Size"</span>,
                <span class="k">"values"</span>: [
                    {
                        <span class="k">"id"</span>: <span class="n">9</span>,
                        <span class="k">"value"</span>: <span class="s">"S"</span>
                    },
                    {
                        <span class="k">"id"</span>: <span class="n">10</span>,
                        <span class="k">"value"</span>: <span class="s">"L"</span>
                    },
                    {
                        <span class="k">"id"</span>: <span class="n">21</span>,
                        <span class="k">"value"</span>: <span class="s">"M"</span>
                    },
                    {
                        <span class="k">"id"</span>: <span class="n">35</span>,
                        <span class="k">"value"</span>: <span class="s">"XS"</span>
                    },
                    "… 1 more, trimmed for the example"
                ]
            },
            {
                <span class="k">"id"</span>: <span class="n">14</span>,
                <span class="k">"name"</span>: <span class="s">"Colour"</span>,
                <span class="k">"values"</span>: [
                    {
                        <span class="k">"id"</span>: <span class="n">15</span>,
                        <span class="k">"value"</span>: <span class="s">"Charcoal"</span>
                    },
                    {
                        <span class="k">"id"</span>: <span class="n">16</span>,
                        <span class="k">"value"</span>: <span class="s">"Navy"</span>
                    },
                    {
                        <span class="k">"id"</span>: <span class="n">17</span>,
                        <span class="k">"value"</span>: <span class="s">"Oatmeal"</span>
                    },
                    {
                        <span class="k">"id"</span>: <span class="n">18</span>,
                        <span class="k">"value"</span>: <span class="s">"Forest"</span>
                    },
                    "… 2 more, trimmed for the example"
                ]
            },
            "… 1 more, trimmed for the example"
        ],
        <span class="k">"weight_units"</span>: [
            "kg",
            "g",
            "mg",
            "lb",
            "… 2 more, trimmed for the example"
        ],
        <span class="k">"dimension_units"</span>: [
            "m",
            "dm",
            "cm",
            "mm",
            "… 3 more, trimmed for the example"
        ],
        <span class="k">"product_fields"</span>: [
            {
                <span class="k">"namekey"</span>: <span class="s">"test_ajax_image"</span>,
                <span class="k">"type"</span>: <span class="s">"ajaximage"</span>,
                <span class="k">"raw_type"</span>: <span class="s">"ajaximage"</span>,
                <span class="k">"label"</span>: <span class="s">"Test Ajax Image"</span>,
                <span class="k">"default"</span>: <span class="s">""</span>,
                <span class="k">"required"</span>: <span class="n">false</span>,
                <span class="k">"options"</span>: [],
                <span class="k">"multiple"</span>: <span class="n">false</span>,
                <span class="k">"translatable"</span>: <span class="n">false</span>,
                <span class="k">"upload_dir"</span>: <span class="s">""</span>,
                <span class="k">"allowed_extensions"</span>: <span class="s">""</span>,
                <span class="k">"date_format"</span>: <span class="s">"%Y-%m-%d"</span>
            },
            {
                <span class="k">"namekey"</span>: <span class="s">"product_gtin"</span>,
                <span class="k">"type"</span>: <span class="s">"text"</span>,
                <span class="k">"raw_type"</span>: <span class="s">"text"</span>,
                <span class="k">"label"</span>: <span class="s">"GTIN"</span>,
                <span class="k">"default"</span>: <span class="s">""</span>,
                <span class="k">"required"</span>: <span class="n">false</span>,
                <span class="k">"options"</span>: [],
                <span class="k">"multiple"</span>: <span class="n">false</span>,
                <span class="k">"translatable"</span>: <span class="n">false</span>,
                <span class="k">"upload_dir"</span>: <span class="s">""</span>,
                <span class="k">"allowed_extensions"</span>: <span class="s">""</span>,
                <span class="k">"date_format"</span>: <span class="s">""</span>
            }
        ],
        <span class="k">"category_fields"</span>: [],
        <span class="k">"bundle_supported"</span>: <span class="n">true</span>,
        <span class="k">"warehouses"</span>: [
            {
                <span class="k">"id"</span>: <span class="n">1</span>,
                <span class="k">"name"</span>: <span class="s">"Default Warehouse"</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">2</span>,
                <span class="k">"name"</span>: <span class="s">"Main Warehouse (renamed)"</span>
            }
        ],
        <span class="k">"tags"</span>: []
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## Replace a product's prices

PUT /products/**{id}**/prices write since 6.6.0

Replaces the whole price set, it does not merge into it. Send every price the product should have, including the ones you are not changing; anything you leave out is deleted.

That is deliberate, because a price set is a set: quantity breaks and audience restrictions only make sense against each other.

### Path

ParameterTypeDescription

idrequiredintegerThe product or variant.

### Body

FieldTypeDescription

pricesrequiredobject\[\]The complete set. Each needs at least a `value` and a `currency_id`; `min_quantity`, `access`, `users`, `zone_ids`, `start_date` and `end_date` are optional and default to no restriction.

### Response a list expand all

FieldTypeDescription

idinteger

valuenumberTax excluded, as stored.

currency\_idinteger

min\_quantityintegerFrom how many items this row applies, which is how a quantity break is expressed.

accessobjectWhich user groups the price is for.modestring`all`, `none` or `groups`.

groupsinteger\[\]User group ids, not view levels.

usersinteger\[\]Named customers, empty for everyone.

zone\_idsinteger\[\]Zones it applies in, empty for everywhere.

start\_dateinteger\|nullUnix timestamp.

end\_dateinteger\|nullUnix timestamp.

### Errors

CodeHTTPMeans

invalid\_request400No prices array was sent.

invalid\_price400A price in the set cannot be stored, and the message says which one and why. Nothing is saved: a set is replaced whole or not at all.

not\_found404No such product, or the operator may not change it.

```
curl -X PUT "$SHOP/hikashop-api/v1/products/{id}/prices" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "prices": [
        {
            "value": 19.9,
            "currency_id": 1,
            "min_quantity": 1
        }
    ]
}'
```

```
{
    <span class="k">"data"</span>: [
        {
            <span class="k">"id"</span>: <span class="n">4947</span>,
            <span class="k">"value"</span>: <span class="n">19.9</span>,
            <span class="k">"currency_id"</span>: <span class="n">1</span>,
            <span class="k">"min_quantity"</span>: <span class="n">1</span>,
            <span class="k">"access"</span>: {
                <span class="k">"mode"</span>: <span class="s">"all"</span>,
                <span class="k">"groups"</span>: []
            },
            <span class="k">"users"</span>: [],
            <span class="k">"zone_ids"</span>: [],
            <span class="k">"start_date"</span>: <span class="n">0</span>,
            <span class="k">"end_date"</span>: <span class="n">0</span>
        }
    ],
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## Replace a product's categories

PUT /products/**{id}**/categories write since 6.6.0

Replaces the set of categories the product is in. As with the prices, send the complete set: what you leave out is removed.

### Path

ParameterTypeDescription

idrequiredintegerThe product.

### Body

FieldTypeDescription

categoriesrequiredinteger\[\]The complete set of category ids. An empty array takes the product out of every category, which hides it from the shop.

### Response a list expand all

FieldTypeDescription

idintegerThe category.

namestringIts name, so a client need not look it up.

### Errors

CodeHTTPMeans

not\_found404No such product, or the operator may not change it.

```
curl -X PUT "$SHOP/hikashop-api/v1/products/{id}/categories" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "categories": [
        "2"
    ]
}'
```

```
{
    <span class="k">"data"</span>: [
        {
            <span class="k">"id"</span>: <span class="n">2</span>,
            <span class="k">"name"</span>: <span class="s">"product category"</span>
        }
    ],
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## A product's translations

GET /products/**{id}**/translations read since 6.6.0

Which of a record's texts can be translated, what they say now in each language, and what the original says. `enabled` is false on a single-language shop, where there is nothing to do.

`columns` is the list of translatable things: HikaShop's own (the name, the description, the SEO texts) plus every custom field the merchant flagged translatable. It is built the same way the backend builds it, so what you are offered is exactly what the shop will store.

The labels and values of a custom field itself are website configuration and are not offered here; they belong in the backend.

### Path

ParameterTypeDescription

idrequiredintegerThe product.

### Response expand all

FieldTypeDescription

enabledbooleanFalse on a single-language shop, where the rest is empty.

languagesobject\[\]The shop's languages. The default one is marked and comes last, because its text is the original rather than a translation of it.idinteger

codestringThe tag, such as `fr-FR`.

shortcodestringThe lower-case underscored form the translation tables key on.

site\_defaultbooleanTrue for the language the shop is written in.

columnsobject\[\]What can be translated on this record: HikaShop's own texts plus every custom field flagged translatable.namestringThe column name, such as `product_name`. This is the key to send a translation under.

typestring`text` for a line, `textarea` for prose, so a client knows which control to draw.

valuesobjectWhat each language says now, keyed by language code and then by column. Keyed by language code, and within that by column name, both of which depend on the shop.

originalobjectWhat the record itself says, keyed by column, so a translator can see what they are translating. Keyed by column name, which depends on the fields this shop has.

### Errors

CodeHTTPMeans

not\_found404No such record, or the operator may not see it.

translation\_disabled400This shop does not translate content.

```
curl "$SHOP/hikashop-api/v1/products/1/translations" \
  -H "Authorization: Bearer $TOKEN"
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"enabled"</span>: <span class="n">true</span>,
        <span class="k">"languages"</span>: [
            {
                <span class="k">"id"</span>: <span class="n">2</span>,
                <span class="k">"code"</span>: <span class="s">"fr-FR"</span>,
                <span class="k">"shortcode"</span>: <span class="s">"fr_fr"</span>,
                <span class="k">"site_default"</span>: <span class="n">false</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">1</span>,
                <span class="k">"code"</span>: <span class="s">"en-GB"</span>,
                <span class="k">"shortcode"</span>: <span class="s">"en_gb"</span>,
                <span class="k">"site_default"</span>: <span class="n">true</span>
            }
        ],
        <span class="k">"columns"</span>: [
            {
                <span class="k">"name"</span>: <span class="s">"product_name"</span>,
                <span class="k">"type"</span>: <span class="s">"text"</span>
            },
            {
                <span class="k">"name"</span>: <span class="s">"product_description"</span>,
                <span class="k">"type"</span>: <span class="s">"html"</span>
            },
            {
                <span class="k">"name"</span>: <span class="s">"product_page_title"</span>,
                <span class="k">"type"</span>: <span class="s">"text"</span>
            },
            {
                <span class="k">"name"</span>: <span class="s">"product_url"</span>,
                <span class="k">"type"</span>: <span class="s">"text"</span>
            },
            "… 4 more, trimmed for the example"
        ],
        <span class="k">"original"</span>: {
            <span class="k">"product_name"</span>: <span class="s">"Test Product (Vendor 2)"</span>,
            <span class="k">"product_description"</span>: <span class="s">"Test product owned by vendor 2"</span>,
            <span class="k">"product_page_title"</span>: <span class="s">""</span>,
            <span class="k">"product_url"</span>: <span class="s">""</span>,
            <span class="k">"product_meta_description"</span>: <span class="s">""</span>,
            <span class="k">"product_keywords"</span>: <span class="s">""</span>,
            <span class="k">"product_alias"</span>: <span class="s">""</span>,
            <span class="k">"product_canonical"</span>: <span class="s">""</span>
        },
        <span class="k">"values"</span>: {
            <span class="k">"2"</span>: {
                <span class="k">"product_name"</span>: <span class="s">"Lampe de bureau"</span>
            }
        }
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## A category's translations

GET /categories/**{id}**/translations read since 6.6.0

The same as for a product, for a category: its name, its description, its SEO texts and its translatable custom fields.

### Path

ParameterTypeDescription

idrequiredintegerThe category.

### Response expand all

FieldTypeDescription

enabledbooleanFalse on a single-language shop, where the rest is empty.

languagesobject\[\]The shop's languages. The default one is marked and comes last, because its text is the original rather than a translation of it.idinteger

codestringThe tag, such as `fr-FR`.

shortcodestringThe lower-case underscored form the translation tables key on.

site\_defaultbooleanTrue for the language the shop is written in.

columnsobject\[\]What can be translated on this record: HikaShop's own texts plus every custom field flagged translatable.namestringThe column name, such as `product_name`. This is the key to send a translation under.

typestring`text` for a line, `textarea` for prose, so a client knows which control to draw.

valuesobjectWhat each language says now, keyed by language code and then by column. Keyed by language code, and within that by column name, both of which depend on the shop.

originalobjectWhat the record itself says, keyed by column, so a translator can see what they are translating. Keyed by column name, which depends on the fields this shop has.

### Errors

CodeHTTPMeans

not\_found404No such record, or the operator may not see it.

translation\_disabled400This shop does not translate content.

```
curl "$SHOP/hikashop-api/v1/categories/2/translations" \
  -H "Authorization: Bearer $TOKEN"
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"enabled"</span>: <span class="n">true</span>,
        <span class="k">"languages"</span>: [
            {
                <span class="k">"id"</span>: <span class="n">2</span>,
                <span class="k">"code"</span>: <span class="s">"fr-FR"</span>,
                <span class="k">"shortcode"</span>: <span class="s">"fr_fr"</span>,
                <span class="k">"site_default"</span>: <span class="n">false</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">1</span>,
                <span class="k">"code"</span>: <span class="s">"en-GB"</span>,
                <span class="k">"shortcode"</span>: <span class="s">"en_gb"</span>,
                <span class="k">"site_default"</span>: <span class="n">true</span>
            }
        ],
        <span class="k">"columns"</span>: [
            {
                <span class="k">"name"</span>: <span class="s">"category_name"</span>,
                <span class="k">"type"</span>: <span class="s">"text"</span>
            },
            {
                <span class="k">"name"</span>: <span class="s">"category_description"</span>,
                <span class="k">"type"</span>: <span class="s">"html"</span>
            },
            {
                <span class="k">"name"</span>: <span class="s">"category_product_page_info"</span>,
                <span class="k">"type"</span>: <span class="s">"html"</span>
            },
            {
                <span class="k">"name"</span>: <span class="s">"category_page_title"</span>,
                <span class="k">"type"</span>: <span class="s">"text"</span>
            },
            "… 4 more, trimmed for the example"
        ],
        <span class="k">"original"</span>: {
            <span class="k">"category_name"</span>: <span class="s">"product category"</span>,
            <span class="k">"category_description"</span>: <span class="s">""</span>,
            <span class="k">"category_product_page_info"</span>: <span class="s">""</span>,
            <span class="k">"category_page_title"</span>: <span class="s">""</span>,
            <span class="k">"category_meta_description"</span>: <span class="s">""</span>,
            <span class="k">"category_keywords"</span>: <span class="s">""</span>,
            <span class="k">"category_alias"</span>: <span class="s">""</span>,
            <span class="k">"category_canonical"</span>: <span class="s">""</span>
        },
        <span class="k">"values"</span>: {
            <span class="k">"2"</span>: {
                <span class="k">"category_name"</span>: <span class="s">"Sacs et vêtements"</span>
            }
        }
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## Save a product's translations

PUT /products/**{id}**/translations write since 6.6.0

Writes the translations of one record. Send only the languages you changed; the rest are left alone.

Where the shop uses Falang, the values go into its tables. Where it does not, they become language overrides keyed on the original text, which is why renaming a product re-keys its translations rather than losing them.

### Path

ParameterTypeDescription

idrequiredintegerThe product.

### Body

An object keyed by language, each holding an object of column name to text:

`{ "2": { "product_name": "Lampe de bureau", "product_description": "…" } }`

The keys are the language ids from `languages` in the GET, and the column names are the ones from `columns`. A language you do not send is left alone, and so is a column you do not send within a language you do.

### Response expand all

FieldTypeDescription

idintegerThe record that was saved.

savedintegerHow many languages were written, so a client can tell that something was actually stored.

### Errors

CodeHTTPMeans

not\_found404No such record, or the operator may not change it.

translation\_disabled400This shop does not translate content.

```
curl -X PUT "$SHOP/hikashop-api/v1/products/1/translations" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "2": {
        "product_name": "Lampe de bureau"
    }
}'
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"id"</span>: <span class="n">1</span>,
        <span class="k">"saved"</span>: <span class="n">1</span>
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## Save a category's translations

PUT /categories/**{id}**/translations write since 6.6.0

The same as for a product, for a category.

### Path

ParameterTypeDescription

idrequiredintegerThe category.

### Body

An object keyed by language, each holding an object of column name to text:

`{ "2": { "product_name": "Lampe de bureau", "product_description": "…" } }`

The keys are the language ids from `languages` in the GET, and the column names are the ones from `columns`. A language you do not send is left alone, and so is a column you do not send within a language you do.

### Response expand all

FieldTypeDescription

idintegerThe record that was saved.

savedintegerHow many languages were written.

### Errors

CodeHTTPMeans

not\_found404No such record, or the operator may not change it.

translation\_disabled400This shop does not translate content.

```
curl -X PUT "$SHOP/hikashop-api/v1/categories/2/translations" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "2": {
        "category_name": "Sacs et v\u00eatements"
    }
}'
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"id"</span>: <span class="n">2</span>,
        <span class="k">"saved"</span>: <span class="n">1</span>
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## Dashboard figures

GET /stats/dashboard read since 6.6.0

Revenue, orders, average basket and new customers over a period, the same figures again for the period before it so a change can be shown, the series behind them, and the best sellers.

Only orders the shop counts as sold are included, so a cancelled order does not inflate a total. Amounts are in the shop's own currency.

### Query

ParameterTypeDescription

rangestring`day`, `week`, `month` or `year`. Defaults to `month`.

### Response expand all

FieldTypeDescription

rangestringThe period the figures cover.

currency\_idintegerThe shop's currency, which every amount here is in.

totalsobjectThe four headline figures.revenuenumberTaken in the period.

ordersintegerHow many were placed.

average\_ordernumberRevenue divided by orders.

customersintegerNew customers in the period.

previousobjectThe same four figures for the preceding period of the same length, for a comparison.revenuenumberTaken in the preceding period.

ordersintegerPlaced in it.

average\_ordernumberIts average basket.

customersintegerNew customers in it.

series\_granularitystringWhether the series is by day, week, month or year, which follows from the range.

revenue\_seriesobject\[\]One point per interval, for a chart.datestringThe interval, as a date.

revenuenumberTaken in it.

top\_productsobject\[\]The best sellers of the period.namestring

quantityintegerHow many were sold.

```
curl "$SHOP/hikashop-api/v1/stats/dashboard?range=month" \
  -H "Authorization: Bearer $TOKEN"
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"range"</span>: <span class="s">"month"</span>,
        <span class="k">"currency_id"</span>: <span class="n">1</span>,
        <span class="k">"totals"</span>: {
            <span class="k">"revenue"</span>: <span class="n">0</span>,
            <span class="k">"orders"</span>: <span class="n">0</span>,
            <span class="k">"average_order"</span>: <span class="n">0</span>,
            <span class="k">"customers"</span>: <span class="n">0</span>
        },
        <span class="k">"previous"</span>: {
            <span class="k">"revenue"</span>: <span class="n">6309.8</span>,
            <span class="k">"orders"</span>: <span class="n">22</span>,
            <span class="k">"average_order"</span>: <span class="n">286.81</span>,
            <span class="k">"customers"</span>: <span class="n">18</span>
        },
        <span class="k">"series_granularity"</span>: <span class="s">"day"</span>,
        <span class="k">"revenue_series"</span>: [
            {
                <span class="k">"date"</span>: <span class="s">"+33 2 00 00 00 00"</span>,
                <span class="k">"revenue"</span>: <span class="n">0</span>
            },
            {
                <span class="k">"date"</span>: <span class="s">"+33 2 00 00 00 00"</span>,
                <span class="k">"revenue"</span>: <span class="n">0</span>
            },
            {
                <span class="k">"date"</span>: <span class="s">"+33 2 00 00 00 00"</span>,
                <span class="k">"revenue"</span>: <span class="n">0</span>
            },
            {
                <span class="k">"date"</span>: <span class="s">"+33 2 00 00 00 00"</span>,
                <span class="k">"revenue"</span>: <span class="n">0</span>
            },
            "… 27 more, trimmed for the example"
        ],
        <span class="k">"top_products"</span>: []
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## The user groups

GET /groups read since 6.6.0

The CMS user groups, for the pickers that restrict a price, a discount or a product to some of them. The list is the same shape on Joomla and on WordPress, which is the point of it: a client does not need to know which it is talking to.

These are the ids an `access` object holds. They are user groups and not Joomla view levels.

### Response a list expand all

FieldTypeDescription

idintegerWhat an access object stores.

titlestringThe name of the group.

```
curl "$SHOP/hikashop-api/v1/groups" \
  -H "Authorization: Bearer $TOKEN"
```

```
{
    <span class="k">"data"</span>: [
        {
            <span class="k">"id"</span>: <span class="n">1</span>,
            <span class="k">"title"</span>: <span class="s">"Mr"</span>
        },
        {
            <span class="k">"id"</span>: <span class="n">9</span>,
            <span class="k">"title"</span>: <span class="s">"Mr"</span>
        },
        {
            <span class="k">"id"</span>: <span class="n">6</span>,
            <span class="k">"title"</span>: <span class="s">"Mr"</span>
        },
        {
            <span class="k">"id"</span>: <span class="n">7</span>,
            <span class="k">"title"</span>: <span class="s">"Mr"</span>
        },
        "… 5 more, trimmed for the example"
    ],
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## Price a product in an order

GET /orders/**{id}**/products/precompute read since 6.6.0

What a product would cost on this order, before adding it. The order's customer, currency and zone all bear on the price, so this asks the shop rather than guessing from the catalogue.

Use it to show a line before it is committed, then `POST /orders/{id}/products` to add it.

### Path

ParameterTypeDescription

idrequiredintegerThe order.

### Query

ParameterTypeDescription

product\_idrequiredintegerThe product or variant to price.

quantityintegerHow many, which matters where the product has quantity breaks. Defaults to `1`.

### Response expand all

FieldTypeDescription

product\_idintegerWhat was priced.

namestring

codestringIts SKU.

quantityintegerThe quantity the price was worked out for.

pricenumberUnit price, tax excluded, in the order currency.

taxnumberTax per unit, worked out for this order rather than in general.

tax\_namekeysstring\[\]Which tax rates that came from.

### Errors

CodeHTTPMeans

not\_found404No such order or no such product, or the operator may not see them.

```
curl "$SHOP/hikashop-api/v1/orders/{id}/products/precompute?product_id=1&quantity=2" \
  -H "Authorization: Bearer $TOKEN"
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"product_id"</span>: <span class="n">1</span>,
        <span class="k">"name"</span>: <span class="s">"Test Product (Vendor 2)"</span>,
        <span class="k">"code"</span>: <span class="s">"TEST001"</span>,
        <span class="k">"quantity"</span>: <span class="n">2</span>,
        <span class="k">"price"</span>: <span class="n">9.99</span>,
        <span class="k">"tax"</span>: <span class="n">0</span>,
        <span class="k">"tax_namekeys"</span>: []
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## Read one customer

GET /customers/**{id}** read since 6.6.0

A customer with their addresses, their orders, which groups they are in and your own customer fields.

`can_edit_account` and `groups_editable` are worth reading before drawing a form: they say whether this operator may change this particular account at all, so a client can leave the controls out rather than offer something that will be refused. A customer can have many addresses and one default of each kind.

### Path

ParameterTypeDescription

idrequiredintegerThe customer id.

### Response expand all

FieldTypeDescription

idintegerThe HikaShop customer id, which is what every customer route takes.

cms\_idintegerThe Joomla or WordPress user id, `0` for a guest with no account.

namestring

emailstring

usernamestringThe login, empty for a guest.

typestring`registered` or `guest`.

blockedbooleanWhether the CMS account is disabled.

can\_edit\_accountbooleanWhether this operator may change the login and password of this particular account. False for an account above their own level, which is how a super user is protected from staff.

groups\_editablebooleanWhether this operator may change which groups the customer is in.

groupsobject\[\]The groups they are in.idinteger

titlestring

available\_groupsobject\[\]Every group, with whether this operator may put the customer into it, so a picker can grey out the rest rather than offering a refusal.idinteger

titlestring

assignablebooleanFalse for a group this operator may not grant.

createdintegerUnix timestamp of the first time the shop saw them.

addressesobject\[\]Their addresses, defaults first.idinteger

typesstring\[\]Which of `billing` and `shipping` it is used for.

namestring

companystring

streetstring

citystring

post\_codestring

telephonestring

defaultbooleanWhether it is the default for one of its types.

formattedobjectThe address laid out the way this shop lays addresses out, which depends on its address format setting.textstringSeveral lines, for an invoice or a label.

one\_linestringOne line, for a list.

ordersobject\[\]Their orders, newest first, enough to list them.idinteger

numberstringThe number the customer sees.

statusstringA namekey.

createdintegerUnix timestamp.

totalnumberTax included, in the order currency.

currency\_idintegerThat currency.

fieldsobject\[\]The definitions of your own customer fields.

custom\_fieldsobjectTheir values, keyed by namekey. The keys depend on the shop; `fields` says what they are.

custom\_field\_filesobjectFor a field holding a file, the file behind the value. Keyed the same way.

sectionsobject\[\]Information other plugins show on this record, each with a `key`, a `title` and `rows` (`label`, `value`, and optionally `url`, `badge` and `ref`). Empty when no plugin adds any; on a customer, core adds their paid downloads. See the guide on adding information and settings.

extensionsobject\[\]Settings other plugins keep on this record, in groups (`key`, `title`, `fields`), each field described like a custom field plus its current `value`. Send changes back as `extensions` with the record's save. Empty when no plugin adds any.

### Errors

CodeHTTPMeans

not\_found404No such customer, or the operator may not see them.

```
curl "$SHOP/hikashop-api/v1/customers/{id}" \
  -H "Authorization: Bearer $TOKEN"
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"id"</span>: <span class="n">14</span>,
        <span class="k">"cms_id"</span>: <span class="n">156</span>,
        <span class="k">"name"</span>: <span class="s">"Admin"</span>,
        <span class="k">"email"</span>: <span class="s">"<joomla-hidden-mail base="" first="YnV5ZXI=" is-email="1" is-link="1" last="ZXhhbXBsZS50ZXN0" text="YnV5ZXJAZXhhbXBsZS50ZXN0">This email address is being protected from spambots. You need JavaScript enabled to view it.</joomla-hidden-mail>"</span>,
        <span class="k">"username"</span>: <span class="s">"admin"</span>,
        <span class="k">"type"</span>: <span class="s">"registered"</span>,
        <span class="k">"blocked"</span>: <span class="n">false</span>,
        <span class="k">"can_edit_account"</span>: <span class="n">false</span>,
        <span class="k">"groups_editable"</span>: <span class="n">false</span>,
        <span class="k">"groups"</span>: [
            {
                <span class="k">"id"</span>: <span class="n">8</span>,
                <span class="k">"title"</span>: <span class="s">"Mr"</span>
            }
        ],
        <span class="k">"available_groups"</span>: [
            {
                <span class="k">"id"</span>: <span class="n">1</span>,
                <span class="k">"title"</span>: <span class="s">"Mr"</span>,
                <span class="k">"assignable"</span>: <span class="n">false</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">9</span>,
                <span class="k">"title"</span>: <span class="s">"Mr"</span>,
                <span class="k">"assignable"</span>: <span class="n">false</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">6</span>,
                <span class="k">"title"</span>: <span class="s">"Mr"</span>,
                <span class="k">"assignable"</span>: <span class="n">false</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">7</span>,
                <span class="k">"title"</span>: <span class="s">"Mr"</span>,
                <span class="k">"assignable"</span>: <span class="n">false</span>
            },
            "… 5 more, trimmed for the example"
        ],
        <span class="k">"created"</span>: <span class="n">1778653121</span>,
        <span class="k">"addresses"</span>: [
            {
                <span class="k">"id"</span>: <span class="n">4372</span>,
                <span class="k">"types"</span>: [
                    "shipping"
                ],
                <span class="k">"name"</span>: <span class="s">"Test Buyer"</span>,
                <span class="k">"company"</span>: <span class="s">"Lilas SARL"</span>,
                <span class="k">"street"</span>: <span class="s">"12 rue des Lilas"</span>,
                <span class="k">"city"</span>: <span class="s">"Nantes"</span>,
                <span class="k">"post_code"</span>: <span class="s">"44000"</span>,
                <span class="k">"telephone"</span>: <span class="s">"+33 2 00 00 00 00"</span>,
                <span class="k">"default"</span>: <span class="n">true</span>,
                <span class="k">"formatted"</span>: {
                    <span class="k">"text"</span>: <span class="s">"Alex Marchand\r\n12 rue des Lilas\r\n44000 Nantes\r\nFrance"</span>,
                    <span class="k">"one_line"</span>: <span class="s">"Marchand Alex - 12 rue des Lilas, Nantes (France)"</span>
                }
            },
            {
                <span class="k">"id"</span>: <span class="n">4371</span>,
                <span class="k">"types"</span>: [
                    "billing"
                ],
                <span class="k">"name"</span>: <span class="s">"Test Buyer"</span>,
                <span class="k">"company"</span>: <span class="s">"Lilas SARL"</span>,
                <span class="k">"street"</span>: <span class="s">"12 rue des Lilas"</span>,
                <span class="k">"city"</span>: <span class="s">"Nantes"</span>,
                <span class="k">"post_code"</span>: <span class="s">"44000"</span>,
                <span class="k">"telephone"</span>: <span class="s">"+33 2 00 00 00 00"</span>,
                <span class="k">"default"</span>: <span class="n">true</span>,
                <span class="k">"formatted"</span>: {
                    <span class="k">"text"</span>: <span class="s">"Alex Marchand\r\n12 rue des Lilas\r\n44000 Nantes\r\nFrance"</span>,
                    <span class="k">"one_line"</span>: <span class="s">"Marchand Alex - 12 rue des Lilas, Nantes (France)"</span>
                }
            },
            {
                <span class="k">"id"</span>: <span class="n">4380</span>,
                <span class="k">"types"</span>: [
                    "billing"
                ],
                <span class="k">"name"</span>: <span class="s">"Test Buyer"</span>,
                <span class="k">"company"</span>: <span class="s">"Lilas SARL"</span>,
                <span class="k">"street"</span>: <span class="s">"12 rue des Lilas"</span>,
                <span class="k">"city"</span>: <span class="s">"Nantes"</span>,
                <span class="k">"post_code"</span>: <span class="s">"44000"</span>,
                <span class="k">"telephone"</span>: <span class="s">"+33 2 00 00 00 00"</span>,
                <span class="k">"default"</span>: <span class="n">false</span>,
                <span class="k">"formatted"</span>: {
                    <span class="k">"text"</span>: <span class="s">"Alex Marchand\r\n12 rue des Lilas\r\n44000 Nantes\r\nFrance"</span>,
                    <span class="k">"one_line"</span>: <span class="s">"Marchand Alex - 12 rue des Lilas, Nantes (France)"</span>
                }
            },
            {
                <span class="k">"id"</span>: <span class="n">4379</span>,
                <span class="k">"types"</span>: [
                    "billing"
                ],
                <span class="k">"name"</span>: <span class="s">"Test Buyer"</span>,
                <span class="k">"company"</span>: <span class="s">"Lilas SARL"</span>,
                <span class="k">"street"</span>: <span class="s">"12 rue des Lilas"</span>,
                <span class="k">"city"</span>: <span class="s">"Nantes"</span>,
                <span class="k">"post_code"</span>: <span class="s">"44000"</span>,
                <span class="k">"telephone"</span>: <span class="s">"+33 2 00 00 00 00"</span>,
                <span class="k">"default"</span>: <span class="n">false</span>,
                <span class="k">"formatted"</span>: {
                    <span class="k">"text"</span>: <span class="s">"Alex Marchand\r\n12 rue des Lilas\r\n44000 Nantes\r\nFrance"</span>,
                    <span class="k">"one_line"</span>: <span class="s">"Marchand Alex - 12 rue des Lilas, Nantes (France)"</span>
                }
            },
            "… 4 more, trimmed for the example"
        ],
        <span class="k">"orders"</span>: [
            {
                <span class="k">"id"</span>: <span class="n">2</span>,
                <span class="k">"number"</span>: <span class="s">"TEST-VOTE-1"</span>,
                <span class="k">"status"</span>: <span class="s">"confirmed"</span>,
                <span class="k">"created"</span>: <span class="n">1786877040</span>,
                <span class="k">"total"</span>: <span class="n">100</span>,
                <span class="k">"currency_id"</span>: <span class="n">1</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">18</span>,
                <span class="k">"number"</span>: <span class="s">"U18"</span>,
                <span class="k">"status"</span>: <span class="s">"confirmed"</span>,
                <span class="k">"created"</span>: <span class="n">1786358640</span>,
                <span class="k">"total"</span>: <span class="n">14.99</span>,
                <span class="k">"currency_id"</span>: <span class="n">1</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">20</span>,
                <span class="k">"number"</span>: <span class="s">"X20"</span>,
                <span class="k">"status"</span>: <span class="s">"confirmed"</span>,
                <span class="k">"created"</span>: <span class="n">1785840240</span>,
                <span class="k">"total"</span>: <span class="n">14.99</span>,
                <span class="k">"currency_id"</span>: <span class="n">1</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">16</span>,
                <span class="k">"number"</span>: <span class="s">"S16"</span>,
                <span class="k">"status"</span>: <span class="s">"created"</span>,
                <span class="k">"created"</span>: <span class="n">1783345950</span>,
                <span class="k">"total"</span>: <span class="n">14.99</span>,
                <span class="k">"currency_id"</span>: <span class="n">1</span>
            },
            "… 96 more, trimmed for the example"
        ],
        <span class="k">"fields"</span>: [],
        <span class="k">"custom_fields"</span>: [],
        <span class="k">"custom_field_files"</span>: [],
        <span class="k">"sections"</span>: [],
        <span class="k">"extensions"</span>: []
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## Delete a customer

DELETE /customers/**{id}** write since 6.6.0

Removes a customer and their addresses.

A customer with orders is refused, which is what the backend does too: delete their orders first, and then the customer.

### Path

ParameterTypeDescription

idrequiredintegerThe customer id.

### Response expand all

FieldTypeDescription

deletedbooleanTrue when the row is gone.

### Errors

CodeHTTPMeans

not\_found404No such customer, or the operator may not delete them.

has\_orders400They have orders. Delete those first.

delete\_failed400The shop refused to delete the row.

```
curl -X DELETE "$SHOP/hikashop-api/v1/customers/{id}" \
  -H "Authorization: Bearer $TOKEN"
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"deleted"</span>: <span class="n">5424</span>
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## Update a customer's profile

PUT /customers/**{id}** write since 6.6.0

Changes the name, the email address, the login, the password, the user groups and your own customer fields, and answers with the customer as it now stands.

The password is written straight into the CMS account and is never returned by anything. Changing the email of a registered customer changes the account they log in with, which is why a clash is refused rather than silently ignored.

### Path

ParameterTypeDescription

idrequiredintegerThe customer id.

### Body

FieldTypeDescription

namestringTheir display name.

emailstringMust not belong to another account.

usernamestringThe login, for a registered customer.

passwordstringA new password. Send it only when changing it.

groupsinteger\[\]The user groups they belong to, as ids from `GET /groups`.

custom\_fieldsobjectYour own customer fields, keyed by namekey.

extensionsobjectSettings other plugins keep on this record, as `{ group key: { namekey: value } }`, for the groups and fields its `extensions` lists. Saved after the record's own fields. See the guide on adding information and settings.

### Response expand all

FieldTypeDescription

idintegerThe HikaShop customer id, which is what every customer route takes.

cms\_idintegerThe Joomla or WordPress user id, `0` for a guest with no account.

namestring

emailstring

usernamestringThe login, empty for a guest.

typestring`registered` or `guest`.

blockedbooleanWhether the CMS account is disabled.

can\_edit\_accountbooleanWhether this operator may change the login and password of this particular account. False for an account above their own level, which is how a super user is protected from staff.

groups\_editablebooleanWhether this operator may change which groups the customer is in.

groupsobject\[\]The groups they are in.idinteger

titlestring

available\_groupsobject\[\]Every group, with whether this operator may put the customer into it, so a picker can grey out the rest rather than offering a refusal.idinteger

titlestring

assignablebooleanFalse for a group this operator may not grant.

createdintegerUnix timestamp of the first time the shop saw them.

addressesobject\[\]Their addresses, defaults first.idinteger

typesstring\[\]Which of `billing` and `shipping` it is used for.

namestring

companystring

streetstring

citystring

post\_codestring

telephonestring

defaultbooleanWhether it is the default for one of its types.

formattedobjectThe address laid out the way this shop lays addresses out, which depends on its address format setting.textstringSeveral lines, for an invoice or a label.

one\_linestringOne line, for a list.

ordersobject\[\]Their orders, newest first, enough to list them.idinteger

numberstringThe number the customer sees.

statusstringA namekey.

createdintegerUnix timestamp.

totalnumberTax included, in the order currency.

currency\_idintegerThat currency.

fieldsobject\[\]The definitions of your own customer fields.

custom\_fieldsobjectTheir values, keyed by namekey. The keys depend on the shop; `fields` says what they are.

custom\_field\_filesobjectFor a field holding a file, the file behind the value. Keyed the same way.

sectionsobject\[\]Information other plugins show on this record, each with a `key`, a `title` and `rows` (`label`, `value`, and optionally `url`, `badge` and `ref`). Empty when no plugin adds any; on a customer, core adds their paid downloads. See the guide on adding information and settings.

extensionsobject\[\]Settings other plugins keep on this record, in groups (`key`, `title`, `fields`), each field described like a custom field plus its current `value`. Send changes back as `extensions` with the record's save. Empty when no plugin adds any.

### Errors

CodeHTTPMeans

not\_found404No such customer, or the operator may not change them.

invalid\_email400The email address is not one.

forbidden\_target400The operator may not change this particular account, which is how a super user is protected from being edited by staff.

username\_taken400Another account has that login.

email\_taken400Another account has that email address.

account\_save\_failed400The CMS refused to save the account.

invalid\_fields400One of your own fields was rejected by its own rules.

invalid\_extensions400The record's own fields were saved, but a plugin refused some of its values: &#96;error.details&#96; says which, as &#96;{ group key: { namekey: message } }&#96;.

```
curl -X PUT "$SHOP/hikashop-api/v1/customers/{id}" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Alex Marchand"
}'
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"id"</span>: <span class="n">20</span>,
        <span class="k">"cms_id"</span>: <span class="n">0</span>,
        <span class="k">"name"</span>: <span class="s">"John Doe"</span>,
        <span class="k">"email"</span>: <span class="s">"<joomla-hidden-mail base="" first="YnV5ZXI=" is-email="1" is-link="1" last="ZXhhbXBsZS50ZXN0" text="YnV5ZXJAZXhhbXBsZS50ZXN0">This email address is being protected from spambots. You need JavaScript enabled to view it.</joomla-hidden-mail>"</span>,
        <span class="k">"username"</span>: <span class="s">""</span>,
        <span class="k">"type"</span>: <span class="s">"guest"</span>,
        <span class="k">"blocked"</span>: <span class="n">false</span>,
        <span class="k">"can_edit_account"</span>: <span class="n">true</span>,
        <span class="k">"groups_editable"</span>: <span class="n">false</span>,
        <span class="k">"groups"</span>: [],
        <span class="k">"available_groups"</span>: [
            {
                <span class="k">"id"</span>: <span class="n">1</span>,
                <span class="k">"title"</span>: <span class="s">"Mr"</span>,
                <span class="k">"assignable"</span>: <span class="n">false</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">9</span>,
                <span class="k">"title"</span>: <span class="s">"Mr"</span>,
                <span class="k">"assignable"</span>: <span class="n">false</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">6</span>,
                <span class="k">"title"</span>: <span class="s">"Mr"</span>,
                <span class="k">"assignable"</span>: <span class="n">false</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">7</span>,
                <span class="k">"title"</span>: <span class="s">"Mr"</span>,
                <span class="k">"assignable"</span>: <span class="n">false</span>
            },
            "… 5 more, trimmed for the example"
        ],
        <span class="k">"created"</span>: <span class="n">1786963440</span>,
        <span class="k">"addresses"</span>: [
            {
                <span class="k">"id"</span>: <span class="n">26</span>,
                <span class="k">"types"</span>: [
                    "billing"
                ],
                <span class="k">"name"</span>: <span class="s">"John Doe"</span>,
                <span class="k">"company"</span>: <span class="s">"Lilas SARL"</span>,
                <span class="k">"street"</span>: <span class="s">"12 rue des Lilas"</span>,
                <span class="k">"city"</span>: <span class="s">"Nantes"</span>,
                <span class="k">"post_code"</span>: <span class="s">"44000"</span>,
                <span class="k">"telephone"</span>: <span class="s">"+33 2 00 00 00 00"</span>,
                <span class="k">"default"</span>: <span class="n">true</span>,
                <span class="k">"formatted"</span>: {
                    <span class="k">"text"</span>: <span class="s">"Alex Marchand\r\n12 rue des Lilas\r\n44000 Nantes\r\nFrance"</span>,
                    <span class="k">"one_line"</span>: <span class="s">"Marchand Alex - 12 rue des Lilas, Nantes (France)"</span>
                }
            },
            {
                <span class="k">"id"</span>: <span class="n">25</span>,
                <span class="k">"types"</span>: [
                    "shipping"
                ],
                <span class="k">"name"</span>: <span class="s">"John Doe"</span>,
                <span class="k">"company"</span>: <span class="s">"Lilas SARL"</span>,
                <span class="k">"street"</span>: <span class="s">"12 rue des Lilas"</span>,
                <span class="k">"city"</span>: <span class="s">"Nantes"</span>,
                <span class="k">"post_code"</span>: <span class="s">"44000"</span>,
                <span class="k">"telephone"</span>: <span class="s">"+33 2 00 00 00 00"</span>,
                <span class="k">"default"</span>: <span class="n">true</span>,
                <span class="k">"formatted"</span>: {
                    <span class="k">"text"</span>: <span class="s">"Alex Marchand\r\n12 rue des Lilas\r\n44000 Nantes\r\nFrance"</span>,
                    <span class="k">"one_line"</span>: <span class="s">"Marchand Alex - 12 rue des Lilas, Nantes (France)"</span>
                }
            }
        ],
        <span class="k">"orders"</span>: [
            {
                <span class="k">"id"</span>: <span class="n">26</span>,
                <span class="k">"number"</span>: <span class="s">"B2D6"</span>,
                <span class="k">"status"</span>: <span class="s">"created"</span>,
                <span class="k">"created"</span>: <span class="n">1785338765</span>,
                <span class="k">"total"</span>: <span class="n">14.99</span>,
                <span class="k">"currency_id"</span>: <span class="n">1</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">28</span>,
                <span class="k">"number"</span>: <span class="s">"B2F8"</span>,
                <span class="k">"status"</span>: <span class="s">"confirmed"</span>,
                <span class="k">"created"</span>: <span class="n">1785321840</span>,
                <span class="k">"total"</span>: <span class="n">14.99</span>,
                <span class="k">"currency_id"</span>: <span class="n">1</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">30</span>,
                <span class="k">"number"</span>: <span class="s">"ZBUNDLE"</span>,
                <span class="k">"status"</span>: <span class="s">"confirmed"</span>,
                <span class="k">"created"</span>: <span class="n">1784803440</span>,
                <span class="k">"total"</span>: <span class="n">14.99</span>,
                <span class="k">"currency_id"</span>: <span class="n">1</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">22</span>,
                <span class="k">"number"</span>: <span class="s">"Z22"</span>,
                <span class="k">"status"</span>: <span class="s">"created"</span>,
                <span class="k">"created"</span>: <span class="n">1783721823</span>,
                <span class="k">"total"</span>: <span class="n">14.99</span>,
                <span class="k">"currency_id"</span>: <span class="n">1</span>
            }
        ],
        <span class="k">"fields"</span>: [],
        <span class="k">"custom_fields"</span>: [],
        <span class="k">"custom_field_files"</span>: [],
        <span class="k">"sections"</span>: [],
        <span class="k">"extensions"</span>: []
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## Give a guest an account

POST /customers/**{id}**/account write since 6.6.0

Turns a guest into a registered customer, keeping their orders and addresses, and answers with the customer as it now stands.

This is the useful direction: someone ordered without an account, then asked for one. Creating the account separately would leave their history behind.

### Path

ParameterTypeDescription

idrequiredintegerThe guest customer.

### Body

FieldTypeDescription

usernamerequiredstringThe login to create.

passwordrequiredstringTheir password. Never returned by anything afterwards.

namestringTheir display name, defaulting to the one on the guest record.

groupsinteger\[\]The user groups to put them in.

### Response expand all

FieldTypeDescription

idintegerThe HikaShop customer id, which is what every customer route takes.

cms\_idintegerThe Joomla or WordPress user id, `0` for a guest with no account.

namestring

emailstring

usernamestringThe login, empty for a guest.

typestring`registered` or `guest`.

blockedbooleanWhether the CMS account is disabled.

can\_edit\_accountbooleanWhether this operator may change the login and password of this particular account. False for an account above their own level, which is how a super user is protected from staff.

groups\_editablebooleanWhether this operator may change which groups the customer is in.

groupsobject\[\]The groups they are in.idinteger

titlestring

available\_groupsobject\[\]Every group, with whether this operator may put the customer into it, so a picker can grey out the rest rather than offering a refusal.idinteger

titlestring

assignablebooleanFalse for a group this operator may not grant.

createdintegerUnix timestamp of the first time the shop saw them.

addressesobject\[\]Their addresses, defaults first.idinteger

typesstring\[\]Which of `billing` and `shipping` it is used for.

namestring

companystring

streetstring

citystring

post\_codestring

telephonestring

defaultbooleanWhether it is the default for one of its types.

formattedobjectThe address laid out the way this shop lays addresses out, which depends on its address format setting.textstringSeveral lines, for an invoice or a label.

one\_linestringOne line, for a list.

ordersobject\[\]Their orders, newest first, enough to list them.idinteger

numberstringThe number the customer sees.

statusstringA namekey.

createdintegerUnix timestamp.

totalnumberTax included, in the order currency.

currency\_idintegerThat currency.

fieldsobject\[\]The definitions of your own customer fields.

custom\_fieldsobjectTheir values, keyed by namekey. The keys depend on the shop; `fields` says what they are.

custom\_field\_filesobjectFor a field holding a file, the file behind the value. Keyed the same way.

### Errors

CodeHTTPMeans

not\_found404No such customer.

already\_registered400They already have an account.

missing\_credentials400A username and a password are both required.

invalid\_email400The address on the guest record is not usable as an account email.

email\_taken400Another account has that email address.

username\_taken400Another account has that login.

account\_save\_failed400The CMS refused to create the account.

```
curl -X POST "$SHOP/hikashop-api/v1/customers/{id}/account" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "username": "doccapture5412",
    "password": "not-a-real-password-9x"
}'
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"id"</span>: <span class="n">5412</span>,
        <span class="k">"cms_id"</span>: <span class="n">181</span>,
        <span class="k">"name"</span>: <span class="s">"<joomla-hidden-mail base="" first="YnV5ZXI=" is-email="1" is-link="1" last="ZXhhbXBsZS50ZXN0" text="YnV5ZXJAZXhhbXBsZS50ZXN0">This email address is being protected from spambots. You need JavaScript enabled to view it.</joomla-hidden-mail>"</span>,
        <span class="k">"email"</span>: <span class="s">"<joomla-hidden-mail base="" first="YnV5ZXI=" is-email="1" is-link="1" last="ZXhhbXBsZS50ZXN0" text="YnV5ZXJAZXhhbXBsZS50ZXN0">This email address is being protected from spambots. You need JavaScript enabled to view it.</joomla-hidden-mail>"</span>,
        <span class="k">"username"</span>: <span class="s">"doccapture5412"</span>,
        <span class="k">"type"</span>: <span class="s">"registered"</span>,
        <span class="k">"blocked"</span>: <span class="n">false</span>,
        <span class="k">"can_edit_account"</span>: <span class="n">true</span>,
        <span class="k">"groups_editable"</span>: <span class="n">false</span>,
        <span class="k">"groups"</span>: [
            {
                <span class="k">"id"</span>: <span class="n">2</span>,
                <span class="k">"title"</span>: <span class="s">"Mr"</span>
            }
        ],
        <span class="k">"available_groups"</span>: [
            {
                <span class="k">"id"</span>: <span class="n">1</span>,
                <span class="k">"title"</span>: <span class="s">"Mr"</span>,
                <span class="k">"assignable"</span>: <span class="n">false</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">9</span>,
                <span class="k">"title"</span>: <span class="s">"Mr"</span>,
                <span class="k">"assignable"</span>: <span class="n">false</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">6</span>,
                <span class="k">"title"</span>: <span class="s">"Mr"</span>,
                <span class="k">"assignable"</span>: <span class="n">false</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">7</span>,
                <span class="k">"title"</span>: <span class="s">"Mr"</span>,
                <span class="k">"assignable"</span>: <span class="n">false</span>
            },
            "… 5 more, trimmed for the example"
        ],
        <span class="k">"created"</span>: <span class="n">1789923608</span>,
        <span class="k">"addresses"</span>: [],
        <span class="k">"orders"</span>: [],
        <span class="k">"fields"</span>: [],
        <span class="k">"custom_fields"</span>: [],
        <span class="k">"custom_field_files"</span>: []
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## Create a product

POST /products public since 6.6.0

Creates a product and answers with its id. Only the name is required; everything else can be set now or later with `PUT /products/{id}`.

Prices, images and categories are separate calls, so a new product is not sellable until it has at least one price.

### Body

Any of the fields a product carries: `name` (required), `code`, `description`, `published`, `msrp`, `gtin`, `condition`, `weight`, `weight_unit`, `width`, `height`, `length`, `dimension_unit`, `min_per_order`, `max_per_order`, `sale_start`, `sale_end`, `page_title`, `meta_description`, `keywords`, `canonical`, `url`, `alias`, `tax_id`, `manufacturer_id`, `contact`, `warehouse_id`, plus `access` and `custom_fields`.

They mean what they mean on `GET /products/{id}`. A field the shop's own schema does not have is ignored rather than refused, which is what lets one client talk to shops of different vintages.

### Response expand all

FieldTypeDescription

idstring

namestring

codestringThe SKU. Unique within the shop.

descriptionstringThe long description, as HTML.

description\_typestringWhich editor the description was written with.

publishedboolean

quantityinteger`-1` when this product does not track stock, which is not the same as `0`.

msrpintegerThe manufacturer's suggested price, shown struck through when the shop is configured to.

gtinstringThe barcode: EAN, UPC or ISBN. This is what `GET /products/lookup` matches on.

conditionstringNew, used, refurbished. Used by the feeds rather than by the shop itself.

weightintegerShipping weight, in `weight_unit`.

weight\_unitstring`kg`, `g`, `lb` or `oz`.

widthintegerIn `dimension_unit`.

heightintegerIn `dimension_unit`.

lengthintegerIn `dimension_unit`.

dimension\_unitstring`m`, `cm`, `mm`, `ft` or `in`.

min\_per\_orderintegerThe smallest quantity a customer may order, `0` for no minimum.

max\_per\_orderintegerThe largest, `0` for no maximum.

sale\_startinteger\|nullUnix timestamp before which the product is not on sale.

sale\_endinteger\|nullUnix timestamp after which it is no longer sold.

page\_titlestringSEO title, empty to use the name.

meta\_descriptionstringSEO description.

keywordsstringSEO keywords.

canonicalstringA canonical URL, when this page should point at another.

urlstringThe address of the product page on the shop.

aliasstringThe slug used in that address.

accessobjectWho may see the product: `mode` (`all`, `none` or `groups`) and `groups`, which are user \*\*group\*\* ids and not Joomla view levels. The two id spaces overlap and disagree, so a value that looks plausible can grant the wrong audience.modestring`all`, `none`, or `groups` when it is restricted to some.

groupsinteger\[\]User group ids, meaningful only when the mode is `groups`.

contactbooleanWhether this product is enquired about rather than bought.

warehouse\_idintegerThe warehouse holding the stock, `0` when the shop has none.

typestring`main` for a product, `variant` for one of its variants.

parent\_idintegerThe parent product when this is a variant, `0` otherwise.

value\_idsinteger\[\]For a variant, the characteristic values it stands for.

manufacturer\_idintegerThe brand, `0` when unset.

manufacturer\_namestringIts name, saving a second call.

tax\_idintegerThe tax category, `0` when the product is untaxed.

tax\_namestringIts name.

tax\_ratenumberThe rate as a fraction, so `0.2` is twenty percent.

pricesobject\[\]Every price row, including the restricted ones. A product with none is not sellable.idstring

valuestringTax excluded, as stored.

currency\_idstring

min\_quantitystringFrom how many items this row applies, which is how quantity breaks are expressed.

accessobjectWho this price is for, in the same shape as the product access.modestringAs above.

groupsinteger\[\]As above.

usersinteger\[\]Named customers, empty for everyone.

zone\_idsinteger\[\]Zones this price applies in, empty for everywhere.

start\_dateinteger\|nullUnix timestamp.

end\_dateinteger\|nullUnix timestamp.

imagesobject\[\]In the order the editor shows them; the first is the main image.idstring

namestring

pathstringRelative to the upload folder.

urlstringAbsolute, ready to display.

orderingstring

descriptionstringThe alt text.

accessobjectWho may see it.modestringAs above.

groupsinteger\[\]As above.

free\_downloadstringFiles only; meaningless on an image.

filesobject\[\]Downloadable files, in the same shape as the images.idstring

namestring

pathstringRelative to the upload folder.

urlstringAbsolute.

orderingstring

descriptionstring

accessobjectWho may download it.

free\_downloadstringWhether it can be downloaded without buying the product.

categoriesobject\[\]The categories the product is in.idinteger

namestring

bundleobject\[\]The products this one is made of, when it is a bundle.idstring

namestring

codestring

quantitystringHow many of it the bundle contains.

optionsobject\[\]Products offered as options alongside this one.idstring

namestring

codestring

quantitystring

relatedobject\[\]Products shown as related.idstring

namestring

codestring

quantitystring

tagsinteger\[\]CMS tag ids.

characteristicsobject\[\]The characteristics this product varies on. Empty when it has no variants.idintegerThe characteristic, such as Size.

namestringIts name.

valuesobject\[\]The values of it this product uses, such as S, M and L.idintegerThe value id, which is what a variant refers to.

valuestringIts name, such as `M`.

variantsobject\[\]Every variant, with its own code, stock, price and images. Empty for a product that does not vary.idintegerThe variant is a product in its own right, and this is its id.

codestringIts own SKU.

quantityintegerIts own stock. This is the figure to change, not the parent's.

publishedboolean

pricenumber\|null`null` when the variant has no price of its own and the parent's applies.

valuesobject\[\]Which characteristic values this variant stands for, one per characteristic.option\_idintegerThe characteristic.

option\_namestringIts name, so the variant can be labelled without a second call.

value\_idintegerThe value.

valuestringIts name.

imagesobject\[\]The variant's own images, in the same shape as the product's.idinteger

namestring

pathstringRelative to the upload folder.

urlstringAbsolute.

orderinginteger

fieldsobject\[\]The definitions of the custom fields that apply to this product, so a client can build a form for them.namekeystringThe key used in `custom_fields`.

typestring`text`, `radio`, `singledropdown`, `file`, and the rest of HikaShop's field types.

raw\_typestringHikaShop's own name for the type, before it is mapped to something a client can render.

labelstringTranslated into the operator's language.

defaultstringThe value used when none is given.

requiredbooleanWhether the shop refuses to save the product without it.

optionsobject\[\]The choices, for a field that has them. Empty for a free text one.

multiplebooleanWhether more than one choice may be selected.

translatablebooleanWhether its value can be translated, which is what the translation routes offer.

upload\_dirstringFor a file field, where its uploads are kept.

allowed\_extensionsstringFor a file field, the extensions it accepts, comma separated. Empty means the shop default.

date\_formatstringFor a date field, the format it is stored in.

custom\_fieldsobjectTheir values, keyed by namekey. The keys depend on the shop; `fields` says what they are.

custom\_field\_filesobjectFor custom fields holding a file, the file behind each value. Keyed the same way.

sectionsobject\[\]Information other plugins show on this record, each with a `key`, a `title` and `rows` (`label`, `value`, and optionally `url`, `badge` and `ref`). Empty when no plugin adds any; on a customer, core adds their paid downloads. See the guide on adding information and settings.

extensionsobject\[\]Settings other plugins keep on this record, in groups (`key`, `title`, `fields`), each field described like a custom field plus its current `value`. Send changes back as `extensions` with the record's save. Empty when no plugin adds any.

### Errors

CodeHTTPMeans

invalid\_fields400One of your own fields was rejected by its own rules.

save\_failed500The shop refused to save the product.

```
curl -X POST "$SHOP/hikashop-api/v1/products" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Documentation capture product",
    "code": "DOC-CAPTURE-1"
}'
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"id"</span>: <span class="n">9149</span>,
        <span class="k">"name"</span>: <span class="s">"Documentation capture product"</span>,
        <span class="k">"code"</span>: <span class="s">"DOC-CAPTURE-1"</span>,
        <span class="k">"description"</span>: <span class="s">""</span>,
        <span class="k">"description_type"</span>: <span class="s">""</span>,
        <span class="k">"published"</span>: <span class="n">false</span>,
        <span class="k">"quantity"</span>: <span class="n">-1</span>,
        <span class="k">"msrp"</span>: <span class="n">0</span>,
        <span class="k">"gtin"</span>: <span class="s">""</span>,
        <span class="k">"condition"</span>: <span class="s">""</span>,
        <span class="k">"weight"</span>: <span class="n">0</span>,
        <span class="k">"weight_unit"</span>: <span class="s">"kg"</span>,
        <span class="k">"width"</span>: <span class="n">0</span>,
        <span class="k">"height"</span>: <span class="n">0</span>,
        <span class="k">"length"</span>: <span class="n">0</span>,
        <span class="k">"dimension_unit"</span>: <span class="s">"m"</span>,
        <span class="k">"min_per_order"</span>: <span class="n">0</span>,
        <span class="k">"max_per_order"</span>: <span class="n">0</span>,
        <span class="k">"sale_start"</span>: <span class="n">0</span>,
        <span class="k">"sale_end"</span>: <span class="n">0</span>,
        <span class="k">"page_title"</span>: <span class="s">""</span>,
        <span class="k">"meta_description"</span>: <span class="s">""</span>,
        <span class="k">"keywords"</span>: <span class="s">""</span>,
        <span class="k">"canonical"</span>: <span class="s">""</span>,
        <span class="k">"url"</span>: <span class="s">""</span>,
        <span class="k">"alias"</span>: <span class="s">"documentation-capture-product"</span>,
        <span class="k">"access"</span>: {
            <span class="k">"mode"</span>: <span class="s">"all"</span>,
            <span class="k">"groups"</span>: []
        },
        <span class="k">"contact"</span>: <span class="n">false</span>,
        <span class="k">"warehouse_id"</span>: <span class="n">0</span>,
        <span class="k">"type"</span>: <span class="s">"main"</span>,
        <span class="k">"parent_id"</span>: <span class="n">0</span>,
        <span class="k">"value_ids"</span>: [],
        <span class="k">"manufacturer_id"</span>: <span class="n">0</span>,
        <span class="k">"manufacturer_name"</span>: <span class="s">""</span>,
        <span class="k">"tax_id"</span>: <span class="n">0</span>,
        <span class="k">"tax_name"</span>: <span class="s">""</span>,
        <span class="k">"tax_rate"</span>: <span class="n">0</span>,
        <span class="k">"prices"</span>: [],
        <span class="k">"images"</span>: [],
        <span class="k">"files"</span>: [],
        <span class="k">"categories"</span>: [
            {
                <span class="k">"id"</span>: <span class="n">2</span>,
                <span class="k">"name"</span>: <span class="s">"product category"</span>
            }
        ],
        <span class="k">"bundle"</span>: [],
        <span class="k">"options"</span>: [],
        <span class="k">"related"</span>: [],
        <span class="k">"tags"</span>: [],
        <span class="k">"characteristics"</span>: [],
        <span class="k">"variants"</span>: [],
        <span class="k">"fields"</span>: [
            {
                <span class="k">"namekey"</span>: <span class="s">"test_ajax_image"</span>,
                <span class="k">"type"</span>: <span class="s">"ajaximage"</span>,
                <span class="k">"raw_type"</span>: <span class="s">"ajaximage"</span>,
                <span class="k">"label"</span>: <span class="s">"Test Ajax Image"</span>,
                <span class="k">"default"</span>: <span class="s">""</span>,
                <span class="k">"required"</span>: <span class="n">false</span>,
                <span class="k">"options"</span>: [],
                <span class="k">"multiple"</span>: <span class="n">false</span>,
                <span class="k">"translatable"</span>: <span class="n">false</span>,
                <span class="k">"upload_dir"</span>: <span class="s">""</span>,
                <span class="k">"allowed_extensions"</span>: <span class="s">""</span>,
                <span class="k">"date_format"</span>: <span class="s">""</span>
            },
            {
                <span class="k">"namekey"</span>: <span class="s">"product_gtin"</span>,
                <span class="k">"type"</span>: <span class="s">"text"</span>,
                <span class="k">"raw_type"</span>: <span class="s">"text"</span>,
                <span class="k">"label"</span>: <span class="s">"GTIN"</span>,
                <span class="k">"default"</span>: <span class="s">""</span>,
                <span class="k">"required"</span>: <span class="n">false</span>,
                <span class="k">"options"</span>: [],
                <span class="k">"multiple"</span>: <span class="n">false</span>,
                <span class="k">"translatable"</span>: <span class="n">false</span>,
                <span class="k">"upload_dir"</span>: <span class="s">""</span>,
                <span class="k">"allowed_extensions"</span>: <span class="s">""</span>,
                <span class="k">"date_format"</span>: <span class="s">""</span>
            }
        ],
        <span class="k">"custom_fields"</span>: {
            <span class="k">"test_ajax_image"</span>: <span class="n">null</span>,
            <span class="k">"product_gtin"</span>: <span class="n">null</span>
        },
        <span class="k">"custom_field_files"</span>: {
            <span class="k">"test_ajax_image"</span>: []
        },
        <span class="k">"sections"</span>: [],
        <span class="k">"extensions"</span>: []
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## Update a product

PUT /products/**{id}** write since 6.6.0

Changes the fields you send and leaves the rest alone, which is the opposite of the price and category calls: this one merges.

Sending nothing to change is refused rather than treated as a success, so a client cannot believe it saved something it did not.

### Path

ParameterTypeDescription

idrequiredintegerThe product or variant.

### Body

The same fields as `POST /products`, all of them optional here. A field you do not send keeps its value; `access` and `custom_fields` are accepted too, and `extensions` for other plugins' settings (`{ group key: { namekey: value } }`, saved after the product's own fields; see the guide on adding information and settings).

### Response expand all

FieldTypeDescription

idstring

namestring

codestringThe SKU. Unique within the shop.

descriptionstringThe long description, as HTML.

description\_typestringWhich editor the description was written with.

publishedboolean

quantityinteger`-1` when this product does not track stock, which is not the same as `0`.

msrpintegerThe manufacturer's suggested price, shown struck through when the shop is configured to.

gtinstringThe barcode: EAN, UPC or ISBN. This is what `GET /products/lookup` matches on.

conditionstringNew, used, refurbished. Used by the feeds rather than by the shop itself.

weightintegerShipping weight, in `weight_unit`.

weight\_unitstring`kg`, `g`, `lb` or `oz`.

widthintegerIn `dimension_unit`.

heightintegerIn `dimension_unit`.

lengthintegerIn `dimension_unit`.

dimension\_unitstring`m`, `cm`, `mm`, `ft` or `in`.

min\_per\_orderintegerThe smallest quantity a customer may order, `0` for no minimum.

max\_per\_orderintegerThe largest, `0` for no maximum.

sale\_startinteger\|nullUnix timestamp before which the product is not on sale.

sale\_endinteger\|nullUnix timestamp after which it is no longer sold.

page\_titlestringSEO title, empty to use the name.

meta\_descriptionstringSEO description.

keywordsstringSEO keywords.

canonicalstringA canonical URL, when this page should point at another.

urlstringThe address of the product page on the shop.

aliasstringThe slug used in that address.

accessobjectWho may see the product: `mode` (`all`, `none` or `groups`) and `groups`, which are user \*\*group\*\* ids and not Joomla view levels. The two id spaces overlap and disagree, so a value that looks plausible can grant the wrong audience.modestring`all`, `none`, or `groups` when it is restricted to some.

groupsinteger\[\]User group ids, meaningful only when the mode is `groups`.

contactbooleanWhether this product is enquired about rather than bought.

warehouse\_idintegerThe warehouse holding the stock, `0` when the shop has none.

typestring`main` for a product, `variant` for one of its variants.

parent\_idintegerThe parent product when this is a variant, `0` otherwise.

value\_idsinteger\[\]For a variant, the characteristic values it stands for.

manufacturer\_idintegerThe brand, `0` when unset.

manufacturer\_namestringIts name, saving a second call.

tax\_idintegerThe tax category, `0` when the product is untaxed.

tax\_namestringIts name.

tax\_ratenumberThe rate as a fraction, so `0.2` is twenty percent.

pricesobject\[\]Every price row, including the restricted ones. A product with none is not sellable.idinteger

valuenumberTax excluded, as stored.

currency\_idinteger

min\_quantityintegerFrom how many items this row applies, which is how quantity breaks are expressed.

accessobjectWho this price is for, in the same shape as the product access.modestringAs above.

groupsinteger\[\]As above.

usersinteger\[\]Named customers, empty for everyone.

zone\_idsinteger\[\]Zones this price applies in, empty for everywhere.

start\_dateinteger\|nullUnix timestamp.

end\_dateinteger\|nullUnix timestamp.

imagesobject\[\]In the order the editor shows them; the first is the main image.idinteger

namestring

pathstringRelative to the upload folder.

urlstringAbsolute, ready to display.

orderinginteger

descriptionstringThe alt text.

accessobjectWho may see it.modestringAs above.

groupsinteger\[\]As above.

free\_downloadbooleanFiles only; meaningless on an image.

filesobject\[\]Downloadable files, in the same shape as the images.idstring

namestring

pathstringRelative to the upload folder.

urlstringAbsolute.

orderingstring

descriptionstring

accessobjectWho may download it.

free\_downloadstringWhether it can be downloaded without buying the product.

categoriesobject\[\]The categories the product is in.idinteger

namestring

bundleobject\[\]The products this one is made of, when it is a bundle.idstring

namestring

codestring

quantitystringHow many of it the bundle contains.

optionsobject\[\]Products offered as options alongside this one.idstring

namestring

codestring

quantitystring

relatedobject\[\]Products shown as related.idstring

namestring

codestring

quantitystring

tagsinteger\[\]CMS tag ids.

characteristicsobject\[\]The characteristics this product varies on. Empty when it has no variants.idintegerThe characteristic, such as Size.

namestringIts name.

valuesobject\[\]The values of it this product uses, such as S, M and L.idintegerThe value id, which is what a variant refers to.

valuestringIts name, such as `M`.

variantsobject\[\]Every variant, with its own code, stock, price and images. Empty for a product that does not vary.idintegerThe variant is a product in its own right, and this is its id.

codestringIts own SKU.

quantityintegerIts own stock. This is the figure to change, not the parent's.

publishedboolean

pricenumber\|null`null` when the variant has no price of its own and the parent's applies.

valuesobject\[\]Which characteristic values this variant stands for, one per characteristic.option\_idintegerThe characteristic.

option\_namestringIts name, so the variant can be labelled without a second call.

value\_idintegerThe value.

valuestringIts name.

imagesobject\[\]The variant's own images, in the same shape as the product's.idinteger

namestring

pathstringRelative to the upload folder.

urlstringAbsolute.

orderinginteger

fieldsobject\[\]The definitions of the custom fields that apply to this product, so a client can build a form for them.namekeystringThe key used in `custom_fields`.

typestring`text`, `radio`, `singledropdown`, `file`, and the rest of HikaShop's field types.

raw\_typestringHikaShop's own name for the type, before it is mapped to something a client can render.

labelstringTranslated into the operator's language.

defaultstringThe value used when none is given.

requiredbooleanWhether the shop refuses to save the product without it.

optionsobject\[\]The choices, for a field that has them. Empty for a free text one.

multiplebooleanWhether more than one choice may be selected.

translatablebooleanWhether its value can be translated, which is what the translation routes offer.

upload\_dirstringFor a file field, where its uploads are kept.

allowed\_extensionsstringFor a file field, the extensions it accepts, comma separated. Empty means the shop default.

date\_formatstringFor a date field, the format it is stored in.

custom\_fieldsobjectTheir values, keyed by namekey. The keys depend on the shop; `fields` says what they are.

custom\_field\_filesobjectFor custom fields holding a file, the file behind each value. Keyed the same way.

sectionsobject\[\]Information other plugins show on this record, each with a `key`, a `title` and `rows` (`label`, `value`, and optionally `url`, `badge` and `ref`). Empty when no plugin adds any; on a customer, core adds their paid downloads. See the guide on adding information and settings.

extensionsobject\[\]Settings other plugins keep on this record, in groups (`key`, `title`, `fields`), each field described like a custom field plus its current `value`. Send changes back as `extensions` with the record's save. Empty when no plugin adds any.

### Errors

CodeHTTPMeans

not\_found404No such product, or the operator may not change it.

invalid\_fields400One of your own fields was rejected by its own rules.

nothing400The body held no field this shop knows, so nothing would have been written.

invalid\_extensions400The product was saved, but a plugin refused some of its values: &#96;error.details&#96; says which, as &#96;{ group key: { namekey: message } }&#96;.

```
curl -X PUT "$SHOP/hikashop-api/v1/products/{id}" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Desk lamp, brass"
}'
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"id"</span>: <span class="n">9136</span>,
        <span class="k">"name"</span>: <span class="s">"Desk lamp, brass"</span>,
        <span class="k">"code"</span>: <span class="s">"HS-TEST-27025"</span>,
        <span class="k">"description"</span>: <span class="s">""</span>,
        <span class="k">"description_type"</span>: <span class="s">""</span>,
        <span class="k">"published"</span>: <span class="n">false</span>,
        <span class="k">"quantity"</span>: <span class="n">-1</span>,
        <span class="k">"msrp"</span>: <span class="n">0</span>,
        <span class="k">"gtin"</span>: <span class="s">""</span>,
        <span class="k">"condition"</span>: <span class="s">""</span>,
        <span class="k">"weight"</span>: <span class="n">0</span>,
        <span class="k">"weight_unit"</span>: <span class="s">"kg"</span>,
        <span class="k">"width"</span>: <span class="n">0</span>,
        <span class="k">"height"</span>: <span class="n">0</span>,
        <span class="k">"length"</span>: <span class="n">0</span>,
        <span class="k">"dimension_unit"</span>: <span class="s">"m"</span>,
        <span class="k">"min_per_order"</span>: <span class="n">0</span>,
        <span class="k">"max_per_order"</span>: <span class="n">0</span>,
        <span class="k">"sale_start"</span>: <span class="n">0</span>,
        <span class="k">"sale_end"</span>: <span class="n">0</span>,
        <span class="k">"page_title"</span>: <span class="s">""</span>,
        <span class="k">"meta_description"</span>: <span class="s">""</span>,
        <span class="k">"keywords"</span>: <span class="s">""</span>,
        <span class="k">"canonical"</span>: <span class="s">""</span>,
        <span class="k">"url"</span>: <span class="s">""</span>,
        <span class="k">"alias"</span>: <span class="s">"desk-lamp-brass"</span>,
        <span class="k">"access"</span>: {
            <span class="k">"mode"</span>: <span class="s">"all"</span>,
            <span class="k">"groups"</span>: []
        },
        <span class="k">"contact"</span>: <span class="n">false</span>,
        <span class="k">"warehouse_id"</span>: <span class="n">0</span>,
        <span class="k">"type"</span>: <span class="s">"main"</span>,
        <span class="k">"parent_id"</span>: <span class="n">0</span>,
        <span class="k">"value_ids"</span>: [],
        <span class="k">"manufacturer_id"</span>: <span class="n">0</span>,
        <span class="k">"manufacturer_name"</span>: <span class="s">""</span>,
        <span class="k">"tax_id"</span>: <span class="n">0</span>,
        <span class="k">"tax_name"</span>: <span class="s">""</span>,
        <span class="k">"tax_rate"</span>: <span class="n">0</span>,
        <span class="k">"prices"</span>: [
            {
                <span class="k">"id"</span>: <span class="n">4947</span>,
                <span class="k">"value"</span>: <span class="n">19.9</span>,
                <span class="k">"currency_id"</span>: <span class="n">1</span>,
                <span class="k">"min_quantity"</span>: <span class="n">1</span>,
                <span class="k">"access"</span>: {
                    <span class="k">"mode"</span>: <span class="s">"all"</span>,
                    <span class="k">"groups"</span>: []
                },
                <span class="k">"users"</span>: [],
                <span class="k">"zone_ids"</span>: [],
                <span class="k">"start_date"</span>: <span class="n">0</span>,
                <span class="k">"end_date"</span>: <span class="n">0</span>
            }
        ],
        <span class="k">"images"</span>: [
            {
                <span class="k">"id"</span>: <span class="n">8333</span>,
                <span class="k">"name"</span>: <span class="s">"documentation-capture.png"</span>,
                <span class="k">"path"</span>: <span class="s">"documentation-capture.png"</span>,
                <span class="k">"url"</span>: <span class="s">"http://localhost:<span class="n">8080</span>/joomla6_ext/images/com_hikashop/upload/documentation-capture.png"</span>,
                <span class="k">"ordering"</span>: <span class="n">1</span>,
                <span class="k">"description"</span>: <span class="s">"A one pixel image"</span>,
                <span class="k">"access"</span>: {
                    <span class="k">"mode"</span>: <span class="s">"all"</span>,
                    <span class="k">"groups"</span>: []
                },
                <span class="k">"free_download"</span>: <span class="n">false</span>
            }
        ],
        <span class="k">"files"</span>: [],
        <span class="k">"categories"</span>: [
            {
                <span class="k">"id"</span>: <span class="n">2</span>,
                <span class="k">"name"</span>: <span class="s">"product category"</span>
            }
        ],
        <span class="k">"bundle"</span>: [],
        <span class="k">"options"</span>: [],
        <span class="k">"related"</span>: [],
        <span class="k">"tags"</span>: [],
        <span class="k">"characteristics"</span>: [],
        <span class="k">"variants"</span>: [],
        <span class="k">"fields"</span>: [
            {
                <span class="k">"namekey"</span>: <span class="s">"test_ajax_image"</span>,
                <span class="k">"type"</span>: <span class="s">"ajaximage"</span>,
                <span class="k">"raw_type"</span>: <span class="s">"ajaximage"</span>,
                <span class="k">"label"</span>: <span class="s">"Test Ajax Image"</span>,
                <span class="k">"default"</span>: <span class="s">""</span>,
                <span class="k">"required"</span>: <span class="n">false</span>,
                <span class="k">"options"</span>: [],
                <span class="k">"multiple"</span>: <span class="n">false</span>,
                <span class="k">"translatable"</span>: <span class="n">false</span>,
                <span class="k">"upload_dir"</span>: <span class="s">""</span>,
                <span class="k">"allowed_extensions"</span>: <span class="s">""</span>,
                <span class="k">"date_format"</span>: <span class="s">""</span>
            },
            {
                <span class="k">"namekey"</span>: <span class="s">"product_gtin"</span>,
                <span class="k">"type"</span>: <span class="s">"text"</span>,
                <span class="k">"raw_type"</span>: <span class="s">"text"</span>,
                <span class="k">"label"</span>: <span class="s">"GTIN"</span>,
                <span class="k">"default"</span>: <span class="s">""</span>,
                <span class="k">"required"</span>: <span class="n">false</span>,
                <span class="k">"options"</span>: [],
                <span class="k">"multiple"</span>: <span class="n">false</span>,
                <span class="k">"translatable"</span>: <span class="n">false</span>,
                <span class="k">"upload_dir"</span>: <span class="s">""</span>,
                <span class="k">"allowed_extensions"</span>: <span class="s">""</span>,
                <span class="k">"date_format"</span>: <span class="s">""</span>
            }
        ],
        <span class="k">"custom_fields"</span>: {
            <span class="k">"test_ajax_image"</span>: <span class="n">null</span>,
            <span class="k">"product_gtin"</span>: <span class="n">null</span>
        },
        <span class="k">"custom_field_files"</span>: {
            <span class="k">"test_ajax_image"</span>: []
        },
        <span class="k">"sections"</span>: [],
        <span class="k">"extensions"</span>: []
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## Delete a product

DELETE /products/**{id}** write since 6.6.0

Deletes a product and its variants.

Orders that already contain it are untouched: an order line records what was sold at the time, and it does not stop meaning something because the catalogue changed.

### Path

ParameterTypeDescription

idrequiredintegerThe product.

### Response expand all

FieldTypeDescription

idintegerThe product that was deleted.

deletedbooleanTrue when the row is gone.

### Errors

CodeHTTPMeans

not\_found404No such product, or the operator may not delete it.

delete\_failed400The shop refused to delete it.

```
curl -X DELETE "$SHOP/hikashop-api/v1/products/{id}" \
  -H "Authorization: Bearer $TOKEN"
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"id"</span>: <span class="n">9136</span>,
        <span class="k">"deleted"</span>: <span class="n">true</span>
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## Reconcile the variant set

PUT /products/**{id}**/variants write since 6.6.0

Takes the variants a product should have and makes the shop agree: it creates the ones that are missing, updates the ones that exist and removes the ones you left out.

A variant is identified by the characteristic values it stands for rather than by an id, because that is what makes it that variant. Send the whole set.

### Path

ParameterTypeDescription

idrequiredintegerThe parent product.

### Body

FieldTypeDescription

variantsrequiredobject\[\]The complete set. Each needs the characteristic `values` it stands for, and may carry `code`, `quantity`, `published` and `price`.

### Response expand all

FieldTypeDescription

characteristicsobject\[\]The characteristics the product now varies on, as they stand after the change.

variantsobject\[\]The variants as they now stand, in the same shape as on the product.

### Errors

CodeHTTPMeans

not\_found404No such product, or the operator may not change it.

```
curl -X PUT "$SHOP/hikashop-api/v1/products/{id}/variants" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "variants": []
}'
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"characteristics"</span>: [],
        <span class="k">"variants"</span>: []
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## Edit one variant

PUT /products/**{id}**/variants/**{vid}** write since 6.6.0

Changes one variant without touching the others, which is what a stock correction or a price change on a single size needs.

### Path

ParameterTypeDescription

idrequiredintegerThe parent product.

vidrequiredintegerThe variant.

### Body

Any of `code`, `quantity`, `published` and `price`, and your own product fields. What you do not send is left alone.

### Response expand all

FieldTypeDescription

idstring

namestring

codestringThe SKU. Unique within the shop.

descriptionstringThe long description, as HTML.

description\_typestringWhich editor the description was written with.

publishedboolean

quantityinteger`-1` when this product does not track stock, which is not the same as `0`.

msrpintegerThe manufacturer's suggested price, shown struck through when the shop is configured to.

gtinstringThe barcode: EAN, UPC or ISBN. This is what `GET /products/lookup` matches on.

conditionstringNew, used, refurbished. Used by the feeds rather than by the shop itself.

weightintegerShipping weight, in `weight_unit`.

weight\_unitstring`kg`, `g`, `lb` or `oz`.

widthintegerIn `dimension_unit`.

heightintegerIn `dimension_unit`.

lengthintegerIn `dimension_unit`.

dimension\_unitstring`m`, `cm`, `mm`, `ft` or `in`.

min\_per\_orderintegerThe smallest quantity a customer may order, `0` for no minimum.

max\_per\_orderintegerThe largest, `0` for no maximum.

sale\_startinteger\|nullUnix timestamp before which the product is not on sale.

sale\_endinteger\|nullUnix timestamp after which it is no longer sold.

page\_titlestringSEO title, empty to use the name.

meta\_descriptionstringSEO description.

keywordsstringSEO keywords.

canonicalstringA canonical URL, when this page should point at another.

urlstringThe address of the product page on the shop.

aliasstringThe slug used in that address.

accessobjectWho may see the product: `mode` (`all`, `none` or `groups`) and `groups`, which are user \*\*group\*\* ids and not Joomla view levels. The two id spaces overlap and disagree, so a value that looks plausible can grant the wrong audience.modestring`all`, `none`, or `groups` when it is restricted to some.

groupsinteger\[\]User group ids, meaningful only when the mode is `groups`.

contactbooleanWhether this product is enquired about rather than bought.

warehouse\_idintegerThe warehouse holding the stock, `0` when the shop has none.

typestring`main` for a product, `variant` for one of its variants.

parent\_idintegerThe parent product when this is a variant, `0` otherwise.

value\_idsinteger\[\]For a variant, the characteristic values it stands for.

manufacturer\_idintegerThe brand, `0` when unset.

manufacturer\_namestringIts name, saving a second call.

tax\_idintegerThe tax category, `0` when the product is untaxed.

tax\_namestringIts name.

tax\_ratenumberThe rate as a fraction, so `0.2` is twenty percent.

pricesobject\[\]Every price row, including the restricted ones. A product with none is not sellable.idstring

valuestringTax excluded, as stored.

currency\_idstring

min\_quantitystringFrom how many items this row applies, which is how quantity breaks are expressed.

accessobjectWho this price is for, in the same shape as the product access.modestringAs above.

groupsinteger\[\]As above.

usersinteger\[\]Named customers, empty for everyone.

zone\_idsinteger\[\]Zones this price applies in, empty for everywhere.

start\_dateinteger\|nullUnix timestamp.

end\_dateinteger\|nullUnix timestamp.

imagesobject\[\]In the order the editor shows them; the first is the main image.idinteger

namestring

pathstringRelative to the upload folder.

urlstringAbsolute, ready to display.

orderinginteger

descriptionstringThe alt text.

accessobjectWho may see it.modestringAs above.

groupsinteger\[\]As above.

free\_downloadbooleanFiles only; meaningless on an image.

filesobject\[\]Downloadable files, in the same shape as the images.idstring

namestring

pathstringRelative to the upload folder.

urlstringAbsolute.

orderingstring

descriptionstring

accessobjectWho may download it.

free\_downloadstringWhether it can be downloaded without buying the product.

categoriesobject\[\]The categories the product is in.idstring

namestring

bundleobject\[\]The products this one is made of, when it is a bundle.idstring

namestring

codestring

quantitystringHow many of it the bundle contains.

optionsobject\[\]Products offered as options alongside this one.idstring

namestring

codestring

quantitystring

relatedobject\[\]Products shown as related.idstring

namestring

codestring

quantitystring

tagsinteger\[\]CMS tag ids.

characteristicsobject\[\]The characteristics this product varies on. Empty when it has no variants.idintegerThe characteristic, such as Size.

namestringIts name.

valuesobject\[\]The values of it this product uses, such as S, M and L.idintegerThe value id, which is what a variant refers to.

valuestringIts name, such as `M`.

variantsobject\[\]Every variant, with its own code, stock, price and images. Empty for a product that does not vary.idintegerThe variant is a product in its own right, and this is its id.

codestringIts own SKU.

quantityintegerIts own stock. This is the figure to change, not the parent's.

publishedboolean

pricenumber\|null`null` when the variant has no price of its own and the parent's applies.

valuesobject\[\]Which characteristic values this variant stands for, one per characteristic.option\_idintegerThe characteristic.

option\_namestringIts name, so the variant can be labelled without a second call.

value\_idintegerThe value.

valuestringIts name.

imagesobject\[\]The variant's own images, in the same shape as the product's.idinteger

namestring

pathstringRelative to the upload folder.

urlstringAbsolute.

orderinginteger

fieldsobject\[\]The definitions of the custom fields that apply to this product, so a client can build a form for them.namekeystringThe key used in `custom_fields`.

typestring`text`, `radio`, `singledropdown`, `file`, and the rest of HikaShop's field types.

raw\_typestringHikaShop's own name for the type, before it is mapped to something a client can render.

labelstringTranslated into the operator's language.

defaultstringThe value used when none is given.

requiredbooleanWhether the shop refuses to save the product without it.

optionsobject\[\]The choices, for a field that has them. Empty for a free text one.

multiplebooleanWhether more than one choice may be selected.

translatablebooleanWhether its value can be translated, which is what the translation routes offer.

upload\_dirstringFor a file field, where its uploads are kept.

allowed\_extensionsstringFor a file field, the extensions it accepts, comma separated. Empty means the shop default.

date\_formatstringFor a date field, the format it is stored in.

custom\_fieldsobjectTheir values, keyed by namekey. The keys depend on the shop; `fields` says what they are.

custom\_field\_filesobjectFor custom fields holding a file, the file behind each value. Keyed the same way.

sectionsobject\[\]Information other plugins show on this record, each with a `key`, a `title` and `rows` (`label`, `value`, and optionally `url`, `badge` and `ref`). Empty when no plugin adds any; on a customer, core adds their paid downloads. See the guide on adding information and settings.

extensionsobject\[\]Settings other plugins keep on this record, in groups (`key`, `title`, `fields`), each field described like a custom field plus its current `value`. Send changes back as `extensions` with the record's save. Empty when no plugin adds any.

### Errors

CodeHTTPMeans

not\_found404No such variant, or the operator may not change it.

invalid\_fields400One of your own fields was rejected by its own rules.

```
curl -X PUT "$SHOP/hikashop-api/v1/products/{id}/variants/{id}" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "quantity": 7
}'
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"id"</span>: <span class="n">8671</span>,
        <span class="k">"name"</span>: <span class="s">"Waxed Canvas Sandals — XS"</span>,
        <span class="k">"code"</span>: <span class="s">"DEMO-0027-XS"</span>,
        <span class="k">"description"</span>: <span class="s">""</span>,
        <span class="k">"description_type"</span>: <span class="s">""</span>,
        <span class="k">"published"</span>: <span class="n">true</span>,
        <span class="k">"quantity"</span>: <span class="n">7</span>,
        <span class="k">"msrp"</span>: <span class="n">0</span>,
        <span class="k">"gtin"</span>: <span class="s">""</span>,
        <span class="k">"condition"</span>: <span class="s">""</span>,
        <span class="k">"weight"</span>: <span class="n">0</span>,
        <span class="k">"weight_unit"</span>: <span class="s">"kg"</span>,
        <span class="k">"width"</span>: <span class="n">0</span>,
        <span class="k">"height"</span>: <span class="n">0</span>,
        <span class="k">"length"</span>: <span class="n">0</span>,
        <span class="k">"dimension_unit"</span>: <span class="s">"m"</span>,
        <span class="k">"min_per_order"</span>: <span class="n">0</span>,
        <span class="k">"max_per_order"</span>: <span class="n">0</span>,
        <span class="k">"sale_start"</span>: <span class="n">0</span>,
        <span class="k">"sale_end"</span>: <span class="n">0</span>,
        <span class="k">"page_title"</span>: <span class="s">""</span>,
        <span class="k">"meta_description"</span>: <span class="s">""</span>,
        <span class="k">"keywords"</span>: <span class="s">""</span>,
        <span class="k">"canonical"</span>: <span class="s">""</span>,
        <span class="k">"url"</span>: <span class="s">""</span>,
        <span class="k">"alias"</span>: <span class="s">""</span>,
        <span class="k">"access"</span>: {
            <span class="k">"mode"</span>: <span class="s">"all"</span>,
            <span class="k">"groups"</span>: []
        },
        <span class="k">"contact"</span>: <span class="n">false</span>,
        <span class="k">"warehouse_id"</span>: <span class="n">0</span>,
        <span class="k">"type"</span>: <span class="s">"variant"</span>,
        <span class="k">"parent_id"</span>: <span class="n">8670</span>,
        <span class="k">"value_ids"</span>: [
            35
        ],
        <span class="k">"manufacturer_id"</span>: <span class="n">0</span>,
        <span class="k">"manufacturer_name"</span>: <span class="s">""</span>,
        <span class="k">"tax_id"</span>: <span class="n">0</span>,
        <span class="k">"tax_name"</span>: <span class="s">""</span>,
        <span class="k">"tax_rate"</span>: <span class="n">0</span>,
        <span class="k">"prices"</span>: [],
        <span class="k">"images"</span>: [
            {
                <span class="k">"id"</span>: <span class="n">7805</span>,
                <span class="k">"name"</span>: <span class="s">"Waxed Canvas Sandals — XS"</span>,
                <span class="k">"path"</span>: <span class="s">"demo-0027-xs.png"</span>,
                <span class="k">"url"</span>: <span class="s">"http://localhost:<span class="n">8080</span>/joomla6_ext/images/com_hikashop/upload/demo-0027-xs.png"</span>,
                <span class="k">"ordering"</span>: <span class="n">1</span>,
                <span class="k">"description"</span>: <span class="s">""</span>,
                <span class="k">"access"</span>: {
                    <span class="k">"mode"</span>: <span class="s">"all"</span>,
                    <span class="k">"groups"</span>: []
                },
                <span class="k">"free_download"</span>: <span class="n">false</span>
            }
        ],
        <span class="k">"files"</span>: [],
        <span class="k">"categories"</span>: [],
        <span class="k">"bundle"</span>: [],
        <span class="k">"options"</span>: [],
        <span class="k">"related"</span>: [],
        <span class="k">"tags"</span>: [],
        <span class="k">"characteristics"</span>: [],
        <span class="k">"variants"</span>: [],
        <span class="k">"fields"</span>: [
            {
                <span class="k">"namekey"</span>: <span class="s">"test_ajax_image"</span>,
                <span class="k">"type"</span>: <span class="s">"ajaximage"</span>,
                <span class="k">"raw_type"</span>: <span class="s">"ajaximage"</span>,
                <span class="k">"label"</span>: <span class="s">"Test Ajax Image"</span>,
                <span class="k">"default"</span>: <span class="s">""</span>,
                <span class="k">"required"</span>: <span class="n">false</span>,
                <span class="k">"options"</span>: [],
                <span class="k">"multiple"</span>: <span class="n">false</span>,
                <span class="k">"translatable"</span>: <span class="n">false</span>,
                <span class="k">"upload_dir"</span>: <span class="s">""</span>,
                <span class="k">"allowed_extensions"</span>: <span class="s">""</span>,
                <span class="k">"date_format"</span>: <span class="s">""</span>
            },
            {
                <span class="k">"namekey"</span>: <span class="s">"product_gtin"</span>,
                <span class="k">"type"</span>: <span class="s">"text"</span>,
                <span class="k">"raw_type"</span>: <span class="s">"text"</span>,
                <span class="k">"label"</span>: <span class="s">"GTIN"</span>,
                <span class="k">"default"</span>: <span class="s">""</span>,
                <span class="k">"required"</span>: <span class="n">false</span>,
                <span class="k">"options"</span>: [],
                <span class="k">"multiple"</span>: <span class="n">false</span>,
                <span class="k">"translatable"</span>: <span class="n">false</span>,
                <span class="k">"upload_dir"</span>: <span class="s">""</span>,
                <span class="k">"allowed_extensions"</span>: <span class="s">""</span>,
                <span class="k">"date_format"</span>: <span class="s">""</span>
            }
        ],
        <span class="k">"custom_fields"</span>: {
            <span class="k">"test_ajax_image"</span>: <span class="n">null</span>,
            <span class="k">"product_gtin"</span>: <span class="n">null</span>
        },
        <span class="k">"custom_field_files"</span>: {
            <span class="k">"test_ajax_image"</span>: []
        },
        <span class="k">"sections"</span>: [],
        <span class="k">"extensions"</span>: []
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## Apply a coupon to an order

POST /orders/**{id}**/coupon write since 6.6.0

Applies a coupon by its code and re-totals the order.

The shop validates it again here against this order: its dates, its quota, its minimum, the products in the cart and the customer. A coupon that appears in `GET /coupons` can still be refused for this particular order, which is the point of validating rather than trusting the list.

### Path

ParameterTypeDescription

idrequiredintegerThe order.

### Body

FieldTypeDescription

coderequiredstringThe coupon code, as the customer would type it.

### Response expand all

FieldTypeDescription

idintegerThe order.

feesobjectThe discount, shipping and payment amounts of the order.  discountobjectIts `amount`, its `tax`, the `tax_namekeys` behind that tax, and the coupon `code` when one was used.amountnumberA positive figure, already subtracted from the total.

taxnumberThe tax on it.

tax\_namekeysstring\[\]Which tax rates that came from.

codestringThe coupon code, empty for a discount applied by hand.

shippingobjectThe shipping charge and what carried it.amountnumberTax excluded.

taxnumberThe tax on it.

tax\_namekeysstring\[\]Which tax rates that came from.

methodstringThe plugin that handled it.

method\_namestringAs the merchant named it.

paymentobjectThe payment fee and what took it.amountnumberTax excluded.

taxnumberThe tax on it.

tax\_namekeysstring\[\]Which tax rates that came from.

methodstringThe plugin that took it.

method\_namestringAs the merchant named it.

totalsobjectThe order totalled, so a client need not compute it and disagree with the shop.totalnumberWhat the customer owes, tax included.

discountnumberThe discount applied, as a positive figure already subtracted.

shippingnumberThe shipping charged.

paymentnumberThe payment fee charged.

taxnumberThe tax within the total, not on top of it.

### Errors

CodeHTTPMeans

not\_found404No such order, or the operator may not change it.

invalid\_coupon400No such code, or it does not apply to this order.

save\_failed500The order could not be saved.

```
curl -X POST "$SHOP/hikashop-api/v1/orders/{id}/coupon" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "code": "APPTEST10"
}'
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"id"</span>: <span class="n">5630</span>,
        <span class="k">"fees"</span>: {
            <span class="k">"discount"</span>: {
                <span class="k">"amount"</span>: <span class="n">10</span>,
                <span class="k">"tax"</span>: <span class="n">0</span>,
                <span class="k">"tax_namekeys"</span>: [],
                <span class="k">"code"</span>: <span class="s">"APPTEST10"</span>
            },
            <span class="k">"shipping"</span>: {
                <span class="k">"amount"</span>: <span class="n">6.9</span>,
                <span class="k">"tax"</span>: <span class="n">0</span>,
                <span class="k">"tax_namekeys"</span>: [],
                <span class="k">"method"</span>: <span class="s">"manual"</span>,
                <span class="k">"method_name"</span>: <span class="s">"Vendor 2 only shipping"</span>
            },
            <span class="k">"payment"</span>: {
                <span class="k">"amount"</span>: <span class="n">0</span>,
                <span class="k">"tax"</span>: <span class="n">0</span>,
                <span class="k">"tax_namekeys"</span>: [],
                <span class="k">"method"</span>: <span class="s">"paypalcheckout"</span>,
                <span class="k">"method_name"</span>: <span class="s">"PayPal Checkout Express Test"</span>
            }
        },
        <span class="k">"totals"</span>: {
            <span class="k">"total"</span>: <span class="n">303.92</span>,
            <span class="k">"discount"</span>: <span class="n">10</span>,
            <span class="k">"shipping"</span>: <span class="n">6.9</span>,
            <span class="k">"payment"</span>: <span class="n">0</span>,
            <span class="k">"tax"</span>: <span class="n">0</span>
        }
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## Remove the discount from an order

DELETE /orders/**{id}**/coupon write since 6.6.0

Takes the coupon or the hand-applied discount off the order and re-totals it. There is nothing to send.

### Path

ParameterTypeDescription

idrequiredintegerThe order.

### Response expand all

FieldTypeDescription

idintegerThe order.

feesobjectThe discount, shipping and payment amounts of the order.  discountobjectIts `amount`, its `tax`, the `tax_namekeys` behind that tax, and the coupon `code` when one was used.amountnumberA positive figure, already subtracted from the total.

taxnumberThe tax on it.

tax\_namekeysstring\[\]Which tax rates that came from.

codestringThe coupon code, empty for a discount applied by hand.

shippingobjectThe shipping charge and what carried it.amountnumberTax excluded.

taxnumberThe tax on it.

tax\_namekeysstring\[\]Which tax rates that came from.

methodstringThe plugin that handled it.

method\_namestringAs the merchant named it.

paymentobjectThe payment fee and what took it.amountnumberTax excluded.

taxnumberThe tax on it.

tax\_namekeysstring\[\]Which tax rates that came from.

methodstringThe plugin that took it.

method\_namestringAs the merchant named it.

totalsobjectThe order totalled, so a client need not compute it and disagree with the shop.totalnumberWhat the customer owes, tax included.

discountnumberThe discount applied, as a positive figure already subtracted.

shippingnumberThe shipping charged.

paymentnumberThe payment fee charged.

taxnumberThe tax within the total, not on top of it.

### Errors

CodeHTTPMeans

not\_found404No such order, or the operator may not change it.

save\_failed500The order could not be saved.

```
curl -X DELETE "$SHOP/hikashop-api/v1/orders/{id}/coupon" \
  -H "Authorization: Bearer $TOKEN"
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"id"</span>: <span class="n">5630</span>,
        <span class="k">"fees"</span>: {
            <span class="k">"discount"</span>: {
                <span class="k">"amount"</span>: <span class="n">0</span>,
                <span class="k">"tax"</span>: <span class="n">0</span>,
                <span class="k">"tax_namekeys"</span>: [],
                <span class="k">"code"</span>: <span class="s">""</span>
            },
            <span class="k">"shipping"</span>: {
                <span class="k">"amount"</span>: <span class="n">6.9</span>,
                <span class="k">"tax"</span>: <span class="n">0</span>,
                <span class="k">"tax_namekeys"</span>: [],
                <span class="k">"method"</span>: <span class="s">"manual"</span>,
                <span class="k">"method_name"</span>: <span class="s">"Vendor 2 only shipping"</span>
            },
            <span class="k">"payment"</span>: {
                <span class="k">"amount"</span>: <span class="n">0</span>,
                <span class="k">"tax"</span>: <span class="n">0</span>,
                <span class="k">"tax_namekeys"</span>: [],
                <span class="k">"method"</span>: <span class="s">"paypalcheckout"</span>,
                <span class="k">"method_name"</span>: <span class="s">"PayPal Checkout Express Test"</span>
            }
        },
        <span class="k">"totals"</span>: {
            <span class="k">"total"</span>: <span class="n">313.92</span>,
            <span class="k">"discount"</span>: <span class="n">0</span>,
            <span class="k">"shipping"</span>: <span class="n">6.9</span>,
            <span class="k">"payment"</span>: <span class="n">0</span>,
            <span class="k">"tax"</span>: <span class="n">0</span>
        }
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## Add a line to an order

POST /orders/**{id}**/products write since 6.6.0

Adds a product to an existing order and re-totals it.

Send a `price` only to override what the shop would charge; leave it out and the order's own pricing applies, which is what `GET /orders/{id}/products/precompute` shows you beforehand.

### Path

ParameterTypeDescription

idrequiredintegerThe order.

### Body

FieldTypeDescription

product\_idrequiredintegerThe product or variant to add.

quantityintegerHow many. Defaults to `1`.

pricenumberUnit price, tax excluded, to override the shop. Omit to let the shop price it.

tax\_namekeysstring\[\]Which tax rates to apply, when overriding the price. Omit to let the shop decide.

### Response expand all

FieldTypeDescription

idintegerThe order.

itemsobject\[\]The lines as they now stand, in the same shape as on the order.idintegerThe line id, which is what the line routes take. It is not the product id.

namestringThe product as it was named when ordered.

codestringIts SKU at the time.

quantityinteger

pricenumberUnit price, tax excluded, as agreed at the time.

taxnumberTax on the line.

editablebooleanFalse once the line can no longer be changed.

totalsobjectThe order totalled, so a client need not compute it and disagree with the shop.totalnumberWhat the customer owes, tax included.

discountnumberThe discount applied, as a positive figure already subtracted.

shippingnumberThe shipping charged.

paymentnumberThe payment fee charged.

taxnumberThe tax within the total, not on top of it.

### Errors

CodeHTTPMeans

not\_found404No such order or product, or the operator may not change the order.

save\_failed500The order could not be saved.

```
curl -X POST "$SHOP/hikashop-api/v1/orders/{id}/products" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "product_id": "1",
    "quantity": 1
}'
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"id"</span>: <span class="n">5630</span>,
        <span class="k">"items"</span>: [
            {
                <span class="k">"id"</span>: <span class="n">20630</span>,
                <span class="k">"name"</span>: <span class="s">"Nordic Design item"</span>,
                <span class="k">"code"</span>: <span class="s">"SEED-7-44"</span>,
                <span class="k">"quantity"</span>: <span class="n">1</span>,
                <span class="k">"price"</span>: <span class="n">307.02</span>,
                <span class="k">"tax"</span>: <span class="n">0</span>,
                <span class="k">"editable"</span>: <span class="n">true</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">20642</span>,
                <span class="k">"name"</span>: <span class="s">"Test Product (Vendor 2)"</span>,
                <span class="k">"code"</span>: <span class="s">"TEST001"</span>,
                <span class="k">"quantity"</span>: <span class="n">1</span>,
                <span class="k">"price"</span>: <span class="n">0</span>,
                <span class="k">"tax"</span>: <span class="n">0</span>,
                <span class="k">"editable"</span>: <span class="n">true</span>
            }
        ],
        <span class="k">"totals"</span>: {
            <span class="k">"total"</span>: <span class="n">313.92</span>,
            <span class="k">"discount"</span>: <span class="n">0</span>,
            <span class="k">"shipping"</span>: <span class="n">6.9</span>,
            <span class="k">"payment"</span>: <span class="n">0</span>,
            <span class="k">"tax"</span>: <span class="n">0</span>
        }
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## Change a line's quantity

PUT /orders/**{id}**/products/**{lineId}** write since 6.6.0

Changes how many of one line the order holds, and re-totals it. A quantity of `0` removes the line.

The id in the path is the **line** id from `items`, not the product id: the same product can appear on an order more than once.

### Path

ParameterTypeDescription

idrequiredintegerThe order.

lineIdrequiredintegerThe line, from &#96;items\[\].id&#96; on the order.

### Body

FieldTypeDescription

quantityrequiredintegerThe new quantity. `0` removes the line.

### Response expand all

FieldTypeDescription

idintegerThe order.

itemsobject\[\]The lines as they now stand.idintegerThe line id, which is what the line routes take. It is not the product id.

namestringThe product as it was named when ordered.

codestringIts SKU at the time.

quantityinteger

pricenumberUnit price, tax excluded, as agreed at the time.

taxnumberTax on the line.

editablebooleanFalse once the line can no longer be changed.

totalsobjectThe order totalled, so a client need not compute it and disagree with the shop.totalnumberWhat the customer owes, tax included.

discountnumberThe discount applied, as a positive figure already subtracted.

shippingnumberThe shipping charged.

paymentnumberThe payment fee charged.

taxnumberThe tax within the total, not on top of it.

### Errors

CodeHTTPMeans

not\_found404No such order or line, or the operator may not change it.

save\_failed500The order could not be saved.

```
curl -X PUT "$SHOP/hikashop-api/v1/orders/{id}/products/{id}" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "quantity": 2
}'
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"id"</span>: <span class="n">5630</span>,
        <span class="k">"items"</span>: [
            {
                <span class="k">"id"</span>: <span class="n">20630</span>,
                <span class="k">"name"</span>: <span class="s">"Nordic Design item"</span>,
                <span class="k">"code"</span>: <span class="s">"SEED-7-44"</span>,
                <span class="k">"quantity"</span>: <span class="n">1</span>,
                <span class="k">"price"</span>: <span class="n">307.02</span>,
                <span class="k">"tax"</span>: <span class="n">0</span>,
                <span class="k">"editable"</span>: <span class="n">true</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">20642</span>,
                <span class="k">"name"</span>: <span class="s">"Test Product (Vendor 2)"</span>,
                <span class="k">"code"</span>: <span class="s">"TEST001"</span>,
                <span class="k">"quantity"</span>: <span class="n">2</span>,
                <span class="k">"price"</span>: <span class="n">0</span>,
                <span class="k">"tax"</span>: <span class="n">0</span>,
                <span class="k">"editable"</span>: <span class="n">true</span>
            }
        ],
        <span class="k">"totals"</span>: {
            <span class="k">"total"</span>: <span class="n">313.92</span>,
            <span class="k">"discount"</span>: <span class="n">0</span>,
            <span class="k">"shipping"</span>: <span class="n">6.9</span>,
            <span class="k">"payment"</span>: <span class="n">0</span>,
            <span class="k">"tax"</span>: <span class="n">0</span>
        }
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## Run a mass action

POST /massactions/**{id}** write since 6.6.0

Runs one of the merchant's own bulk operations over a selection.

It runs the same code the backend runs, so whatever the action does there it does here, including whatever a third-party plugin added to it. Give it the ids to work on.

### Path

ParameterTypeDescription

idrequiredintegerThe mass action, from &#96;GET /massactions&#96;.

### Body

FieldTypeDescription

idsrequiredinteger\[\]The records to run it over, from the listing the action belongs to.

### Response expand all

FieldTypeDescription

okbooleanWhether the action reported success.

countintegerHow many records it worked on.

reportstringWhatever the action had to say, ready to show. Its wording is the action's own.

### Errors

CodeHTTPMeans

invalid\_request400No ids were sent, or the action is not one this shop has.

forbidden403The operator may not work on that kind of record.

```
curl -X POST "$SHOP/hikashop-api/v1/massactions/2" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "ids": [
        "9135"
    ]
}'
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"ok"</span>: <span class="n">true</span>,
        <span class="k">"count"</span>: <span class="n">1</span>,
        <span class="k">"report"</span>: []
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## Create an order by hand

POST /orders write since 6.6.0

Creates an empty order for a customer, to be filled in with lines, fees and an address.

Give it either an existing `user_id` or a `guest` with at least an email address, which is how an order gets taken over the telephone from somebody who has never bought before.

### Body

FieldTypeDescription

user\_idintegerAn existing customer. Give this or `guest`.

guestobjectA new guest customer, needing at least `email` and usually a name.

### Response expand all

FieldTypeDescription

idintegerThe order that was created, to add lines to.

### Errors

CodeHTTPMeans

no\_customer400Neither a user\_id nor a usable guest was given.

save\_failed500The order could not be created.

```
curl -X POST "$SHOP/hikashop-api/v1/orders" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "guest": {
        "email": "<joomla-hidden-mail base="" first="YnV5ZXI=" is-email="1" is-link="1" last="ZXhhbXBsZS50ZXN0" text="YnV5ZXJAZXhhbXBsZS50ZXN0">This email address is being protected from spambots. You need JavaScript enabled to view it.</joomla-hidden-mail>",
        "name": "Alex Marchand"
    }
}'
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"id"</span>: <span class="n">5648</span>
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## Save an order's custom fields

PUT /orders/**{id}**/fields write since 6.6.0

Writes the merchant's own order fields. Only the fields you send are touched.

### Path

ParameterTypeDescription

idrequiredintegerThe order.

### Body

FieldTypeDescription

fieldsobjectKeyed by field namekey. May be left out when only `extensions` are sent.

extensionsobjectSettings other plugins keep on this record, as `{ group key: { namekey: value } }`, for the groups and fields its `extensions` lists. Saved after the record's own fields. See the guide on adding information and settings.

### Response expand all

FieldTypeDescription

idintegerThe order.

custom\_fieldsobjectThe values as they now stand. The keys depend on the shop.

custom\_field\_filesobjectFor a field holding a file, the file behind the value. Keyed the same way.

extensionsobject\[\]The other plugins' settings on the order as they now stand, as in `GET /orders/{id}`.

### Errors

CodeHTTPMeans

not\_found404No such order, or the operator may not change it.

invalid\_fields400A field was rejected by its own rules.

save\_failed500The order could not be saved.

invalid\_extensions400The record's own fields were saved, but a plugin refused some of its values: &#96;error.details&#96; says which, as &#96;{ group key: { namekey: message } }&#96;.

```
curl -X PUT "$SHOP/hikashop-api/v1/orders/{id}/fields" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "fields": []
}'
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"id"</span>: <span class="n">5630</span>,
        <span class="k">"custom_fields"</span>: {
            <span class="k">"hstestfile1755"</span>: <span class="n">null</span>,
            <span class="k">"hstestfile1859"</span>: <span class="n">null</span>,
            <span class="k">"hstestfile26994"</span>: <span class="n">null</span>,
            <span class="k">"hstestfile28016"</span>: <span class="n">null</span>,
            <span class="k">"hstestfile27610"</span>: <span class="n">null</span>
        },
        <span class="k">"custom_field_files"</span>: {
            <span class="k">"hstestfile1755"</span>: [],
            <span class="k">"hstestfile1859"</span>: [],
            <span class="k">"hstestfile26994"</span>: [],
            <span class="k">"hstestfile28016"</span>: [],
            <span class="k">"hstestfile27610"</span>: []
        },
        <span class="k">"extensions"</span>: []
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## Save an address of an order

PUT /orders/**{id}**/address/**{type}** write since 6.6.0

Writes the billing or shipping address of an order, using the fields `GET` gave you.

The address on an order is its own copy, so changing it here does not change the customer's address book, and vice versa. That is deliberate: an invoice should not change because somebody moved.

### Path

ParameterTypeDescription

idrequiredintegerThe order.

typerequiredstring&#96;billing&#96; or &#96;shipping&#96;.

### Body

FieldTypeDescription

fieldsrequiredobjectKeyed by address field namekey, the same keys `GET` returned in `values`.

### Response expand all

FieldTypeDescription

typestringWhich address was written.

address\_idintegerThe address row, created if there was none.

valuesobjectThe values as stored. Keyed by whatever address fields this shop has.

country\_namestringThe country spelled out.

state\_namestringThe state spelled out, empty where the country has none.

summaryobjectThe address ready to show, without re-reading the order.namestring

companystring

formattedobjectLaid out the way this shop lays addresses out, which follows its address format setting.textstringSeveral lines, for an invoice or a label.

one\_linestringOne line, for a list.

streetstring

citystring

post\_codestring

### Errors

CodeHTTPMeans

not\_found404No such order, or the operator may not change it.

invalid\_fields400A field was rejected by its own rules.

invalid\_address400The address is not one the shop will accept, usually a missing required field.

```
curl -X PUT "$SHOP/hikashop-api/v1/orders/{id}/address/billing" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "fields": {
        "address_title": "Mr",
        "address_firstname": "Alex",
        "address_lastname": "Marchand",
        "address_street": "12 rue des Lilas",
        "address_post_code": "44000",
        "address_city": "Nantes",
        "address_telephone": "+33 2 00 00 00 00",
        "address_country": "country_France_73",
        "address_state": "state_Paris_1381"
    }
}'
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"type"</span>: <span class="s">"billing"</span>,
        <span class="k">"address_id"</span>: <span class="n">4385</span>,
        <span class="k">"values"</span>: {
            <span class="k">"address_title"</span>: <span class="s">"Mr"</span>,
            <span class="k">"address_firstname"</span>: <span class="s">"Alex"</span>,
            <span class="k">"address_lastname"</span>: <span class="s">"Marchand"</span>,
            <span class="k">"address_company"</span>: <span class="s">"Lilas SARL"</span>,
            <span class="k">"address_street"</span>: <span class="s">"12 rue des Lilas"</span>,
            <span class="k">"address_post_code"</span>: <span class="s">"44000"</span>,
            <span class="k">"address_city"</span>: <span class="s">"Nantes"</span>,
            <span class="k">"address_telephone"</span>: <span class="s">"+33 2 00 00 00 00"</span>,
            <span class="k">"address_country"</span>: <span class="s">"country_France_73"</span>,
            <span class="k">"address_state"</span>: <span class="s">"state_Paris_1381"</span>,
            <span class="k">"address_vat"</span>: <span class="s">"FR00000000000"</span>
        },
        <span class="k">"country_name"</span>: <span class="s">"France"</span>,
        <span class="k">"state_name"</span>: <span class="s">"Paris"</span>,
        <span class="k">"summary"</span>: {
            <span class="k">"name"</span>: <span class="s">"John Doe"</span>,
            <span class="k">"company"</span>: <span class="s">"Lilas SARL"</span>,
            <span class="k">"formatted"</span>: {
                <span class="k">"text"</span>: <span class="s">"Alex Marchand\r\n12 rue des Lilas\r\n44000 Nantes\r\nFrance"</span>,
                <span class="k">"one_line"</span>: <span class="s">"Marchand Alex - 12 rue des Lilas, Nantes (France)"</span>
            },
            <span class="k">"street"</span>: <span class="s">"12 rue des Lilas"</span>,
            <span class="k">"city"</span>: <span class="s">"Nantes"</span>,
            <span class="k">"post_code"</span>: <span class="s">"44000"</span>
        }
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## Attach an image or a file

POST /products/**{id}**/images write since 6.6.0

Adds an image or a downloadable file to a product, either by sending the bytes or by pointing at something already in the upload folder.

Send `data` as base64 to upload, or `path` to attach a file that `GET /media/browse` already showed you. The extension is checked against what the shop allows, so a refusal is the shop's policy rather than a fault.

The same route serves `/images` and `/files`; which one you call decides where it goes.

### Path

ParameterTypeDescription

idrequiredintegerThe product.

### Body

FieldTypeDescription

datastringThe bytes, base64 encoded. Give this or `path`.

pathstringA file already in the upload folder, relative to it, as `GET /media/browse` returns.

namestringThe file name to store it under. Defaults to the one in the path.

descriptionstringThe alt text for an image, or a note on a file.

accessobjectWho may see or download it, in the usual mode and groups shape.

### Response expand all

FieldTypeDescription

idinteger

namestring

pathstringRelative to the upload folder.

urlstringAbsolute, ready to display.

orderingintegerWhere it sits among the others; the first image is the one the shop shows.

descriptionstringThe alt text for an image, or a note on a file.

accessobjectWho may see or download it.modestring`all`, `none`, or `groups` when it is restricted to some.

groupsinteger\[\]User \*\*group\*\* ids, and not Joomla view levels. The two id spaces overlap and disagree, so a value that looks plausible can grant the wrong audience.

free\_downloadbooleanFiles only: whether it can be downloaded without buying the product.

### Errors

CodeHTTPMeans

not\_found404No such product, or the operator may not change it.

bad\_type400The extension is not one this shop accepts.

write\_failed500The upload folder refused the file, which is usually a permissions problem.

```
curl -X POST "$SHOP/hikashop-api/v1/products/{id}/images" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "data": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8DwHwAFAAH/q842iQAAAABJRU5ErkJggg==",
    "name": "documentation-capture.png",
    "description": "A one pixel image"
}'
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"id"</span>: <span class="n">8336</span>,
        <span class="k">"name"</span>: <span class="s">"documentation-capture.png"</span>,
        <span class="k">"path"</span>: <span class="s">"documentation-capture.png"</span>,
        <span class="k">"url"</span>: <span class="s">"http://localhost:<span class="n">8080</span>/joomla6_ext/images/com_hikashop/upload/documentation-capture.png"</span>,
        <span class="k">"ordering"</span>: <span class="n">1</span>,
        <span class="k">"description"</span>: <span class="s">"A one pixel image"</span>,
        <span class="k">"access"</span>: {
            <span class="k">"mode"</span>: <span class="s">"all"</span>,
            <span class="k">"groups"</span>: []
        },
        <span class="k">"free_download"</span>: <span class="n">false</span>
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## Edit an image or a file

PUT /products/**{id}**/files/**{fileId}** write since 6.6.0

Changes the name, the description or the access of something already attached, without re-uploading the bytes.

### Path

ParameterTypeDescription

idrequiredintegerThe product.

fileIdrequiredintegerThe image or file.

### Body

Any of `name`, `description`, `access` and, for a file, `free_download`. What you do not send is left alone.

### Response expand all

FieldTypeDescription

idinteger

namestring

pathstringRelative to the upload folder.

urlstringAbsolute, ready to display.

orderingintegerWhere it sits among the others; the first image is the one the shop shows.

descriptionstringThe alt text for an image, or a note on a file.

accessobjectWho may see or download it.modestring`all`, `none`, or `groups` when it is restricted to some.

groupsinteger\[\]User \*\*group\*\* ids, and not Joomla view levels. The two id spaces overlap and disagree, so a value that looks plausible can grant the wrong audience.

free\_downloadbooleanFiles only: whether it can be downloaded without buying the product.

### Errors

CodeHTTPMeans

not\_found404No such file on that product, or the operator may not change it.

```
curl -X PUT "$SHOP/hikashop-api/v1/products/{id}/files/{id}" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "documentation-capture.png",
    "description": "A one pixel image"
}'
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"id"</span>: <span class="n">8336</span>,
        <span class="k">"name"</span>: <span class="s">"documentation-capture.png"</span>,
        <span class="k">"path"</span>: <span class="s">"documentation-capture.png"</span>,
        <span class="k">"url"</span>: <span class="s">"http://localhost:<span class="n">8080</span>/joomla6_ext/images/com_hikashop/upload/documentation-capture.png"</span>,
        <span class="k">"ordering"</span>: <span class="n">1</span>,
        <span class="k">"description"</span>: <span class="s">"A one pixel image"</span>,
        <span class="k">"access"</span>: {
            <span class="k">"mode"</span>: <span class="s">"all"</span>,
            <span class="k">"groups"</span>: []
        },
        <span class="k">"free_download"</span>: <span class="n">false</span>
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## Remove an image or a file

DELETE /products/**{id}**/files/**{fileId}** write since 6.6.0

Detaches an image or a file from a product.

The bytes stay in the upload folder: another product may be using the same file, and the API will not delete somebody's media because one product stopped pointing at it.

### Path

ParameterTypeDescription

idrequiredintegerThe product.

fileIdrequiredintegerThe image or file.

### Response expand all

FieldTypeDescription

idintegerWhat was detached.

deletedbooleanTrue when the row is gone.

### Errors

CodeHTTPMeans

not\_found404No such file on that product, or the operator may not change it.

```
curl -X DELETE "$SHOP/hikashop-api/v1/products/{id}/files/{id}" \
  -H "Authorization: Bearer $TOKEN"
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"id"</span>: <span class="n">8337</span>,
        <span class="k">"deleted"</span>: <span class="n">true</span>
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## Reorder images and files

PUT /products/**{id}**/media/order write since 6.6.0

Sets the order of a product's images or files. The first image is the one the shop shows, so this is how you choose it.

### Path

ParameterTypeDescription

idrequiredintegerThe product.

### Body

FieldTypeDescription

imagesinteger\[\]File ids in the order you want them.

filesinteger\[\]The same for downloadable files.

### Response expand all

FieldTypeDescription

imagesobject\[\]The images as they now stand, in their new order, each in the same shape as on the product.idinteger

namestring

pathstringRelative to the upload folder.

urlstringAbsolute, ready to display.

orderingintegerWhere it sits among the others; the first image is the one the shop shows.

descriptionstringThe alt text for an image, or a note on a file.

accessobjectWho may see or download it.modestring`all`, `none`, or `groups` when it is restricted to some.

groupsinteger\[\]User \*\*group\*\* ids, and not Joomla view levels. The two id spaces overlap and disagree, so a value that looks plausible can grant the wrong audience.

free\_downloadbooleanFiles only: whether it can be downloaded without buying the product.

filesobject\[\]The files as they now stand, in the same shape as on the product.idinteger

namestring

pathstringRelative to the upload folder.

urlstringAbsolute, ready to display.

orderingintegerWhere it sits among the others; the first image is the one the shop shows.

descriptionstringThe alt text for an image, or a note on a file.

accessobjectWho may see or download it.modestring`all`, `none`, or `groups` when it is restricted to some.

groupsinteger\[\]User \*\*group\*\* ids, and not Joomla view levels. The two id spaces overlap and disagree, so a value that looks plausible can grant the wrong audience.

free\_downloadbooleanFiles only: whether it can be downloaded without buying the product.

### Errors

CodeHTTPMeans

not\_found404No such product, or the operator may not change it.

```
curl -X PUT "$SHOP/hikashop-api/v1/products/{id}/media/order" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "images": [
        7756,
        7757
    ]
}'
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"images"</span>: [
            {
                <span class="k">"id"</span>: <span class="n">7756</span>,
                <span class="k">"name"</span>: <span class="s">"Lacquered Fountain Pen — Broad"</span>,
                <span class="k">"path"</span>: <span class="s">"demo-0002.png"</span>,
                <span class="k">"url"</span>: <span class="s">"http://localhost:<span class="n">8080</span>/joomla6_ext/images/com_hikashop/upload/demo-0002.png"</span>,
                <span class="k">"ordering"</span>: <span class="n">0</span>,
                <span class="k">"description"</span>: <span class="s">""</span>,
                <span class="k">"access"</span>: {
                    <span class="k">"mode"</span>: <span class="s">"all"</span>,
                    <span class="k">"groups"</span>: []
                },
                <span class="k">"free_download"</span>: <span class="n">false</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">7757</span>,
                <span class="k">"name"</span>: <span class="s">"Lacquered Fountain Pen — Broad"</span>,
                <span class="k">"path"</span>: <span class="s">"demo-0002-2.png"</span>,
                <span class="k">"url"</span>: <span class="s">"http://localhost:<span class="n">8080</span>/joomla6_ext/images/com_hikashop/upload/demo-0002-2.png"</span>,
                <span class="k">"ordering"</span>: <span class="n">1</span>,
                <span class="k">"description"</span>: <span class="s">""</span>,
                <span class="k">"access"</span>: {
                    <span class="k">"mode"</span>: <span class="s">"all"</span>,
                    <span class="k">"groups"</span>: []
                },
                <span class="k">"free_download"</span>: <span class="n">false</span>
            }
        ],
        <span class="k">"files"</span>: []
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## The bytes of an image

GET /media/content read since 6.6.0

The bytes of one image from the upload folder, so a client can edit it: crop it, rotate it, and send it back.

This is the one route that does not answer with the envelope. It answers with the file, and with the cross-origin header that lets a browser read it into a canvas, which the shop's own image URLs do not carry. Without it, a web client cannot export an edited image at all.

A path that tries to leave the upload folder is refused rather than resolved.

### Query

ParameterTypeDescription

pathrequiredstringThe image, relative to the upload folder.

### Response

The content of the file requested, with the content type taken from its extension.

### Errors

CodeHTTPMeans

not\_found404No such file, or a path that tried to leave the upload folder.

## Upload the value of a file field

POST /fields/**{table}**/**{namekey}**/file write since 6.6.0

Uploads the file that is the value of one of your own custom fields. Only the two field types that hold one accept it: `ajaximage` and `ajaxfile`.

The field is named rather than numbered, and the table says which kind of record it belongs to, so the same route serves a product field, a category field and a customer field.

### Path

ParameterTypeDescription

tablerequiredstringWhich kind of record: &#96;product&#96;, &#96;category&#96;, &#96;user&#96;, &#96;order&#96;, &#96;address&#96;.

namekeyrequiredstringThe field, as &#96;fields\[\].namekey&#96; gives it.

### Body

FieldTypeDescription

datarequiredstringThe bytes, base64 encoded.

namestringThe file name to store it under.

### Response expand all

FieldTypeDescription

pathstringRelative to the field's own upload folder. This is the value to store on the record.

namestringThe file name it was stored under.

urlstringAbsolute, where the shop serves it from.

### Errors

CodeHTTPMeans

not\_found404No such record kind.

bad\_field400No such field, or it does not hold a file.

bad\_type400The extension is not one this shop accepts.

write\_failed500The upload folder refused the file.

```
curl -X POST "$SHOP/hikashop-api/v1/fields/product/test_ajax_image/file" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "data": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8DwHwAFAAH/q842iQAAAABJRU5ErkJggg==",
    "name": "documentation-capture-field.png"
}'
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"path"</span>: <span class="s">"documentation-capture-field_2.png"</span>,
        <span class="k">"name"</span>: <span class="s">"documentation-capture-field_2.png"</span>,
        <span class="k">"url"</span>: <span class="s">"http://localhost:<span class="n">8080</span>/joomla6_ext/images/com_hikashop/upload/documentation-capture-field_2.png"</span>
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## The shipping and payment methods an order can move to

GET /orders/**{id}**/methods read since 6.6.0

What this order could ship and be paid by, with what it uses now, so a change can be offered as a choice rather than as free text.

A method is identified by its plugin and its instance together, written `plugin_id`, which is the pairing the backend posts back. An order that ships from several warehouses carries one method per shipment, and `multiple` says so.

### Path

ParameterTypeDescription

idrequiredintegerThe order.

### Response expand all

FieldTypeDescription

shippingobjectThe shipping choice.currentstringWhat the order uses now, as `plugin_id`. `_` when nothing is set, so the current one always matches an option.

multiplebooleanTrue when the order ships in several shipments and carries a method for each.

optionsobject\[\]What it could move to.valuestringThe `plugin_id` pairing to send when changing the method.

labelstringAs the merchant named it.

groupsobject\[\]For an order that ships in several shipments, the shipments and the method chosen for each. Empty otherwise.

paymentobjectThe payment choice, in the same shape.currentstringWhat the order uses now.

multiplebooleanAlways false: an order is paid one way.

optionsobject\[\]What it could move to.valuestringThe `plugin_id` pairing to send.

labelstringAs the merchant named it.

### Errors

CodeHTTPMeans

not\_found404No such order, or the operator may not see it.

```
curl "$SHOP/hikashop-api/v1/orders/{id}/methods" \
  -H "Authorization: Bearer $TOKEN"
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"shipping"</span>: {
            <span class="k">"current"</span>: <span class="s">"manual_1"</span>,
            <span class="k">"multiple"</span>: <span class="n">false</span>,
            <span class="k">"options"</span>: [
                {
                    <span class="k">"value"</span>: <span class="s">"manual_1"</span>,
                    <span class="k">"label"</span>: <span class="s">"Vendor 2 only shipping"</span>
                },
                {
                    <span class="k">"value"</span>: <span class="s">"manual_6"</span>,
                    <span class="k">"label"</span>: <span class="s">"Test Flat Shipping"</span>
                },
                {
                    <span class="k">"value"</span>: <span class="s">"manual_3"</span>,
                    <span class="k">"label"</span>: <span class="s">"Express Test Flat Rate"</span>
                },
                {
                    <span class="k">"value"</span>: <span class="s">"fedextest_2-1"</span>,
                    <span class="k">"label"</span>: <span class="s">"FedEx TEST - FedEx Ground"</span>
                }
            ],
            <span class="k">"groups"</span>: []
        },
        <span class="k">"payment"</span>: {
            <span class="k">"current"</span>: <span class="s">"paypalcheckout_3"</span>,
            <span class="k">"multiple"</span>: <span class="n">false</span>,
            <span class="k">"options"</span>: [
                {
                    <span class="k">"value"</span>: <span class="s">"banktransfer_1"</span>,
                    <span class="k">"label"</span>: <span class="s">"Bank transfer"</span>
                },
                {
                    <span class="k">"value"</span>: <span class="s">"linepay_2"</span>,
                    <span class="k">"label"</span>: <span class="s">"LINE Pay"</span>
                },
                {
                    <span class="k">"value"</span>: <span class="s">"paypalcheckout_3"</span>,
                    <span class="k">"label"</span>: <span class="s">"PayPal Checkout Express Test"</span>
                }
            ]
        }
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## Make an address the default

PUT /customers/**{id}**/addresses/**{aid}**/default write since 6.6.0

Marks one of a customer's addresses as their default, and answers with the customer as it now stands.

The default is per kind: an address used for billing becomes the default billing address, and the one it replaces stops being it. Nothing is sent in the body.

### Path

ParameterTypeDescription

idrequiredintegerThe customer.

aidrequiredintegerThe address, from &#96;addresses\[\].id&#96;.

### Response expand all

FieldTypeDescription

idintegerThe HikaShop customer id, which is what every customer route takes.

cms\_idintegerThe Joomla or WordPress user id, `0` for a guest with no account.

namestring

emailstring

usernamestringThe login, empty for a guest.

typestring`registered` or `guest`.

blockedbooleanWhether the CMS account is disabled.

can\_edit\_accountbooleanWhether this operator may change the login and password of this particular account. False for an account above their own level, which is how a super user is protected from staff.

groups\_editablebooleanWhether this operator may change which groups the customer is in.

groupsobject\[\]The groups they are in.idinteger

titlestring

available\_groupsobject\[\]Every group, with whether this operator may put the customer into it, so a picker can grey out the rest rather than offering a refusal.idinteger

titlestring

assignablebooleanFalse for a group this operator may not grant.

createdintegerUnix timestamp of the first time the shop saw them.

addressesobject\[\]Their addresses, defaults first.idinteger

typesstring\[\]Which of `billing` and `shipping` it is used for.

namestring

companystring

streetstring

citystring

post\_codestring

telephonestring

defaultbooleanWhether it is the default for one of its types.

formattedobjectThe address laid out the way this shop lays addresses out, which depends on its address format setting.textstringSeveral lines, for an invoice or a label.

one\_linestringOne line, for a list.

ordersobject\[\]Their orders, newest first, enough to list them.idinteger

numberstringThe number the customer sees.

statusstringA namekey.

createdintegerUnix timestamp.

totalnumberTax included, in the order currency.

currency\_idintegerThat currency.

fieldsobject\[\]The definitions of your own customer fields.

custom\_fieldsobjectTheir values, keyed by namekey. The keys depend on the shop; `fields` says what they are.

custom\_field\_filesobjectFor a field holding a file, the file behind the value. Keyed the same way.

### Errors

CodeHTTPMeans

not\_found404No such customer or address, or the operator may not change them.

```
curl -X PUT "$SHOP/hikashop-api/v1/customers/{id}/addresses/{id}/default" \
  -H "Authorization: Bearer $TOKEN"
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"id"</span>: <span class="n">20</span>,
        <span class="k">"cms_id"</span>: <span class="n">0</span>,
        <span class="k">"name"</span>: <span class="s">"John Doe"</span>,
        <span class="k">"email"</span>: <span class="s">"<joomla-hidden-mail base="" first="YnV5ZXI=" is-email="1" is-link="1" last="ZXhhbXBsZS50ZXN0" text="YnV5ZXJAZXhhbXBsZS50ZXN0">This email address is being protected from spambots. You need JavaScript enabled to view it.</joomla-hidden-mail>"</span>,
        <span class="k">"username"</span>: <span class="s">""</span>,
        <span class="k">"type"</span>: <span class="s">"guest"</span>,
        <span class="k">"blocked"</span>: <span class="n">false</span>,
        <span class="k">"can_edit_account"</span>: <span class="n">true</span>,
        <span class="k">"groups_editable"</span>: <span class="n">false</span>,
        <span class="k">"groups"</span>: [],
        <span class="k">"available_groups"</span>: [
            {
                <span class="k">"id"</span>: <span class="n">1</span>,
                <span class="k">"title"</span>: <span class="s">"Mr"</span>,
                <span class="k">"assignable"</span>: <span class="n">false</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">9</span>,
                <span class="k">"title"</span>: <span class="s">"Mr"</span>,
                <span class="k">"assignable"</span>: <span class="n">false</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">6</span>,
                <span class="k">"title"</span>: <span class="s">"Mr"</span>,
                <span class="k">"assignable"</span>: <span class="n">false</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">7</span>,
                <span class="k">"title"</span>: <span class="s">"Mr"</span>,
                <span class="k">"assignable"</span>: <span class="n">false</span>
            },
            "… 5 more, trimmed for the example"
        ],
        <span class="k">"created"</span>: <span class="n">1786963440</span>,
        <span class="k">"addresses"</span>: [
            {
                <span class="k">"id"</span>: <span class="n">26</span>,
                <span class="k">"types"</span>: [
                    "billing"
                ],
                <span class="k">"name"</span>: <span class="s">"John Doe"</span>,
                <span class="k">"company"</span>: <span class="s">"Lilas SARL"</span>,
                <span class="k">"street"</span>: <span class="s">"12 rue des Lilas"</span>,
                <span class="k">"city"</span>: <span class="s">"Nantes"</span>,
                <span class="k">"post_code"</span>: <span class="s">"44000"</span>,
                <span class="k">"telephone"</span>: <span class="s">"+33 2 00 00 00 00"</span>,
                <span class="k">"default"</span>: <span class="n">true</span>,
                <span class="k">"formatted"</span>: {
                    <span class="k">"text"</span>: <span class="s">"Alex Marchand\r\n12 rue des Lilas\r\n44000 Nantes\r\nFrance"</span>,
                    <span class="k">"one_line"</span>: <span class="s">"Marchand Alex - 12 rue des Lilas, Nantes (France)"</span>
                }
            },
            {
                <span class="k">"id"</span>: <span class="n">25</span>,
                <span class="k">"types"</span>: [
                    "shipping"
                ],
                <span class="k">"name"</span>: <span class="s">"John Doe"</span>,
                <span class="k">"company"</span>: <span class="s">"Lilas SARL"</span>,
                <span class="k">"street"</span>: <span class="s">"12 rue des Lilas"</span>,
                <span class="k">"city"</span>: <span class="s">"Nantes"</span>,
                <span class="k">"post_code"</span>: <span class="s">"44000"</span>,
                <span class="k">"telephone"</span>: <span class="s">"+33 2 00 00 00 00"</span>,
                <span class="k">"default"</span>: <span class="n">true</span>,
                <span class="k">"formatted"</span>: {
                    <span class="k">"text"</span>: <span class="s">"Alex Marchand\r\n12 rue des Lilas\r\n44000 Nantes\r\nFrance"</span>,
                    <span class="k">"one_line"</span>: <span class="s">"Marchand Alex - 12 rue des Lilas, Nantes (France)"</span>
                }
            }
        ],
        <span class="k">"orders"</span>: [
            {
                <span class="k">"id"</span>: <span class="n">26</span>,
                <span class="k">"number"</span>: <span class="s">"B2D6"</span>,
                <span class="k">"status"</span>: <span class="s">"created"</span>,
                <span class="k">"created"</span>: <span class="n">1785338765</span>,
                <span class="k">"total"</span>: <span class="n">14.99</span>,
                <span class="k">"currency_id"</span>: <span class="n">1</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">28</span>,
                <span class="k">"number"</span>: <span class="s">"B2F8"</span>,
                <span class="k">"status"</span>: <span class="s">"confirmed"</span>,
                <span class="k">"created"</span>: <span class="n">1785321840</span>,
                <span class="k">"total"</span>: <span class="n">14.99</span>,
                <span class="k">"currency_id"</span>: <span class="n">1</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">30</span>,
                <span class="k">"number"</span>: <span class="s">"ZBUNDLE"</span>,
                <span class="k">"status"</span>: <span class="s">"confirmed"</span>,
                <span class="k">"created"</span>: <span class="n">1784803440</span>,
                <span class="k">"total"</span>: <span class="n">14.99</span>,
                <span class="k">"currency_id"</span>: <span class="n">1</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">22</span>,
                <span class="k">"number"</span>: <span class="s">"Z22"</span>,
                <span class="k">"status"</span>: <span class="s">"created"</span>,
                <span class="k">"created"</span>: <span class="n">1783721823</span>,
                <span class="k">"total"</span>: <span class="n">14.99</span>,
                <span class="k">"currency_id"</span>: <span class="n">1</span>
            }
        ],
        <span class="k">"fields"</span>: [],
        <span class="k">"custom_fields"</span>: [],
        <span class="k">"custom_field_files"</span>: []
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## Create a characteristic or one of its values

POST /products/characteristics write since 6.6.0

Creates a characteristic, such as Size, or a value of one, such as XL.

Send a `name` for a characteristic, or a `value` with the `parent_id` of the characteristic it belongs to. They are the same records at two levels, which is why one route serves both.

### Body

FieldTypeDescription

namestringThe name of a new characteristic. Give this or `value`.

valuestringThe name of a new value, with `parent_id`.

parent\_idintegerThe characteristic a value belongs to.

### Response expand all

FieldTypeDescription

idintegerWhat was created, which is what a variant refers to.

valuestringIts name.

parent\_idinteger`0` for a characteristic, the characteristic for a value.

### Errors

CodeHTTPMeans

invalid\_request400Neither a name nor a value was given.

save\_failed500The shop refused to save it.

```
curl -X POST "$SHOP/hikashop-api/v1/products/characteristics" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Documentation capture"
}'
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"id"</span>: <span class="n">904</span>,
        <span class="k">"value"</span>: <span class="s">"Documentation capture"</span>,
        <span class="k">"parent_id"</span>: <span class="n">0</span>
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## Create a product category

POST /products/categories write since 6.6.0

Creates a category under another, or at the top of the product tree when no parent is given.

### Body

FieldTypeDescription

namerequiredstringIts name.

parent\_idintegerThe category to put it under. Omit for the top of the tree.

publishedbooleanDefaults to published.

descriptionstringThe long description, as HTML.

meta\_descriptionstringSEO description.

accessobjectWho may see it.

custom\_fieldsobjectYour own category fields, keyed by namekey.

### Response expand all

FieldTypeDescription

idintegerThe category that was created.

namestring

parent\_idintegerWhere it sits.

publishedboolean

### Errors

CodeHTTPMeans

invalid\_fields400One of your own fields was rejected by its own rules.

save\_failed500The shop refused to save it.

```
curl -X POST "$SHOP/hikashop-api/v1/products/categories" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Documentation capture"
}'
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"id"</span>: <span class="n">288</span>,
        <span class="k">"name"</span>: <span class="s">"Documentation capture"</span>,
        <span class="k">"parent_id"</span>: <span class="n">2</span>,
        <span class="k">"published"</span>: <span class="n">true</span>
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## Create a manufacturer

POST /products/manufacturers write since 6.6.0

Creates a brand. HikaShop keeps manufacturers in the category tree under their own root, so this takes the same fields as a category and answers the same way.

### Body

FieldTypeDescription

namerequiredstringThe brand name.

parent\_idintegerA manufacturer to nest it under, which most shops do not use.

publishedbooleanDefaults to published.

descriptionstringThe long description, as HTML.

meta\_descriptionstringSEO description.

accessobjectWho may see it.

custom\_fieldsobjectYour own category fields.

### Response expand all

FieldTypeDescription

idintegerThe manufacturer that was created, which is what `manufacturer_id` on a product stores.

namestring

parent\_idintegerIts root.

publishedboolean

### Errors

CodeHTTPMeans

invalid\_fields400One of your own fields was rejected by its own rules.

save\_failed500The shop refused to save it.

```
curl -X POST "$SHOP/hikashop-api/v1/products/manufacturers" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Documentation capture brand"
}'
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"id"</span>: <span class="n">289</span>,
        <span class="k">"name"</span>: <span class="s">"Documentation capture brand"</span>,
        <span class="k">"parent_id"</span>: <span class="n">10</span>,
        <span class="k">"published"</span>: <span class="n">true</span>
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## Update a category

PUT /categories/**{id}** write since 6.6.0

Changes the fields you send and leaves the rest alone. It serves manufacturers and the other trees as well, since they are all categories.

### Path

ParameterTypeDescription

idrequiredintegerThe category.

### Body

Any of `name`, `parent_id`, `published`, `description`, `meta_description`, `access` and `custom_fields`. What you do not send keeps its value.

### Response expand all

FieldTypeDescription

idstring

fieldsobject\[\]The definitions of your own category fields.namekeystringThe key its value is stored under.

labelstringTranslated into the operator's language.

typestringWhat to render: `text`, `radio`, `singledropdown`, `file`, and the rest.

raw\_typestringHikaShop's own name for the type.

requiredbooleanWhether the shop refuses to save without it.

defaultstringThe value used when none is given.

optionsobject\[\]The choices, for a field that has them.valuestringWhat to send back when this choice is picked.

labelstringWhat to show.

label\_keystringThe translation key behind the label, when there is one.

multiplebooleanWhether more than one may be chosen.

translatablebooleanWhether its value can be translated.

upload\_dirstringFor a file field, where its uploads are kept.

allowed\_extensionsstringFor a file field, the extensions it accepts. Empty means the shop default.

date\_formatstringFor a date field, the format it is stored in.

namestring

parent\_idintegerIts parent.

typestringWhich tree it belongs to: `product`, `manufacturer`, `tax`, and so on.

descriptionstringThe long description, as HTML.

meta\_descriptionstringSEO description.

publishedboolean

accessobjectWho may see it.modestring`all`, `none`, or `groups` when it is restricted to some.

groupsinteger\[\]User \*\*group\*\* ids, and not Joomla view levels. The two id spaces overlap and disagree, so a value that looks plausible can grant the wrong audience.

imagestring\|nullAbsolute URL of its image, `null` when it has none.

custom\_fieldsobjectTheir values, keyed by namekey. The keys depend on the shop; `fields` says what they are.

custom\_field\_filesobjectFor a field holding a file, the file behind the value. Keyed the same way.

### Errors

CodeHTTPMeans

not\_found404No such category, or the operator may not change it.

invalid\_fields400One of your own fields was rejected by its own rules.

```
curl -X PUT "$SHOP/hikashop-api/v1/categories/{id}" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Shampoo"
}'
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"fields"</span>: [],
        <span class="k">"id"</span>: <span class="n">252</span>,
        <span class="k">"name"</span>: <span class="s">"Shampoo"</span>,
        <span class="k">"parent_id"</span>: <span class="n">220</span>,
        <span class="k">"type"</span>: <span class="s">"product"</span>,
        <span class="k">"description"</span>: <span class="s">""</span>,
        <span class="k">"meta_description"</span>: <span class="s">""</span>,
        <span class="k">"published"</span>: <span class="n">true</span>,
        <span class="k">"access"</span>: {
            <span class="k">"mode"</span>: <span class="s">"all"</span>,
            <span class="k">"groups"</span>: []
        },
        <span class="k">"image"</span>: <span class="s">"http://localhost:<span class="n">8080</span>/joomla6_ext/images/com_hikashop/upload/demo-cat-252.png"</span>,
        <span class="k">"custom_fields"</span>: [],
        <span class="k">"custom_field_files"</span>: []
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## Delete a category

DELETE /categories/**{id}** write since 6.6.0

Deletes a category. The products in it are not deleted; they simply stop being in it, and a product left in no category at all disappears from the shop's listings.

### Path

ParameterTypeDescription

idrequiredintegerThe category.

### Response expand all

FieldTypeDescription

idintegerThe category that was deleted.

deletedbooleanTrue when the row is gone.

### Errors

CodeHTTPMeans

not\_found404No such category, or the operator may not delete it.

```
curl -X DELETE "$SHOP/hikashop-api/v1/categories/{id}" \
  -H "Authorization: Bearer $TOKEN"
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"id"</span>: <span class="n">287</span>,
        <span class="k">"deleted"</span>: <span class="n">true</span>
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## List the entries of the HikaShop log

GET /logs read since 6.8.0

The log of System &gt; Logs, newest first: what payment and shipping methods write when their Debug option is on, and the errors HikaShop meets. The data of an entry is left out; `data_size` says how much there is, and `GET /logs/{id}` returns it.

Read a payment problem by finding one entry about the order (`order_id`), then listing its `request`: that gives every line the notification wrote, in order.

### Query

ParameterTypeDescription

startintegerOffset. Defaults to `0`.

limitintegerDefaults to `50`, capped at `200`.

sourcestringOnly this source.

typestring`payment`, `shipping`, `plugin` or `core`.

levelstringThis level and the worse ones: `debug`, `info`, `warning` or `error`.

order\_idintegerOnly the entries about this order.

requeststringOnly the entries one request wrote.

sincestringFrom this date: a Unix timestamp, or a date such as `2026-10-01`.

untilstringUp to this date; a bare day such as `2026-10-01` is included.

searchstringText in the message, the data, the source, the address or the IP.

### Response a list expand all

FieldTypeDescription

order\_idintegerThe order it is about, `0` when none. A payment plugin records the order it loaded.

idinteger

createdintegerUnix timestamp of when it was written.

levelstring`debug`, `info`, `warning` or `error`.

sourcestringWhat wrote it: a plugin name such as `paypal`, or a part of HikaShop such as `mail`.

typestring`payment`, `shipping`, `plugin` or `core`.

messagestringThe text of the entry, or the beginning of its data when it only had data.

user\_idintegerThe user logged in when it was written, `0` for a guest or a call from a server.

ipstringIP address of the request. A payment notification comes from the provider's servers.

urlstringAddress of the request, with secrets in its query masked.

requeststringId shared by every entry one request wrote; filter on it to read a notification from start to end.

data\_sizeintegerBytes of data the entry holds beyond its message, `0` when none.

### Envelope meta

FieldTypeDescription

startintegerEchoes the offset used.

limitintegerEchoes the page size used.

totalintegerEntries matching the filters, before paging.

```
curl "$SHOP/hikashop-api/v1/logs?limit=2" \
  -H "Authorization: Bearer $TOKEN"
```

```
{
    <span class="k">"data"</span>: [
        {
            <span class="k">"id"</span>: <span class="n">4</span>,
            <span class="k">"created"</span>: <span class="n">1792671482</span>,
            <span class="k">"level"</span>: <span class="s">"debug"</span>,
            <span class="k">"source"</span>: <span class="s">"ups2"</span>,
            <span class="k">"type"</span>: <span class="s">"shipping"</span>,
            <span class="k">"message"</span>: <span class="s">"Rate request"</span>,
            <span class="k">"order_id"</span>: <span class="n">0</span>,
            <span class="k">"user_id"</span>: <span class="n">0</span>,
            <span class="k">"ip"</span>: <span class="s">"203.0.113.7"</span>,
            <span class="k">"url"</span>: <span class="s">"cli: seed.php"</span>,
            <span class="k">"request"</span>: <span class="s">"6356ff9319045d36"</span>,
            <span class="k">"data_size"</span>: <span class="n">16</span>
        },
        {
            <span class="k">"id"</span>: <span class="n">2</span>,
            <span class="k">"created"</span>: <span class="n">1792671482</span>,
            <span class="k">"level"</span>: <span class="s">"info"</span>,
            <span class="k">"source"</span>: <span class="s">"paypal"</span>,
            <span class="k">"type"</span>: <span class="s">"payment"</span>,
            <span class="k">"message"</span>: <span class="s">"Notification refused: bad signature"</span>,
            <span class="k">"order_id"</span>: <span class="n">1</span>,
            <span class="k">"user_id"</span>: <span class="n">0</span>,
            <span class="k">"ip"</span>: <span class="s">"203.0.113.7"</span>,
            <span class="k">"url"</span>: <span class="s">"cli: seed.php"</span>,
            <span class="k">"request"</span>: <span class="s">"6356ff9319045d36"</span>,
            <span class="k">"data_size"</span>: <span class="n">0</span>
        }
    ],
    <span class="k">"meta"</span>: {
        <span class="k">"start"</span>: <span class="n">0</span>,
        <span class="k">"limit"</span>: <span class="n">2</span>,
        <span class="k">"total"</span>: <span class="n">3</span>
    },
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## Read one entry of the HikaShop log with its data

GET /logs/**{id}** read since 6.8.0

One entry with everything it holds. Card numbers and security codes, passwords, keys and tokens were masked when it was written; a gateway's own field names can still slip through, so read the data before passing it on.

### Path

ParameterTypeDescription

idrequiredintegerThe log entry.

### Response expand all

FieldTypeDescription

idinteger

createdintegerUnix timestamp of when it was written.

levelstring`debug`, `info`, `warning` or `error`.

sourcestringWhat wrote it: a plugin name such as `paypal`, or a part of HikaShop such as `mail`.

typestring`payment`, `shipping`, `plugin` or `core`.

messagestringThe text of the entry, or the beginning of its data when it only had data.

order\_idintegerThe order it is about, `0` when none. A payment plugin records the order it loaded.

user\_idintegerThe user logged in when it was written, `0` for a guest or a call from a server.

ipstringIP address of the request. A payment notification comes from the provider's servers.

urlstringAddress of the request, with secrets in its query masked.

requeststringId shared by every entry one request wrote; filter on it to read a notification from start to end.

data\_sizeintegerBytes of data the entry holds beyond its message, `0` when none.

dataobject\|array\|stringWhat the entry holds beyond its message: the decoded JSON when it was an array or an object, the text otherwise, an empty string when none.

### Errors

CodeHTTPMeans

not\_found404No such entry.

```
curl "$SHOP/hikashop-api/v1/logs/4" \
  -H "Authorization: Bearer $TOKEN"
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"id"</span>: <span class="n">4</span>,
        <span class="k">"created"</span>: <span class="n">1792671482</span>,
        <span class="k">"level"</span>: <span class="s">"debug"</span>,
        <span class="k">"source"</span>: <span class="s">"ups2"</span>,
        <span class="k">"type"</span>: <span class="s">"shipping"</span>,
        <span class="k">"message"</span>: <span class="s">"Rate request"</span>,
        <span class="k">"order_id"</span>: <span class="n">0</span>,
        <span class="k">"user_id"</span>: <span class="n">0</span>,
        <span class="k">"ip"</span>: <span class="s">"203.0.113.7"</span>,
        <span class="k">"url"</span>: <span class="s">"cli: seed.php"</span>,
        <span class="k">"request"</span>: <span class="s">"6356ff9319045d36"</span>,
        <span class="k">"data_size"</span>: <span class="n">16</span>,
        <span class="k">"data"</span>: <span class="s">"<xml>rates</xml>"</span>
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## Read one discount or coupon

GET /discounts/**{id}** read since 6.6.0

One reduction with every restriction it carries.

### Path

ParameterTypeDescription

idrequiredintegerThe discount or coupon.

### Response expand all

FieldTypeDescription

idinteger

typestring`discount` applies by itself, `coupon` waits for its code.

codestringWhat the customer types. Empty on a discount.

kindstringWhether the value is a percentage or a fixed amount.

valuenumberThe reduction, read according to `kind`.

currency\_idintegerThe currency a fixed amount is in.

publishedboolean

startinteger\|nullUnix timestamp before which it does not apply.

endinteger\|nullUnix timestamp after which it expires.

minimum\_ordernumberOrder total below which it does not apply, `0` for none.

maximum\_ordernumberOrder total above which it stops applying, `0` for none.

quotaintegerHow many times it may be used in total, `0` for no limit.

quota\_per\_userintegerHow many times one customer may use it, `0` for no limit.

used\_timesintegerHow many times it already has been.

tax\_includedbooleanWhether the value is understood as tax included.

tax\_idintegerThe tax category of the reduction itself.

shipping\_percentnumberA reduction on the shipping rather than on the goods.

minimum\_productsintegerFewest items in the cart for it to apply.

maximum\_productsintegerMost items for it to still apply.

product\_idsinteger\[\]Restricted to these products. Empty means all of them.

exclude\_product\_idsinteger\[\]Never applies to these.

category\_idsinteger\[\]Restricted to these categories.

category\_childsbooleanWhether those categories include their sub-categories.

exclude\_category\_idsinteger\[\]Never applies in these categories.

exclude\_category\_childsbooleanWhether those exclusions include sub-categories.

zone\_idsinteger\[\]Restricted to these zones.

user\_idsinteger\[\]Restricted to these customers.

accessobjectWhich user groups it is for, in the usual `mode` and `groups` shape.modestring`all`, `none`, or `groups` when it is restricted to some.

groupsinteger\[\]User \*\*group\*\* ids, and not Joomla view levels. The two id spaces overlap and disagree, so a value that looks plausible can grant the wrong audience.

exclude\_accessobjectWhich user groups it is never for.modestring`all`, `none`, or `groups` when it is restricted to some.

groupsinteger\[\]User \*\*group\*\* ids, and not Joomla view levels. The two id spaces overlap and disagree, so a value that looks plausible can grant the wrong audience.

auto\_loadbooleanFor a coupon, whether the shop applies it without the customer typing it.

product\_onlybooleanWhether it reduces only the goods and leaves the fees alone.

discounted\_productsintegerHow many products in the cart it applied to, on a discount that has been used.

### Errors

CodeHTTPMeans

not\_found404No such discount, or the operator may not see it.

```
curl "$SHOP/hikashop-api/v1/discounts/1" \
  -H "Authorization: Bearer $TOKEN"
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"id"</span>: <span class="n">1</span>,
        <span class="k">"type"</span>: <span class="s">"coupon"</span>,
        <span class="k">"code"</span>: <span class="s">"APPTEST10"</span>,
        <span class="k">"kind"</span>: <span class="s">"flat"</span>,
        <span class="k">"value"</span>: <span class="n">10</span>,
        <span class="k">"currency_id"</span>: <span class="n">1</span>,
        <span class="k">"published"</span>: <span class="n">true</span>,
        <span class="k">"start"</span>: <span class="n">0</span>,
        <span class="k">"end"</span>: <span class="n">0</span>,
        <span class="k">"minimum_order"</span>: <span class="n">0</span>,
        <span class="k">"maximum_order"</span>: <span class="n">0</span>,
        <span class="k">"quota"</span>: <span class="n">0</span>,
        <span class="k">"quota_per_user"</span>: <span class="n">0</span>,
        <span class="k">"used_times"</span>: <span class="n">0</span>,
        <span class="k">"tax_included"</span>: <span class="n">false</span>,
        <span class="k">"tax_id"</span>: <span class="n">0</span>,
        <span class="k">"shipping_percent"</span>: <span class="n">0</span>,
        <span class="k">"minimum_products"</span>: <span class="n">0</span>,
        <span class="k">"maximum_products"</span>: <span class="n">0</span>,
        <span class="k">"product_ids"</span>: [],
        <span class="k">"exclude_product_ids"</span>: [],
        <span class="k">"category_ids"</span>: [],
        <span class="k">"category_childs"</span>: <span class="n">false</span>,
        <span class="k">"exclude_category_ids"</span>: [],
        <span class="k">"exclude_category_childs"</span>: <span class="n">false</span>,
        <span class="k">"zone_ids"</span>: [],
        <span class="k">"user_ids"</span>: [],
        <span class="k">"access"</span>: {
            <span class="k">"mode"</span>: <span class="s">"all"</span>,
            <span class="k">"groups"</span>: []
        },
        <span class="k">"exclude_access"</span>: {
            <span class="k">"mode"</span>: <span class="s">"none"</span>,
            <span class="k">"groups"</span>: []
        },
        <span class="k">"auto_load"</span>: <span class="n">false</span>,
        <span class="k">"product_only"</span>: <span class="n">false</span>,
        <span class="k">"discounted_products"</span>: <span class="n">0</span>
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## Create a discount or a coupon

POST /discounts write since 6.6.0

Creates a reduction and answers with it as the shop stored it.

`type` decides which kind it is: a `coupon` needs a `code`, a `discount` applies by itself. Either way `value` is required, read according to `kind`.

### Body

Any field of a discount. `type` and `value` are required, and a coupon also needs a `code`. The restriction lists take ids, and an empty list means no restriction of that kind.

### Response expand all

FieldTypeDescription

idinteger

typestring`discount` applies by itself, `coupon` waits for its code.

codestringWhat the customer types. Empty on a discount.

kindstringWhether the value is a percentage or a fixed amount.

valuenumberThe reduction, read according to `kind`.

currency\_idintegerThe currency a fixed amount is in.

publishedboolean

startinteger\|nullUnix timestamp before which it does not apply.

endinteger\|nullUnix timestamp after which it expires.

minimum\_ordernumberOrder total below which it does not apply, `0` for none.

maximum\_ordernumberOrder total above which it stops applying, `0` for none.

quotaintegerHow many times it may be used in total, `0` for no limit.

quota\_per\_userintegerHow many times one customer may use it, `0` for no limit.

used\_timesintegerHow many times it already has been.

tax\_includedbooleanWhether the value is understood as tax included.

tax\_idintegerThe tax category of the reduction itself.

shipping\_percentnumberA reduction on the shipping rather than on the goods.

minimum\_productsintegerFewest items in the cart for it to apply.

maximum\_productsintegerMost items for it to still apply.

product\_idsinteger\[\]Restricted to these products. Empty means all of them.

exclude\_product\_idsinteger\[\]Never applies to these.

category\_idsinteger\[\]Restricted to these categories.

category\_childsbooleanWhether those categories include their sub-categories.

exclude\_category\_idsinteger\[\]Never applies in these categories.

exclude\_category\_childsbooleanWhether those exclusions include sub-categories.

zone\_idsinteger\[\]Restricted to these zones.

user\_idsinteger\[\]Restricted to these customers.

accessobjectWhich user groups it is for, in the usual `mode` and `groups` shape.modestring`all`, `none`, or `groups` when it is restricted to some.

groupsinteger\[\]User \*\*group\*\* ids, and not Joomla view levels. The two id spaces overlap and disagree, so a value that looks plausible can grant the wrong audience.

exclude\_accessobjectWhich user groups it is never for.modestring`all`, `none`, or `groups` when it is restricted to some.

groupsinteger\[\]User \*\*group\*\* ids, and not Joomla view levels. The two id spaces overlap and disagree, so a value that looks plausible can grant the wrong audience.

auto\_loadbooleanFor a coupon, whether the shop applies it without the customer typing it.

product\_onlybooleanWhether it reduces only the goods and leaves the fees alone.

discounted\_productsintegerHow many products in the cart it applied to, on a discount that has been used.

### Errors

CodeHTTPMeans

code\_required400A coupon needs a code.

code\_taken400Another coupon already uses that code.

value\_required400A reduction needs a value.

not\_found404Not reachable when creating: the same handler serves the update, where it means no such discount.

save\_failed500The shop refused to save it.

```
curl -X POST "$SHOP/hikashop-api/v1/discounts" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "coupon",
    "code": "DOCCAPTURE",
    "kind": "percent",
    "value": 10
}'
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"id"</span>: <span class="n">492</span>,
        <span class="k">"type"</span>: <span class="s">"coupon"</span>,
        <span class="k">"code"</span>: <span class="s">"DOCCAPTURE"</span>,
        <span class="k">"kind"</span>: <span class="s">"percent"</span>,
        <span class="k">"value"</span>: <span class="n">10</span>,
        <span class="k">"currency_id"</span>: <span class="n">0</span>,
        <span class="k">"published"</span>: <span class="n">true</span>,
        <span class="k">"start"</span>: <span class="n">0</span>,
        <span class="k">"end"</span>: <span class="n">0</span>,
        <span class="k">"minimum_order"</span>: <span class="n">0</span>,
        <span class="k">"maximum_order"</span>: <span class="n">0</span>,
        <span class="k">"quota"</span>: <span class="n">0</span>,
        <span class="k">"quota_per_user"</span>: <span class="n">0</span>,
        <span class="k">"used_times"</span>: <span class="n">0</span>,
        <span class="k">"tax_included"</span>: <span class="n">false</span>,
        <span class="k">"tax_id"</span>: <span class="n">0</span>,
        <span class="k">"shipping_percent"</span>: <span class="n">0</span>,
        <span class="k">"minimum_products"</span>: <span class="n">0</span>,
        <span class="k">"maximum_products"</span>: <span class="n">0</span>,
        <span class="k">"product_ids"</span>: [],
        <span class="k">"exclude_product_ids"</span>: [],
        <span class="k">"category_ids"</span>: [],
        <span class="k">"category_childs"</span>: <span class="n">false</span>,
        <span class="k">"exclude_category_ids"</span>: [],
        <span class="k">"exclude_category_childs"</span>: <span class="n">false</span>,
        <span class="k">"zone_ids"</span>: [],
        <span class="k">"user_ids"</span>: [],
        <span class="k">"access"</span>: {
            <span class="k">"mode"</span>: <span class="s">"all"</span>,
            <span class="k">"groups"</span>: []
        },
        <span class="k">"exclude_access"</span>: {
            <span class="k">"mode"</span>: <span class="s">"none"</span>,
            <span class="k">"groups"</span>: []
        },
        <span class="k">"auto_load"</span>: <span class="n">false</span>,
        <span class="k">"product_only"</span>: <span class="n">false</span>,
        <span class="k">"discounted_products"</span>: <span class="n">0</span>
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## Update a discount or a coupon

PUT /discounts/**{id}** write since 6.6.0

Changes the fields you send and leaves the rest alone, and answers with the reduction as it now stands.

### Path

ParameterTypeDescription

idrequiredintegerThe discount or coupon.

### Body

Any field of a discount. What you do not send keeps its value. A restriction list you do send replaces the one it had.

### Response expand all

FieldTypeDescription

idinteger

typestring`discount` applies by itself, `coupon` waits for its code.

codestringWhat the customer types. Empty on a discount.

kindstringWhether the value is a percentage or a fixed amount.

valuenumberThe reduction, read according to `kind`.

currency\_idintegerThe currency a fixed amount is in.

publishedboolean

startinteger\|nullUnix timestamp before which it does not apply.

endinteger\|nullUnix timestamp after which it expires.

minimum\_ordernumberOrder total below which it does not apply, `0` for none.

maximum\_ordernumberOrder total above which it stops applying, `0` for none.

quotaintegerHow many times it may be used in total, `0` for no limit.

quota\_per\_userintegerHow many times one customer may use it, `0` for no limit.

used\_timesintegerHow many times it already has been.

tax\_includedbooleanWhether the value is understood as tax included.

tax\_idintegerThe tax category of the reduction itself.

shipping\_percentnumberA reduction on the shipping rather than on the goods.

minimum\_productsintegerFewest items in the cart for it to apply.

maximum\_productsintegerMost items for it to still apply.

product\_idsinteger\[\]Restricted to these products. Empty means all of them.

exclude\_product\_idsinteger\[\]Never applies to these.

category\_idsinteger\[\]Restricted to these categories.

category\_childsbooleanWhether those categories include their sub-categories.

exclude\_category\_idsinteger\[\]Never applies in these categories.

exclude\_category\_childsbooleanWhether those exclusions include sub-categories.

zone\_idsinteger\[\]Restricted to these zones.

user\_idsinteger\[\]Restricted to these customers.

accessobjectWhich user groups it is for, in the usual `mode` and `groups` shape.modestring`all`, `none`, or `groups` when it is restricted to some.

groupsinteger\[\]User \*\*group\*\* ids, and not Joomla view levels. The two id spaces overlap and disagree, so a value that looks plausible can grant the wrong audience.

exclude\_accessobjectWhich user groups it is never for.modestring`all`, `none`, or `groups` when it is restricted to some.

groupsinteger\[\]User \*\*group\*\* ids, and not Joomla view levels. The two id spaces overlap and disagree, so a value that looks plausible can grant the wrong audience.

auto\_loadbooleanFor a coupon, whether the shop applies it without the customer typing it.

product\_onlybooleanWhether it reduces only the goods and leaves the fees alone.

discounted\_productsintegerHow many products in the cart it applied to, on a discount that has been used.

### Errors

CodeHTTPMeans

not\_found404No such discount, or the operator may not change it.

code\_required400A coupon needs a code, so it cannot be cleared on one.

code\_taken400Another coupon already uses that code.

value\_required400A reduction needs a value.

save\_failed500The shop refused to save it.

```
curl -X PUT "$SHOP/hikashop-api/v1/discounts/1" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "kind": "flat",
    "value": 10
}'
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"id"</span>: <span class="n">1</span>,
        <span class="k">"type"</span>: <span class="s">"coupon"</span>,
        <span class="k">"code"</span>: <span class="s">"APPTEST10"</span>,
        <span class="k">"kind"</span>: <span class="s">"flat"</span>,
        <span class="k">"value"</span>: <span class="n">10</span>,
        <span class="k">"currency_id"</span>: <span class="n">1</span>,
        <span class="k">"published"</span>: <span class="n">true</span>,
        <span class="k">"start"</span>: <span class="n">0</span>,
        <span class="k">"end"</span>: <span class="n">0</span>,
        <span class="k">"minimum_order"</span>: <span class="n">0</span>,
        <span class="k">"maximum_order"</span>: <span class="n">0</span>,
        <span class="k">"quota"</span>: <span class="n">0</span>,
        <span class="k">"quota_per_user"</span>: <span class="n">0</span>,
        <span class="k">"used_times"</span>: <span class="n">0</span>,
        <span class="k">"tax_included"</span>: <span class="n">false</span>,
        <span class="k">"tax_id"</span>: <span class="n">0</span>,
        <span class="k">"shipping_percent"</span>: <span class="n">0</span>,
        <span class="k">"minimum_products"</span>: <span class="n">0</span>,
        <span class="k">"maximum_products"</span>: <span class="n">0</span>,
        <span class="k">"product_ids"</span>: [],
        <span class="k">"exclude_product_ids"</span>: [],
        <span class="k">"category_ids"</span>: [],
        <span class="k">"category_childs"</span>: <span class="n">false</span>,
        <span class="k">"exclude_category_ids"</span>: [],
        <span class="k">"exclude_category_childs"</span>: <span class="n">false</span>,
        <span class="k">"zone_ids"</span>: [],
        <span class="k">"user_ids"</span>: [],
        <span class="k">"access"</span>: {
            <span class="k">"mode"</span>: <span class="s">"all"</span>,
            <span class="k">"groups"</span>: []
        },
        <span class="k">"exclude_access"</span>: {
            <span class="k">"mode"</span>: <span class="s">"none"</span>,
            <span class="k">"groups"</span>: []
        },
        <span class="k">"auto_load"</span>: <span class="n">false</span>,
        <span class="k">"product_only"</span>: <span class="n">false</span>,
        <span class="k">"discounted_products"</span>: <span class="n">0</span>
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## Delete a discount or a coupon

DELETE /discounts/**{id}** write since 6.6.0

Deletes a reduction. Orders that already used it keep the amount they were given: the discount on an order is a figure, not a pointer at this row.

### Path

ParameterTypeDescription

idrequiredintegerThe discount or coupon.

### Response expand all

FieldTypeDescription

deletedbooleanTrue when the row is gone.

### Errors

CodeHTTPMeans

not\_found404No such discount, or the operator may not delete it.

```
curl -X DELETE "$SHOP/hikashop-api/v1/discounts/{id}" \
  -H "Authorization: Bearer $TOKEN"
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"deleted"</span>: <span class="n">493</span>
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## Create a customer

POST /customers write since 6.6.0

Creates a customer from an email address and a name, as a guest: no account, no password, nothing for them to log in with.

`POST /customers/{id}/account` turns one into a registered customer afterwards.

### Body

FieldTypeDescription

emailrequiredstringMust not belong to another customer.

namestringTheir display name.

### Response expand all

FieldTypeDescription

idintegerThe customer that was created.

### Errors

CodeHTTPMeans

email\_taken400Another customer already has that address.

save\_failed500The shop refused to save it.

```
curl -X POST "$SHOP/hikashop-api/v1/customers" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "<joomla-hidden-mail base="" first="YnV5ZXI=" is-email="1" is-link="1" last="ZXhhbXBsZS50ZXN0" text="YnV5ZXJAZXhhbXBsZS50ZXN0">This email address is being protected from spambots. You need JavaScript enabled to view it.</joomla-hidden-mail>",
    "name": "Alex Marchand"
}'
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"id"</span>: <span class="n">5428</span>
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## Attach a downloadable file

POST /products/**{id}**/files write since 6.6.0

The same as attaching an image, for the files a customer downloads after buying. `free_download` decides whether they have to buy it first.

### Path

ParameterTypeDescription

idrequiredintegerThe product.

### Body

FieldTypeDescription

datastringThe bytes, base64 encoded. Give this or `path`.

pathstringA file already in the upload folder.

namestringThe file name to store it under.

descriptionstringA note on the file.

accessobjectWho may download it.

### Response expand all

FieldTypeDescription

idinteger

namestring

pathstringRelative to the upload folder.

urlstringAbsolute, ready to display.

orderingintegerWhere it sits among the others; the first image is the one the shop shows.

descriptionstringThe alt text for an image, or a note on a file.

accessobjectWho may see or download it.modestring`all`, `none`, or `groups` when it is restricted to some.

groupsinteger\[\]User \*\*group\*\* ids, and not Joomla view levels. The two id spaces overlap and disagree, so a value that looks plausible can grant the wrong audience.

free\_downloadbooleanFiles only: whether it can be downloaded without buying the product.

### Errors

CodeHTTPMeans

not\_found404No such product, or the operator may not change it.

bad\_type400The extension is not one this shop accepts.

write\_failed500The upload folder refused the file.

```
curl -X POST "$SHOP/hikashop-api/v1/products/{id}/files" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "data": "JVBERi0xLjQKJcOkw7zDtsOfCjIgMCBvYmoKPDwvTGVuZ3RoIDMgMCBSL0ZpbHRlci9GbGF0ZURlY29kZT4+CnN0cmVhbQp4nD3HsQ2AMAxE0T5TXA9IjhOSeAAkKmpLLIAoEAWK2F9wQKK5e/qXcMYKUdE4RSxHTXjuvet3D1CNPqBQZmxbKimw5jJUOJyzcSSJifKPZJa5ffwAAP//AwBQSwMEFAAGAAgAAAAhAA==",
    "name": "documentation-capture.pdf",
    "description": "A small file"
}'
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"id"</span>: <span class="n">8338</span>,
        <span class="k">"name"</span>: <span class="s">"documentation-capture.pdf"</span>,
        <span class="k">"path"</span>: <span class="s">"documentation-capture_2.pdf"</span>,
        <span class="k">"url"</span>: <span class="s">""</span>,
        <span class="k">"ordering"</span>: <span class="n">1</span>,
        <span class="k">"description"</span>: <span class="s">"A small file"</span>,
        <span class="k">"access"</span>: {
            <span class="k">"mode"</span>: <span class="s">"all"</span>,
            <span class="k">"groups"</span>: []
        },
        <span class="k">"free_download"</span>: <span class="n">false</span>
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## A blank address form

GET /customers/**{id}**/addresses read since 6.6.0

The address form of a customer: the shop's own address fields, and the values of the address asked for. Without an address id it is a blank form, which is what you draw to add one.

The form comes with the values because a shop decides its own address fields, so build from `fields` rather than assuming a shape.

### Path

ParameterTypeDescription

idrequiredintegerThe customer.

### Response expand all

FieldTypeDescription

address\_idintegerThe address this form is for, `0` for a new one.

typesstring\[\]Which of `billing` and `shipping` it is used for.

defaultstring\|nullWhich kind it is the default for, `null` when it is not a default.

fieldsobject\[\]The shop's address fields, in display order.namekeystringThe key its value is stored under.

typestringWhat to render: `text`, `radio`, `singledropdown`, `file`, and the rest.

raw\_typestringHikaShop's own name for the type.

labelstringTranslated into the operator's language.

defaultstringThe value used when none is given.

requiredbooleanWhether the shop refuses to save without it.

optionsobject\[\]The choices, for a field that has them.valuestringWhat to send back when this choice is picked.

labelstringWhat to show.

label\_keystringThe translation key behind the label, when there is one.

multiplebooleanWhether more than one may be chosen.

translatablebooleanWhether its value can be translated.

upload\_dirstringFor a file field, where its uploads are kept.

allowed\_extensionsstringFor a file field, the extensions it accepts. Empty means the shop default.

date\_formatstringFor a date field, the format it is stored in.

valuesobjectThe current values, keyed by field namekey. Empty on a blank form. Keyed by whatever address fields this shop has.

country\_namestringThe country spelled out, since the value is a zone namekey.

state\_namestringThe state spelled out, empty where the country has none.

### Errors

CodeHTTPMeans

not\_found404No such customer or address, or the operator may not see them.

```
curl "$SHOP/hikashop-api/v1/customers/{id}/addresses" \
  -H "Authorization: Bearer $TOKEN"
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"address_id"</span>: <span class="n">0</span>,
        <span class="k">"types"</span>: [
            "billing"
        ],
        <span class="k">"default"</span>: <span class="n">false</span>,
        <span class="k">"fields"</span>: [
            {
                <span class="k">"namekey"</span>: <span class="s">"address_title"</span>,
                <span class="k">"type"</span>: <span class="s">"singledropdown"</span>,
                <span class="k">"raw_type"</span>: <span class="s">"singledropdown"</span>,
                <span class="k">"label"</span>: <span class="s">"Title"</span>,
                <span class="k">"default"</span>: <span class="s">""</span>,
                <span class="k">"required"</span>: <span class="n">true</span>,
                <span class="k">"options"</span>: [
                    {
                        <span class="k">"value"</span>: <span class="s">"Mr"</span>,
                        <span class="k">"label"</span>: <span class="s">"Mr"</span>,
                        <span class="k">"label_key"</span>: <span class="s">"HIKA_TITLE_MR"</span>
                    },
                    {
                        <span class="k">"value"</span>: <span class="s">"Mrs"</span>,
                        <span class="k">"label"</span>: <span class="s">"Mrs"</span>,
                        <span class="k">"label_key"</span>: <span class="s">"HIKA_TITLE_MRS"</span>
                    },
                    {
                        <span class="k">"value"</span>: <span class="s">"Miss"</span>,
                        <span class="k">"label"</span>: <span class="s">"Miss"</span>,
                        <span class="k">"label_key"</span>: <span class="s">"HIKA_TITLE_MISS"</span>
                    },
                    {
                        <span class="k">"value"</span>: <span class="s">"Ms"</span>,
                        <span class="k">"label"</span>: <span class="s">"Ms"</span>,
                        <span class="k">"label_key"</span>: <span class="s">"HIKA_TITLE_MS"</span>
                    },
                    "… 1 more, trimmed for the example"
                ],
                <span class="k">"multiple"</span>: <span class="n">false</span>,
                <span class="k">"translatable"</span>: <span class="n">false</span>,
                <span class="k">"upload_dir"</span>: <span class="s">""</span>,
                <span class="k">"allowed_extensions"</span>: <span class="s">""</span>,
                <span class="k">"date_format"</span>: <span class="s">""</span>
            },
            {
                <span class="k">"namekey"</span>: <span class="s">"address_firstname"</span>,
                <span class="k">"type"</span>: <span class="s">"text"</span>,
                <span class="k">"raw_type"</span>: <span class="s">"text"</span>,
                <span class="k">"label"</span>: <span class="s">"First name"</span>,
                <span class="k">"default"</span>: <span class="s">""</span>,
                <span class="k">"required"</span>: <span class="n">true</span>,
                <span class="k">"options"</span>: [],
                <span class="k">"multiple"</span>: <span class="n">false</span>,
                <span class="k">"translatable"</span>: <span class="n">false</span>,
                <span class="k">"upload_dir"</span>: <span class="s">""</span>,
                <span class="k">"allowed_extensions"</span>: <span class="s">""</span>,
                <span class="k">"date_format"</span>: <span class="s">""</span>
            },
            {
                <span class="k">"namekey"</span>: <span class="s">"address_lastname"</span>,
                <span class="k">"type"</span>: <span class="s">"text"</span>,
                <span class="k">"raw_type"</span>: <span class="s">"text"</span>,
                <span class="k">"label"</span>: <span class="s">"Last name"</span>,
                <span class="k">"default"</span>: <span class="s">""</span>,
                <span class="k">"required"</span>: <span class="n">true</span>,
                <span class="k">"options"</span>: [],
                <span class="k">"multiple"</span>: <span class="n">false</span>,
                <span class="k">"translatable"</span>: <span class="n">false</span>,
                <span class="k">"upload_dir"</span>: <span class="s">""</span>,
                <span class="k">"allowed_extensions"</span>: <span class="s">""</span>,
                <span class="k">"date_format"</span>: <span class="s">""</span>
            },
            {
                <span class="k">"namekey"</span>: <span class="s">"address_company"</span>,
                <span class="k">"type"</span>: <span class="s">"text"</span>,
                <span class="k">"raw_type"</span>: <span class="s">"text"</span>,
                <span class="k">"label"</span>: <span class="s">"Company"</span>,
                <span class="k">"default"</span>: <span class="s">""</span>,
                <span class="k">"required"</span>: <span class="n">false</span>,
                <span class="k">"options"</span>: [],
                <span class="k">"multiple"</span>: <span class="n">false</span>,
                <span class="k">"translatable"</span>: <span class="n">false</span>,
                <span class="k">"upload_dir"</span>: <span class="s">""</span>,
                <span class="k">"allowed_extensions"</span>: <span class="s">""</span>,
                <span class="k">"date_format"</span>: <span class="s">""</span>
            },
            "… 7 more, trimmed for the example"
        ],
        <span class="k">"values"</span>: {
            <span class="k">"address_title"</span>: <span class="s">"Mr"</span>,
            <span class="k">"address_firstname"</span>: <span class="s">"Alex"</span>,
            <span class="k">"address_lastname"</span>: <span class="s">"Marchand"</span>,
            <span class="k">"address_company"</span>: <span class="s">"Lilas SARL"</span>,
            <span class="k">"address_street"</span>: <span class="s">"12 rue des Lilas"</span>,
            <span class="k">"address_post_code"</span>: <span class="s">"44000"</span>,
            <span class="k">"address_city"</span>: <span class="s">"Nantes"</span>,
            <span class="k">"address_telephone"</span>: <span class="s">"+33 2 00 00 00 00"</span>,
            <span class="k">"address_country"</span>: <span class="s">""</span>,
            <span class="k">"address_state"</span>: <span class="s">""</span>,
            <span class="k">"address_vat"</span>: <span class="s">"FR00000000000"</span>
        },
        <span class="k">"country_name"</span>: <span class="s">""</span>,
        <span class="k">"state_name"</span>: <span class="s">""</span>
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## An address with its form

GET /customers/**{customerId}**/addresses/**{addressId}** read since 6.6.0

The address form of a customer: the shop's own address fields, and the values of the address asked for. Without an address id it is a blank form, which is what you draw to add one.

The form comes with the values because a shop decides its own address fields, so build from `fields` rather than assuming a shape.

### Path

ParameterTypeDescription

customerIdrequiredintegerThe customer.

addressIdrequiredintegerThe address.

### Response expand all

FieldTypeDescription

address\_idintegerThe address this form is for, `0` for a new one.

typesstring\[\]Which of `billing` and `shipping` it is used for.

defaultstring\|nullWhich kind it is the default for, `null` when it is not a default.

fieldsobject\[\]The shop's address fields, in display order.namekeystringThe key its value is stored under.

typestringWhat to render: `text`, `radio`, `singledropdown`, `file`, and the rest.

raw\_typestringHikaShop's own name for the type.

labelstringTranslated into the operator's language.

defaultstringThe value used when none is given.

requiredbooleanWhether the shop refuses to save without it.

optionsobject\[\]The choices, for a field that has them.valuestringWhat to send back when this choice is picked.

labelstringWhat to show.

label\_keystringThe translation key behind the label, when there is one.

multiplebooleanWhether more than one may be chosen.

translatablebooleanWhether its value can be translated.

upload\_dirstringFor a file field, where its uploads are kept.

allowed\_extensionsstringFor a file field, the extensions it accepts. Empty means the shop default.

date\_formatstringFor a date field, the format it is stored in.

valuesobjectThe current values, keyed by field namekey. Empty on a blank form. Keyed by whatever address fields this shop has.

country\_namestringThe country spelled out, since the value is a zone namekey.

state\_namestringThe state spelled out, empty where the country has none.

### Errors

CodeHTTPMeans

not\_found404No such customer or address, or the operator may not see them.

```
curl "$SHOP/hikashop-api/v1/customers/{id}/addresses/{id}" \
  -H "Authorization: Bearer $TOKEN"
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"address_id"</span>: <span class="n">23</span>,
        <span class="k">"types"</span>: [
            "shipping"
        ],
        <span class="k">"default"</span>: <span class="n">false</span>,
        <span class="k">"fields"</span>: [
            {
                <span class="k">"namekey"</span>: <span class="s">"address_title"</span>,
                <span class="k">"type"</span>: <span class="s">"singledropdown"</span>,
                <span class="k">"raw_type"</span>: <span class="s">"singledropdown"</span>,
                <span class="k">"label"</span>: <span class="s">"Title"</span>,
                <span class="k">"default"</span>: <span class="s">""</span>,
                <span class="k">"required"</span>: <span class="n">true</span>,
                <span class="k">"options"</span>: [
                    {
                        <span class="k">"value"</span>: <span class="s">"Mr"</span>,
                        <span class="k">"label"</span>: <span class="s">"Mr"</span>,
                        <span class="k">"label_key"</span>: <span class="s">"HIKA_TITLE_MR"</span>
                    },
                    {
                        <span class="k">"value"</span>: <span class="s">"Mrs"</span>,
                        <span class="k">"label"</span>: <span class="s">"Mrs"</span>,
                        <span class="k">"label_key"</span>: <span class="s">"HIKA_TITLE_MRS"</span>
                    },
                    {
                        <span class="k">"value"</span>: <span class="s">"Miss"</span>,
                        <span class="k">"label"</span>: <span class="s">"Miss"</span>,
                        <span class="k">"label_key"</span>: <span class="s">"HIKA_TITLE_MISS"</span>
                    },
                    {
                        <span class="k">"value"</span>: <span class="s">"Ms"</span>,
                        <span class="k">"label"</span>: <span class="s">"Ms"</span>,
                        <span class="k">"label_key"</span>: <span class="s">"HIKA_TITLE_MS"</span>
                    },
                    "… 1 more, trimmed for the example"
                ],
                <span class="k">"multiple"</span>: <span class="n">false</span>,
                <span class="k">"translatable"</span>: <span class="n">false</span>,
                <span class="k">"upload_dir"</span>: <span class="s">""</span>,
                <span class="k">"allowed_extensions"</span>: <span class="s">""</span>,
                <span class="k">"date_format"</span>: <span class="s">""</span>
            },
            {
                <span class="k">"namekey"</span>: <span class="s">"address_firstname"</span>,
                <span class="k">"type"</span>: <span class="s">"text"</span>,
                <span class="k">"raw_type"</span>: <span class="s">"text"</span>,
                <span class="k">"label"</span>: <span class="s">"First name"</span>,
                <span class="k">"default"</span>: <span class="s">""</span>,
                <span class="k">"required"</span>: <span class="n">true</span>,
                <span class="k">"options"</span>: [],
                <span class="k">"multiple"</span>: <span class="n">false</span>,
                <span class="k">"translatable"</span>: <span class="n">false</span>,
                <span class="k">"upload_dir"</span>: <span class="s">""</span>,
                <span class="k">"allowed_extensions"</span>: <span class="s">""</span>,
                <span class="k">"date_format"</span>: <span class="s">""</span>
            },
            {
                <span class="k">"namekey"</span>: <span class="s">"address_lastname"</span>,
                <span class="k">"type"</span>: <span class="s">"text"</span>,
                <span class="k">"raw_type"</span>: <span class="s">"text"</span>,
                <span class="k">"label"</span>: <span class="s">"Last name"</span>,
                <span class="k">"default"</span>: <span class="s">""</span>,
                <span class="k">"required"</span>: <span class="n">true</span>,
                <span class="k">"options"</span>: [],
                <span class="k">"multiple"</span>: <span class="n">false</span>,
                <span class="k">"translatable"</span>: <span class="n">false</span>,
                <span class="k">"upload_dir"</span>: <span class="s">""</span>,
                <span class="k">"allowed_extensions"</span>: <span class="s">""</span>,
                <span class="k">"date_format"</span>: <span class="s">""</span>
            },
            {
                <span class="k">"namekey"</span>: <span class="s">"address_company"</span>,
                <span class="k">"type"</span>: <span class="s">"text"</span>,
                <span class="k">"raw_type"</span>: <span class="s">"text"</span>,
                <span class="k">"label"</span>: <span class="s">"Company"</span>,
                <span class="k">"default"</span>: <span class="s">""</span>,
                <span class="k">"required"</span>: <span class="n">false</span>,
                <span class="k">"options"</span>: [],
                <span class="k">"multiple"</span>: <span class="n">false</span>,
                <span class="k">"translatable"</span>: <span class="n">false</span>,
                <span class="k">"upload_dir"</span>: <span class="s">""</span>,
                <span class="k">"allowed_extensions"</span>: <span class="s">""</span>,
                <span class="k">"date_format"</span>: <span class="s">""</span>
            },
            "… 7 more, trimmed for the example"
        ],
        <span class="k">"values"</span>: {
            <span class="k">"address_title"</span>: <span class="s">"Mr"</span>,
            <span class="k">"address_firstname"</span>: <span class="s">"Alex"</span>,
            <span class="k">"address_lastname"</span>: <span class="s">"Marchand"</span>,
            <span class="k">"address_company"</span>: <span class="s">"Lilas SARL"</span>,
            <span class="k">"address_street"</span>: <span class="s">"12 rue des Lilas"</span>,
            <span class="k">"address_post_code"</span>: <span class="s">"44000"</span>,
            <span class="k">"address_city"</span>: <span class="s">"Nantes"</span>,
            <span class="k">"address_telephone"</span>: <span class="s">"+33 2 00 00 00 00"</span>,
            <span class="k">"address_country"</span>: <span class="s">"country_France_73"</span>,
            <span class="k">"address_state"</span>: <span class="s">""</span>,
            <span class="k">"address_vat"</span>: <span class="s">"FR00000000000"</span>
        },
        <span class="k">"country_name"</span>: <span class="s">"France"</span>,
        <span class="k">"state_name"</span>: <span class="s">""</span>
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## Add an address

POST /customers/**{id}**/addresses write since 6.6.0

Writes an address of a customer. Without an address id it creates one; with one it saves that one.

`types` says what the address is for, billing or shipping or both, and `default` makes it the default for those. An address is validated by the shop's own field rules, so a missing required field is refused rather than half-saved.

### Path

ParameterTypeDescription

idrequiredintegerThe customer.

### Body

FieldTypeDescription

fieldsrequiredobjectKeyed by address field namekey, the same keys the form returned in `values`.

typesstring\[\]Which of `billing` and `shipping` this address is for. Defaults to both.

defaultbooleanMake it the default for its types.

### Response expand all

FieldTypeDescription

idintegerThe HikaShop customer id, which is what every customer route takes.

cms\_idintegerThe Joomla or WordPress user id, `0` for a guest with no account.

namestring

emailstring

usernamestringThe login, empty for a guest.

typestring`registered` or `guest`.

blockedbooleanWhether the CMS account is disabled.

can\_edit\_accountbooleanWhether this operator may change the login and password of this particular account. False for an account above their own level, which is how a super user is protected from staff.

groups\_editablebooleanWhether this operator may change which groups the customer is in.

groupsobject\[\]The groups they are in.idinteger

titlestring

available\_groupsobject\[\]Every group, with whether this operator may put the customer into it, so a picker can grey out the rest rather than offering a refusal.idinteger

titlestring

assignablebooleanFalse for a group this operator may not grant.

createdintegerUnix timestamp of the first time the shop saw them.

addressesobject\[\]Their addresses, defaults first.idinteger

typesstring\[\]Which of `billing` and `shipping` it is used for.

namestring

companystring

streetstring

citystring

post\_codestring

telephonestring

defaultbooleanWhether it is the default for one of its types.

formattedobjectThe address laid out the way this shop lays addresses out, which depends on its address format setting.textstringSeveral lines, for an invoice or a label.

one\_linestringOne line, for a list.

ordersobject\[\]Their orders, newest first, enough to list them.idinteger

numberstringThe number the customer sees.

statusstringA namekey.

createdintegerUnix timestamp.

totalnumberTax included, in the order currency.

currency\_idintegerThat currency.

fieldsobject\[\]The definitions of your own customer fields.

custom\_fieldsobjectTheir values, keyed by namekey. The keys depend on the shop; `fields` says what they are.

custom\_field\_filesobjectFor a field holding a file, the file behind the value. Keyed the same way.

### Errors

CodeHTTPMeans

not\_found404No such customer or address, or the operator may not change them.

invalid\_fields400A field was rejected by its own rules.

invalid\_address400The address is not one the shop will accept, usually a missing required field.

```
curl -X POST "$SHOP/hikashop-api/v1/customers/{id}/addresses" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "fields": {
        "address_title": "Mr",
        "address_firstname": "Alex",
        "address_lastname": "Marchand",
        "address_street": "12 rue des Lilas",
        "address_post_code": "44000",
        "address_city": "Nantes",
        "address_telephone": "+33 2 00 00 00 00",
        "address_country": "country_Albania_2",
        "address_state": "state_Beratit_274"
    }
}'
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"id"</span>: <span class="n">14</span>,
        <span class="k">"cms_id"</span>: <span class="n">156</span>,
        <span class="k">"name"</span>: <span class="s">"Admin"</span>,
        <span class="k">"email"</span>: <span class="s">"<joomla-hidden-mail base="" first="YnV5ZXI=" is-email="1" is-link="1" last="ZXhhbXBsZS50ZXN0" text="YnV5ZXJAZXhhbXBsZS50ZXN0">This email address is being protected from spambots. You need JavaScript enabled to view it.</joomla-hidden-mail>"</span>,
        <span class="k">"username"</span>: <span class="s">"admin"</span>,
        <span class="k">"type"</span>: <span class="s">"registered"</span>,
        <span class="k">"blocked"</span>: <span class="n">false</span>,
        <span class="k">"can_edit_account"</span>: <span class="n">false</span>,
        <span class="k">"groups_editable"</span>: <span class="n">false</span>,
        <span class="k">"groups"</span>: [
            {
                <span class="k">"id"</span>: <span class="n">8</span>,
                <span class="k">"title"</span>: <span class="s">"Mr"</span>
            }
        ],
        <span class="k">"available_groups"</span>: [
            {
                <span class="k">"id"</span>: <span class="n">1</span>,
                <span class="k">"title"</span>: <span class="s">"Mr"</span>,
                <span class="k">"assignable"</span>: <span class="n">false</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">9</span>,
                <span class="k">"title"</span>: <span class="s">"Mr"</span>,
                <span class="k">"assignable"</span>: <span class="n">false</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">6</span>,
                <span class="k">"title"</span>: <span class="s">"Mr"</span>,
                <span class="k">"assignable"</span>: <span class="n">false</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">7</span>,
                <span class="k">"title"</span>: <span class="s">"Mr"</span>,
                <span class="k">"assignable"</span>: <span class="n">false</span>
            },
            "… 5 more, trimmed for the example"
        ],
        <span class="k">"created"</span>: <span class="n">1778653121</span>,
        <span class="k">"addresses"</span>: [
            {
                <span class="k">"id"</span>: <span class="n">4372</span>,
                <span class="k">"types"</span>: [
                    "shipping"
                ],
                <span class="k">"name"</span>: <span class="s">"Test Buyer"</span>,
                <span class="k">"company"</span>: <span class="s">"Lilas SARL"</span>,
                <span class="k">"street"</span>: <span class="s">"12 rue des Lilas"</span>,
                <span class="k">"city"</span>: <span class="s">"Nantes"</span>,
                <span class="k">"post_code"</span>: <span class="s">"44000"</span>,
                <span class="k">"telephone"</span>: <span class="s">"+33 2 00 00 00 00"</span>,
                <span class="k">"default"</span>: <span class="n">true</span>,
                <span class="k">"formatted"</span>: {
                    <span class="k">"text"</span>: <span class="s">"Alex Marchand\r\n12 rue des Lilas\r\n44000 Nantes\r\nFrance"</span>,
                    <span class="k">"one_line"</span>: <span class="s">"Marchand Alex - 12 rue des Lilas, Nantes (France)"</span>
                }
            },
            {
                <span class="k">"id"</span>: <span class="n">4371</span>,
                <span class="k">"types"</span>: [
                    "billing"
                ],
                <span class="k">"name"</span>: <span class="s">"Test Buyer"</span>,
                <span class="k">"company"</span>: <span class="s">"Lilas SARL"</span>,
                <span class="k">"street"</span>: <span class="s">"12 rue des Lilas"</span>,
                <span class="k">"city"</span>: <span class="s">"Nantes"</span>,
                <span class="k">"post_code"</span>: <span class="s">"44000"</span>,
                <span class="k">"telephone"</span>: <span class="s">"+33 2 00 00 00 00"</span>,
                <span class="k">"default"</span>: <span class="n">true</span>,
                <span class="k">"formatted"</span>: {
                    <span class="k">"text"</span>: <span class="s">"Alex Marchand\r\n12 rue des Lilas\r\n44000 Nantes\r\nFrance"</span>,
                    <span class="k">"one_line"</span>: <span class="s">"Marchand Alex - 12 rue des Lilas, Nantes (France)"</span>
                }
            },
            {
                <span class="k">"id"</span>: <span class="n">4387</span>,
                <span class="k">"types"</span>: [
                    "billing"
                ],
                <span class="k">"name"</span>: <span class="s">"Test Buyer"</span>,
                <span class="k">"company"</span>: <span class="s">"Lilas SARL"</span>,
                <span class="k">"street"</span>: <span class="s">"12 rue des Lilas"</span>,
                <span class="k">"city"</span>: <span class="s">"Nantes"</span>,
                <span class="k">"post_code"</span>: <span class="s">"44000"</span>,
                <span class="k">"telephone"</span>: <span class="s">"+33 2 00 00 00 00"</span>,
                <span class="k">"default"</span>: <span class="n">false</span>,
                <span class="k">"formatted"</span>: {
                    <span class="k">"text"</span>: <span class="s">"Alex Marchand\r\n12 rue des Lilas\r\n44000 Nantes\r\nFrance"</span>,
                    <span class="k">"one_line"</span>: <span class="s">"Marchand Alex - 12 rue des Lilas, Nantes (France)"</span>
                }
            },
            {
                <span class="k">"id"</span>: <span class="n">4380</span>,
                <span class="k">"types"</span>: [
                    "billing"
                ],
                <span class="k">"name"</span>: <span class="s">"Test Buyer"</span>,
                <span class="k">"company"</span>: <span class="s">"Lilas SARL"</span>,
                <span class="k">"street"</span>: <span class="s">"12 rue des Lilas"</span>,
                <span class="k">"city"</span>: <span class="s">"Nantes"</span>,
                <span class="k">"post_code"</span>: <span class="s">"44000"</span>,
                <span class="k">"telephone"</span>: <span class="s">"+33 2 00 00 00 00"</span>,
                <span class="k">"default"</span>: <span class="n">false</span>,
                <span class="k">"formatted"</span>: {
                    <span class="k">"text"</span>: <span class="s">"Alex Marchand\r\n12 rue des Lilas\r\n44000 Nantes\r\nFrance"</span>,
                    <span class="k">"one_line"</span>: <span class="s">"Marchand Alex - 12 rue des Lilas, Nantes (France)"</span>
                }
            },
            "… 5 more, trimmed for the example"
        ],
        <span class="k">"orders"</span>: [
            {
                <span class="k">"id"</span>: <span class="n">2</span>,
                <span class="k">"number"</span>: <span class="s">"TEST-VOTE-1"</span>,
                <span class="k">"status"</span>: <span class="s">"confirmed"</span>,
                <span class="k">"created"</span>: <span class="n">1786877040</span>,
                <span class="k">"total"</span>: <span class="n">100</span>,
                <span class="k">"currency_id"</span>: <span class="n">1</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">18</span>,
                <span class="k">"number"</span>: <span class="s">"U18"</span>,
                <span class="k">"status"</span>: <span class="s">"confirmed"</span>,
                <span class="k">"created"</span>: <span class="n">1786358640</span>,
                <span class="k">"total"</span>: <span class="n">14.99</span>,
                <span class="k">"currency_id"</span>: <span class="n">1</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">20</span>,
                <span class="k">"number"</span>: <span class="s">"X20"</span>,
                <span class="k">"status"</span>: <span class="s">"confirmed"</span>,
                <span class="k">"created"</span>: <span class="n">1785840240</span>,
                <span class="k">"total"</span>: <span class="n">14.99</span>,
                <span class="k">"currency_id"</span>: <span class="n">1</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">16</span>,
                <span class="k">"number"</span>: <span class="s">"S16"</span>,
                <span class="k">"status"</span>: <span class="s">"created"</span>,
                <span class="k">"created"</span>: <span class="n">1783345950</span>,
                <span class="k">"total"</span>: <span class="n">14.99</span>,
                <span class="k">"currency_id"</span>: <span class="n">1</span>
            },
            "… 96 more, trimmed for the example"
        ],
        <span class="k">"fields"</span>: [],
        <span class="k">"custom_fields"</span>: [],
        <span class="k">"custom_field_files"</span>: []
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## Add an address

PUT /customers/**{id}**/addresses write since 6.6.0

Writes an address of a customer. Without an address id it creates one; with one it saves that one.

`types` says what the address is for, billing or shipping or both, and `default` makes it the default for those. An address is validated by the shop's own field rules, so a missing required field is refused rather than half-saved.

### Path

ParameterTypeDescription

idrequiredintegerThe customer.

### Body

FieldTypeDescription

fieldsrequiredobjectKeyed by address field namekey, the same keys the form returned in `values`.

typesstring\[\]Which of `billing` and `shipping` this address is for. Defaults to both.

defaultbooleanMake it the default for its types.

### Response expand all

FieldTypeDescription

idintegerThe HikaShop customer id, which is what every customer route takes.

cms\_idintegerThe Joomla or WordPress user id, `0` for a guest with no account.

namestring

emailstring

usernamestringThe login, empty for a guest.

typestring`registered` or `guest`.

blockedbooleanWhether the CMS account is disabled.

can\_edit\_accountbooleanWhether this operator may change the login and password of this particular account. False for an account above their own level, which is how a super user is protected from staff.

groups\_editablebooleanWhether this operator may change which groups the customer is in.

groupsobject\[\]The groups they are in.idinteger

titlestring

available\_groupsobject\[\]Every group, with whether this operator may put the customer into it, so a picker can grey out the rest rather than offering a refusal.idinteger

titlestring

assignablebooleanFalse for a group this operator may not grant.

createdintegerUnix timestamp of the first time the shop saw them.

addressesobject\[\]Their addresses, defaults first.idinteger

typesstring\[\]Which of `billing` and `shipping` it is used for.

namestring

companystring

streetstring

citystring

post\_codestring

telephonestring

defaultbooleanWhether it is the default for one of its types.

formattedobjectThe address laid out the way this shop lays addresses out, which depends on its address format setting.textstringSeveral lines, for an invoice or a label.

one\_linestringOne line, for a list.

ordersobject\[\]Their orders, newest first, enough to list them.idinteger

numberstringThe number the customer sees.

statusstringA namekey.

createdintegerUnix timestamp.

totalnumberTax included, in the order currency.

currency\_idintegerThat currency.

fieldsobject\[\]The definitions of your own customer fields.

custom\_fieldsobjectTheir values, keyed by namekey. The keys depend on the shop; `fields` says what they are.

custom\_field\_filesobjectFor a field holding a file, the file behind the value. Keyed the same way.

### Errors

CodeHTTPMeans

not\_found404No such customer or address, or the operator may not change them.

invalid\_fields400A field was rejected by its own rules.

invalid\_address400The address is not one the shop will accept, usually a missing required field.

```
curl -X PUT "$SHOP/hikashop-api/v1/customers/{id}/addresses" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "fields": {
        "address_title": "Mr",
        "address_firstname": "Alex",
        "address_lastname": "Marchand",
        "address_street": "12 rue des Lilas",
        "address_post_code": "44000",
        "address_city": "Nantes",
        "address_telephone": "+33 2 00 00 00 00",
        "address_country": "country_Albania_2",
        "address_state": "state_Beratit_274"
    }
}'
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"id"</span>: <span class="n">14</span>,
        <span class="k">"cms_id"</span>: <span class="n">156</span>,
        <span class="k">"name"</span>: <span class="s">"Admin"</span>,
        <span class="k">"email"</span>: <span class="s">"<joomla-hidden-mail base="" first="YnV5ZXI=" is-email="1" is-link="1" last="ZXhhbXBsZS50ZXN0" text="YnV5ZXJAZXhhbXBsZS50ZXN0">This email address is being protected from spambots. You need JavaScript enabled to view it.</joomla-hidden-mail>"</span>,
        <span class="k">"username"</span>: <span class="s">"admin"</span>,
        <span class="k">"type"</span>: <span class="s">"registered"</span>,
        <span class="k">"blocked"</span>: <span class="n">false</span>,
        <span class="k">"can_edit_account"</span>: <span class="n">false</span>,
        <span class="k">"groups_editable"</span>: <span class="n">false</span>,
        <span class="k">"groups"</span>: [
            {
                <span class="k">"id"</span>: <span class="n">8</span>,
                <span class="k">"title"</span>: <span class="s">"Mr"</span>
            }
        ],
        <span class="k">"available_groups"</span>: [
            {
                <span class="k">"id"</span>: <span class="n">1</span>,
                <span class="k">"title"</span>: <span class="s">"Mr"</span>,
                <span class="k">"assignable"</span>: <span class="n">false</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">9</span>,
                <span class="k">"title"</span>: <span class="s">"Mr"</span>,
                <span class="k">"assignable"</span>: <span class="n">false</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">6</span>,
                <span class="k">"title"</span>: <span class="s">"Mr"</span>,
                <span class="k">"assignable"</span>: <span class="n">false</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">7</span>,
                <span class="k">"title"</span>: <span class="s">"Mr"</span>,
                <span class="k">"assignable"</span>: <span class="n">false</span>
            },
            "… 5 more, trimmed for the example"
        ],
        <span class="k">"created"</span>: <span class="n">1778653121</span>,
        <span class="k">"addresses"</span>: [
            {
                <span class="k">"id"</span>: <span class="n">4372</span>,
                <span class="k">"types"</span>: [
                    "shipping"
                ],
                <span class="k">"name"</span>: <span class="s">"Test Buyer"</span>,
                <span class="k">"company"</span>: <span class="s">"Lilas SARL"</span>,
                <span class="k">"street"</span>: <span class="s">"12 rue des Lilas"</span>,
                <span class="k">"city"</span>: <span class="s">"Nantes"</span>,
                <span class="k">"post_code"</span>: <span class="s">"44000"</span>,
                <span class="k">"telephone"</span>: <span class="s">"+33 2 00 00 00 00"</span>,
                <span class="k">"default"</span>: <span class="n">true</span>,
                <span class="k">"formatted"</span>: {
                    <span class="k">"text"</span>: <span class="s">"Alex Marchand\r\n12 rue des Lilas\r\n44000 Nantes\r\nFrance"</span>,
                    <span class="k">"one_line"</span>: <span class="s">"Marchand Alex - 12 rue des Lilas, Nantes (France)"</span>
                }
            },
            {
                <span class="k">"id"</span>: <span class="n">4371</span>,
                <span class="k">"types"</span>: [
                    "billing"
                ],
                <span class="k">"name"</span>: <span class="s">"Test Buyer"</span>,
                <span class="k">"company"</span>: <span class="s">"Lilas SARL"</span>,
                <span class="k">"street"</span>: <span class="s">"12 rue des Lilas"</span>,
                <span class="k">"city"</span>: <span class="s">"Nantes"</span>,
                <span class="k">"post_code"</span>: <span class="s">"44000"</span>,
                <span class="k">"telephone"</span>: <span class="s">"+33 2 00 00 00 00"</span>,
                <span class="k">"default"</span>: <span class="n">true</span>,
                <span class="k">"formatted"</span>: {
                    <span class="k">"text"</span>: <span class="s">"Alex Marchand\r\n12 rue des Lilas\r\n44000 Nantes\r\nFrance"</span>,
                    <span class="k">"one_line"</span>: <span class="s">"Marchand Alex - 12 rue des Lilas, Nantes (France)"</span>
                }
            },
            {
                <span class="k">"id"</span>: <span class="n">4388</span>,
                <span class="k">"types"</span>: [
                    "billing"
                ],
                <span class="k">"name"</span>: <span class="s">"Test Buyer"</span>,
                <span class="k">"company"</span>: <span class="s">"Lilas SARL"</span>,
                <span class="k">"street"</span>: <span class="s">"12 rue des Lilas"</span>,
                <span class="k">"city"</span>: <span class="s">"Nantes"</span>,
                <span class="k">"post_code"</span>: <span class="s">"44000"</span>,
                <span class="k">"telephone"</span>: <span class="s">"+33 2 00 00 00 00"</span>,
                <span class="k">"default"</span>: <span class="n">false</span>,
                <span class="k">"formatted"</span>: {
                    <span class="k">"text"</span>: <span class="s">"Alex Marchand\r\n12 rue des Lilas\r\n44000 Nantes\r\nFrance"</span>,
                    <span class="k">"one_line"</span>: <span class="s">"Marchand Alex - 12 rue des Lilas, Nantes (France)"</span>
                }
            },
            {
                <span class="k">"id"</span>: <span class="n">4387</span>,
                <span class="k">"types"</span>: [
                    "billing"
                ],
                <span class="k">"name"</span>: <span class="s">"Test Buyer"</span>,
                <span class="k">"company"</span>: <span class="s">"Lilas SARL"</span>,
                <span class="k">"street"</span>: <span class="s">"12 rue des Lilas"</span>,
                <span class="k">"city"</span>: <span class="s">"Nantes"</span>,
                <span class="k">"post_code"</span>: <span class="s">"44000"</span>,
                <span class="k">"telephone"</span>: <span class="s">"+33 2 00 00 00 00"</span>,
                <span class="k">"default"</span>: <span class="n">false</span>,
                <span class="k">"formatted"</span>: {
                    <span class="k">"text"</span>: <span class="s">"Alex Marchand\r\n12 rue des Lilas\r\n44000 Nantes\r\nFrance"</span>,
                    <span class="k">"one_line"</span>: <span class="s">"Marchand Alex - 12 rue des Lilas, Nantes (France)"</span>
                }
            },
            "… 6 more, trimmed for the example"
        ],
        <span class="k">"orders"</span>: [
            {
                <span class="k">"id"</span>: <span class="n">2</span>,
                <span class="k">"number"</span>: <span class="s">"TEST-VOTE-1"</span>,
                <span class="k">"status"</span>: <span class="s">"confirmed"</span>,
                <span class="k">"created"</span>: <span class="n">1786877040</span>,
                <span class="k">"total"</span>: <span class="n">100</span>,
                <span class="k">"currency_id"</span>: <span class="n">1</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">18</span>,
                <span class="k">"number"</span>: <span class="s">"U18"</span>,
                <span class="k">"status"</span>: <span class="s">"confirmed"</span>,
                <span class="k">"created"</span>: <span class="n">1786358640</span>,
                <span class="k">"total"</span>: <span class="n">14.99</span>,
                <span class="k">"currency_id"</span>: <span class="n">1</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">20</span>,
                <span class="k">"number"</span>: <span class="s">"X20"</span>,
                <span class="k">"status"</span>: <span class="s">"confirmed"</span>,
                <span class="k">"created"</span>: <span class="n">1785840240</span>,
                <span class="k">"total"</span>: <span class="n">14.99</span>,
                <span class="k">"currency_id"</span>: <span class="n">1</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">16</span>,
                <span class="k">"number"</span>: <span class="s">"S16"</span>,
                <span class="k">"status"</span>: <span class="s">"created"</span>,
                <span class="k">"created"</span>: <span class="n">1783345950</span>,
                <span class="k">"total"</span>: <span class="n">14.99</span>,
                <span class="k">"currency_id"</span>: <span class="n">1</span>
            },
            "… 96 more, trimmed for the example"
        ],
        <span class="k">"fields"</span>: [],
        <span class="k">"custom_fields"</span>: [],
        <span class="k">"custom_field_files"</span>: []
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## Save an address

POST /customers/**{customerId}**/addresses/**{addressId}** write since 6.6.0

Writes an address of a customer. Without an address id it creates one; with one it saves that one.

`types` says what the address is for, billing or shipping or both, and `default` makes it the default for those. An address is validated by the shop's own field rules, so a missing required field is refused rather than half-saved.

### Path

ParameterTypeDescription

customerIdrequiredintegerThe customer.

addressIdrequiredintegerThe address.

### Body

FieldTypeDescription

fieldsrequiredobjectKeyed by address field namekey, the same keys the form returned in `values`.

typesstring\[\]Which of `billing` and `shipping` this address is for. Defaults to both.

defaultbooleanMake it the default for its types.

### Response expand all

FieldTypeDescription

idintegerThe HikaShop customer id, which is what every customer route takes.

cms\_idintegerThe Joomla or WordPress user id, `0` for a guest with no account.

namestring

emailstring

usernamestringThe login, empty for a guest.

typestring`registered` or `guest`.

blockedbooleanWhether the CMS account is disabled.

can\_edit\_accountbooleanWhether this operator may change the login and password of this particular account. False for an account above their own level, which is how a super user is protected from staff.

groups\_editablebooleanWhether this operator may change which groups the customer is in.

groupsobject\[\]The groups they are in.idinteger

titlestring

available\_groupsobject\[\]Every group, with whether this operator may put the customer into it, so a picker can grey out the rest rather than offering a refusal.idinteger

titlestring

assignablebooleanFalse for a group this operator may not grant.

createdintegerUnix timestamp of the first time the shop saw them.

addressesobject\[\]Their addresses, defaults first.idinteger

typesstring\[\]Which of `billing` and `shipping` it is used for.

namestring

companystring

streetstring

citystring

post\_codestring

telephonestring

defaultbooleanWhether it is the default for one of its types.

formattedobjectThe address laid out the way this shop lays addresses out, which depends on its address format setting.textstringSeveral lines, for an invoice or a label.

one\_linestringOne line, for a list.

ordersobject\[\]Their orders, newest first, enough to list them.idinteger

numberstringThe number the customer sees.

statusstringA namekey.

createdintegerUnix timestamp.

totalnumberTax included, in the order currency.

currency\_idintegerThat currency.

fieldsobject\[\]The definitions of your own customer fields.

custom\_fieldsobjectTheir values, keyed by namekey. The keys depend on the shop; `fields` says what they are.

custom\_field\_filesobjectFor a field holding a file, the file behind the value. Keyed the same way.

### Errors

CodeHTTPMeans

not\_found404No such customer or address, or the operator may not change them.

invalid\_fields400A field was rejected by its own rules.

invalid\_address400The address is not one the shop will accept, usually a missing required field.

```
curl -X POST "$SHOP/hikashop-api/v1/customers/{id}/addresses/{id}" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "fields": {
        "address_title": "Mr",
        "address_firstname": "Alex",
        "address_lastname": "Marchand",
        "address_street": "12 rue des Lilas",
        "address_post_code": "44000",
        "address_city": "Nantes",
        "address_telephone": "+33 2 00 00 00 00",
        "address_country": "country_Albania_2",
        "address_state": "state_Beratit_274"
    }
}'
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"id"</span>: <span class="n">14</span>,
        <span class="k">"cms_id"</span>: <span class="n">156</span>,
        <span class="k">"name"</span>: <span class="s">"Admin"</span>,
        <span class="k">"email"</span>: <span class="s">"<joomla-hidden-mail base="" first="YnV5ZXI=" is-email="1" is-link="1" last="ZXhhbXBsZS50ZXN0" text="YnV5ZXJAZXhhbXBsZS50ZXN0">This email address is being protected from spambots. You need JavaScript enabled to view it.</joomla-hidden-mail>"</span>,
        <span class="k">"username"</span>: <span class="s">"admin"</span>,
        <span class="k">"type"</span>: <span class="s">"registered"</span>,
        <span class="k">"blocked"</span>: <span class="n">false</span>,
        <span class="k">"can_edit_account"</span>: <span class="n">false</span>,
        <span class="k">"groups_editable"</span>: <span class="n">false</span>,
        <span class="k">"groups"</span>: [
            {
                <span class="k">"id"</span>: <span class="n">8</span>,
                <span class="k">"title"</span>: <span class="s">"Mr"</span>
            }
        ],
        <span class="k">"available_groups"</span>: [
            {
                <span class="k">"id"</span>: <span class="n">1</span>,
                <span class="k">"title"</span>: <span class="s">"Mr"</span>,
                <span class="k">"assignable"</span>: <span class="n">false</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">9</span>,
                <span class="k">"title"</span>: <span class="s">"Mr"</span>,
                <span class="k">"assignable"</span>: <span class="n">false</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">6</span>,
                <span class="k">"title"</span>: <span class="s">"Mr"</span>,
                <span class="k">"assignable"</span>: <span class="n">false</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">7</span>,
                <span class="k">"title"</span>: <span class="s">"Mr"</span>,
                <span class="k">"assignable"</span>: <span class="n">false</span>
            },
            "… 5 more, trimmed for the example"
        ],
        <span class="k">"created"</span>: <span class="n">1778653121</span>,
        <span class="k">"addresses"</span>: [
            {
                <span class="k">"id"</span>: <span class="n">4372</span>,
                <span class="k">"types"</span>: [
                    "shipping"
                ],
                <span class="k">"name"</span>: <span class="s">"Test Buyer"</span>,
                <span class="k">"company"</span>: <span class="s">"Lilas SARL"</span>,
                <span class="k">"street"</span>: <span class="s">"12 rue des Lilas"</span>,
                <span class="k">"city"</span>: <span class="s">"Nantes"</span>,
                <span class="k">"post_code"</span>: <span class="s">"44000"</span>,
                <span class="k">"telephone"</span>: <span class="s">"+33 2 00 00 00 00"</span>,
                <span class="k">"default"</span>: <span class="n">true</span>,
                <span class="k">"formatted"</span>: {
                    <span class="k">"text"</span>: <span class="s">"Alex Marchand\r\n12 rue des Lilas\r\n44000 Nantes\r\nFrance"</span>,
                    <span class="k">"one_line"</span>: <span class="s">"Marchand Alex - 12 rue des Lilas, Nantes (France)"</span>
                }
            },
            {
                <span class="k">"id"</span>: <span class="n">4371</span>,
                <span class="k">"types"</span>: [
                    "billing"
                ],
                <span class="k">"name"</span>: <span class="s">"Test Buyer"</span>,
                <span class="k">"company"</span>: <span class="s">"Lilas SARL"</span>,
                <span class="k">"street"</span>: <span class="s">"12 rue des Lilas"</span>,
                <span class="k">"city"</span>: <span class="s">"Nantes"</span>,
                <span class="k">"post_code"</span>: <span class="s">"44000"</span>,
                <span class="k">"telephone"</span>: <span class="s">"+33 2 00 00 00 00"</span>,
                <span class="k">"default"</span>: <span class="n">true</span>,
                <span class="k">"formatted"</span>: {
                    <span class="k">"text"</span>: <span class="s">"Alex Marchand\r\n12 rue des Lilas\r\n44000 Nantes\r\nFrance"</span>,
                    <span class="k">"one_line"</span>: <span class="s">"Marchand Alex - 12 rue des Lilas, Nantes (France)"</span>
                }
            },
            {
                <span class="k">"id"</span>: <span class="n">4388</span>,
                <span class="k">"types"</span>: [
                    "billing"
                ],
                <span class="k">"name"</span>: <span class="s">"Test Buyer"</span>,
                <span class="k">"company"</span>: <span class="s">"Lilas SARL"</span>,
                <span class="k">"street"</span>: <span class="s">"12 rue des Lilas"</span>,
                <span class="k">"city"</span>: <span class="s">"Nantes"</span>,
                <span class="k">"post_code"</span>: <span class="s">"44000"</span>,
                <span class="k">"telephone"</span>: <span class="s">"+33 2 00 00 00 00"</span>,
                <span class="k">"default"</span>: <span class="n">false</span>,
                <span class="k">"formatted"</span>: {
                    <span class="k">"text"</span>: <span class="s">"Alex Marchand\r\n12 rue des Lilas\r\n44000 Nantes\r\nFrance"</span>,
                    <span class="k">"one_line"</span>: <span class="s">"Marchand Alex - 12 rue des Lilas, Nantes (France)"</span>
                }
            },
            {
                <span class="k">"id"</span>: <span class="n">4387</span>,
                <span class="k">"types"</span>: [
                    "billing"
                ],
                <span class="k">"name"</span>: <span class="s">"Test Buyer"</span>,
                <span class="k">"company"</span>: <span class="s">"Lilas SARL"</span>,
                <span class="k">"street"</span>: <span class="s">"12 rue des Lilas"</span>,
                <span class="k">"city"</span>: <span class="s">"Nantes"</span>,
                <span class="k">"post_code"</span>: <span class="s">"44000"</span>,
                <span class="k">"telephone"</span>: <span class="s">"+33 2 00 00 00 00"</span>,
                <span class="k">"default"</span>: <span class="n">false</span>,
                <span class="k">"formatted"</span>: {
                    <span class="k">"text"</span>: <span class="s">"Alex Marchand\r\n12 rue des Lilas\r\n44000 Nantes\r\nFrance"</span>,
                    <span class="k">"one_line"</span>: <span class="s">"Marchand Alex - 12 rue des Lilas, Nantes (France)"</span>
                }
            },
            "… 6 more, trimmed for the example"
        ],
        <span class="k">"orders"</span>: [
            {
                <span class="k">"id"</span>: <span class="n">2</span>,
                <span class="k">"number"</span>: <span class="s">"TEST-VOTE-1"</span>,
                <span class="k">"status"</span>: <span class="s">"confirmed"</span>,
                <span class="k">"created"</span>: <span class="n">1786877040</span>,
                <span class="k">"total"</span>: <span class="n">100</span>,
                <span class="k">"currency_id"</span>: <span class="n">1</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">18</span>,
                <span class="k">"number"</span>: <span class="s">"U18"</span>,
                <span class="k">"status"</span>: <span class="s">"confirmed"</span>,
                <span class="k">"created"</span>: <span class="n">1786358640</span>,
                <span class="k">"total"</span>: <span class="n">14.99</span>,
                <span class="k">"currency_id"</span>: <span class="n">1</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">20</span>,
                <span class="k">"number"</span>: <span class="s">"X20"</span>,
                <span class="k">"status"</span>: <span class="s">"confirmed"</span>,
                <span class="k">"created"</span>: <span class="n">1785840240</span>,
                <span class="k">"total"</span>: <span class="n">14.99</span>,
                <span class="k">"currency_id"</span>: <span class="n">1</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">16</span>,
                <span class="k">"number"</span>: <span class="s">"S16"</span>,
                <span class="k">"status"</span>: <span class="s">"created"</span>,
                <span class="k">"created"</span>: <span class="n">1783345950</span>,
                <span class="k">"total"</span>: <span class="n">14.99</span>,
                <span class="k">"currency_id"</span>: <span class="n">1</span>
            },
            "… 96 more, trimmed for the example"
        ],
        <span class="k">"fields"</span>: [],
        <span class="k">"custom_fields"</span>: [],
        <span class="k">"custom_field_files"</span>: []
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## Save an address

PUT /customers/**{customerId}**/addresses/**{addressId}** write since 6.6.0

Writes an address of a customer. Without an address id it creates one; with one it saves that one.

`types` says what the address is for, billing or shipping or both, and `default` makes it the default for those. An address is validated by the shop's own field rules, so a missing required field is refused rather than half-saved.

### Path

ParameterTypeDescription

customerIdrequiredintegerThe customer.

addressIdrequiredintegerThe address.

### Body

FieldTypeDescription

fieldsrequiredobjectKeyed by address field namekey, the same keys the form returned in `values`.

typesstring\[\]Which of `billing` and `shipping` this address is for. Defaults to both.

defaultbooleanMake it the default for its types.

### Response expand all

FieldTypeDescription

idintegerThe HikaShop customer id, which is what every customer route takes.

cms\_idintegerThe Joomla or WordPress user id, `0` for a guest with no account.

namestring

emailstring

usernamestringThe login, empty for a guest.

typestring`registered` or `guest`.

blockedbooleanWhether the CMS account is disabled.

can\_edit\_accountbooleanWhether this operator may change the login and password of this particular account. False for an account above their own level, which is how a super user is protected from staff.

groups\_editablebooleanWhether this operator may change which groups the customer is in.

groupsobject\[\]The groups they are in.idinteger

titlestring

available\_groupsobject\[\]Every group, with whether this operator may put the customer into it, so a picker can grey out the rest rather than offering a refusal.idinteger

titlestring

assignablebooleanFalse for a group this operator may not grant.

createdintegerUnix timestamp of the first time the shop saw them.

addressesobject\[\]Their addresses, defaults first.idinteger

typesstring\[\]Which of `billing` and `shipping` it is used for.

namestring

companystring

streetstring

citystring

post\_codestring

telephonestring

defaultbooleanWhether it is the default for one of its types.

formattedobjectThe address laid out the way this shop lays addresses out, which depends on its address format setting.textstringSeveral lines, for an invoice or a label.

one\_linestringOne line, for a list.

ordersobject\[\]Their orders, newest first, enough to list them.idinteger

numberstringThe number the customer sees.

statusstringA namekey.

createdintegerUnix timestamp.

totalnumberTax included, in the order currency.

currency\_idintegerThat currency.

fieldsobject\[\]The definitions of your own customer fields.

custom\_fieldsobjectTheir values, keyed by namekey. The keys depend on the shop; `fields` says what they are.

custom\_field\_filesobjectFor a field holding a file, the file behind the value. Keyed the same way.

### Errors

CodeHTTPMeans

not\_found404No such customer or address, or the operator may not change them.

invalid\_fields400A field was rejected by its own rules.

invalid\_address400The address is not one the shop will accept, usually a missing required field.

```
curl -X PUT "$SHOP/hikashop-api/v1/customers/{id}/addresses/{id}" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "fields": {
        "address_title": "Mr",
        "address_firstname": "Alex",
        "address_lastname": "Marchand",
        "address_street": "12 rue des Lilas",
        "address_post_code": "44000",
        "address_city": "Nantes",
        "address_telephone": "+33 2 00 00 00 00",
        "address_country": "country_Albania_2",
        "address_state": "state_Beratit_274"
    }
}'
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"id"</span>: <span class="n">14</span>,
        <span class="k">"cms_id"</span>: <span class="n">156</span>,
        <span class="k">"name"</span>: <span class="s">"Admin"</span>,
        <span class="k">"email"</span>: <span class="s">"<joomla-hidden-mail base="" first="YnV5ZXI=" is-email="1" is-link="1" last="ZXhhbXBsZS50ZXN0" text="YnV5ZXJAZXhhbXBsZS50ZXN0">This email address is being protected from spambots. You need JavaScript enabled to view it.</joomla-hidden-mail>"</span>,
        <span class="k">"username"</span>: <span class="s">"admin"</span>,
        <span class="k">"type"</span>: <span class="s">"registered"</span>,
        <span class="k">"blocked"</span>: <span class="n">false</span>,
        <span class="k">"can_edit_account"</span>: <span class="n">false</span>,
        <span class="k">"groups_editable"</span>: <span class="n">false</span>,
        <span class="k">"groups"</span>: [
            {
                <span class="k">"id"</span>: <span class="n">8</span>,
                <span class="k">"title"</span>: <span class="s">"Mr"</span>
            }
        ],
        <span class="k">"available_groups"</span>: [
            {
                <span class="k">"id"</span>: <span class="n">1</span>,
                <span class="k">"title"</span>: <span class="s">"Mr"</span>,
                <span class="k">"assignable"</span>: <span class="n">false</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">9</span>,
                <span class="k">"title"</span>: <span class="s">"Mr"</span>,
                <span class="k">"assignable"</span>: <span class="n">false</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">6</span>,
                <span class="k">"title"</span>: <span class="s">"Mr"</span>,
                <span class="k">"assignable"</span>: <span class="n">false</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">7</span>,
                <span class="k">"title"</span>: <span class="s">"Mr"</span>,
                <span class="k">"assignable"</span>: <span class="n">false</span>
            },
            "… 5 more, trimmed for the example"
        ],
        <span class="k">"created"</span>: <span class="n">1778653121</span>,
        <span class="k">"addresses"</span>: [
            {
                <span class="k">"id"</span>: <span class="n">4372</span>,
                <span class="k">"types"</span>: [
                    "shipping"
                ],
                <span class="k">"name"</span>: <span class="s">"Test Buyer"</span>,
                <span class="k">"company"</span>: <span class="s">"Lilas SARL"</span>,
                <span class="k">"street"</span>: <span class="s">"12 rue des Lilas"</span>,
                <span class="k">"city"</span>: <span class="s">"Nantes"</span>,
                <span class="k">"post_code"</span>: <span class="s">"44000"</span>,
                <span class="k">"telephone"</span>: <span class="s">"+33 2 00 00 00 00"</span>,
                <span class="k">"default"</span>: <span class="n">true</span>,
                <span class="k">"formatted"</span>: {
                    <span class="k">"text"</span>: <span class="s">"Alex Marchand\r\n12 rue des Lilas\r\n44000 Nantes\r\nFrance"</span>,
                    <span class="k">"one_line"</span>: <span class="s">"Marchand Alex - 12 rue des Lilas, Nantes (France)"</span>
                }
            },
            {
                <span class="k">"id"</span>: <span class="n">4371</span>,
                <span class="k">"types"</span>: [
                    "billing"
                ],
                <span class="k">"name"</span>: <span class="s">"Test Buyer"</span>,
                <span class="k">"company"</span>: <span class="s">"Lilas SARL"</span>,
                <span class="k">"street"</span>: <span class="s">"12 rue des Lilas"</span>,
                <span class="k">"city"</span>: <span class="s">"Nantes"</span>,
                <span class="k">"post_code"</span>: <span class="s">"44000"</span>,
                <span class="k">"telephone"</span>: <span class="s">"+33 2 00 00 00 00"</span>,
                <span class="k">"default"</span>: <span class="n">true</span>,
                <span class="k">"formatted"</span>: {
                    <span class="k">"text"</span>: <span class="s">"Alex Marchand\r\n12 rue des Lilas\r\n44000 Nantes\r\nFrance"</span>,
                    <span class="k">"one_line"</span>: <span class="s">"Marchand Alex - 12 rue des Lilas, Nantes (France)"</span>
                }
            },
            {
                <span class="k">"id"</span>: <span class="n">4388</span>,
                <span class="k">"types"</span>: [
                    "billing"
                ],
                <span class="k">"name"</span>: <span class="s">"Test Buyer"</span>,
                <span class="k">"company"</span>: <span class="s">"Lilas SARL"</span>,
                <span class="k">"street"</span>: <span class="s">"12 rue des Lilas"</span>,
                <span class="k">"city"</span>: <span class="s">"Nantes"</span>,
                <span class="k">"post_code"</span>: <span class="s">"44000"</span>,
                <span class="k">"telephone"</span>: <span class="s">"+33 2 00 00 00 00"</span>,
                <span class="k">"default"</span>: <span class="n">false</span>,
                <span class="k">"formatted"</span>: {
                    <span class="k">"text"</span>: <span class="s">"Alex Marchand\r\n12 rue des Lilas\r\n44000 Nantes\r\nFrance"</span>,
                    <span class="k">"one_line"</span>: <span class="s">"Marchand Alex - 12 rue des Lilas, Nantes (France)"</span>
                }
            },
            {
                <span class="k">"id"</span>: <span class="n">4387</span>,
                <span class="k">"types"</span>: [
                    "billing"
                ],
                <span class="k">"name"</span>: <span class="s">"Test Buyer"</span>,
                <span class="k">"company"</span>: <span class="s">"Lilas SARL"</span>,
                <span class="k">"street"</span>: <span class="s">"12 rue des Lilas"</span>,
                <span class="k">"city"</span>: <span class="s">"Nantes"</span>,
                <span class="k">"post_code"</span>: <span class="s">"44000"</span>,
                <span class="k">"telephone"</span>: <span class="s">"+33 2 00 00 00 00"</span>,
                <span class="k">"default"</span>: <span class="n">false</span>,
                <span class="k">"formatted"</span>: {
                    <span class="k">"text"</span>: <span class="s">"Alex Marchand\r\n12 rue des Lilas\r\n44000 Nantes\r\nFrance"</span>,
                    <span class="k">"one_line"</span>: <span class="s">"Marchand Alex - 12 rue des Lilas, Nantes (France)"</span>
                }
            },
            "… 6 more, trimmed for the example"
        ],
        <span class="k">"orders"</span>: [
            {
                <span class="k">"id"</span>: <span class="n">2</span>,
                <span class="k">"number"</span>: <span class="s">"TEST-VOTE-1"</span>,
                <span class="k">"status"</span>: <span class="s">"confirmed"</span>,
                <span class="k">"created"</span>: <span class="n">1786877040</span>,
                <span class="k">"total"</span>: <span class="n">100</span>,
                <span class="k">"currency_id"</span>: <span class="n">1</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">18</span>,
                <span class="k">"number"</span>: <span class="s">"U18"</span>,
                <span class="k">"status"</span>: <span class="s">"confirmed"</span>,
                <span class="k">"created"</span>: <span class="n">1786358640</span>,
                <span class="k">"total"</span>: <span class="n">14.99</span>,
                <span class="k">"currency_id"</span>: <span class="n">1</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">20</span>,
                <span class="k">"number"</span>: <span class="s">"X20"</span>,
                <span class="k">"status"</span>: <span class="s">"confirmed"</span>,
                <span class="k">"created"</span>: <span class="n">1785840240</span>,
                <span class="k">"total"</span>: <span class="n">14.99</span>,
                <span class="k">"currency_id"</span>: <span class="n">1</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">16</span>,
                <span class="k">"number"</span>: <span class="s">"S16"</span>,
                <span class="k">"status"</span>: <span class="s">"created"</span>,
                <span class="k">"created"</span>: <span class="n">1783345950</span>,
                <span class="k">"total"</span>: <span class="n">14.99</span>,
                <span class="k">"currency_id"</span>: <span class="n">1</span>
            },
            "… 96 more, trimmed for the example"
        ],
        <span class="k">"fields"</span>: [],
        <span class="k">"custom_fields"</span>: [],
        <span class="k">"custom_field_files"</span>: []
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## Delete an address

DELETE /customers/**{id}**/addresses write since 6.6.0

Removes an address from a customer. Orders that used it keep their own copy of it.

### Path

ParameterTypeDescription

idrequiredintegerThe customer.

### Response expand all

FieldTypeDescription

idintegerThe HikaShop customer id, which is what every customer route takes.

cms\_idintegerThe Joomla or WordPress user id, `0` for a guest with no account.

namestring

emailstring

usernamestringThe login, empty for a guest.

typestring`registered` or `guest`.

blockedbooleanWhether the CMS account is disabled.

can\_edit\_accountbooleanWhether this operator may change the login and password of this particular account. False for an account above their own level, which is how a super user is protected from staff.

groups\_editablebooleanWhether this operator may change which groups the customer is in.

groupsobject\[\]The groups they are in.idinteger

titlestring

available\_groupsobject\[\]Every group, with whether this operator may put the customer into it, so a picker can grey out the rest rather than offering a refusal.idinteger

titlestring

assignablebooleanFalse for a group this operator may not grant.

createdintegerUnix timestamp of the first time the shop saw them.

addressesobject\[\]Their addresses, defaults first.idinteger

typesstring\[\]Which of `billing` and `shipping` it is used for.

namestring

companystring

streetstring

citystring

post\_codestring

telephonestring

defaultbooleanWhether it is the default for one of its types.

formattedobjectThe address laid out the way this shop lays addresses out, which depends on its address format setting.textstringSeveral lines, for an invoice or a label.

one\_linestringOne line, for a list.

ordersobject\[\]Their orders, newest first, enough to list them.idinteger

numberstringThe number the customer sees.

statusstringA namekey.

createdintegerUnix timestamp.

totalnumberTax included, in the order currency.

currency\_idintegerThat currency.

fieldsobject\[\]The definitions of your own customer fields.

custom\_fieldsobjectTheir values, keyed by namekey. The keys depend on the shop; `fields` says what they are.

custom\_field\_filesobjectFor a field holding a file, the file behind the value. Keyed the same way.

### Errors

CodeHTTPMeans

not\_found404No such customer or address, or the operator may not change them.

```
curl -X DELETE "$SHOP/hikashop-api/v1/customers/{id}/addresses/{id}" \
  -H "Authorization: Bearer $TOKEN"
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"id"</span>: <span class="n">14</span>,
        <span class="k">"cms_id"</span>: <span class="n">156</span>,
        <span class="k">"name"</span>: <span class="s">"Admin"</span>,
        <span class="k">"email"</span>: <span class="s">"<joomla-hidden-mail base="" first="YnV5ZXI=" is-email="1" is-link="1" last="ZXhhbXBsZS50ZXN0" text="YnV5ZXJAZXhhbXBsZS50ZXN0">This email address is being protected from spambots. You need JavaScript enabled to view it.</joomla-hidden-mail>"</span>,
        <span class="k">"username"</span>: <span class="s">"admin"</span>,
        <span class="k">"type"</span>: <span class="s">"registered"</span>,
        <span class="k">"blocked"</span>: <span class="n">false</span>,
        <span class="k">"can_edit_account"</span>: <span class="n">false</span>,
        <span class="k">"groups_editable"</span>: <span class="n">false</span>,
        <span class="k">"groups"</span>: [
            {
                <span class="k">"id"</span>: <span class="n">8</span>,
                <span class="k">"title"</span>: <span class="s">"Mr"</span>
            }
        ],
        <span class="k">"available_groups"</span>: [
            {
                <span class="k">"id"</span>: <span class="n">1</span>,
                <span class="k">"title"</span>: <span class="s">"Mr"</span>,
                <span class="k">"assignable"</span>: <span class="n">false</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">9</span>,
                <span class="k">"title"</span>: <span class="s">"Mr"</span>,
                <span class="k">"assignable"</span>: <span class="n">false</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">6</span>,
                <span class="k">"title"</span>: <span class="s">"Mr"</span>,
                <span class="k">"assignable"</span>: <span class="n">false</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">7</span>,
                <span class="k">"title"</span>: <span class="s">"Mr"</span>,
                <span class="k">"assignable"</span>: <span class="n">false</span>
            },
            "… 5 more, trimmed for the example"
        ],
        <span class="k">"created"</span>: <span class="n">1778653121</span>,
        <span class="k">"addresses"</span>: [
            {
                <span class="k">"id"</span>: <span class="n">4372</span>,
                <span class="k">"types"</span>: [
                    "shipping"
                ],
                <span class="k">"name"</span>: <span class="s">"Test Buyer"</span>,
                <span class="k">"company"</span>: <span class="s">"Lilas SARL"</span>,
                <span class="k">"street"</span>: <span class="s">"12 rue des Lilas"</span>,
                <span class="k">"city"</span>: <span class="s">"Nantes"</span>,
                <span class="k">"post_code"</span>: <span class="s">"44000"</span>,
                <span class="k">"telephone"</span>: <span class="s">"+33 2 00 00 00 00"</span>,
                <span class="k">"default"</span>: <span class="n">true</span>,
                <span class="k">"formatted"</span>: {
                    <span class="k">"text"</span>: <span class="s">"Alex Marchand\r\n12 rue des Lilas\r\n44000 Nantes\r\nFrance"</span>,
                    <span class="k">"one_line"</span>: <span class="s">"Marchand Alex - 12 rue des Lilas, Nantes (France)"</span>
                }
            },
            {
                <span class="k">"id"</span>: <span class="n">4371</span>,
                <span class="k">"types"</span>: [
                    "billing"
                ],
                <span class="k">"name"</span>: <span class="s">"Test Buyer"</span>,
                <span class="k">"company"</span>: <span class="s">"Lilas SARL"</span>,
                <span class="k">"street"</span>: <span class="s">"12 rue des Lilas"</span>,
                <span class="k">"city"</span>: <span class="s">"Nantes"</span>,
                <span class="k">"post_code"</span>: <span class="s">"44000"</span>,
                <span class="k">"telephone"</span>: <span class="s">"+33 2 00 00 00 00"</span>,
                <span class="k">"default"</span>: <span class="n">true</span>,
                <span class="k">"formatted"</span>: {
                    <span class="k">"text"</span>: <span class="s">"Alex Marchand\r\n12 rue des Lilas\r\n44000 Nantes\r\nFrance"</span>,
                    <span class="k">"one_line"</span>: <span class="s">"Marchand Alex - 12 rue des Lilas, Nantes (France)"</span>
                }
            },
            {
                <span class="k">"id"</span>: <span class="n">4388</span>,
                <span class="k">"types"</span>: [
                    "billing"
                ],
                <span class="k">"name"</span>: <span class="s">"Test Buyer"</span>,
                <span class="k">"company"</span>: <span class="s">"Lilas SARL"</span>,
                <span class="k">"street"</span>: <span class="s">"12 rue des Lilas"</span>,
                <span class="k">"city"</span>: <span class="s">"Nantes"</span>,
                <span class="k">"post_code"</span>: <span class="s">"44000"</span>,
                <span class="k">"telephone"</span>: <span class="s">"+33 2 00 00 00 00"</span>,
                <span class="k">"default"</span>: <span class="n">false</span>,
                <span class="k">"formatted"</span>: {
                    <span class="k">"text"</span>: <span class="s">"Alex Marchand\r\n12 rue des Lilas\r\n44000 Nantes\r\nFrance"</span>,
                    <span class="k">"one_line"</span>: <span class="s">"Marchand Alex - 12 rue des Lilas, Nantes (France)"</span>
                }
            },
            {
                <span class="k">"id"</span>: <span class="n">4387</span>,
                <span class="k">"types"</span>: [
                    "billing"
                ],
                <span class="k">"name"</span>: <span class="s">"Test Buyer"</span>,
                <span class="k">"company"</span>: <span class="s">"Lilas SARL"</span>,
                <span class="k">"street"</span>: <span class="s">"12 rue des Lilas"</span>,
                <span class="k">"city"</span>: <span class="s">"Nantes"</span>,
                <span class="k">"post_code"</span>: <span class="s">"44000"</span>,
                <span class="k">"telephone"</span>: <span class="s">"+33 2 00 00 00 00"</span>,
                <span class="k">"default"</span>: <span class="n">false</span>,
                <span class="k">"formatted"</span>: {
                    <span class="k">"text"</span>: <span class="s">"Alex Marchand\r\n12 rue des Lilas\r\n44000 Nantes\r\nFrance"</span>,
                    <span class="k">"one_line"</span>: <span class="s">"Marchand Alex - 12 rue des Lilas, Nantes (France)"</span>
                }
            },
            "… 6 more, trimmed for the example"
        ],
        <span class="k">"orders"</span>: [
            {
                <span class="k">"id"</span>: <span class="n">2</span>,
                <span class="k">"number"</span>: <span class="s">"TEST-VOTE-1"</span>,
                <span class="k">"status"</span>: <span class="s">"confirmed"</span>,
                <span class="k">"created"</span>: <span class="n">1786877040</span>,
                <span class="k">"total"</span>: <span class="n">100</span>,
                <span class="k">"currency_id"</span>: <span class="n">1</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">18</span>,
                <span class="k">"number"</span>: <span class="s">"U18"</span>,
                <span class="k">"status"</span>: <span class="s">"confirmed"</span>,
                <span class="k">"created"</span>: <span class="n">1786358640</span>,
                <span class="k">"total"</span>: <span class="n">14.99</span>,
                <span class="k">"currency_id"</span>: <span class="n">1</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">20</span>,
                <span class="k">"number"</span>: <span class="s">"X20"</span>,
                <span class="k">"status"</span>: <span class="s">"confirmed"</span>,
                <span class="k">"created"</span>: <span class="n">1785840240</span>,
                <span class="k">"total"</span>: <span class="n">14.99</span>,
                <span class="k">"currency_id"</span>: <span class="n">1</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">16</span>,
                <span class="k">"number"</span>: <span class="s">"S16"</span>,
                <span class="k">"status"</span>: <span class="s">"created"</span>,
                <span class="k">"created"</span>: <span class="n">1783345950</span>,
                <span class="k">"total"</span>: <span class="n">14.99</span>,
                <span class="k">"currency_id"</span>: <span class="n">1</span>
            },
            "… 96 more, trimmed for the example"
        ],
        <span class="k">"fields"</span>: [],
        <span class="k">"custom_fields"</span>: [],
        <span class="k">"custom_field_files"</span>: []
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## Delete an address

DELETE /customers/**{customerId}**/addresses/**{addressId}** write since 6.6.0

Removes an address from a customer. Orders that used it keep their own copy of it.

### Path

ParameterTypeDescription

customerIdrequiredintegerThe customer.

addressIdrequiredintegerThe address.

### Response expand all

FieldTypeDescription

idintegerThe HikaShop customer id, which is what every customer route takes.

cms\_idintegerThe Joomla or WordPress user id, `0` for a guest with no account.

namestring

emailstring

usernamestringThe login, empty for a guest.

typestring`registered` or `guest`.

blockedbooleanWhether the CMS account is disabled.

can\_edit\_accountbooleanWhether this operator may change the login and password of this particular account. False for an account above their own level, which is how a super user is protected from staff.

groups\_editablebooleanWhether this operator may change which groups the customer is in.

groupsobject\[\]The groups they are in.idinteger

titlestring

available\_groupsobject\[\]Every group, with whether this operator may put the customer into it, so a picker can grey out the rest rather than offering a refusal.idinteger

titlestring

assignablebooleanFalse for a group this operator may not grant.

createdintegerUnix timestamp of the first time the shop saw them.

addressesobject\[\]Their addresses, defaults first.idinteger

typesstring\[\]Which of `billing` and `shipping` it is used for.

namestring

companystring

streetstring

citystring

post\_codestring

telephonestring

defaultbooleanWhether it is the default for one of its types.

formattedobjectThe address laid out the way this shop lays addresses out, which depends on its address format setting.textstringSeveral lines, for an invoice or a label.

one\_linestringOne line, for a list.

ordersobject\[\]Their orders, newest first, enough to list them.idinteger

numberstringThe number the customer sees.

statusstringA namekey.

createdintegerUnix timestamp.

totalnumberTax included, in the order currency.

currency\_idintegerThat currency.

fieldsobject\[\]The definitions of your own customer fields.

custom\_fieldsobjectTheir values, keyed by namekey. The keys depend on the shop; `fields` says what they are.

custom\_field\_filesobjectFor a field holding a file, the file behind the value. Keyed the same way.

### Errors

CodeHTTPMeans

not\_found404No such customer or address, or the operator may not change them.

```
curl -X DELETE "$SHOP/hikashop-api/v1/customers/{id}/addresses/{id}" \
  -H "Authorization: Bearer $TOKEN"
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"id"</span>: <span class="n">14</span>,
        <span class="k">"cms_id"</span>: <span class="n">156</span>,
        <span class="k">"name"</span>: <span class="s">"Admin"</span>,
        <span class="k">"email"</span>: <span class="s">"<joomla-hidden-mail base="" first="YnV5ZXI=" is-email="1" is-link="1" last="ZXhhbXBsZS50ZXN0" text="YnV5ZXJAZXhhbXBsZS50ZXN0">This email address is being protected from spambots. You need JavaScript enabled to view it.</joomla-hidden-mail>"</span>,
        <span class="k">"username"</span>: <span class="s">"admin"</span>,
        <span class="k">"type"</span>: <span class="s">"registered"</span>,
        <span class="k">"blocked"</span>: <span class="n">false</span>,
        <span class="k">"can_edit_account"</span>: <span class="n">false</span>,
        <span class="k">"groups_editable"</span>: <span class="n">false</span>,
        <span class="k">"groups"</span>: [
            {
                <span class="k">"id"</span>: <span class="n">8</span>,
                <span class="k">"title"</span>: <span class="s">"Mr"</span>
            }
        ],
        <span class="k">"available_groups"</span>: [
            {
                <span class="k">"id"</span>: <span class="n">1</span>,
                <span class="k">"title"</span>: <span class="s">"Mr"</span>,
                <span class="k">"assignable"</span>: <span class="n">false</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">9</span>,
                <span class="k">"title"</span>: <span class="s">"Mr"</span>,
                <span class="k">"assignable"</span>: <span class="n">false</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">6</span>,
                <span class="k">"title"</span>: <span class="s">"Mr"</span>,
                <span class="k">"assignable"</span>: <span class="n">false</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">7</span>,
                <span class="k">"title"</span>: <span class="s">"Mr"</span>,
                <span class="k">"assignable"</span>: <span class="n">false</span>
            },
            "… 5 more, trimmed for the example"
        ],
        <span class="k">"created"</span>: <span class="n">1778653121</span>,
        <span class="k">"addresses"</span>: [
            {
                <span class="k">"id"</span>: <span class="n">4372</span>,
                <span class="k">"types"</span>: [
                    "shipping"
                ],
                <span class="k">"name"</span>: <span class="s">"Test Buyer"</span>,
                <span class="k">"company"</span>: <span class="s">"Lilas SARL"</span>,
                <span class="k">"street"</span>: <span class="s">"12 rue des Lilas"</span>,
                <span class="k">"city"</span>: <span class="s">"Nantes"</span>,
                <span class="k">"post_code"</span>: <span class="s">"44000"</span>,
                <span class="k">"telephone"</span>: <span class="s">"+33 2 00 00 00 00"</span>,
                <span class="k">"default"</span>: <span class="n">true</span>,
                <span class="k">"formatted"</span>: {
                    <span class="k">"text"</span>: <span class="s">"Alex Marchand\r\n12 rue des Lilas\r\n44000 Nantes\r\nFrance"</span>,
                    <span class="k">"one_line"</span>: <span class="s">"Marchand Alex - 12 rue des Lilas, Nantes (France)"</span>
                }
            },
            {
                <span class="k">"id"</span>: <span class="n">4371</span>,
                <span class="k">"types"</span>: [
                    "billing"
                ],
                <span class="k">"name"</span>: <span class="s">"Test Buyer"</span>,
                <span class="k">"company"</span>: <span class="s">"Lilas SARL"</span>,
                <span class="k">"street"</span>: <span class="s">"12 rue des Lilas"</span>,
                <span class="k">"city"</span>: <span class="s">"Nantes"</span>,
                <span class="k">"post_code"</span>: <span class="s">"44000"</span>,
                <span class="k">"telephone"</span>: <span class="s">"+33 2 00 00 00 00"</span>,
                <span class="k">"default"</span>: <span class="n">true</span>,
                <span class="k">"formatted"</span>: {
                    <span class="k">"text"</span>: <span class="s">"Alex Marchand\r\n12 rue des Lilas\r\n44000 Nantes\r\nFrance"</span>,
                    <span class="k">"one_line"</span>: <span class="s">"Marchand Alex - 12 rue des Lilas, Nantes (France)"</span>
                }
            },
            {
                <span class="k">"id"</span>: <span class="n">4388</span>,
                <span class="k">"types"</span>: [
                    "billing"
                ],
                <span class="k">"name"</span>: <span class="s">"Test Buyer"</span>,
                <span class="k">"company"</span>: <span class="s">"Lilas SARL"</span>,
                <span class="k">"street"</span>: <span class="s">"12 rue des Lilas"</span>,
                <span class="k">"city"</span>: <span class="s">"Nantes"</span>,
                <span class="k">"post_code"</span>: <span class="s">"44000"</span>,
                <span class="k">"telephone"</span>: <span class="s">"+33 2 00 00 00 00"</span>,
                <span class="k">"default"</span>: <span class="n">false</span>,
                <span class="k">"formatted"</span>: {
                    <span class="k">"text"</span>: <span class="s">"Alex Marchand\r\n12 rue des Lilas\r\n44000 Nantes\r\nFrance"</span>,
                    <span class="k">"one_line"</span>: <span class="s">"Marchand Alex - 12 rue des Lilas, Nantes (France)"</span>
                }
            },
            {
                <span class="k">"id"</span>: <span class="n">4387</span>,
                <span class="k">"types"</span>: [
                    "billing"
                ],
                <span class="k">"name"</span>: <span class="s">"Test Buyer"</span>,
                <span class="k">"company"</span>: <span class="s">"Lilas SARL"</span>,
                <span class="k">"street"</span>: <span class="s">"12 rue des Lilas"</span>,
                <span class="k">"city"</span>: <span class="s">"Nantes"</span>,
                <span class="k">"post_code"</span>: <span class="s">"44000"</span>,
                <span class="k">"telephone"</span>: <span class="s">"+33 2 00 00 00 00"</span>,
                <span class="k">"default"</span>: <span class="n">false</span>,
                <span class="k">"formatted"</span>: {
                    <span class="k">"text"</span>: <span class="s">"Alex Marchand\r\n12 rue des Lilas\r\n44000 Nantes\r\nFrance"</span>,
                    <span class="k">"one_line"</span>: <span class="s">"Marchand Alex - 12 rue des Lilas, Nantes (France)"</span>
                }
            },
            "… 6 more, trimmed for the example"
        ],
        <span class="k">"orders"</span>: [
            {
                <span class="k">"id"</span>: <span class="n">2</span>,
                <span class="k">"number"</span>: <span class="s">"TEST-VOTE-1"</span>,
                <span class="k">"status"</span>: <span class="s">"confirmed"</span>,
                <span class="k">"created"</span>: <span class="n">1786877040</span>,
                <span class="k">"total"</span>: <span class="n">100</span>,
                <span class="k">"currency_id"</span>: <span class="n">1</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">18</span>,
                <span class="k">"number"</span>: <span class="s">"U18"</span>,
                <span class="k">"status"</span>: <span class="s">"confirmed"</span>,
                <span class="k">"created"</span>: <span class="n">1786358640</span>,
                <span class="k">"total"</span>: <span class="n">14.99</span>,
                <span class="k">"currency_id"</span>: <span class="n">1</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">20</span>,
                <span class="k">"number"</span>: <span class="s">"X20"</span>,
                <span class="k">"status"</span>: <span class="s">"confirmed"</span>,
                <span class="k">"created"</span>: <span class="n">1785840240</span>,
                <span class="k">"total"</span>: <span class="n">14.99</span>,
                <span class="k">"currency_id"</span>: <span class="n">1</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">16</span>,
                <span class="k">"number"</span>: <span class="s">"S16"</span>,
                <span class="k">"status"</span>: <span class="s">"created"</span>,
                <span class="k">"created"</span>: <span class="n">1783345950</span>,
                <span class="k">"total"</span>: <span class="n">14.99</span>,
                <span class="k">"currency_id"</span>: <span class="n">1</span>
            },
            "… 96 more, trimmed for the example"
        ],
        <span class="k">"fields"</span>: [],
        <span class="k">"custom_fields"</span>: [],
        <span class="k">"custom_field_files"</span>: []
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## Redeem a pairing code

POST /pair public since 6.6.0

Exchanges a single-use code, generated in **System &gt; App Devices** of the shop's backend, for the device's own token. This is the only route that answers without one.

The token comes back **once**. Only its hash is stored, so a lost token is re-paired, never recovered. Attempts are rate limited per address.

### Body

FieldTypeDescription

coderequiredstringThe pairing code as shown in the backend. Case and spacing are normalised, so the grouping dash is optional.

device\_namestringWhat to call this device in the device list. Defaults to `Device`.

platformstringA free label kept for the listing. Anything that is not a letter, a digit, a dash or an underscore is stripped.

### Response expand all

FieldTypeDescription

tokenstringSend this as the bearer token from now on. It is not retrievable again.

scopesstring\[\]`read`, and `write` when the code granted it.

device\_idintegerThe row in the device list, which is what you revoke later.

### Errors

CodeHTTPMeans

invalid\_request400No code was sent.

invalid\_code403The code is unknown, already used, or expired.

too\_many\_requests429Too many attempts from this address.

```
curl -X POST "$SHOP/hikashop-api/v1/pair" \
  -H "Content-Type: application/json" \
  -d '{
    "device_name": "Counter tablet",
    "platform": "android",
    "code": "9CED9F"
}'
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"token"</span>: <span class="s">"hk_dev_3f9c1a……"</span>,
        <span class="k">"scopes"</span>: [
            "read",
            "write"
        ],
        <span class="k">"device_id"</span>: <span class="n">129</span>
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## List products

GET /products read since 6.6.0

The catalogue as the backend sees it, unpublished products included, which is what makes this different from the front end.

Variants are not listed on their own. A parent carries `has_variants`, and `GET /products/{id}` returns the variants themselves.

### Query

ParameterTypeDescription

startintegerOffset into the result set. Defaults to `0`.

limitintegerPage size. Defaults to `20` and is capped at `100`.

searchstringMatches the product name and the product code.

idsstringComma separated product ids, to resolve a known set in one call.

category\_idintegerRestrict to one category.

### Response a list expand all

FieldTypeDescription

idinteger

namestring

codestringThe SKU. Unique within the shop.

quantityinteger`-1` when the product does not track stock, which is not the same as `0`.

publishedboolean

has\_variantsbooleanAsk `GET /products/{id}` for the variants themselves.

imagestring\|nullAbsolute URL of the main image, or `null`.

pricenumber\|null`null` when the product has no price row at all.

currency\_idintegerA row in the shop's currency table, not an ISO code.

custom\_fieldsobjectThe listing values of this product, keyed by field namekey. The keys are whatever this shop has configured, so there is no list to give. `fields` in the envelope says what they are.

### Envelope meta

FieldTypeDescription

startintegerEchoes the offset used.

limitintegerEchoes the page size used.

totalintegerRows matching the filter, before paging. This is how you know there is another page.

fieldsobject\[\]The custom fields shown on listings, so a client can label the values it just received.

```
curl "$SHOP/hikashop-api/v1/products?limit=2" \
  -H "Authorization: Bearer $TOKEN"
```

```
{
    <span class="k">"data"</span>: [
        {
            <span class="k">"id"</span>: <span class="n">8731</span>,
            <span class="k">"name"</span>: <span class="s">"Anodised Film Camera — 35 mm"</span>,
            <span class="k">"code"</span>: <span class="s">"DEMO-0073"</span>,
            <span class="k">"quantity"</span>: <span class="n">79</span>,
            <span class="k">"published"</span>: <span class="n">true</span>,
            <span class="k">"has_variants"</span>: <span class="n">false</span>,
            <span class="k">"image"</span>: <span class="s">"http://localhost:<span class="n">8080</span>/joomla6_ext/images/com_hikashop/upload/demo-0073.png"</span>,
            <span class="k">"price"</span>: <span class="n">71.21</span>,
            <span class="k">"currency_id"</span>: <span class="n">1</span>,
            <span class="k">"custom_fields"</span>: []
        },
        {
            <span class="k">"id"</span>: <span class="n">8816</span>,
            <span class="k">"name"</span>: <span class="s">"Anodised Headphones"</span>,
            <span class="k">"code"</span>: <span class="s">"DEMO-0133"</span>,
            <span class="k">"quantity"</span>: <span class="n">14</span>,
            <span class="k">"published"</span>: <span class="n">true</span>,
            <span class="k">"has_variants"</span>: <span class="n">false</span>,
            <span class="k">"image"</span>: <span class="s">"http://localhost:<span class="n">8080</span>/joomla6_ext/images/com_hikashop/upload/demo-0133.png"</span>,
            <span class="k">"price"</span>: <span class="n">317.13</span>,
            <span class="k">"currency_id"</span>: <span class="n">1</span>,
            <span class="k">"custom_fields"</span>: []
        }
    ],
    <span class="k">"meta"</span>: {
        <span class="k">"start"</span>: <span class="n">0</span>,
        <span class="k">"limit"</span>: <span class="n">2</span>,
        <span class="k">"total"</span>: <span class="n">309</span>,
        <span class="k">"fields"</span>: []
    },
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## List orders

GET /orders read since 6.6.0

The orders the operator may see, newest first. It is the listing the app's order screen is built on, so it carries just enough to draw a row and no more; ask for one order when you need the rest.

### Query

ParameterTypeDescription

startintegerOffset. Defaults to `0`.

limitintegerDefaults to `20`, capped at `100`.

searchstringMatches the order number and the customer.

statusstringA status namekey, as listed by `GET /statuses`.

### Response a list expand all

FieldTypeDescription

idintegerThe order id, which is what every other order route takes.

numberstringThe order number the customer sees, which is not the id.

statusstringA namekey, not a label. `GET /statuses` translates it.

createdintegerUnix timestamp.

totalnumberWhat the customer owes, tax included, in the order currency.

currency\_idintegerThe order keeps the currency it was placed in, which need not be the shop default.

customerobjectEnough to name the buyer in a list.namestring

emailstring

custom\_fieldsobjectThe listing values of your own order fields, keyed by namekey. The keys are whatever this shop has configured; `fields` in the envelope says what they are.

### Envelope meta

FieldTypeDescription

startintegerEchoes the offset used.

limitintegerEchoes the page size used.

totalintegerOrders matching the filter, before paging.

fieldsobject\[\]The definitions behind `custom_fields`.

```
curl "$SHOP/hikashop-api/v1/orders?limit=2" \
  -H "Authorization: Bearer $TOKEN"
```

```
{
    <span class="k">"data"</span>: [
        {
            <span class="k">"id"</span>: <span class="n">2</span>,
            <span class="k">"number"</span>: <span class="s">"TEST-VOTE-1"</span>,
            <span class="k">"status"</span>: <span class="s">"confirmed"</span>,
            <span class="k">"created"</span>: <span class="n">1786877040</span>,
            <span class="k">"total"</span>: <span class="n">100</span>,
            <span class="k">"currency_id"</span>: <span class="n">1</span>,
            <span class="k">"customer"</span>: {
                <span class="k">"name"</span>: <span class="s">"Admin"</span>,
                <span class="k">"email"</span>: <span class="s">"<joomla-hidden-mail base="" first="YnV5ZXI=" is-email="1" is-link="1" last="ZXhhbXBsZS50ZXN0" text="YnV5ZXJAZXhhbXBsZS50ZXN0">This email address is being protected from spambots. You need JavaScript enabled to view it.</joomla-hidden-mail>"</span>
            },
            <span class="k">"custom_fields"</span>: []
        },
        {
            <span class="k">"id"</span>: <span class="n">18</span>,
            <span class="k">"number"</span>: <span class="s">"U18"</span>,
            <span class="k">"status"</span>: <span class="s">"confirmed"</span>,
            <span class="k">"created"</span>: <span class="n">1786358640</span>,
            <span class="k">"total"</span>: <span class="n">14.99</span>,
            <span class="k">"currency_id"</span>: <span class="n">1</span>,
            <span class="k">"customer"</span>: {
                <span class="k">"name"</span>: <span class="s">"Admin"</span>,
                <span class="k">"email"</span>: <span class="s">"<joomla-hidden-mail base="" first="YnV5ZXI=" is-email="1" is-link="1" last="ZXhhbXBsZS50ZXN0" text="YnV5ZXJAZXhhbXBsZS50ZXN0">This email address is being protected from spambots. You need JavaScript enabled to view it.</joomla-hidden-mail>"</span>
            },
            <span class="k">"custom_fields"</span>: []
        }
    ],
    <span class="k">"meta"</span>: {
        <span class="k">"start"</span>: <span class="n">0</span>,
        <span class="k">"limit"</span>: <span class="n">2</span>,
        <span class="k">"total"</span>: <span class="n">640</span>,
        <span class="k">"fields"</span>: []
    },
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## Read one order

GET /orders/**{id}** read since 6.6.0

The whole order: its lines, its totals, its addresses, its history and your own fields.

Money is in the currency the order was placed in, which is not necessarily the shop's. Do not convert it: an order is a record of what was agreed at the time.

### Path

ParameterTypeDescription

idrequiredintegerThe order id.

### Response expand all

FieldTypeDescription

idinteger

numberstringThe number the customer sees.

statusstringA namekey.

createdintegerUnix timestamp.

modifiedintegerUnix timestamp of the last change.

currency\_idintegerThe currency the order was placed in.

totalsobjectThe figures. See the shape below.totalnumberWhat the customer owes, tax included.

discountnumberThe discount applied, as a positive figure already subtracted.

shippingnumberThe shipping charged.

paymentnumberThe payment fee charged.

taxnumberThe tax within the total, not on top of it.

customerobjectWho placed it.namestring

emailstring

payment\_methodstringHow it was paid, as the shop names it.

shipping\_methodstringHow it ships.

invoice\_numberstringEmpty until an invoice has been issued.

invoice\_createdinteger\|nullUnix timestamp of the invoice.

itemsobject\[\]The lines: `id`, `name`, `code`, `quantity`, `price`, `tax` and whether the line can still be edited.idintegerThe line id, which is what `PUT /orders/{id}/products/{lineId}` takes. It is not the product id.

namestringThe product as it was named when ordered, which may since have changed.

codestringIts SKU at the time.

quantityinteger

pricenumberUnit price, tax excluded, as agreed at the time.

taxnumberTax on the line.

editablebooleanFalse once the line can no longer be changed, for instance on a shipped order.

billing\_addressobject\|nullThe address as it was at the time, `null` when there is none. It is a copy, not a pointer at the customer's current address.

shipping\_addressobject\|nullThe same, for delivery.

shipping\_address\_overridebooleanWhether the delivery address was set apart from the billing one.

historyobject\[\]What has happened to the order, oldest first.statusstringThe namekey it moved to.

createdintegerUnix timestamp.

typestringWhat caused it: a payment notification, an operator, the shop itself.

reasonstringThe note recorded with the change, when there was one.

notifiedbooleanWhether the customer was emailed about it.

fieldsobject\[\]The definitions of your own order fields.namekeystringThe key its value is stored under.

typestringWhat to render: `text`, `radio`, `singledropdown`, `file`, and the rest.

raw\_typestringHikaShop's own name for the type.

labelstringTranslated into the operator's language.

defaultstringThe value used when none is given.

requiredbooleanWhether the shop refuses to save without it.

optionsobject\[\]The choices, for a field that has them.valuestringWhat to send back when this choice is picked.

labelstringWhat to show.

label\_keystringThe translation key behind the label, when there is one.

multiplebooleanWhether more than one may be chosen.

translatablebooleanWhether its value can be translated.

upload\_dirstringFor a file field, where its uploads are kept.

allowed\_extensionsstringFor a file field, the extensions it accepts. Empty means the shop default.

date\_formatstringFor a date field, the format it is stored in.

custom\_fieldsobjectTheir values, keyed by namekey. The keys depend on the shop; `fields` says what they are.

custom\_field\_filesobjectFor a field holding a file, the file behind the value. Keyed the same way.

feesobjectThe `discount`, `shipping` and `payment` amounts, which is what `PUT /orders/{id}/fees` writes.  discountobjectIts `amount`, its `tax`, the `tax_namekeys` behind that tax, and the coupon `code` when one was used.amountnumberA positive figure, already subtracted from the total.

taxnumberThe tax on it.

tax\_namekeysstring\[\]Which tax rates that came from.

codestringThe coupon code, empty for a discount applied by hand.

shippingobjectThe shipping charge and what carried it.amountnumberTax excluded.

taxnumberThe tax on it.

tax\_namekeysstring\[\]Which tax rates that came from.

methodstringThe plugin that handled it.

method\_namestringAs the merchant named it.

paymentobjectThe payment fee and what took it.amountnumberTax excluded.

taxnumberThe tax on it.

tax\_namekeysstring\[\]Which tax rates that came from.

methodstringThe plugin that took it.

method\_namestringAs the merchant named it.

tax\_ratesobject\[\]The rates that made up the tax, each with its namekey and rate, so a total can be explained rather than only shown.namekeystringThe tax rate as the shop names it.

ratenumberAs a fraction, so `0.1` is ten percent.

sectionsobject\[\]Information other plugins show on this record, each with a `key`, a `title` and `rows` (`label`, `value`, and optionally `url`, `badge` and `ref`). Empty when no plugin adds any; on a customer, core adds their paid downloads. See the guide on adding information and settings.

extensionsobject\[\]Settings other plugins keep on this record, in groups (`key`, `title`, `fields`), each field described like a custom field plus its current `value`. Send changes back as `extensions` with the record's save. Empty when no plugin adds any.

```
curl "$SHOP/hikashop-api/v1/orders/{id}" \
  -H "Authorization: Bearer $TOKEN"
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"id"</span>: <span class="n">5630</span>,
        <span class="k">"number"</span>: <span class="s">"S5630"</span>,
        <span class="k">"status"</span>: <span class="s">"confirmed"</span>,
        <span class="k">"created"</span>: <span class="n">1738143180</span>,
        <span class="k">"modified"</span>: <span class="n">1790620951</span>,
        <span class="k">"currency_id"</span>: <span class="n">1</span>,
        <span class="k">"totals"</span>: {
            <span class="k">"total"</span>: <span class="n">313.92</span>,
            <span class="k">"discount"</span>: <span class="n">0</span>,
            <span class="k">"shipping"</span>: <span class="n">6.9</span>,
            <span class="k">"payment"</span>: <span class="n">0</span>,
            <span class="k">"tax"</span>: <span class="n">0</span>
        },
        <span class="k">"customer"</span>: {
            <span class="k">"name"</span>: <span class="s">"Admin"</span>,
            <span class="k">"email"</span>: <span class="s">"<joomla-hidden-mail base="" first="YnV5ZXI=" is-email="1" is-link="1" last="ZXhhbXBsZS50ZXN0" text="YnV5ZXJAZXhhbXBsZS50ZXN0">This email address is being protected from spambots. You need JavaScript enabled to view it.</joomla-hidden-mail>"</span>
        },
        <span class="k">"payment_method"</span>: <span class="s">"paypalcheckout"</span>,
        <span class="k">"shipping_method"</span>: <span class="s">"manual"</span>,
        <span class="k">"invoice_number"</span>: <span class="s">"B5630"</span>,
        <span class="k">"invoice_created"</span>: <span class="n">1738143180</span>,
        <span class="k">"items"</span>: [
            {
                <span class="k">"id"</span>: <span class="n">20630</span>,
                <span class="k">"name"</span>: <span class="s">"Nordic Design item"</span>,
                <span class="k">"code"</span>: <span class="s">"SEED-7-44"</span>,
                <span class="k">"quantity"</span>: <span class="n">1</span>,
                <span class="k">"price"</span>: <span class="n">307.02</span>,
                <span class="k">"tax"</span>: <span class="n">0</span>,
                <span class="k">"editable"</span>: <span class="n">true</span>
            },
            {
                <span class="k">"id"</span>: <span class="n">20642</span>,
                <span class="k">"name"</span>: <span class="s">"Test Product (Vendor 2)"</span>,
                <span class="k">"code"</span>: <span class="s">"TEST001"</span>,
                <span class="k">"quantity"</span>: <span class="n">1</span>,
                <span class="k">"price"</span>: <span class="n">0</span>,
                <span class="k">"tax"</span>: <span class="n">0</span>,
                <span class="k">"editable"</span>: <span class="n">true</span>
            }
        ],
        <span class="k">"billing_address"</span>: <span class="n">null</span>,
        <span class="k">"shipping_address"</span>: <span class="n">null</span>,
        <span class="k">"shipping_address_override"</span>: [],
        <span class="k">"history"</span>: [],
        <span class="k">"fields"</span>: [
            {
                <span class="k">"namekey"</span>: <span class="s">"hstestfile1755"</span>,
                <span class="k">"type"</span>: <span class="s">"ajaxfile"</span>,
                <span class="k">"raw_type"</span>: <span class="s">"ajaxfile"</span>,
                <span class="k">"label"</span>: <span class="s">"Test attachment"</span>,
                <span class="k">"default"</span>: <span class="s">""</span>,
                <span class="k">"required"</span>: <span class="n">false</span>,
                <span class="k">"options"</span>: [],
                <span class="k">"multiple"</span>: <span class="n">false</span>,
                <span class="k">"translatable"</span>: <span class="n">false</span>,
                <span class="k">"upload_dir"</span>: <span class="s">""</span>,
                <span class="k">"allowed_extensions"</span>: <span class="s">""</span>,
                <span class="k">"date_format"</span>: <span class="s">""</span>
            },
            {
                <span class="k">"namekey"</span>: <span class="s">"hstestfile1859"</span>,
                <span class="k">"type"</span>: <span class="s">"ajaxfile"</span>,
                <span class="k">"raw_type"</span>: <span class="s">"ajaxfile"</span>,
                <span class="k">"label"</span>: <span class="s">"Test attachment"</span>,
                <span class="k">"default"</span>: <span class="s">""</span>,
                <span class="k">"required"</span>: <span class="n">false</span>,
                <span class="k">"options"</span>: [],
                <span class="k">"multiple"</span>: <span class="n">false</span>,
                <span class="k">"translatable"</span>: <span class="n">false</span>,
                <span class="k">"upload_dir"</span>: <span class="s">""</span>,
                <span class="k">"allowed_extensions"</span>: <span class="s">""</span>,
                <span class="k">"date_format"</span>: <span class="s">""</span>
            },
            {
                <span class="k">"namekey"</span>: <span class="s">"hstestfile26994"</span>,
                <span class="k">"type"</span>: <span class="s">"ajaxfile"</span>,
                <span class="k">"raw_type"</span>: <span class="s">"ajaxfile"</span>,
                <span class="k">"label"</span>: <span class="s">"Test attachment"</span>,
                <span class="k">"default"</span>: <span class="s">""</span>,
                <span class="k">"required"</span>: <span class="n">false</span>,
                <span class="k">"options"</span>: [],
                <span class="k">"multiple"</span>: <span class="n">false</span>,
                <span class="k">"translatable"</span>: <span class="n">false</span>,
                <span class="k">"upload_dir"</span>: <span class="s">""</span>,
                <span class="k">"allowed_extensions"</span>: <span class="s">""</span>,
                <span class="k">"date_format"</span>: <span class="s">""</span>
            },
            {
                <span class="k">"namekey"</span>: <span class="s">"hstestfile28016"</span>,
                <span class="k">"type"</span>: <span class="s">"ajaxfile"</span>,
                <span class="k">"raw_type"</span>: <span class="s">"ajaxfile"</span>,
                <span class="k">"label"</span>: <span class="s">"Test attachment"</span>,
                <span class="k">"default"</span>: <span class="s">""</span>,
                <span class="k">"required"</span>: <span class="n">false</span>,
                <span class="k">"options"</span>: [],
                <span class="k">"multiple"</span>: <span class="n">false</span>,
                <span class="k">"translatable"</span>: <span class="n">false</span>,
                <span class="k">"upload_dir"</span>: <span class="s">""</span>,
                <span class="k">"allowed_extensions"</span>: <span class="s">""</span>,
                <span class="k">"date_format"</span>: <span class="s">""</span>
            },
            "… 1 more, trimmed for the example"
        ],
        <span class="k">"custom_fields"</span>: {
            <span class="k">"hstestfile1755"</span>: <span class="n">null</span>,
            <span class="k">"hstestfile1859"</span>: <span class="n">null</span>,
            <span class="k">"hstestfile26994"</span>: <span class="n">null</span>,
            <span class="k">"hstestfile28016"</span>: <span class="n">null</span>,
            <span class="k">"hstestfile27610"</span>: <span class="n">null</span>
        },
        <span class="k">"custom_field_files"</span>: [],
        <span class="k">"fees"</span>: {
            <span class="k">"discount"</span>: {
                <span class="k">"amount"</span>: <span class="n">0</span>,
                <span class="k">"tax"</span>: <span class="n">0</span>,
                <span class="k">"tax_namekeys"</span>: [],
                <span class="k">"code"</span>: <span class="s">""</span>
            },
            <span class="k">"shipping"</span>: {
                <span class="k">"amount"</span>: <span class="n">6.9</span>,
                <span class="k">"tax"</span>: <span class="n">0</span>,
                <span class="k">"tax_namekeys"</span>: [],
                <span class="k">"method"</span>: <span class="s">"manual"</span>,
                <span class="k">"method_name"</span>: <span class="s">"Vendor 2 only shipping"</span>
            },
            <span class="k">"payment"</span>: {
                <span class="k">"amount"</span>: <span class="n">0</span>,
                <span class="k">"tax"</span>: <span class="n">0</span>,
                <span class="k">"tax_namekeys"</span>: [],
                <span class="k">"method"</span>: <span class="s">"paypalcheckout"</span>,
                <span class="k">"method_name"</span>: <span class="s">"PayPal Checkout Express Test"</span>
            }
        },
        <span class="k">"tax_rates"</span>: [
            {
                <span class="k">"namekey"</span>: <span class="s">"apptest_vat10"</span>,
                <span class="k">"rate"</span>: <span class="n">0.1</span>
            },
            {
                <span class="k">"namekey"</span>: <span class="s">"apptest_vat20"</span>,
                <span class="k">"rate"</span>: <span class="n">0.2</span>
            },
            {
                <span class="k">"namekey"</span>: <span class="s">"gst"</span>,
                <span class="k">"rate"</span>: <span class="n">0.06</span>
            },
            {
                <span class="k">"namekey"</span>: <span class="s">"recargo 5,2%"</span>,
                <span class="k">"rate"</span>: <span class="n">0.052</span>
            },
            "… 1 more, trimmed for the example"
        ],
        <span class="k">"sections"</span>: [],
        <span class="k">"extensions"</span>: []
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## Set the order fees

PUT /orders/**{id}**/fees write since 6.6.0

Replaces the discount, shipping and payment amounts and re-totals the order, so a client does not have to compute a total itself and risk disagreeing with the shop.

What you do not send keeps its current value.

### Path

ParameterTypeDescription

idrequiredintegerThe order id.

### Body

FieldTypeDescription

feesrequiredobjectAny of `discount`, `shipping` and `payment`, each an object with at least an `amount`, tax excluded. A discount is a positive figure and is subtracted.

### Response expand all

FieldTypeDescription

idinteger

feesobjectThe discount, shipping and payment amounts of the order.  discountobjectIts `amount`, its `tax`, the `tax_namekeys` behind that tax, and the coupon `code` when one was used.amountnumberA positive figure, already subtracted from the total.

taxnumberThe tax on it.

tax\_namekeysstring\[\]Which tax rates that came from.

codestringThe coupon code, empty for a discount applied by hand.

shippingobjectThe shipping charge and what carried it.amountnumberTax excluded.

taxnumberThe tax on it.

tax\_namekeysstring\[\]Which tax rates that came from.

methodstringThe plugin that handled it.

method\_namestringAs the merchant named it.

paymentobjectThe payment fee and what took it.amountnumberTax excluded.

taxnumberThe tax on it.

tax\_namekeysstring\[\]Which tax rates that came from.

methodstringThe plugin that took it.

method\_namestringAs the merchant named it.

totalsobjectThe order totalled, so a client need not compute it and disagree with the shop.totalnumberWhat the customer owes, tax included.

discountnumberThe discount applied, as a positive figure already subtracted.

shippingnumberThe shipping charged.

paymentnumberThe payment fee charged.

taxnumberThe tax within the total, not on top of it.

### Errors

CodeHTTPMeans

not\_found404No such order, or the operator may not change it.

save\_failed500The order could not be saved.

```
curl -X PUT "$SHOP/hikashop-api/v1/orders/{id}/fees" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "fees": {
        "shipping": {
            "amount": 4.9
        }
    }
}'
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"id"</span>: <span class="n">5630</span>,
        <span class="k">"fees"</span>: {
            <span class="k">"discount"</span>: {
                <span class="k">"amount"</span>: <span class="n">0</span>,
                <span class="k">"tax"</span>: <span class="n">0</span>,
                <span class="k">"tax_namekeys"</span>: [],
                <span class="k">"code"</span>: <span class="s">""</span>
            },
            <span class="k">"shipping"</span>: {
                <span class="k">"amount"</span>: <span class="n">4.9</span>,
                <span class="k">"tax"</span>: <span class="n">0</span>,
                <span class="k">"tax_namekeys"</span>: [],
                <span class="k">"method"</span>: <span class="s">"manual"</span>,
                <span class="k">"method_name"</span>: <span class="s">"Vendor 2 only shipping"</span>
            },
            <span class="k">"payment"</span>: {
                <span class="k">"amount"</span>: <span class="n">0</span>,
                <span class="k">"tax"</span>: <span class="n">0</span>,
                <span class="k">"tax_namekeys"</span>: [],
                <span class="k">"method"</span>: <span class="s">"paypalcheckout"</span>,
                <span class="k">"method_name"</span>: <span class="s">"PayPal Checkout Express Test"</span>
            }
        },
        <span class="k">"totals"</span>: {
            <span class="k">"total"</span>: <span class="n">311.92</span>,
            <span class="k">"discount"</span>: <span class="n">0</span>,
            <span class="k">"shipping"</span>: <span class="n">4.9</span>,
            <span class="k">"payment"</span>: <span class="n">0</span>,
            <span class="k">"tax"</span>: <span class="n">0</span>
        }
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## An address of an order, with its form

GET /orders/**{id}**/address/**{type}** read since 6.6.0

The billing or shipping address of an order, together with the form the shop would use to edit it.

The form is sent with the values because a shop decides its own address fields: which exist, which are required, and in what order. Build the form from `fields` rather than assuming a shape, and `PUT` the same keys back.

### Path

ParameterTypeDescription

idrequiredintegerThe order id.

typerequiredstring&#96;billing&#96; or &#96;shipping&#96;.

### Response expand all

FieldTypeDescription

typestringWhich address this is.

address\_idintegerThe address row, `0` when the order has none of that kind.

fieldsobject\[\]The shop's address fields, in display order.namekeystringThe key to send the value back under.

typestringWhat to render: `text`, `zone`, `singledropdown`, and the rest.

raw\_typestringHikaShop's own name for the type.

labelstringTranslated into the operator's language.

defaultstringThe value used when none is given.

requiredbooleanWhether the shop refuses to save the address without it.

optionsobject\[\]The choices, for a field that has them. A country or a state is filled from the zones rather than from here.valuestringWhat to send back when this choice is picked.

labelstringWhat to show.

label\_keystringThe translation key behind the label, when there is one.

multiplebooleanWhether more than one may be chosen.

translatablebooleanNot meaningful on an address, where values are the customer's own words.

upload\_dirstringUnused on an address field.

allowed\_extensionsstringUnused on an address field.

date\_formatstringFor a date field, the format it is stored in.

valuesobjectThe current values, keyed by field namekey. Keyed by whatever address fields this shop has.

country\_namestringThe country spelled out, since the value itself is a zone id.

state\_namestringThe state spelled out, empty where the country has none.

### Errors

CodeHTTPMeans

not\_found404No such order, or the operator may not see it.

```
curl "$SHOP/hikashop-api/v1/orders/{id}/address/billing" \
  -H "Authorization: Bearer $TOKEN"
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"type"</span>: <span class="s">"billing"</span>,
        <span class="k">"address_id"</span>: <span class="n">19</span>,
        <span class="k">"fields"</span>: [
            {
                <span class="k">"namekey"</span>: <span class="s">"address_title"</span>,
                <span class="k">"type"</span>: <span class="s">"singledropdown"</span>,
                <span class="k">"raw_type"</span>: <span class="s">"singledropdown"</span>,
                <span class="k">"label"</span>: <span class="s">"Title"</span>,
                <span class="k">"default"</span>: <span class="s">""</span>,
                <span class="k">"required"</span>: <span class="n">true</span>,
                <span class="k">"options"</span>: [
                    {
                        <span class="k">"value"</span>: <span class="s">"Mr"</span>,
                        <span class="k">"label"</span>: <span class="s">"Mr"</span>,
                        <span class="k">"label_key"</span>: <span class="s">"HIKA_TITLE_MR"</span>
                    },
                    {
                        <span class="k">"value"</span>: <span class="s">"Mrs"</span>,
                        <span class="k">"label"</span>: <span class="s">"Mrs"</span>,
                        <span class="k">"label_key"</span>: <span class="s">"HIKA_TITLE_MRS"</span>
                    },
                    {
                        <span class="k">"value"</span>: <span class="s">"Miss"</span>,
                        <span class="k">"label"</span>: <span class="s">"Miss"</span>,
                        <span class="k">"label_key"</span>: <span class="s">"HIKA_TITLE_MISS"</span>
                    },
                    {
                        <span class="k">"value"</span>: <span class="s">"Ms"</span>,
                        <span class="k">"label"</span>: <span class="s">"Ms"</span>,
                        <span class="k">"label_key"</span>: <span class="s">"HIKA_TITLE_MS"</span>
                    },
                    "… 1 more, trimmed for the example"
                ],
                <span class="k">"multiple"</span>: <span class="n">false</span>,
                <span class="k">"translatable"</span>: <span class="n">false</span>,
                <span class="k">"upload_dir"</span>: <span class="s">""</span>,
                <span class="k">"allowed_extensions"</span>: <span class="s">""</span>,
                <span class="k">"date_format"</span>: <span class="s">""</span>
            },
            {
                <span class="k">"namekey"</span>: <span class="s">"address_firstname"</span>,
                <span class="k">"type"</span>: <span class="s">"text"</span>,
                <span class="k">"raw_type"</span>: <span class="s">"text"</span>,
                <span class="k">"label"</span>: <span class="s">"First name"</span>,
                <span class="k">"default"</span>: <span class="s">""</span>,
                <span class="k">"required"</span>: <span class="n">true</span>,
                <span class="k">"options"</span>: [],
                <span class="k">"multiple"</span>: <span class="n">false</span>,
                <span class="k">"translatable"</span>: <span class="n">false</span>,
                <span class="k">"upload_dir"</span>: <span class="s">""</span>,
                <span class="k">"allowed_extensions"</span>: <span class="s">""</span>,
                <span class="k">"date_format"</span>: <span class="s">""</span>
            },
            {
                <span class="k">"namekey"</span>: <span class="s">"address_lastname"</span>,
                <span class="k">"type"</span>: <span class="s">"text"</span>,
                <span class="k">"raw_type"</span>: <span class="s">"text"</span>,
                <span class="k">"label"</span>: <span class="s">"Last name"</span>,
                <span class="k">"default"</span>: <span class="s">""</span>,
                <span class="k">"required"</span>: <span class="n">true</span>,
                <span class="k">"options"</span>: [],
                <span class="k">"multiple"</span>: <span class="n">false</span>,
                <span class="k">"translatable"</span>: <span class="n">false</span>,
                <span class="k">"upload_dir"</span>: <span class="s">""</span>,
                <span class="k">"allowed_extensions"</span>: <span class="s">""</span>,
                <span class="k">"date_format"</span>: <span class="s">""</span>
            },
            {
                <span class="k">"namekey"</span>: <span class="s">"address_company"</span>,
                <span class="k">"type"</span>: <span class="s">"text"</span>,
                <span class="k">"raw_type"</span>: <span class="s">"text"</span>,
                <span class="k">"label"</span>: <span class="s">"Company"</span>,
                <span class="k">"default"</span>: <span class="s">""</span>,
                <span class="k">"required"</span>: <span class="n">false</span>,
                <span class="k">"options"</span>: [],
                <span class="k">"multiple"</span>: <span class="n">false</span>,
                <span class="k">"translatable"</span>: <span class="n">false</span>,
                <span class="k">"upload_dir"</span>: <span class="s">""</span>,
                <span class="k">"allowed_extensions"</span>: <span class="s">""</span>,
                <span class="k">"date_format"</span>: <span class="s">""</span>
            },
            "… 7 more, trimmed for the example"
        ],
        <span class="k">"values"</span>: {
            <span class="k">"address_title"</span>: <span class="s">"Mr"</span>,
            <span class="k">"address_firstname"</span>: <span class="s">"Alex"</span>,
            <span class="k">"address_lastname"</span>: <span class="s">"Marchand"</span>,
            <span class="k">"address_company"</span>: <span class="s">"Lilas SARL"</span>,
            <span class="k">"address_street"</span>: <span class="s">"12 rue des Lilas"</span>,
            <span class="k">"address_post_code"</span>: <span class="s">"44000"</span>,
            <span class="k">"address_city"</span>: <span class="s">"Nantes"</span>,
            <span class="k">"address_telephone"</span>: <span class="s">"+33 2 00 00 00 00"</span>,
            <span class="k">"address_country"</span>: <span class="s">""</span>,
            <span class="k">"address_state"</span>: <span class="s">""</span>,
            <span class="k">"address_vat"</span>: <span class="s">"FR00000000000"</span>
        },
        <span class="k">"country_name"</span>: <span class="s">""</span>,
        <span class="k">"state_name"</span>: <span class="s">""</span>
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## The coupons that can be applied

GET /coupons read since 6.6.0

The shop's published coupons, so an operator can pick one rather than remember a code. Applying it is a separate call, and the shop validates it again there: a coupon listed here can still be refused for this particular order.

### Response a list expand all

FieldTypeDescription

idinteger

codestringWhat the customer would type. This is what you send to apply it.

flat\_amountnumberA fixed reduction, `0` when the coupon is a percentage.

percent\_amountnumberA percentage reduction, `0` when the coupon is a fixed amount.

currency\_idintegerThe currency a flat amount is expressed in.

startinteger\|nullUnix timestamp before which it is not valid.

endinteger\|nullUnix timestamp after which it expires.

quotaintegerHow many times it may be used in total, `0` for no limit.

used\_timesintegerHow many times it already has been.

minimum\_ordernumberThe order total below which it does not apply, `0` for none.

```
curl "$SHOP/hikashop-api/v1/coupons" \
  -H "Authorization: Bearer $TOKEN"
```

```
{
    <span class="k">"data"</span>: [
        {
            <span class="k">"id"</span>: <span class="n">1</span>,
            <span class="k">"code"</span>: <span class="s">"APPTEST10"</span>,
            <span class="k">"flat_amount"</span>: <span class="n">10</span>,
            <span class="k">"percent_amount"</span>: <span class="n">0</span>,
            <span class="k">"currency_id"</span>: <span class="n">1</span>,
            <span class="k">"start"</span>: <span class="n">0</span>,
            <span class="k">"end"</span>: <span class="n">0</span>,
            <span class="k">"quota"</span>: <span class="n">0</span>,
            <span class="k">"used_times"</span>: <span class="n">0</span>,
            <span class="k">"minimum_order"</span>: <span class="n">0</span>
        },
        {
            <span class="k">"id"</span>: <span class="n">2</span>,
            <span class="k">"code"</span>: <span class="s">"APPTEST20PCT"</span>,
            <span class="k">"flat_amount"</span>: <span class="n">0</span>,
            <span class="k">"percent_amount"</span>: <span class="n">20</span>,
            <span class="k">"currency_id"</span>: <span class="n">1</span>,
            <span class="k">"start"</span>: <span class="n">0</span>,
            <span class="k">"end"</span>: <span class="n">0</span>,
            <span class="k">"quota"</span>: <span class="n">0</span>,
            <span class="k">"used_times"</span>: <span class="n">0</span>,
            <span class="k">"minimum_order"</span>: <span class="n">0</span>
        },
        {
            <span class="k">"id"</span>: <span class="n">432</span>,
            <span class="k">"code"</span>: <span class="s">"E2E1786215715618"</span>,
            <span class="k">"flat_amount"</span>: <span class="n">0</span>,
            <span class="k">"percent_amount"</span>: <span class="n">12</span>,
            <span class="k">"currency_id"</span>: <span class="n">0</span>,
            <span class="k">"start"</span>: <span class="n">0</span>,
            <span class="k">"end"</span>: <span class="n">0</span>,
            <span class="k">"quota"</span>: <span class="n">0</span>,
            <span class="k">"used_times"</span>: <span class="n">0</span>,
            <span class="k">"minimum_order"</span>: <span class="n">0</span>
        },
        {
            <span class="k">"id"</span>: <span class="n">434</span>,
            <span class="k">"code"</span>: <span class="s">"E2E1786215747620"</span>,
            <span class="k">"flat_amount"</span>: <span class="n">0</span>,
            <span class="k">"percent_amount"</span>: <span class="n">12</span>,
            <span class="k">"currency_id"</span>: <span class="n">0</span>,
            <span class="k">"start"</span>: <span class="n">0</span>,
            <span class="k">"end"</span>: <span class="n">0</span>,
            <span class="k">"quota"</span>: <span class="n">0</span>,
            <span class="k">"used_times"</span>: <span class="n">0</span>,
            <span class="k">"minimum_order"</span>: <span class="n">0</span>
        }
    ],
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

## Change an order's status

POST /orders/**{id}**/status write since 6.6.0

Moves the order and, when asked, sends the customer the same notification the backend would have sent.

This calls the same code the backend does, so stock, invoices and every plugin listening on a status change behave exactly as they do there. It is not a database update.

### Path

ParameterTypeDescription

idrequiredintegerThe order id.

### Body

FieldTypeDescription

statusrequiredstringA status \*\*namekey\*\*, as listed by `GET /statuses`. Not the translated label.

notifybooleanSend the customer the notification for the new status. Defaults to `false`.

reasonstringRecorded in the order history, and included in the notification when there is one.

### Response expand all

FieldTypeDescription

idintegerThe order id.

statusstringThe namekey the order now has.

changedbooleanFalse when the order already had that status.

notifiedbooleanWhether the customer was actually emailed, which can be false even when you asked, if the status has no notification configured.

### Errors

CodeHTTPMeans

invalid\_status400No such status namekey on this shop.

not\_found404No such order, or the operator may not see it.

save\_failed500The order could not be saved.

```
curl -X POST "$SHOP/hikashop-api/v1/orders/{id}/status" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "status": "confirmed",
    "notify": false,
    "reason": "Documentation capture"
}'
```

```
{
    <span class="k">"data"</span>: {
        <span class="k">"id"</span>: <span class="n">5626</span>,
        <span class="k">"status"</span>: <span class="s">"confirmed"</span>,
        <span class="k">"changed"</span>: <span class="n">true</span>,
        <span class="k">"notified"</span>: <span class="n">false</span>
    },
    <span class="k">"meta"</span>: <span class="n">null</span>,
    <span class="k">"error"</span>: <span class="n">null</span>
}
```

##  [ Customize the display ](/support/documentation/153-customize-the-display)

Details    Written by: Xavier    Category: [Developer area](/support/documentation/hikashop/developer-area)     Published: 30 January 2013     Hits: 149052

| - [Description](#description) - [Where to add custom CSS](#where_to_css) - [How to find the CSS to change](#css) - [Responsive Customization](#responsive) - [Changing Text Labels](#labels) - [Layout customization](#layout) - [View Builder](#view_builder) | ![](/images/icon_doc/icon_display_180.png) |
|---|---|

### <a name="description"></a>Description

This tutorial will explain how to find the elements you want to customize and how to customize them.

If you need to change the CSS properties of an element, then you have to follow the CSS Edition part.
For additional information about the most common changes please see our FAQ: [Here](/support/faq.html#styl "FAQ CSS")

To move an element in the page, or add something in it, follow the Layout customizations part.
For additional information about the most common changes please see our FAQ: [Here](/support/faq.html#layo "FAQ Layout")

### <a name="where_to_css"></a>Where to add custom CSS

There are several ways to add custom CSS to your website. While HikaShop provides its own mechanism, **we recommend using your Joomla template's custom CSS facility** whenever possible. Centralizing all your site-wide styling in one location makes maintenance much easier and ensures consistency.

**1. Joomla Template (Recommended)**

Most modern Joomla templates provide a dedicated way to add custom CSS without modifying the theme's core files:

- **Cassiopeia (Default Joomla Template):** Use the `user.css` file. [View Guide](https://guide.joomla.org/user-manual/templates/templates-cassiopeia-template-customisation)
- **Helix Ultimate:** Create a `custom.css` file in the `/css` folder of your template or use the `Custom Code` tab in the Template Options. [View Guide](https://www.joomshaper.com/documentation/helix-framework/helix-ultimate-2/custom-code-css-js-meta)
- **Gantry 5:** Create a `custom.scss` file in the `/custom/scss/` folder of your template. [View Guide](https://docs.gantry.org/gantry5/tutorials/adding-a-custom-style-sheet)
- **Astroid Framework:** Create a `custom.css` file in the `/css` folder or use the `Custom Code` tab in the Template Options. [View Guide](https://docs.astroidframe.work/user-manual/custom-code)
- **T4 Framework:** T4 templates allow adding custom CSS/SCSS through the template settings. [View Guide](https://www.joomlart.com/documentation/t4-framework/css-scss-customization)
- **YOOtheme Pro:** For more advanced styling, Child Themes can be used. [View Guide](https://yootheme.com/support/yootheme-pro/joomla/developers-child-themes#less-styles)
- **Custom CSS Plugins:** If your template doesn't offer an easy way, you can use a dedicated custom CSS plugin. [View Guide](https://www.joomlashack.com/blog/joomla/custom-css/)

**2. HikaShop Configuration**

If you prefer to keep HikaShop-specific styles separate or if your template doesn't support custom CSS, you can use the HikaShop settings:

In **System &gt; Configuration &gt; Display &gt; CSS**, you can edit the "Styles for frontend" file. Add your custom CSS code at the end of this file. This ensures your custom code overrides the default styles and remains safe during updates.

![add CSS code in HikaShop's configuration page](/images/stories/doc_display_3.png)

### <a name="css"></a>How to find the CSS to change

To change the size and the color of an element (like the price on a product listing), you first need to identify the element's distinct class or ID. You can do this using your browser's developer tools (often accessible by pressing **F12**).

![](/images/stories/doc_display_1.png)

Right-click on the element you want to customize and choose "Inspect" or "Inspect element".

A panel will open displaying the HTML structure. Look for the `class="..."` or `id="..."` attributes of the element.

![add CSS code in HikaShop's configuration page](/images/stories/doc_display_2.png)

For instance, the price usually has the class "hikashop\_product\_price".

### Common CSS Examples

**1. Change price color and size:**

```
.hikashop_product_price {
    color: #99cc00;
    font-size: 18px;
}
```

**2. Hide the price:**

```
.hikashop_product_price {
    display: none;
}
```

**3. Customize the "Add to cart" button:**

```
.hikashop_cart_input_button {
    background-color: #333333; /* Dark background */
    color: #ffffff; /* White text */
    border-radius: 5px; /* Rounded corners */
    border: none;
    padding: 10px 20px;
}
.hikashop_cart_input_button:hover {
    background-color: #555555; /* Lighter background on hover */
}
```

**4. Target a specific module only:**

If you want to apply changes only to a specific module, prepend the module's ID.

```
#module_25 .hikashop_product_price {
    color: #ff0000;
}
```

(Replace `#module_25` with the actual ID of your module).

To learn more about CSS, you can visit these websites:

- <http://www.w3schools.com/css/>
- <https://developer.mozilla.org/en-US/learn/css>
- <https://css-tricks.com/specifics-on-css-specificity/>

**Pro-Tip: My CSS is not applied!**
If your custom CSS isn't working, it's often due to **CSS Specificity** (priority). Try making your selector more specific by adding a parent ID, for example: `#hikashop_checkout_content .hikashop_product_price { color: red; }`. As a last resort, you can use `!important`.

### <a name="responsive"></a>Responsive Customization

HikaShop is natively responsive, but you might want to adjust the display for specific screen sizes using **CSS Media Queries**. This allows you to hide elements on mobile or change your layout for different devices.

**Example: Hide the product description on mobile**

```
@media (max-width: 480px) {
    .hikashop_product_description_main {
        display: none;
    }
}
```

**Example: Change font size only on tablets**

```
@media (min-width: 481px) and (max-width: 1024px) {
    .hikashop_product_name {
        font-size: 1.5em;
    }
}
```

### <a name="labels"></a>Changing Text Labels (Language Overrides)

Customizing the display often involves changing text labels like "Add to cart" or "VAT". Instead of editing HikaShop core files, you should use Language Overrides. This ensures your changes are preserved during updates. For more details on how to do this, please see our [Language Overrides Guide](https://www.hikashop.com/download/languages.html#modify).

### Common HikaShop CSS Classes

Here are some of the most common classes you might want to target for customization:

| Class Name | Description |
|---|---|
| `.hikashop_product_name` | The title/name of the product on listings and details. |
| `.hikashop_product_price` | The area where the price is displayed. |
| `.hikashop_product_description_main` | The main description of the product. |
| `.hikashop_cart_input_button` | The main "Add to cart" button. |
| `.hikashop_product_stock` | The stock level/availability information. |
| `.hikashop_product_image_main` | The main image container for a product. |

### <a name="layout"></a>Layout customizations

To go further with customization, you can override the view files of HikaShop via the menu Display&gt;Views.

We highly recommend that you edit the view files of HikaShop via that menu as explained below and not directly. That way, you won't lose your changes when updating your HikaShop.

Note that since Joomla 3, you can also go in the override section of the Joomla template manager to create overrides. Either way, the overrides can be edited on both interfaces as they are compatible between one another. Similarly to when you're using the view override mechanism in HikaShop, when using the template manager, the files are also stored in `templates/[YOUR_TEMPLATE]/html/com_hikashop/`.

To know which view you have to edit, just set the ["Display view files"](/support/documentation/54-hikashop-config.html#advanced_main) setting to "all" under the "Advanced" tab of the HikaShop configuration.

This will add dashed borders around each view file used with the name of the view file used on the top left corner of the view file. It will have 2 parts separated by a /. The left part will be the view name and the right part will be the file name so you'll be able to easily find what you need to edit.

![](/images/stories/doc_display_4.png)

**Note:** Since HikaShop 6.3.0, enabling "Display view files" also adds an edit icon next to the view names on the frontend, allowing for quick access to the view editor.

### <a name="view_builder"></a>View Builder

HikaShop includes a **"view builder"** system which allows you to move, swap or delete different elements in most of the frontend views without needing deep HTML or PHP knowledge. When a view supports drag &amp; drop, a "view builder" area will appear on top of the code editor. This editor will dynamically modify the code below as you drag and drop elements. Once finished, just save your changes to validate them.

The View Builder experience has been refined with a cleaner interface and auto-scroll support when dragging elements.

Developers and integrators will also appreciate a new workflow improvement: when the "Display view files" setting is activated, an edit icon now appears next to the view file names on the frontend. Clicking it opens a popup with the view edit form immediately, saving you from searching for the specific view file in the backend.

![HikaShop View Builder Interface](/images/blog/hikashop-6-3-0/new_view_builder_interface.png)

In the edition page, you can also find all the different parts between the HTML comments.

&lt;!-- ... --&gt;

![](/images/stories/doc_display_5.png)

Now you just have to cut and paste the part for the product name before the product image part.

And "voilà" you have moved the name before the picture of the product.

**Listing types:**

By checking the following tab you'll be able to know which file to edit via "Hikashop-&gt;Display-&gt;Views" regarding the value of the "Type of layout" and "Type of item layout" options.

![](/images/stories/listing_types2.png)

**Product page customization:**

By checking the following picture you'll be able to know which file to edit via "Hikashop-&gt;Display-&gt;Views" regarding what you exactly want to change on product page.

![](/images/stories/Product_customization.jpg)

To change the cart module display, you have to edit the view "product / cart". If you want to customize the emails, you have to go in HikaShop &gt; System &gt; Emails, only available in the business edition of HikaShop.

If you need more customizations, it requires HTML and probably PHP skills. If you don't have enough knowledge you can learn these programming languages on the web. You can also post a request on the Commercial Jobs section of our forum if you need to find a third party developer to help you personalize HikaShop if you don't know PHP.

##  [ Developer documentation ](/support/documentation/62-hikashop-developer-documentation)

Details    Written by: Administrator    Category: [Developer area](/support/documentation/hikashop/developer-area)     Published: 10 September 2010     Hits: 242108

Dear developer,

HikaShop runs on both Joomla and WordPress. Its plugin system is built on top of each CMS's native extension mechanism, allowing you to extend the shop's functionality with custom plugins.

## HikaShop Developer Documentation

HikaShop provides a powerful plugin system. On Joomla, HikaShop plugins are standard Joomla plugins. On WordPress, they are WordPress plugins that register HikaShop event hooks.

HikaShop events are triggered when certain actions are performed (order creation, product deletion, etc.). To use these events, you need to create a plugin of the group "hikashop", "hikashoppayment" or "hikashopshipping".

This document explains the available events, the HikaShop API, and providing code samples for common tasks.

### Summary

- Plugin system
- [How to create a HikaShop plugin](#howto)
- [Input handling with hikaInput](#input-handling)
- [How to create a HikaShop Payment plugin](#howtopayment)
- [How to create a HikaShop Shipping plugin](#howtoshipping)
- HikaShop API
- [Order API](#order)
- [Product API](#product)
- [Category API](#category)
- [Address API](#address)
- [Shipping API](#shipping)
- [Payment API](#payment)
- [UCP (Universal Commerce Protocol)](#ucp)
- [WebMCP (AI agents in the browser)](#webmcp)
- [Vote API](#vote)
- [Cart API](#cart)
- [View API](#views)
- [Discount/Coupon API](#discount)
- [User API](#user)
- [Field API](#fields)
- [Order Status API](#orderstatus)
- [Filter API](#filter)
- [Currency and Taxation API](#currency)
- [Waitlist API](#waitlist)
- [File API](#file)
- [Email API](#email)
- [Configuration API](#config)
- [Massaction API](#massaction)
- [Dashboard API](#dashboard)
- [Other Events](#other)
- [Assets Management](#assets)
- [Main Objects](#objects)
- [Database Structure](#db)
- [PHP code samples](#code)
- [Overrides](#override)
- [View Overrides](#view-overrides)
- [Plugin View Overrides](#plugin-overrides)
- [Class Overrides](#class-overrides)
- [Javascript events](#js)

The first thing you have to do is to create a plugin. The group will be "**hikashop**" unless you create a payment or shipping plugin, in which case it will be "**hikashoppayment**" or "**hikashopshipping**" respectively.

**On Joomla**, HikaShop plugins are standard Joomla plugins. We recommend that you first learn how to create Joomla plugins: [Joomla Plugin Development Documentation](https://manual.joomla.org/docs/building-extensions/plugins/basic-content-plugin/)

**On WordPress**, HikaShop plugins are standard WordPress plugins. The HikaShop compatibility layer translates WordPress hooks into HikaShop events, so the same plugin code works on both platforms when you extend the `hikashopPlugin` class.

### How to create a HikaShop plugin

When you create a plugin for HikaShop, while you can extend `JPlugin` (or `\Joomla\CMS\Plugin\CMSPlugin` on modern Joomla), we highly recommend extending the **`hikashopPlugin`** class.

The `hikashopPlugin` class provides a compatibility bridge across Joomla 3, 4, 5, 6 and WordPress, and includes several useful helper methods:

- `showPage($name)`: Renders a specific plugin view file, supporting template overrides (e.g., `$this->showPage('thanks')` will look for `yourplugin_thanks.php`).
- `listPlugins($name, &$values)`: Helps list all instances of a plugin type.

#### Input Handling with `hikaInput`

To ensure your plugin works across all Joomla versions and WordPress (where `JRequest` is deprecated and input handling varies), we recommend using the **`hikaInput`** class provided by HikaShop:

```
$input = hikaInput::get();
$myValue = $input->get('my_param', 'default_value', 'string');
```

**Multiple instances:** You can allow a plugin to have several instances (each with its own configuration) by setting `public $multiple = true;`. You then define the configuration fields in the `public $pluginConfig` array. For each field, you specify a label, a type (e.g., 'boolean', 'category', 'list', 'text'), and optional parameters or default values. This is useful for plugins that need different settings for different scenarios, like the **Shop Close Hours** plugin (`plg_hikashop_shopclosehours`). The `hikashopPlugin` class automatically handles the display and saving of these parameters for each instance.

In your plugin, simply create functions matches the names of the events you want to handle.

Here is an example using two events: `onBeforeOrderCreate` and `onAfterOrderCreate`. By extending `hikashopPlugin`, the database object `$this->db` is automatically initialized.

```
class plgHikashopName extends hikashopPlugin {
	function __construct(&$subject, $config){
		parent::__construct($subject, $config);
	}

	function onBeforeOrderCreate(&$order, &$do){
		/* code to be executed before the order is created */
	}

	function onAfterOrderCreate(&$order){
		/* code to be executed after the order is created */
	}
}
```

All events have different parameters. You can find the list of events below. Marc Studer also developed a helpful plugin to see which HikaShop event is triggered on each page: [hikashop\_dump\_events on GitHub](https://github.com/garstud/hikashop_dump_events).

#### What your method returns

Most events ignore what your method returns, and you change things through the parameters you are given by reference. A few collect the return values instead, and hand the caller the list of everything the listening plugins returned.

- Returning `null`, which is what a method with no `return` does, is the same as not listening at all. Both platforms drop it before the list is built, so HikaShop cannot tell the two apart.
- To say "I handled this", either return a value the event documents, or set a parameter passed by reference for that purpose. `onHikashopUploadStoreFile` takes the first road and looks for a literal `true` among the returns; `onBeforeVATOnlineCheck` takes the second and gives you a `$processed` to set.
- Returning `false` is a real answer and reaches the list. Only `null` disappears.

We recommend studying the **HikaShop Email history plugin** (`/plugins/hikashop/email_history/`), as it is one of the simplest examples for understanding the HikaShop plugin structure. Its goal is to store all emails sent to customers in a database table and display them in a list in the admin panel.

### How to create a HikaShop Payment plugin

First, we invite you to read the information on the [Payment API](#payment) section.

Then, you can go to the [Example Payment Plugin GitHub](https://github.com/hikashop-nicolas/plg_hikashoppayment_example) and look at the files. Each line of the plugin is documented, explaining how a payment plugin should be structured. It's an excellent base if you are a developer but have never integrated a payment gateway before.

You can also study the source code of payment plugins included in HikaShop by exploring the `/plugins/hikashoppayment/` folder of your installation.

### How to create a HikaShop Shipping plugin

First, we invite you to read the information on the [Shipping API](#shipping) section.

Then, you can go to the [Example Shipping Plugin GitHub](https://github.com/hikashop-nicolas/plg_hikashopshipping_example) and look at the files. Each line of the plugin is documented, explaining how a shipping plugin should be structured. It covers advanced topics like multiple packages, custom HTML selection, and automated carrier export.

You can also study the source code of shipping plugins included in HikaShop by exploring the `/plugins/hikashopshipping/` folder of your installation.

### Order API

Available events for the Order API:

> - [onBeforeOrderCreate(&amp;$order, &amp;$do)](#onBeforeOrderCreate)
> - [onBeforeOrderUpdate(&amp;$order, &amp;$do)](#onBeforeOrderUpdate)
> - [onBeforeOrderDelete(&amp;$elements, &amp;$do)](#onBeforeOrderDelete)
> - [onAfterOrderCreate(&amp;$order, &amp;$send\_email)](#onAfterOrderCreate)
> - [onAfterOrderConfirm(&amp;$order, &amp;$methods, $method\_id)](#onAfterOrderConfirm)
> - [onAfterOrderUpdate(&amp;$order, &amp;$send\_email)](#onAfterOrderUpdate)
> - [onAfterOrderDelete($elements)](#onAfterOrderDelete)
> - [onAfterInvoiceCreate(&amp;$order)](#onAfterInvoiceCreate)
> - [onHistoryDisplay(&amp;$history)](#onHistoryDisplay)
> - [onBeforeOrderExport(&amp;$rows, &amp;$this)](#onBeforeOrderExport)
> - [onBeforeOrderNumberGenerate(&amp;$data, &amp;$result)](#onBeforeOrderNumberGenerate)
> - [onBeforeInvoiceNumberGenerate(&amp;$data, &amp;$result)](#onBeforeInvoiceNumberGenerate)
> - [onBeforeOrderProductsUpdate(&amp;$order, &amp;$do)](#onBeforeOrderProductsUpdate)
> - [onBeforeOrderPaymentCapture(&amp;$order, $order\_full\_price, &amp;$order\_capture\_price, &amp;$do)](#onBeforeOrderPaymentCapture)
> - [onBeforeOrderListing($paramBase, &amp;$extrafilters, &amp;$pageInfo, &amp;$filters, &amp;$tables, &amp;$searchMap, &amp;$select)](#onBeforeOrderListing)
> - [onBeforeCalculateProductPriceForQuantityInOrder(&amp;$orderProduct)](#onBeforeCalculateProductPriceForQuantityInOrder)
> - [onAfterCalculateProductPriceForQuantityInOrder(&amp;$orderProduct)](#onAfterCalculateProductPriceForQuantityInOrder)
> - [onAfterLoadFullOrder(&amp;$order)](#onAfterLoadFullOrder)
> - [onAfterOrderListing(&amp;$rows, &amp;$extrafields, $pageInfo)](#onAfterOrderListing)
> - [onBeforeModifyOrder(&amp;$order, &amp;$order\_status, &amp;$history, &amp;$email)](#onBeforeModifyOrder)
> - [onBeforeCreateRecurringSuborder($order\_id, &amp;$order)](#onBeforeCreateRecurringSuborder)
> - [onBeforeOrderExportQuery(&amp;$filters, $paramBase)](#onBeforeOrderExportQuery)
> - [onBeforeFrontendOrderListing($paramBase, &amp;$pageInfo, &amp;$filters, &amp;$searchMap)](#onBeforeFrontendOrderListing)
> - [onHikashopOrderTrackingDisplay($order)](#onHikashopOrderTrackingDisplay)
> - [onHikashopThankYouDisplay(&amp;$order, &amp;$blocks)](#onHikashopThankYouDisplay)

Functions are called if they exist; you don't have to define them all.
These functions are triggered by HikaShop when an order is saved or deleted. The cron task is only available on commercial versions of HikaShop.

#### onBeforeOrderCreate(&amp;$order, &amp;$do)

Triggered before a new order is saved. The `$order` object contains the full order data. Setting `$do` to `false` cancels the order creation.

- `&$order`: The order object.
- `&$do`: A boolean. Set it to `false` to cancel the order creation.

#### onBeforeOrderUpdate(&amp;$order, &amp;$do)

Triggered before an existing order is updated. The `$order` object contains the updated information. Setting `$do` to `false` cancels the update.

- `&$order`: The order object.
- `&$do`: A boolean. Set it to `false` to cancel the update.

#### onBeforeOrderDelete(&amp;$elements, &amp;$do)

Triggered before one or several orders are deleted. `$elements` is an array of order IDs. Setting `$do` to `false` cancels the deletion.

- `&$elements`: An array of order IDs to be deleted.
- `&$do`: A boolean. Set it to `false` to cancel the deletion.

#### onAfterOrderCreate(&amp;$order, &amp;$send\_email)

Triggered after an order is successfully created. The `$order` object contains the full order data. Setting `$send_email` to `false` prevents the customer notification email.

- `&$order`: The order object.
- `&$send_email`: A boolean. Set it to `false` to prevent the customer notification email.

#### onAfterOrderConfirm

This event belongs to the payment plugin of the method the customer chose. It is documented with the other payment events, under [the Payment API](#onAfterOrderConfirm).

#### onAfterOrderUpdate(&amp;$order, &amp;$send\_email)

Triggered after an order is updated. The `$order` object contains the updated information. Setting `$send_email` to `false` prevents the status change notification email.

- `&$order`: The order object.
- `&$send_email`: A boolean. Set it to `false` to prevent the status change notification email.

#### onAfterOrderDelete($elements)

Triggered after one or several orders are deleted. `$elements` is either a single ID or an array of order IDs.

- `$elements`: A single order ID or an array of order IDs.

#### onAfterInvoiceCreate(&amp;$order)

Triggered after an invoice is generated for an order. This usually happens when the order status changes to "confirmed" or "shipped".

#### onAfterLoadFullOrder(&amp;$order)

Triggered after an order is fully loaded from the database, including its products, addresses, and history. `$order` is the complete order object. This is a good place to add custom fields or other data to the order object, or to modify the order object before it is used.

- `&$order`: The complete order object.

#### onBeforeOrderProductsUpdate(&amp;$order, &amp;$do)

Triggered before the products of an order are updated in the database (e.g., when editing an order in the backend).

- `&$order`: The order object containing the modified `product` array.
- `&$do`: A boolean. Set it to `false` to cancel the products update.

#### onHistoryDisplay(&amp;$history)

Triggered when the history of an order is displayed in the backend. You can use it to modify the `$history` object before display.

#### onBeforeOrderExport(&amp;$rows, &amp;$obj)

Triggered before orders are exported. `$rows` contains the array of order objects to be exported.

#### onBeforeOrderNumberGenerate(&amp;$data, &amp;$result)

Triggered during order creation to generate the order number. `$data` contains the order attributes. You can set a custom order number in `$result` to override the default HikaShop format.

#### onBeforeInvoiceNumberGenerate(&amp;$data, &amp;$result)

Triggered when an invoice number is generated. `$data` contains the order attributes. Set custom text in `$result` to override the default invoice number format.

#### onBeforeOrderPaymentCapture(&amp;$order, $order\_full\_price, &amp;$order\_capture\_price, &amp;$do)

Triggered before a payment capture is processed (for payment methods supporting authorization/capture).

- `&$order`: The order object.
- `$order_full_price`: The total amount of the order.
- `&$order_capture_price`: The amount to be captured. You can modify this value.
- `&$do`: A boolean. Set it to `false` to cancel the capture.

#### onBeforeOrderListing($paramBase, &amp;$extrafilters, &amp;$pageInfo, &amp;$filters, &amp;$tables, &amp;$searchMap, &amp;$select)

Triggered before running the database query to load orders in the backend. You can modify the query (adding conditions, joins, etc.) or add custom filters to the listing.

To add a custom filter, register your plugin in the `$extrafilters` array and implement a `displayFilter` function.

```
class plgHikashopName extends JPlugin {
    function onBeforeOrderListing($paramBase, &$extrafilters, &$pageInfo, &$filters, &$tables, &$searchMap, &$select) {
        // Register for extra filter display
        $extrafilters['my_extra_filter'] = $this;

        $app = JFactory::getApplication();
        $pageInfo->filter->filter_order_published = $app->getUserStateFromRequest($paramBase.".filter_order_published", 'filter_order_published', 1, 'int');

        if(!empty($pageInfo->filter->filter_order_published)) {
            $filters[] = 'b.order_published = ' . (int)$pageInfo->filter->filter_order_published;
        }
    }

    function displayFilter($name, $info) {
        if($name == 'my_extra_filter') {
            $values = array(
                JHTML::_('select.option', '0', JText::_('HIKA_ALL')),
                JHTML::_('select.option', '1', JText::_('HIKA_PUBLISHED')),
                JHTML::_('select.option', '-1', JText::_('HIKA_UNPUBLISHED')),
            );
            return JHTML::_('select.genericlist', $values, 'filter_order_published', 'onchange="document.adminForm.submit();"', 'value', 'text', @$info->filter_order_published, 'order_published');
        }
    }
}
```

You can refer to the [Orders Product Filter](https://www.hikashop.com/marketplace/product/272-orders-product-filter.html) plugin for a complete example.

#### onBeforeCalculateProductPriceForQuantityInOrder(&amp;$orderProduct)

Triggered during order creation before calculating the total price of a product in the order. `$orderProduct` contains the product details and its unit price.

- `&$orderProduct`: The order product object.

#### onAfterCalculateProductPriceForQuantityInOrder(&amp;$orderProduct)

Triggered after calculating the total price of a product in the order. You can use it to override the `order_product_total_price` and `order_product_total_price_no_vat` values.

- `&$orderProduct`: The order product object.

#### onAfterOrderListing(&amp;$rows, &amp;$extrafields, $pageInfo)

Triggered once the order listing of your backend has loaded its orders, so that you can add your own column to it.

- `&$rows`: The orders being displayed.
- `&$extrafields`: The extra columns of the listing. Add yours to display it.
- `$pageInfo`: The pagination, the filters and the sort order of the listing.

#### onBeforeModifyOrder(&amp;$order, &amp;$order\_status, &amp;$history, &amp;$email)

Triggered when the status of an order is about to change, before anything is written. Change the status, the history entry it will record, or the email the customer receives.

- `&$order`: The order, carrying the history entry about to be added.
- `&$order_status`: The status the order will move to.
- `&$history`: The history entry recording the change.
- `&$email`: The email about to be sent, or false when none is.

#### onBeforeCreateRecurringSuborder($order\_id, &amp;$order)

Triggered before a new order is created for the next term of a subscription. Change the order about to be created, or its products, to make the renewal differ from the original.

- `$order_id`: The order the subscription started from.
- `&$order`: The renewal order about to be created.

#### onBeforeOrderExportQuery(&amp;$filters, $paramBase)

Triggered when orders are exported from your backend, so that you can restrict what the export contains.

- `&$filters`: The WHERE clauses of the export query.
- `$paramBase`: The parameter prefix of the listing the export was started from.

#### onBeforeFrontendOrderListing($paramBase, &amp;$pageInfo, &amp;$filters, &amp;$searchMap)

Triggered before the order history a customer sees on your website is loaded, so that you can change which orders it lists or what the search looks into.

- `$paramBase`: The parameter prefix of the listing.
- `&$pageInfo`: The pagination, the filters and the sort order.
- `&$filters`: The WHERE clauses of the query.
- `&$searchMap`: The columns the search box looks into.

#### onHikashopOrderTrackingDisplay($order)

Triggered on the thank you page displayed once an order is placed. It is where an analytics or conversion tracking plugin outputs its code, with the order available to it.

- `$order`: The order that was just placed. `$order->thankyou_first_view` is true on the first display of the page only, false on a reload or when the customer opens it again, so that a purchase is counted once.

#### onHikashopThankYouDisplay(&amp;$order, &amp;$blocks)

Triggered on the thank you page, before its order summary. A plugin adds a block of its own (downloads, licences, a booking's details...) to `$blocks`.

- `&$order`: The order, as loaded by the order class (products, addresses, customer).
- `&$blocks`: An array to add to: each block is an array with a `title` (may be empty) and its `html`.

A payment plugin gives the page its own part (bank details, where to send a check...) with a `getThankYouContent(&$order)` method, returning the HTML, or an array with `html`, optional `steps` (an array of array(title, text)) and `awaiting_payment` (true while the customer still has to pay). A payment method with that method ends the checkout on the thank you page.

A template can word the page for its trade (a stay instead of an order, for example) with a language file of its own, `templates/<template>/language/<tag>/tpl_<template>_thankyou.ini` (on WordPress, `wp-content/themes/<theme>/language/<tag>.tpl_<theme>_thankyou.ini`), redefining the keys of the page (HIKA\_THANKYOU\_\*, ORDER\_NUMBER, SUMMARY\_OF\_YOUR\_ORDER...). It is loaded when the page is prepared, before the payment method gives its part, and the site's language overrides still come first.

### Product API

This API allows you to perform actions when products are created, updated, deleted, or displayed.

Available events for the Product API:

> - [onBeforeProductCreate(&amp;$element,&amp;$do)](#onBeforeProductCreate)
> - [onAfterProductCreate(&amp;$element)](#onAfterProductCreate)
> - [onBeforeProductUpdate(&amp;$element,&amp;$do)](#onBeforeProductUpdate)
> - [onAfterProductUpdate(&amp;$element)](#onAfterProductUpdate)
> - [onBeforeProductDelete(&amp;$ids,&amp;$do)](#onBeforeProductDelete)
> - [onAfterProductDelete(&amp;$ids)](#onAfterProductDelete)
> - [onBeforeProductListingLoad(&amp;$filters,&amp;$order,&amp;$view,&amp;$select,&amp;$select2,&amp;$a,&amp;$b,&amp;$on)](#onBeforeProductListingLoad)
> - [onBeforeProductCopy(&amp;$template,&amp;$product,&amp;$do)](#onBeforeProductCopy)
> - [onAfterProductCopy(&amp;$template,&amp;$product)](#onAfterProductCopy)
> - [onBeforeProductExport(&amp;$products,&amp;$categories,&amp;$this)](#onBeforeProductExport)
> - [onBeforeLoadProductPrice(&amp;$filters,&amp;$rows,&amp;$options)](#onBeforeLoadProductPrice)
> - [onAfterLoadProductPrice(&amp;$prices,&amp;$rows,&amp;$filters,&amp;$options)](#onAfterLoadProductPrice)
> - [onBeforeLoadProductPriceDiscount(&amp;$filters, $rows, $trigger\_options)](#onBeforeLoadProductPriceDiscount)
> - [onAfterLoadProductPriceDiscount(&amp;$discounts, &amp;$rows, $filters, $trigger\_options)](#onAfterLoadProductPriceDiscount)
> - [onBeforeCalculateProductPriceForQuantity(&amp;$product)](#onBeforeCalculateProductPriceForQuantity)
> - [onAfterCalculateProductPriceForQuantity(&amp;$product)](#onAfterCalculateProductPriceForQuantity)
> - [onAfterProductCharacteristicsLoad(&amp;$product, &amp;$mainCharacteristics, &amp;$characteristics)](#onAfterProductCharacteristicsLoad)
> - [onAfterVariantChecked(&amp;$variant, &amp;$element)](#onAfterVariantChecked)
> - [onAfterVariantsCreation($product\_id, $new\_variants\_ids, $element)](#onAfterVariantsCreation)
> - [onHkContentParse(&amp;$description, $description\_type)](#onHkContentParse)
> - [onHkContentParserLoad(&amp;$plugin\_values)](#onHkContentParserLoad)
> - [onProductLayoutSelect(&amp;$values)](#onProductLayoutSelect)
> - [onBeforeProductStockUpdate(&amp;$updates, $cancel)](#onBeforeProductStockUpdate)

#### onBeforeProductCreate(&amp;$element, &amp;$do)

Triggered before a product is created. `$element` contains the product data. Setting `$do` to `false` cancels the creation.

- `&$element`: The product object to be created.
- `&$do`: A boolean. Set it to `false` to cancel the product creation.

#### onAfterProductCreate(&amp;$element)

Triggered after a product is successfully created. `$element` includes the new `product_id`.

- `&$element`: The created product object.

#### onBeforeProductUpdate(&amp;$element, &amp;$do)

Triggered before a product is updated. `$element` contains the updated data. Setting `$do` to `false` cancels the update.

- `&$element`: The product object to be updated.
- `&$do`: A boolean. Set it to `false` to cancel the update.

#### onAfterProductUpdate(&amp;$element)

Triggered after a product is successfully updated.

#### onBeforeProductDelete(&amp;$ids, &amp;$do)

Triggered before one or more products are deleted. `$ids` is an array of product IDs. Setting `$do` to `false` cancels the deletion.

- `&$ids`: An array of product IDs to be deleted.
- `&$do`: A boolean. Set it to `false` to cancel the deletion.

#### onAfterProductDelete(&amp;$ids)

Triggered after one or more products are successfully deleted.

#### onBeforeProductListingLoad(&amp;$filters, &amp;$order, &amp;$view, &amp;$select, &amp;$select2, &amp;$a, &amp;$b, &amp;$on)

Triggered when products are loaded for a listing on the frontend. You can modify the query parts before it's executed.

- `&$filters`: An array of WHERE clauses (strings).
- `&$order`: The ORDER BY clause (string).
- `&$view`: The current view object.
- `&$select`: The main SELECT part (string).
- `&$select2`: Additional SELECT parts (string).
- `&$a`: The table alias for `product_category` (string).
- `&$b`: The table alias for `product` (string).
- `&$on`: The JOIN/ON clause (string).

You can also add a `LEFT JOIN` by appending it to the `$on` variable:

```
$on .= ' LEFT JOIN #__hikashop_price AS p ON b.product_id = p.price_product_id';
$order = ' p.price_value ASC';
```

#### onBeforeProductCopy(&amp;$template, &amp;$product, &amp;$do)

Triggered before copying a product. You can update the `$template` or the `$product` values. Setting `$do` to `false` cancels the copy.

- `&$template`: The product object used as a template for the copy.
- `&$product`: The product object being copied.
- `&$do`: A boolean. Set it to `false` to cancel the copy.

#### onAfterProductCopy(&amp;$template, &amp;$product)

Triggered after a product is successfully copied.

- `&$template`: The template product object.
- `&$product`: The newly created product object.

#### onBeforeProductExport(&amp;$products, &amp;$categories, &amp;$obj)

Triggered before products are exported. `$products` and `$categories` contain the respective objects to be exported.

- `&$products`: An array of product objects to be exported.
- `&$categories`: An array of category objects associated with the products.
- `&$obj`: The export object.

#### onBeforeLoadProductPrice(&amp;$filters, &amp;$rows, &amp;$options)

Triggered before HikaShop loads prices for a list of products. You can modify the `$filters` or `$options` to change which prices are loaded.

- `&$filters`: An array of WHERE clauses for the price query.
- `&$rows`: The product rows for which prices are being loaded.
- `&$options`: An array of options (zone\_id, currency\_id, etc).

#### onAfterLoadProductPrice(&amp;$prices, &amp;$rows, &amp;$filters, &amp;$options)

Triggered after HikaShop has loaded prices. `$prices` is an array of price objects.

- `&$prices`: The loaded price objects.
- `&$rows`: The product rows.
- `&$filters`: The filters used for the query.
- `&$options`: The options used for the query.

#### onBeforeCalculateProductPriceForQuantity(&amp;$product)

Triggered before calculating the unit price of a product based on the quantity in the cart. `$product` contains the product data and its available prices.

- `&$product`: The product object containing its prices and the quantity in the cart.

#### onAfterCalculateProductPriceForQuantity(&amp;$product)

Triggered after calculating the unit price. You can use it to override the final unit price chosen by HikaShop.

- `&$product`: The product object with its calculated unit price.

#### onAfterProductCharacteristicsLoad(&amp;$product, &amp;$mainCharacteristics, &amp;$characteristics)

Triggered once the characteristics of a product have been loaded for the cart, so that you can change which ones are offered.

- `&$product`: The product the characteristics belong to.
- `&$mainCharacteristics`: The characteristics of the main product.
- `&$characteristics`: The characteristics loaded.

#### onAfterVariantChecked(&amp;$variant, &amp;$element)

Triggered once a variant has been prepared for display, with its name built from its characteristics and its stock settled. Change the variant before it reaches the page.

- `&$variant`: The variant, with its name and its quantity resolved.
- `&$element`: The main product it belongs to.

#### onAfterVariantsCreation($product\_id, $new\_variants\_ids, $element)

Triggered once HikaShop has generated the variants of a product from its characteristics, so that you can complete what it created.

- `$product_id`: The main product.
- `$new_variants_ids`: The ids of the variants just created.
- `$element`: The main product object.

#### onHkContentParse(&amp;$description, $description\_type)

Triggered when the description of a product written in another syntax has to be turned into HTML. A plugin providing that syntax replaces the description with the HTML it produces.

- `&$description`: The description to parse, replaced by the HTML.
- `$description_type`: The syntax it is written in.

#### onHkContentParserLoad(&amp;$plugin\_values)

Triggered when HikaShop lists the syntaxes a description can be written in, HTML being the only one it provides. Register yours to have it offered on the product form.

- `&$plugin_values`: The syntaxes, keyed by name, each giving its plugin and its editor.

#### onProductLayoutSelect(&amp;$values)

Triggered when the layouts a product listing can use are listed. Add an entry to offer a layout of your own.

- `&$values`: The layouts available, as an array of select options.

#### onBeforeProductStockUpdate(&amp;$updates, $cancel)

Triggered before the stock and the sales counters of the products of an order are changed, whether the order is being placed or cancelled. Change the updates to decide what is written.

- `&$updates`: The stock and sales changes about to be applied, per product.
- `$cancel`: True when the order is being cancelled and the stock given back.

### <a name="category"></a>Category API

This API allows you to perform actions when categories are created, updated, or deleted.

Available events for the Category API:

- [onBeforeCategoryCreate(&amp;$element,&amp;$do)](#onBeforeCategoryCreate)
- [onAfterCategoryCreate(&amp;$element)](#onAfterCategoryCreate)
- [onBeforeCategoryUpdate(&amp;$element,&amp;$do)](#onBeforeCategoryUpdate)
- [onAfterCategoryUpdate(&amp;$element)](#onAfterCategoryUpdate)
- [onBeforeCategoryDelete(&amp;$ids,&amp;$do)](#onBeforeCategoryDelete)
- [onAfterCategoryDelete(&amp;$ids)](#onAfterCategoryDelete)
- [onBeforeCategoryListingLoad(&amp;$filters, &amp;$order, &amp;$parentObject, &amp;$leftjoin)](#onBeforeCategoryListingLoad)

#### onBeforeCategoryCreate(&amp;$element, &amp;$do)

Triggered before a category is created. `$element` contains the category data. Setting `$do` to `false` cancels the creation.

- `&$element`: The category object to be created.
- `&$do`: A boolean. Set it to `false` to cancel the creation.

#### onAfterCategoryCreate(&amp;$element)

Triggered after a category is successfully created. The `$element` object includes the new `category_id`.

- `&$element`: The created category object.

#### onBeforeCategoryUpdate(&amp;$element, &amp;$do)

Triggered before a category is updated. `$element` contains the updated data. Setting `$do` to `false` cancels the update.

- `&$element`: The category object with updated information.
- `&$do`: A boolean. Set it to `false` to cancel the update.

#### onAfterCategoryUpdate(&amp;$element)

Triggered after a category is successfully updated.

- `&$element`: The updated category object.

#### onBeforeCategoryDelete(&amp;$ids, &amp;$do)

Triggered before one or more categories are deleted. `$ids` is an array of category IDs. Setting `$do` to `false` cancels the deletion.

- `&$ids`: An array of category IDs to be deleted.
- `&$do`: A boolean. Set it to `false` to cancel the deletion.

#### onAfterCategoryDelete(&amp;$ids)

Triggered after one or more categories are successfully deleted.

- `&$ids`: An array of deleted category IDs.

#### onBeforeCategoryListingLoad(&amp;$filters, &amp;$order, &amp;$parentObject, &amp;$leftjoin)

Triggered when categories are loaded for display on frontend and backend listings. The `$filters` variable is an array of conditions used to form the MySQL query. You can modify this array to change how categories are loaded by adding or removing conditions.

- `&$filters`: An array of WHERE clauses (strings) for the category query.
- `&$order`: The ORDER BY clause for the query.
- `&$parentObject`: The parent object (usually a category) context for the listing.
- `&$leftjoin`: An array of LEFT JOIN clauses added to the query.

### <a name="address"></a>Address API

This API allows you to perform actions when addresses are created, updated, or deleted.

Available events for the Address API:

> - [onBeforeAddressCreate(&amp;$element,&amp;$do)](#onBeforeAddressCreate)
> - [onBeforeAddressUpdate(&amp;$element,&amp;$do)](#onBeforeAddressUpdate)
> - [onAfterAddressCreate(&amp;$element)](#onAfterAddressCreate)
> - [onAfterAddressUpdate(&amp;$element)](#onAfterAddressUpdate)
> - [onBeforeAddressDelete(&amp;$ids,&amp;$do)](#onBeforeAddressDelete)
> - [onAfterAddressDelete(&amp;$ids)](#onAfterAddressDelete)
> - [onUserAddressesLoad(&amp;$addresses, $user\_id, $type)](#onUserAddressesLoad)
> - [onUserAddressLoad(&amp;$address, $address\_id)](#onUserAddressLoad)

#### onBeforeAddressCreate(&amp;$element, &amp;$do)

Triggered before an address is created. The `$element` object contains the address information. Setting `$do` to `false` cancels the creation.

- `&$element`: The address object to be created.
- `&$do`: A boolean. Set it to `false` to cancel the creation.

#### onBeforeAddressUpdate(&amp;$element, &amp;$do)

Triggered before an address is updated. The `$element` object contains the new address information. Setting `$do` to `false` cancels the update.

- `&$element`: The address object with updated information.
- `&$do`: A boolean. Set it to `false` to cancel the update.

#### onAfterAddressCreate(&amp;$element)

Triggered after an address is successfully created. The `$element` object contains the address information, including the new `address_id`.

- `&$element`: The created address object.

#### onAfterAddressUpdate(&amp;$element)

Triggered after an address is successfully updated. The `$element` object contains the updated address information.

- `&$element`: The updated address object.

#### onBeforeAddressDelete(&amp;$ids, &amp;$do)

Triggered before one or more addresses are deleted. The `$ids` variable is an array of address IDs. Setting `$do` to `false` cancels the deletion.

- `&$ids`: An array of address IDs to be deleted.
- `&$do`: A boolean. Set it to `false` to cancel the deletion.

#### onAfterAddressDelete(&amp;$ids)

Triggered after one or more addresses are successfully deleted. The `$ids` variable is an array of address IDs.

- `&$ids`: An array of deleted address IDs.

#### onUserAddressesLoad(&amp;$addresses, $user\_id, $type)

Triggered when HikaShop loads user addresses (e.g., when displaying the address selection during checkout).

- `&$addresses`: An array of address objects found in the database. You can modify this array (add, remove, or change address objects).
- `$user_id`: The ID of the user whose addresses are being loaded.
- `$type`: The type of addresses being loaded ("both", "billing", or "shipping").

#### onUserAddressLoad(&amp;$address, $address\_id)

Triggered when HikaShop loads a single address from the database.

- `&$address`: The address object.
- `$address_id`: The ID of the address being loaded.

### Shipping API

This API allows you to perform actions related to shipping methods and price calculations.

Available events for the Shipping API:

- [onShippingDisplay(&amp;$order, &amp;$methods, &amp;$available\_methods, &amp;$errors)](#onShippingDisplay)
- [onShippingSave(&amp;$order, &amp;$methods, &amp;$shipping\_id)](#onShippingSave)
- [onShippingConfiguration(&amp;$element)](#onShippingConfiguration)
- [onShippingConfigurationSave(&amp;$element)](#onShippingConfigurationSave)
- [shippingMethods(&amp;$method)](#shippingMethods)
- [onAfterProcessShippings(&amp;$usable\_rates, &amp;$cart)](#onAfterProcessShippings)
- [onShippingWarehouseFilter(&amp;$shipping\_groups, &amp;$order, &amp;$rates)](#onShippingWarehouseFilter)

#### onShippingDisplay(&amp;$order, &amp;$methods, &amp;$available\_methods, &amp;$errors)

Triggered when shipping methods are displayed during checkout. `$available_methods` contains the methods that will be shown to the customer.

- `&$order`: The order object.
- `&$methods`: An array of eligible shipping method objects.
- `&$available_methods`: An array of shipping methods that will be available for selection.
- `&$errors`: An array of error messages, to explain why no method was found.

Suppose that you are making a shipping plugin for a shipping service like UPS. Here, you would first filter your method options out of the $methods array. Then, connect to the UPS web service to decide, based on the $order information, what shipping methods are possible, and finally add them to the $usable\_methods. And if the UPS server returns several shipping services for a situation, you can potentially clone the method object to have several of them in $usable\_methods. And since you can't have two shipping methods with the same id, you'll have to append an extra code for each cloned shipping method's shipping\_id, and then implement the shippingMethods method in your plugin to provide HikaShop with a list of the possible ids. We would recommend you check the code of plugins/hikashopshipping/ups2 as this is not easy to do without basing yourself on an example.

You can add error messages to the $messages in case no shipping methods were found.

For some shipping carriers, you'll have to propose a selection mechanism (for example, to select a pickup point via a widget provided by the carrier API). You can do so by adding your HTML in an attribute "custom\_html" in the object of the shipping method, before adding it to the $usable\_methods array. In it, you'll want to have a hidden input with the name constructed like this:

```
$name = 'checkout[shipping][custom]'.(isset($order->shipping_warehouse_id) ? ('['.$order->shipping_warehouse_id.']') : '').'['.$rate->shipping_id.']';
```

This way, HikaShop will display your custom HTML automatically when the shipping method of your plugin is displayed. It will also save it into the cart automatically for you. The data will be available in $cart-&gt;cart\_params-&gt;shipping in places where the cart object is available.
Also, you can implement the method onShippingCustomSave($cart, $method, $group, $data) in your plugin. This method will be called when the checkout receives the data from the hidden input in your custom\_html. $cart will contain the cart data, $method will contain the data of your shipping method. $group will be the warehouse id, and $data will be the data provided by your hidden input. If your method returns false, you can prevent HikaShop from saving the data in $cart-&gt;cart\_params-&gt;shipping.

If you wish to display an error message to the customer when the hidden input of your custom html is not filled, you can implement the onBeforeCartSave event of the Cart API in your plugin. There, check if check if data is provided in the correct subarray (based on the warehouse id and the shipping id of your shipping method). If checkout\[shipping\]\[custom\] is available in the POST but the data is not provided in the correct subarray, then you can cancel the cart save and use the enqueueMessage method to display an error message to the user.

#### onShippingSave(&amp;$order, &amp;$methods, &amp;$shipping\_id)

Triggered when the shipping method is saved during checkout. `$shipping_id` is the ID of the selected shipping method.

- `&$order`: The order object.
- `&$methods`: The array of shipping methods.
- `&$shipping_id`: The selected shipping method ID (string).

Suppose that you are making a shipping plugin for a shipping service like UPS. Here, you would first filter your method options out of the $methods array. Then, you could get the list of usable methods that you would have cached in the session in the function onShippingDisplay and see if the selected method is in them.

#### onShippingConfiguration(&amp;$element)

Triggered on the backend shipping method configuration page. Use this to display additional configuration fields.

- `&$element`: The shipping method object.

#### onShippingConfigurationSave(&amp;$element)

Triggered when the shipping method configuration is saved in the backend. In most cases, you won't have to use this function.

- `&$element`: The shipping method object being saved.

#### shippingMethods(&amp;$method)

Triggered when a dropdown of shipping methods is displayed (e.g., in payment plugins' "shipping methods" option or order details). Return an array like `array('ID1'=>'Name 1','ID2'=>'Name 2')`.

- `&$method`: The shipping method plugin instance.

You can look at the UPS shipping plugin for an example of implementation.

#### onAfterProcessShippings(&amp;$usable\_rates, &amp;$cart)

Triggered after usable shipping methods have been determined. Allows reprocessing or extra modifications once available shipping methods are known.

- `&$usable_rates`: An array of usable shipping rate objects.
- `&$cart`: The cart object.

#### onShippingWarehouseFilter(&amp;$shipping\_groups, &amp;$order, &amp;$rates)

Triggered once the products of an order have been split into shipping groups, one per warehouse. Change the groups to decide what is shipped together and therefore how many shipping methods the customer is asked for.

- `&$shipping_groups`: The groups of products, keyed by warehouse id.
- `&$order`: The order object.
- `&$rates`: The shipping rates available.

### Payment API

This API allows you to perform actions related to payment methods and price calculations.

Available events for the Payment API:

- [onPaymentDisplay(&amp;$order, &amp;$methods, &amp;$available\_methods)](#onPaymentDisplay)
- [onPaymentSave(&amp;$order, &amp;$methods, &amp;$payment\_id)](#onPaymentSave)
- [onPaymentConfiguration(&amp;$element)](#onPaymentConfiguration)
- [onPaymentConfigurationSave(&amp;$element)](#onPaymentConfigurationSave)
- [onAfterOrderConfirm(&amp;$order,&amp;$methods,$method\_id)](#onAfterOrderConfirm)
- [onPaymentNotification(&amp;$statuses)](#onPaymentNotification)
- [onAfterProcessPayments(&amp;$usable\_rates, &amp;$cart)](#onAfterProcessPayments)
- [onCheckPaymentOptions(&amp;$paymentOptions, &amp;$order)](#onCheckPaymentOptions)

#### onPaymentDisplay(&amp;$order, &amp;$methods, &amp;$available\_methods)

Triggered when payment methods are displayed during checkout. `$available_methods` contains the methods that will be shown to the customer.

- `&$order`: The order object.
- `&$methods`: An array of eligible payment method objects.
- `&$available_methods`: An array of payment methods that will be available for selection.

#### onPaymentSave(&amp;$order, &amp;$methods, &amp;$payment\_id)

Triggered when a payment method is saved during checkout. `$payment_id` is the ID of the selected payment method.

- `&$order`: The order object.
- `&$methods`: The array of payment methods.
- `&$payment_id`: The selected payment method ID (string).

#### onPaymentConfiguration(&amp;$element)

Triggered on the backend payment method configuration page. Use this to display additional configuration fields.

- `&$element`: The payment method object.

#### onPaymentConfigurationSave(&amp;$element)

Triggered when the payment method configuration is saved in the backend. In most cases, you won't have to use this function.

- `&$element`: The payment method object being saved.

#### onAfterOrderConfirm(&amp;$order,&amp;$methods,$method\_id)

Triggered when the order payment is confirmed. This is usually where you initiate the redirect to the payment gateway or perform final processing.

- `&$order`: The order object.
- `&$methods`: An array of eligible method objects (payment or shipping).
- `$method_id`: The ID of the selected method.

In the information sent to it, you will probably be able to specify a notification url. You might want to use a url like this: http://yourwebsite.com/index.php?option=com\_hikashop&amp;ctrl=checkout&amp;task=notify&amp;notif\_payment=PAYMENT\_PLUGIN\_NAME&amp;tmpl=component&amp;lang=CURRENT\_LANG\_CODE where PAYMENT\_PLUGIN\_NAME and yourwebsite.com need to be replaced by your information. That will allow you to have the function onPaymentNotification of your plugin being triggered when hikashop receives a notification. Also, we highly recommend to add the lang parameter and replace CURRENT\_LANG\_CODE with the current 2 letter code of the current language so that the "status changed" email going to the user will be translated in the user's language.

We invite you to look at the paypal payment plugin for an example of implementation

#### onPaymentNotification(&amp;$statuses)

Triggered when a payment notification (webhook) is received for your plugin. Here you will have to make sure that the notification is secure and then you will be able to update the order based on the payment information.

- `&$statuses`: An array containing the available order statuses. You can map the gateway status to a HikaShop order status.

#### onAfterProcessPayments(&amp;$usable\_rates, &amp;$cart)

Triggered after payment methods have been processed and their prices (including taxes) calculated.

- `&$usable_rates`: Array of processed payment method objects.
- `&$cart`: The current cart object.

#### onCheckPaymentOptions(&amp;$paymentOptions, &amp;$order)

Triggered when HikaShop asks what the payment of an order supports. A payment plugin sets the entries of $paymentOptions it can handle, and the backend then offers the matching buttons on the order.

- `&$paymentOptions`: An array with the keys recurring, term and refund, each false by default.
- `&$order`: The order object.

### UCP (Universal Commerce Protocol)

The [Universal Commerce Protocol (UCP)](https://ucp.dev/) allows AI agents to discover, search, and purchase products on your store. HikaShop implements UCP through a system plugin that exposes REST API endpoints. Payment plugins can opt into UCP by implementing one or more of the following methods. All three are optional.

For a complete setup guide and flow diagrams, see the [UCP tutorial](https://www.hikashop.com/support/documentation/529-universal-commerce-protocol.html). The [Example Payment Plugin](https://github.com/hikashop-nicolas/plg_hikashoppayment_example) also contains documented implementations of all three methods.

Available methods for UCP support:

- [getPaymentURL(&amp;$order, &amp;$method)](#getPaymentURL)
- [onUcpPaymentProcess(&amp;$order, &amp;$paymentContext, &amp;$paymentResult)](#onUcpPaymentProcess)
- [getUcpGooglePayConfig()](#getUcpGooglePayConfig)

#### getPaymentURL(&amp;$order, &amp;$method)

Called by the UCP plugin when an AI agent completes a checkout **without** providing a payment token (hosted checkout flow). The method should create a hosted checkout session on the payment gateway and return the URL where the customer will be redirected to complete payment.

- `&$order`: The HikaShop order object (with `order_id`, `order_full_price`, `order_currency_id`, etc.).
- `&$method`: The payment method object with its parameters in `payment_params`.

**Return value**: A URL string on success, or `false` on failure. On failure, set `$this->last_error` with the error message.

Typically, you will also want to store the gateway's session/checkout ID in `order_payment_params` so that the `onPaymentNotification` method can look up the order when the gateway sends a webhook after the customer pays.

#### onUcpPaymentProcess(&amp;$order, &amp;$paymentContext, &amp;$paymentResult)

Called by the UCP plugin when an AI agent completes a checkout **with** a payment token (e.g., a Google Pay token). The method should charge the token via the payment gateway's API.

- `&$order`: The HikaShop order object.
- `&$paymentContext`: An associative array containing:
- `'credential'`: Array with `'token'` (the encrypted payment token) and `'type'`.
- `'handler_id'`: The payment handler identifier (e.g., `'com.google.pay'`).
- `'payment_instrument'`: Information about the payment instrument (card brand, last digits, etc.).
- `'risk_signals'`: Optional risk assessment data from the AI platform.
- `&$paymentResult`: An object to populate with the payment outcome:
- `success` (bool): Whether the payment succeeded.
- `message` (string): Error message on failure.
- `transaction_id` (string): The gateway's transaction ID on success.
- `requires_redirect` (bool): Set to `true` if a 3D Secure challenge is required.
- `continue_url` (string): The 3DS challenge URL when `requires_redirect` is `true`.

**Important**: Always check that `$order->order_payment_method === $this->name` at the start and return early if it doesn't match, since all payment plugins receive this event.

#### getUcpGooglePayConfig()

Called by the UCP plugin during discovery (`GET /.well-known/ucp`) to detect whether this payment plugin supports Google Pay tokenization. The UCP plugin iterates over all published payment methods and calls this method on each one. The first non-null result is used.

**Return value**: An associative array with two keys, or `null` if not supported:

- `'gateway'`: The gateway identifier as defined by Google Pay (e.g., `'stripe'`, `'worldline'`, `'adyen'`). See the [Google Pay gateway reference](https://developers.google.com/pay/api/web/reference/request-objects#gateway).
- `'gatewayMerchantId'`: Your merchant identifier on the gateway (e.g., publishable key for Stripe, PSPID for Worldline).

The base class `hikashopPaymentPlugin` defines a default implementation that returns `null`. Override it in your plugin if your gateway supports Google Pay.

### WebMCP (AI agents in the browser)

Since HikaShop 6.8.0, every frontend page registers tools for the AI agents working in the visitor's browser (WebMCP): search\_products, list\_categories, list\_filters, get\_product, show\_products, add\_to\_cart, get\_cart and update\_cart\_item. They answer JSON from the controller `ctrl=agent`, built on the same classes as the listings and the cart. A plugin that adds its own filter type, item custom field type or prices can make its part understandable to the agents with the methods and events below. All are optional.

- [agentChoices($filter) and agentValue($value, $filter) on a filter type class](#webmcpFilterType)
- [agentDescribe(&amp;$field, &amp;$data) and agentValue($value, &amp;$field, $product) on a field type class](#webmcpFieldType)
- [onHikashopAgentProduct(&amp;$element, &amp;$data, $context, $params)](#onHikashopAgentProduct)
- [onHikashopAgentTools(&amp;$tools)](#onHikashopAgentTools)
- [onHikashopAgentCall($name, $input, &amp;$answer, &amp;$code)](#onHikashopAgentCall)

#### agentChoices($filter) and agentValue($value, $filter) on a filter type class

For a filter type of a plugin (`plg.yourtype`), list\_filters calls `agentChoices($filter)` on its class. Return an array describing what the filter takes, for example `'type'`, `'value_format'`, `'meaning'` and `'values'` (a list of `array('value' => ..., 'label' => ...)`), or `null` to leave the filter out. Without the method, the filter is not listed, but it still applies when an agent gives it a value.

search\_products and show\_products call `agentValue($value, $filter)` with what the agent gave (a string, a number, an array or an object decoded as an array) and expect the string the filter's form would send as `filter_<namekey>`.

#### agentDescribe(&amp;$field, &amp;$data) and agentValue($value, &amp;$field, $product) on a field type class

get\_product lists the item custom fields of the product with their namekey, name, type, required flag, choices and default. `agentDescribe(&$field, &$data)` on the field type class can complete or change that entry (`$data`), typically with a `'value_format'`. add\_to\_cart calls `agentValue($value, &$field, $product)` with what the agent gave for the field and the product (or variant) being added, and expects the value the product form would post in `data[item][namekey]`. To refuse the value, throw an `InvalidArgumentException`: its message goes back to the agent. The value then goes through the usual field check and the cart events, as from the product page. The Price per category plugin uses it to turn `{"adult": 2}` into the breakdown text of its hidden field.

#### onHikashopAgentProduct(&amp;$element, &amp;$data, $context, $params)

Called for each product of an answer, to add to or correct what the agent gets.

- `&$element`: The product (a listing row with its prices for `search`, the full product for `product`, the cart product for `cart`).
- `&$data`: The array sent to the agent for that product (or cart line).
- `$context`: `'search'`, `'product'` or `'cart'`.
- `$params`: For `search`, `'filters'` holds the filter values applied (namekey =&gt; value as the filter reads it), so a plugin can price what was searched, such as a stay.

#### onHikashopAgentTools(&amp;$tools)

Called on every frontend page to let a plugin add tools of its own to the ones of the shop, for what the core tools do not cover (an auction, a quote, a loyalty balance...). Append one array per tool to `&$tools`:

- `name`: Lowercase letters, digits and underscores, starting with a letter, 3 to 64 characters. A name of a core tool or of another plugin's tool is refused (and logged).
- `title`: Optional, a readable name; the name by default.
- `description`: What the tool does and when to use it, written for the agent. Required.
- `inputSchema`: The JSON schema of the input, as an array: `type` object, `properties`, `required`.
- `annotations`: The hints of the WebMCP specification, as booleans: `readOnlyHint`, `consequentialHint` for a tool whose action is significant or cannot be undone, so that the browser can ask the visitor first, and `untrustedContentHint` when the answer carries text written by others. Any other key is dropped.
- `write`: Optional. A tool which is not `readOnlyHint` is a write tool by default: it is called with POST and the form token of the session, which the script gets by itself, so another site cannot call it for a visitor.

A tool with `consequentialHint` can have the visitor confirm in the page itself, where an agent cannot answer for them. Have the tool answer `array('status' => 'confirmation_required', 'summary' => 'what will be done, in a sentence', 'confirmation' => 'a code only the shop can check', 'expires_in_seconds' => 120)` when it is called without a `confirmation`. The script then opens a window with the summary, and only if the visitor clicks Confirm calls the tool again with the same input and the code, which is the answer the agent gets. If the visitor declines, the agent is told `declined_by_visitor`. A `confirmation` given by the agent itself is dropped. The code should be tied to the visitor, the values of the call and an expiry, so that it cannot be reused for something else, and the tool must check everything again when it is given back.

The tools run in the visitor's own session: a plugin checks what the visitor may do exactly as its page does, and answers a visitor who is not logged in with an error saying so rather than redirecting.

#### onHikashopAgentCall($name, $input, &amp;$answer, &amp;$code)

Called when an agent runs a tool declared with onHikashopAgentTools. Only the plugin which declared the tool answers it: test `$name` and leave the other names alone.

- `$name`: The tool.
- `$input`: The input of the agent, an array. Check it: it is not validated against the schema.
- `&$answer`: Set an array, sent as JSON. An error is `array('error' => array('code' => 'some_code', 'message' => 'A sentence the agent can relay to the visitor.'))`.
- `&$code`: The HTTP code, 200 by default; an answer with an error is 400 unless you set another.

An exception is logged in the HikaShop log and answered with a generic error, so a database message never reaches the agent. After a write tool the page gets a `hikashop:agent-tool` event on `window`, with the name, the input and the answer in `detail`, for a page that shows what the tool changed.

### Vote API

This API allows you to perform actions related to the HikaShop voting system.

Available events for the Vote API:

- [onBeforeVoteCreate(&amp;$element, &amp;$do, &amp;$errors)](#onBeforeVoteCreate)
- [onAfterVoteCreate(&amp;$element, &amp;$return\_data)](#onAfterVoteCreate)
- [onBeforeVoteUpdate(&amp;$element, &amp;$do, &amp;$oldElement, &amp;$errors)](#onBeforeVoteUpdate)
- [onAfterVoteUpdate(&amp;$element, &amp;$return\_data)](#onAfterVoteUpdate)
- [onBeforeVoteDelete(&amp;$elements, &amp;$do, &amp;$currentElements)](#onBeforeVoteDelete)
- [onAfterVoteDelete(&amp;$elements)](#onAfterVoteDelete)

#### onBeforeVoteCreate(&amp;$element, &amp;$do, &amp;$errors)

Triggered before a vote or comment is created.

- `&$element`: The vote object.
- `&$do`: Boolean to allow or cancel.
- `&$errors`: Array of error messages.

#### onAfterVoteCreate(&amp;$element, &amp;$return\_data)

Triggered after a vote or comment is created.

- `&$element`: The created vote object.
- `&$return_data`: Array containing average rating and total votes.

#### onBeforeVoteUpdate(&amp;$element, &amp;$do, &amp;$oldElement, &amp;$errors)

Triggered before a vote is updated.

- `&$element`: The updated vote object.
- `&$do`: Boolean to allow or cancel.
- `&$oldElement`: The original vote object before changes.
- `&$errors`: Array of error messages.

#### onAfterVoteUpdate(&amp;$element, &amp;$return\_data)

Triggered after a vote is updated.

- `&$element`: The updated vote object.
- `&$return_data`: Array containing the new average and total.

#### onBeforeVoteDelete(&amp;$elements, &amp;$do, &amp;$currentElements)

Triggered before one or more votes are deleted.

- `&$elements`: Array of vote IDs.
- `&$do`: Boolean to allow or cancel.
- `&$currentElements`: Array of vote objects being deleted.

#### onAfterVoteDelete(&amp;$elements)

Triggered after one or more votes are deleted.

- `&$elements`: Array of deleted vote IDs.

### <a name="cart"></a>Cart API

- [onBeforeCartUpdate(&amp;$cartClass,&amp;$cart,$product\_id,$quantity,$add,$type,$resetCartWhenUpdate,$force,&amp;$do)](#onBeforeCartUpdate)
- [onBeforeCartSave(&amp;$element,&amp;$do)](#onBeforeCartSave)
- [onAfterCartUpdate(&amp;$cartClass,&amp;$cart,$product\_id,$quantity,$add,$type,$resetCartWhenUpdate,$force)](#onAfterCartUpdate)
- [onAfterCartSave(&amp;$element)](#onAfterCartSave)
- [onBeforeCartProductsLoad(&amp;$cart, &amp;$options, &amp;$filters)](#onBeforeCartProductsLoad)
- [onAfterCartCouponLoad(&amp;$cart)](#onAfterCartCouponLoad)
- [onAfterCheckCartQuantities(&amp;$cart, $parent\_products, &amp;$ret)](#onAfterCheckCartQuantities)
- [onAfterCartProductsLoad(&amp;$cart)](#onAfterCartProductsLoad)
- [onAfterCartShippingLoad(&amp;$cart)](#onAfterCartShippingLoad)
- [onHikaShopCartSelectPayment(&amp;$cart, &amp;$cart\_payment\_id)](#onHikaShopCartSelectPayment)
- [onAfterFullCartLoad(&amp;$cart)](#onAfterFullCartLoad)
- [onAfterProductQuantityCheck(&amp;$product, &amp;$wantedQuantity,&amp;$quantity, &amp;$cartContent, &amp;$cart\_product\_id\_for\_product, &amp;$displayErrors)](#onAfterProductQuantityCheck)
- [onGetCartProductsInfo(&amp;$cart, &amp;$ret)](#onGetCartProductsInfo)
- [onHikashopAclGroups(&amp;$userGroups, $user\_id, $field)](#onHikashopAclGroups)
- [onHikashopAclCategories(&amp;$aclcats, &amp;$acltrans)](#onHikashopAclCategories)
- [onBeforeCartIdLoad(&amp;$filters, $type)](#onBeforeCartIdLoad)
- [onBeforeCartLoad(&amp;$cart, &amp;$options)](#onBeforeCartLoad)
- [onAfterCartLoad(&amp;$cart, &amp;$options)](#onAfterCartLoad)
- [onBeforeCartDelete(&amp;$elements, &amp;$do)](#onBeforeCartDelete)
- [onAfterCartDelete(&amp;$elements)](#onAfterCartDelete)
- [onBeforeProductQuantityCheck(&amp;$products, &amp;$cart, &amp;$options)](#onBeforeProductQuantityCheck)
- [onBeforeCheckCartQuantities(&amp;$cart, &amp;$parent\_products)](#onBeforeCheckCartQuantities)
- [onCompareCartProducts($p, $cart\_product, &amp;$do)](#onCompareCartProducts)
- [onAfterProductCheckQuantities(&amp;$products, &amp;$cart, $options)](#onAfterProductCheckQuantities)
- [onAfterCartRemoveAdditional(&amp;$cart, $removeAdditional)](#onAfterCartRemoveAdditional)
- [onUnknownCheckCartQuantities(&amp;$cart, $parent\_products, &amp;$ret)](#onUnknownCheckCartQuantities)

Nine events fire while `getFullCart()` assembles a cart, across three nested calls. Two of them repeat, once per product or once per variant, and one only fires when no payment method has been chosen yet. Click any event to jump to its description.

```
sequenceDiagram
    autonumber
    participant C as cart::getFullCart()
    participant G as cart::get()
    participant Q as checkCartQuantities()
    participant P as Your plugin

    C->>G: load the cart row
    G->>P: onBeforeCartLoad
    G->>P: onAfterCartLoad
    C->>P: onBeforeCartProductsLoad
    C->>Q: check the quantities
    Q->>P: onBeforeCheckCartQuantities
    loop each product
        Q->>P: onAfterProductQuantityCheck
    end
    Q->>P: onAfterCheckCartQuantities
    loop each variant
        C->>P: onAfterProductCharacteristicsLoad
    end
    C->>P: onAfterCartProductsLoad
    C->>P: onAfterCartCouponLoad
    C->>P: onAfterCartShippingLoad
    opt no payment method chosen yet
        C->>P: onHikaShopCartSelectPayment
    end
    C->>P: onAfterFullCartLoad
```

#### onBeforeCartUpdate(&amp;$cartClass,&amp;$cart,$product\_id,$quantity,$add,$type,$resetCartWhenUpdate,$force,&amp;$do) **DEPRECATED use onBeforeCartSave instead**

This event will be triggered by HikaShop before the cart is updated, the object $cartClass is the instance of the cart class which calls that event, $cart has the existing or the new cart information, $product\_id is a variable with the id of the product added in the cart.
$quantity is the quantity of the product to add to the cart, the $add variable says whether the quantity replaces the quantity of the product already in the cart or is added to it, and finally, $type is a variable containing the type of the item to update generally 'product'

#### onBeforeCartSave(&amp;$element,&amp;$do)

This event will be triggered by HikaShop before the cart is saved, when a product is added, removed, modified, when a shipping or payment method is selected, etc. In the object $element, you can have an attribute cart\_products which is an array of products to be added/modified. You can use the variable $do to cancel the save.

#### onAfterCartUpdate(&amp;$cartClass,&amp;$cart,$product\_id,$quantity,$add,$type,$resetCartWhenUpdate,$force) **DEPRECATED use onAfterCartSave instead**

This event will be triggered by HikaShop after the cart is updated, the object $cartClass is the instance of the cart class which calls that event, $cart has the existing or the new cart information, $product\_id is a variable with the id of the product added in the cart.
$quantity is the quantity of the product to add to the cart, the $add variable says whether the quantity replaces the quantity of the product already in the cart or is added to it, and finally, $type is a variable containing the type of the item to update generally 'product'

#### onAfterCartSave(&amp;$element)

This event will be triggered by HikaShop after the cart is saved, when a product is added, removed, modified, when a shipping or payment method is selected, etc. In the object $element, you can have an attribute cart\_products which is an array of products which were added/modified.

#### onBeforeCartProductsLoad(&amp;$cart, &amp;$options, &amp;$filters)

This event will be triggered by HikaShop when the cart is being loaded, just before the cart products data is loaded. The object $cart contains all the cart data that is already loaded at that point. The $options array contains option values used when loading carts. The $filters array contains an array of MySQL conditions for the loading of the products.

#### onAfterCheckCartQuantities(&amp;$cart, $parent\_products, &amp;$ret)

Triggered after all product quantities in the cart have been checked against stock and limitations.

- `&$cart`: The cart object.
- `$parent_products`: An array of parent product objects for variants.
- `&$ret`: A boolean indicating if the cart quantities are valid.

#### onAfterCartProductsLoad(&amp;$cart)

Triggered when the cart is loaded, after all product data has been retrieved.

- `&$cart`: The cart object with its loaded products.

#### onAfterCartCouponLoad(&amp;$cart)

Triggered when the cart is loaded, after the coupon has been applied.

- `&$cart`: The cart object.

#### onAfterCartShippingLoad(&amp;$cart)

Triggered when the cart is loaded, after the shipping method has been applied.

- `&$cart`: The cart object.

#### onHikaShopCartSelectPayment(&amp;$cart, &amp;$cart\_payment\_id)

Triggered when a payment method is auto-selected for the cart. You can modify `$cart_payment_id` to change the selection.

- `&$cart`: The cart object.
- `&$cart_payment_id`: The ID of the selected payment method.

#### onAfterFullCartLoad(&amp;$cart)

Triggered at the very end of the cart loading process, once everything (products, addresses, shipping, payment, coupons) is finalized.

- `&$cart`: The full cart object.

#### onAfterProductQuantityCheck(&amp;$product, &amp;$wantedQuantity, &amp;$quantity, &amp;$cartContent, &amp;$cart\_product\_id\_for\_product, &amp;$displayErrors)

Triggered to check if a product is purchasable. `$wantedQuantity` is what the user requested, and `$quantity` is the allowed amount. Set `$quantity` to `0` to prevent purchase. Set `$displayErrors` to `false` to suppress HikaShop's default error messages.

- `&$product`: The product object being checked.
- `&$wantedQuantity`: The quantity requested by the user.
- `&$quantity`: The quantity allowed by HikaShop (can be modified).
- `&$cartContent`: The current whole content of the cart.
- `&$cart_product_id_for_product`: The ID of the product in the cart.
- `&$displayErrors`: Boolean to control error message display.

#### onGetCartProductsInfo(&amp;$cart, &amp;$ret)

Triggered when returning cart data to JavaScript. `$ret` is the array of data sent to the JS side. Anything added to `$ret` will be available in the `cart.update` JS event.

- `&$cart`: The cart object.
- `&$ret`: An associative array of data to be sent to the frontend.

#### onHikashopAclGroups(&amp;$userGroups, $user\_id, $field)

Triggered by `hikashop_addACLFilters()`, which is how every listing of the shop narrows what it shows to the access of the visitor: the products and the categories carry a list of Joomla user groups, and the query keeps the rows whose list holds one of the groups of the visitor. The event hands you those groups, so a plugin can add one or take one away for the request. The Domains plugin uses it to keep the products of one domain name off the others. Access on products and categories is a Business feature, so this fires on the Business edition only.

- `&$userGroups`: The ids of the Joomla user groups the shop reads for this request.
- `$user_id`: The Joomla user the groups belong to, zero for a visitor.
- `$field`: The column being filtered, `product_access` or `category_access`.

#### onHikashopAclCategories(&amp;$aclcats, &amp;$acltrans)

Triggered by the ACL tab of the HikaShop configuration, after the component's own list of screens. A plugin with screens of its own adds a row there, so that the merchant sets which groups may view, manage and delete them, like the rest of the shop. The controller of the plugin reads the setting through `getACLName()`, which gives the key of the row; the Seat Map plugin uses it for its plans. The ACL tab is a Business feature, so this fires on the Business edition only.

- `&$aclcats`: The rows of the tab, the key of a row (the name the controller gives) mapped to its actions, among `view`, `manage` and `delete`.
- `&$acltrans`: The language key of the label of a row, by key; without one the label is the key, translated when a HIKA\_ key for it exists.

#### onBeforeCartIdLoad(&amp;$filters, $type)

Triggered when HikaShop looks for the cart of the current visitor, before the query which finds it. HikaShop matches a cart on the session of the visitor, and on their user id once they are logged in, so a customer carries the same cart from one address of the website to the next. Add a condition to `$filters` to narrow that, or return a cart id to answer with a cart of your own and skip the query altogether. The Domains plugin uses it to give each domain name of a shop a cart of its own.

- `&$filters`: The conditions of the query, as an array of SQL strings joined with AND. The table is aliased `cart`.
- `&$cart_id`: Zero. Set it to a cart id and HikaShop uses that cart instead of searching for one.
- `$type`: `cart` or `wishlist`.

#### onBeforeCartLoad(&amp;$cart, &amp;$options)

Triggered before HikaShop loads a cart from the database. `$options` allows you to customize the loading process.

- `&$cart`: The cart object.
- `&$options`: An array of options for loading the cart.

#### onAfterCartLoad(&amp;$cart, &amp;$options)

Triggered after a cart is loaded but before it's returned. Use this to modify the `$cart` object after it has been populated from the database.

- `&$cart`: The loaded cart object.
- `&$options`: The options used for loading.

#### onBeforeCartDelete(&amp;$elements, &amp;$do)

Triggered before one or more carts are deleted. `$elements` is an array of cart IDs. Setting `$do` to `false` cancels the deletion.

- `&$elements`: An array of cart IDs to be deleted.
- `&$do`: A boolean. Set it to `false` to cancel the deletion.

#### onAfterCartDelete(&amp;$elements)

Triggered after one or more carts are successfully deleted.

- `&$elements`: An array of deleted cart IDs.

#### onBeforeProductQuantityCheck(&amp;$products, &amp;$cart, &amp;$options)

Triggered before checking product quantities in the cart. It allows plugins to modify products or options before HikaShop performs its own checks (stock, limits, dates).

- `&$products`: The list of products being added or updated.
- `&$cart`: The current cart object.
- `&$options`: Additional options for the check.

#### onCompareCartProducts($p, $cart\_product, &amp;$do)

Triggered when HikaShop compares Two products to see if they should be grouped in the cart. Set `$do = false` to force them to be separate items.

- `$p`: The first product object.
- `$cart_product`: The second product object.
- `&$do`: A boolean. Set it to `false` to prevent grouping.

#### onBeforeCheckCartQuantities(&amp;$cart, &amp;$parent\_products)

Triggered at the beginning of the `checkCartQuantities` process (modern checkout) to allow global stock/limitation pre-checks.

- `&$cart`: The cart object.
- `&$parent_products`: An array of parent product objects for variants.

#### onAfterProductCheckQuantities(&amp;$products, &amp;$cart, $options)

Triggered when the cart has checked the quantities of its products against the stock and the limits, and before the products left without a quantity are removed from it. Change a quantity to overrule what HikaShop decided.

- `&$products`: The products of the cart with the quantity each is allowed.
- `&$cart`: The cart object.
- `$options`: The options the check was run with.

#### onAfterCartRemoveAdditional(&amp;$cart, $removeAdditional)

Triggered once an additional item a plugin had added to the cart has been removed by the customer, so that the plugin can clean up what it had stored with it.

- `&$cart`: The cart the item was removed from.
- `$removeAdditional`: The key of the item removed.

#### onUnknownCheckCartQuantities(&amp;$cart, $parent\_products, &amp;$ret)

Triggered when the quantities of a cart have to be checked and its type is not one HikaShop handles itself, a type added by a plugin. Set $ret to false to refuse the cart.

- `&$cart`: The cart being checked.
- `$parent_products`: The main products of the variants in the cart.
- `&$ret`: The result of the check. Set it to false to refuse the cart.

### Checkout API

This API allows you to customize the HikaShop checkout workflow.

The checkout is not one sequence but two paths that alternate. The view renders every block of the current step, so the display events fire once per block, while the controller receives what the customer submitted and fires once per step. Click any event to jump to its description.

```
flowchart TB
    START(["Customer opens the checkout"]) --> INIT["onInitCheckoutStep"]
    INIT -->|"for the first block of the step"| R1

    R1["onBeforeCheckoutViewDisplay"] --> R2["the block renders"] --> R3["onAfterCheckoutViewDisplay"]
    R3 -.->|"a block with no view of its own uses this instead"| R4["onCheckoutStepDisplay"]
    R3 -->|"more blocks left in this step"| R1

    R3 --> WAIT{"The customer acts"}
    WAIT -->|"changes a block"| SUB["onAfterCheckoutStep"] --> BACK
    WAIT -->|"moves to the next step"| STEP["onAfterCheckoutStep"] --> EMPTY["onCheckoutEmptyContentCheck"] --> BACK
    BACK(["the step is rendered again"])

    WAIT -->|"places the order"| O1["onBeforeOrderCreate"]
    O1 --> O2["onAfterOrderCreate"] --> O3["onAfterOrderConfirm"]
```

*The rendering events fire once for every block of the step, which is what the loop shows. `onBeforeOrderCreate` is where you refuse an order, by setting its `$do` to false. `onAfterOrderConfirm` belongs to the payment plugin of the method the customer chose.*

Available events for the Checkout API:

- [onCheckoutStepList(&amp;$list)](#onCheckoutStepList)
- [onInitCheckoutStep($task, &amp;$view)](#onInitCheckoutStep)
- [onBeforeCheckoutViewDisplay($layoutName, &amp;$view)](#onBeforeCheckoutViewDisplay)
- [onAfterCheckoutViewDisplay($layoutName, &amp;$view, &amp;$html)](#onAfterCheckoutViewDisplay)
- [onAfterCheckoutStep($controllerName, &amp;$go\_back, $original\_go\_back, &amp;$controller)](#onAfterCheckoutStep)
- [onCheckoutStepDisplay($layoutName, &amp;$html, &amp;$view, $pos, $options)](#onCheckoutStepDisplay)
- [onCheckoutEmptyContentCheck(&amp;$controller, &amp;$params, &amp;$empty)](#onCheckoutEmptyContentCheck)
- [onCheckoutWorkflowLoad(&amp;$checkout\_workflow, &amp;$shop\_closed, $cart\_id)](#onCheckoutWorkflowLoad)

#### onCheckoutStepList(&amp;$list)

Triggered on the configuration page. Add your custom views to `$list` (e.g., `$list['plg.shop.myview'] = 'My Custom View'`) so they can be placed in the checkout workflow.

- `&$list`: An associative array of workflow block types. Keys are internal names, values are display names.

#### onAfterCheckoutStep($controllerName, &amp;$go\_back, $original\_go\_back, &amp;$controller)

Triggered when the user clicks "Next" on a checkout step. Use this to validate or process data from your view. Set `$go_back` to `true` to prevent moving to the next step.

- `$controllerName`: The name of the current controller.
- `&$go_back`: Boolean. Set to `true` to block progression and stay on the current step.
- `$original_go_back`: The initial state of the go\_back flag.
- `&$controller`: The checkout controller instance.

#### onInitCheckoutStep($task, &amp;$view)

Triggered when a checkout step or block is initialized. Use this to prepare data required for your custom checkout blocks.

- `$task`: The task/block name being initialized.
- `&$view`: The checkout view object.

#### onBeforeCheckoutViewDisplay($layoutName, &amp;$view)

Triggered before a checkout layout (block) is displayed. `$layoutName` is the name of the block (e.g., 'cart', 'login').

- `$layoutName`: The name of the current layout/block.
- `&$view`: The checkout view object.

#### onAfterCheckoutViewDisplay($layoutName, &amp;$view, &amp;$html)

Triggered after a checkout layout is displayed. `$html` contains the generated HTML of the block.

- `$layoutName`: The name of the current layout/block.
- `&$view`: The checkout view object.
- `&$html`: The generated HTML output of the block.

#### onCheckoutStepDisplay($layoutName, &amp;$html, &amp;$view, $pos, $options)

Triggered when a non-standard checkout block needs to be displayed.

- `$layoutName`: The name of the custom task.
- `&$html`: The HTML output (append your content here).
- `&$view`: The checkout view object.
- `$pos`: The position of the block in the workflow step.
- `$options`: The configuration options of the block.

#### onCheckoutEmptyContentCheck(&amp;$controller, &amp;$params, &amp;$empty)

Triggered when HikaShop checks if a checkout step is empty. Use this to dynamically show or hide custom checkout blocks.

- `&$controller`: The checkout controller object.
- `&$params`: The block parameters.
- `&$empty`: A boolean indicating if the block is empty. Set it to `false` to force display.

#### onCheckoutWorkflowLoad(&amp;$checkout\_workflow, &amp;$shop\_closed, $cart\_id)

Triggered after the checkout workflow is loaded. Perfect for dynamically changing the workflow or closing the checkout (`$shop_closed = true`).

- `&$checkout_workflow`: The workflow structure.
- `&$shop_closed`: Boolean to block the checkout process.
- `$cart_id`: The ID of the cart being processed.

### Display API

This API allows you to customize the display of various elements in HikaShop.

Available events for the Display API:

- [onDisplayImport(&amp;$importData)](#onDisplayImport)
- [onHikashopImportSources(&amp;$sources)](#onHikashopImportSources)
- [onProductFormDisplay(&amp;$element, &amp;$html)](#onProductFormDisplay)
- [onProductDisplay(&amp;$element, &amp;$html)](#onProductDisplay)
- [onProductBlocksDisplay(&amp;$element, &amp;$html)](#onProductBlocksDisplay)
- [onAfterOrderProductsListingDisplay(&amp;$order, $mail)](#onAfterOrderProductsListingDisplay)
- [onHikashopBeforeDisplayView(&amp;$view)](#onHikashopBeforeDisplayView)
- [onHikashopAfterDisplayView(&amp;$view)](#onHikashopAfterDisplayView)
- [onViewsListingLoad(&amp;$templates, &amp;$pageInfo)](#onViewsListingLoad)
- [onHikashopMicrodataProductInfo(&amp;$obj, &amp;$element, $main)](#onHikashopMicrodataProductInfo)
- [onHikashopMicrodataExtraObjects(&amp;$extraObjects, &amp;$element, $main)](#onHikashopMicrodataExtraObjects)
- [onHikashopPopupList(&amp;$plugins)](#onHikashopPopupList)
- [onHikashopPopupDisplay($popupMode, 'content', &amp;$html, $text, $title, $url, $id, $params)](#onHikashopPopupDisplay)

#### onDisplayImport(&amp;$importData)

Triggered when displaying the import interface. `$importData` is an array with the data for each tab.

- `&$importData`: An associative array where keys are tab identifiers and values are data objects for those tabs.

#### onHikashopImportSources(&amp;$sources)

Triggered when the "Import from another shop" screen is built and when an import runs. A plugin adds a shop to import from by adding an entry to `$sources`; the screen (the settings, the parts to import, the progress) is built from it.

- `&$sources`: An associative array, shop key =&gt; description. The description holds `label` (the name of the shop), `helper` (the helper which holds the steps, loaded with `hikashop_get('helper.' . $helper)`), `name` (the prefix of its settings in the configuration table), `platforms` (`joomla` and/or `wordpress`), `detect` (tables, without the prefix, one of which must exist on the site for the shop to be offered, or `null` for a shop which lives elsewhere), `fields` (the settings to ask: `name`, `type` text, checkbox, radio or language, `label`, `default`, `help`), `steps` (state number =&gt; language key, from the initialization to the finish) and `parts` (what can be left out: `label`, the `steps` it covers and the parts it `requires`).

The helper extends `hikashopImportHelper`. Its `doImport()` runs the step of the current state, `restoreSession()` puts back the settings that `getStartPage()` stored. See back/helpers/import/j2.php for an example.

#### onProductFormDisplay(&amp;$element, &amp;$html)

Triggered when displaying the product form in the backend.

- `&$element`: The product object being displayed.
- `&$html`: The HTML content. You can append your custom HTML here.

#### onProductDisplay(&amp;$element, &amp;$html)

Triggered when displaying a product edit page in the backend.

- `&$element`: The product object.
- `&$html`: The HTML content.

#### onProductBlocksDisplay(&amp;$element, &amp;$html)

Triggered when displaying the blocks of the product in the backend.

- `&$element`: The product object.
- `&$html`: The HTML content.

#### onAfterOrderProductsListingDisplay(&amp;$order, $mail)

Triggered after displaying the listing of products in an order. `$order` is an object containing order data.

- `&$order`: The order object.
- `$mail`: A boolean. `true` if the display is for an email, `false` otherwise.

#### onHikashopBeforeDisplayView(&amp;$view)

Triggered before displaying a view. `$view` is the view instance. You can use `$view->getName()` and `$view->getLayout()` to target specific views. This event is commonly used to inject extra columns or data into backend listings.

- `&$view`: The view object instance.

#### onHikashopAfterDisplayView(&amp;$view)

Triggered after a view is displayed.

- `&$view`: The view object instance.

#### onHikashopPopupList(&amp;$plugins)

Triggered when HikaShop looks for the popup systems available, before displaying one. Register yours under the content or the image key to have it offered as a popup mode.

- `&$plugins`: An array with a content and an image key, each listing the popup systems.

#### onHikashopPopupDisplay($popupMode, 'content', &amp;$html, $text, $title, $url, $id, $params)

Triggered when a popup has to be displayed with a mode a plugin registered through onHikashopPopupList. Fill $html with your own markup; HikaShop falls back to its default popup when it stays empty.

- `$popupMode`: The popup mode selected in the configuration.
- `'content'`: The kind of popup, always content here.
- `&$html`: The HTML of the popup. Fill it to take over the display.
- `$text`: The text of the link opening the popup.
- `$title`: The title of the popup.
- `$url`: The address the popup loads.
- `$id`: The id of the popup.
- `$params`: The width, the height and the other options of the popup.

### View API

This API allows you to interact with the view override system in the backend of HikaShop.

#### onViewsListingLoad(&amp;$templates, &amp;$pageInfo)

Triggered to collect available views for the views listing in the backend. Plugins can use this to add their own views to the list, allowing users to override them through the HikaShop interface.

- `&$templates`: An array of view objects.
- `&$pageInfo`: Information about pagination and search.

#### onBeforeViewUpdate(&amp;$element, &amp;$do)

Triggered before a view override is saved. Set `$do = false` to cancel.

- `&$element`: The view object being saved.
- `&$do`: A boolean. Set it to `false` to cancel the update.

#### onAfterViewUpdate(&amp;$element)

Triggered after a view override is saved.

- `&$element`: The saved view object.

#### onBeforeViewDelete(&amp;$element)

Triggered before a view override is deleted.

- `&$element`: The view object to be deleted.

#### onAfterViewDelete(&amp;$element)

Triggered after a view override is deleted.

- `&$element`: The deleted view object.

```
public function onHikashopBeforeDisplayView(&$view) {
    if(!hikashop_isClient('administrator'))
        return;
    if($view->getName() != 'order' || $view->getLayout() != 'listing')
        return;

    if(empty($view->extrafields))
        $view->extrafields = array();

    $column = new stdClass();
    $column->name = JText::_('MY_EXTRA_COLUMN');
    $column->value = 'extra_column';
    $view->extrafields['extra_column'] = $column;

    if(!empty($view->rows)) {
        foreach($view->rows as $k => $row) {
            $view->rows[$k]->extra_column = 'HTML Content';
        }
    }
}
```

#### onViewsListingFilter(&amp;$pluginViews, $client\_id)

Allows plugins to inject their own view files into the HikaShop view listing for the override system.

- `&$pluginViews`: An array of view group/view name strings.
- `$client_id`: The client ID (0 for frontend, 1 for administrator).

#### onHikashopMicrodataProductInfo(&amp;$obj, &amp;$element, $main)

Triggered on the product page after the JSON-LD structured data object is fully built (product info, offers, reviews, variants) but before it is encoded and injected into the page head. Use this event to modify the schema type, add properties, or enrich the structured data for specific product types (e.g. hotel rooms, event tickets).

- `&$obj`: The JSON-LD object (stdClass). You can modify its properties, change `$obj->{'@type'}`, or add new schema.org properties.
- `&$element`: The full product element (includes variants, images, etc.).
- `$main`: The main product object (for variants, this is the parent product).

#### onHikashopMicrodataExtraObjects(&amp;$extraObjects, &amp;$element, $main)

Triggered on the product page after the main JSON-LD block has been injected. Use this event to add additional JSON-LD objects to the page (e.g. a separate LodgingBusiness or LocalBusiness block alongside the Product).

- `&$extraObjects`: An array of stdClass objects. Each object you add will be encoded as a separate JSON-LD script block in the page head.
- `&$element`: The full product element.
- `$main`: The main product object.

### Coupon API

This API allows you to customize coupon loading and validation.

Available events for the Coupon API:

- [onBeforeCouponLoad(&amp;$coupon, &amp;$do)](#onBeforeCouponLoad)
- [onBeforeCouponCheck(&amp;$coupon, &amp;$total, &amp;$zones, &amp;$products, &amp;$display\_error, &amp;$error\_message, &amp;$do)](#onBeforeCouponCheck)
- [onAfterCouponCheck(&amp;$coupon, &amp;$total, &amp;$zones, &amp;$products, &amp;$display\_error, &amp;$error\_message, &amp;$do)](#onAfterCouponCheck)

#### onBeforeCouponLoad(&amp;$coupon, &amp;$do)

Triggered before loading a coupon. Setting `$do` to `false` cancels the loading.

- `&$coupon`: The coupon code string or object.
- `&$do`: A boolean. Set it to `false` to cancel the loading.

#### onBeforeCouponCheck(&amp;$coupon, &amp;$total, &amp;$zones, &amp;$products, &amp;$display\_error, &amp;$error\_message, &amp;$do)

Triggered before validating a coupon. You can modify the coupon values, set `$display_error` to `false` to hide default errors, or provide a custom `$error_message`. Setting `$do` to `false` skips HikaShop's default checks.

- `&$coupon`: The coupon object.
- `&$total`: The total object.
- `&$zones`: An array of zone IDs.
- `&$products`: An array of product objects in the cart.
- `&$display_error`: A boolean. Set it to `false` to suppress the default error message.
- `&$error_message`: A string. Provide a custom message if validation fails.
- `&$do`: A boolean. Set it to `false` to skip default HikaShop validation.

#### onAfterCouponCheck(&amp;$coupon, &amp;$total, &amp;$zones, &amp;$products, &amp;$display\_error, &amp;$error\_message, &amp;$do)

Triggered after a coupon is checked but before it is processed.

- `&$coupon`: The coupon object.
- `&$total`: The total object.
- `&$zones`: An array of zone IDs.
- `&$products`: An array of product objects.
- `&$display_error`: A boolean.
- `&$error_message`: A string.
- `&$do`: A boolean.

### Discount API

This API allows you to customize how discounts and coupons are handled.

Available events for the Discount API:

- [onBeforeDiscountCreate(&amp;$discount, &amp;$do)](#onBeforeDiscountCreate)
- [onBeforeDiscountUpdate(&amp;$discount, &amp;$do)](#onBeforeDiscountUpdate)
- [onAfterDiscountCreate(&amp;$discount)](#onAfterDiscountCreate)
- [onAfterDiscountUpdate(&amp;$discount)](#onAfterDiscountUpdate)
- [onBeforeDiscountDelete(&amp;$ids, &amp;$do)](#onBeforeDiscountDelete)
- [onAfterDiscountDelete(&amp;$ids)](#onAfterDiscountDelete)
- [onBeforeLoadProductPriceDiscount(&amp;$filters, $rows, $trigger\_options)](#onBeforeLoadProductPriceDiscount)
- [onAfterLoadProductPriceDiscount(&amp;$discounts, &amp;$rows, $filters, $trigger\_options)](#onAfterLoadProductPriceDiscount)
- [onBeforeDiscountOnlyCheckQuery(&amp;$selects, &amp;$joins, &amp;$discount\_filter)](#onBeforeDiscountOnlyCheckQuery)
- [onAfterDiscountOnlyCheckQuery(&amp;$discounts, &amp;$join\_discount\_links, &amp;$filters)](#onAfterDiscountOnlyCheckQuery)
- [onDiscountBlocksDisplay(&amp;$element, &amp;$html)](#onDiscountBlocksDisplay)
- [onSelectDiscount(&amp;$product, &amp;$discountsSelected, &amp;$discounts, $zone\_id, &amp;$parent)](#onSelectDiscount)

#### onBeforeDiscountCreate(&amp;$discount, &amp;$do)

Triggered before a discount or coupon is created. Setting `$do` to `false` cancels the creation.

- `&$discount`: The discount object to be created.
- `&$do`: A boolean. Set it to `false` to cancel the creation.

#### onBeforeDiscountUpdate(&amp;$discount, &amp;$do)

Triggered before a discount or coupon is updated. Setting `$do` to `false` cancels the update.

- `&$discount`: The discount object to be updated.
- `&$do`: A boolean. Set it to `false` to cancel the update.

#### onAfterDiscountCreate(&amp;$discount)

Triggered after a discount or coupon is successfully created.

- `&$discount`: The created discount object.

#### onAfterDiscountUpdate(&amp;$discount)

Triggered after a discount or coupon is successfully updated.

- `&$discount`: The updated discount object.

#### onBeforeDiscountDelete(&amp;$ids, &amp;$do)

Triggered before one or more discounts are deleted. Setting `$do` to `false` cancels the deletion.

- `&$ids`: An array of discount IDs to be deleted.
- `&$do`: A boolean. Set it to `false` to cancel the deletion.

#### onAfterDiscountDelete(&amp;$ids)

Triggered after one or more discounts are successfully deleted.

- `&$ids`: An array of deleted discount IDs.

#### onBeforeLoadProductPriceDiscount(&amp;$filters, $rows, $trigger\_options)

Triggered before HikaShop loads discounts for a list of products.

- `&$filters`: An array of WHERE clauses (strings) for the discount query.
- `$rows`: An array of product objects for which discounts are being loaded.
- `$trigger_options`: An associative array of context options (user\_id, zone\_id, currency\_id, etc).

#### onAfterLoadProductPriceDiscount(&amp;$discounts, &amp;$rows, $filters, $trigger\_options)

Triggered after discounts have been loaded from the database but before they are applied to price calculations.

- `&$discounts`: An array of discount objects loaded from the database.
- `&$rows`: The product objects.
- `$filters`: The filters used in the query.
- `$trigger_options`: The context options.

#### onBeforeDiscountOnlyCheckQuery(&amp;$selects, &amp;$joins, &amp;$discount\_filter)

Triggered before the query that checks for available discounts in "Discounted products only" listings.

- `&$selects`: Array of columns to select.
- `&$joins`: Array of JOIN clauses.
- `&$discount_filter`: Array of WHERE clauses.

#### onAfterDiscountOnlyCheckQuery(&amp;$discounts, &amp;$join\_discount\_links, &amp;$filters)

Triggered after the discount check query.

- `&$discounts`: The result of the query.
- `&$join_discount_links`: Array of JOIN conditions for the main product query.
- `&$filters`: Array of WHERE clauses for the main product query.

#### onDiscountBlocksDisplay(&amp;$element, &amp;$html)

Triggered when displaying the discount/coupon edit form in the backend. Use this to inject custom configuration blocks.

#### onSelectDiscount(&amp;$product, &amp;$discountsSelected, &amp;$discounts, $zone\_id, &amp;$parent)

Triggered once HikaShop has sorted the discounts which apply to a product by priority, and before it keeps one. Reorder or change the selection to decide which discount wins.

- `&$product`: The product the discount is being chosen for.
- `&$discountsSelected`: The discounts kept, grouped by priority then by depth.
- `&$discounts`: Every discount that was considered.
- `$zone_id`: The zone the prices are computed for.
- `&$parent`: The main product when the one above is a variant.

### User API

This API allows you to perform actions related to HikaShop users.

Available events for the User API:

- [onBeforeUserCreate(&amp;$element, &amp;$do)](#onBeforeUserCreate)
- [onBeforeUserUpdate(&amp;$element, &amp;$do)](#onBeforeUserUpdate)
- [onAfterUserCreate(&amp;$element)](#onAfterUserCreate)
- [onAfterUserUpdate(&amp;$element)](#onAfterUserUpdate)
- [onBeforeUserDelete(&amp;$ids, &amp;$do)](#onBeforeUserDelete)
- [onAfterUserDelete(&amp;$ids)](#onAfterUserDelete)
- [onUserAccountDisplay(&amp;$buttons)](#onUserAccountDisplay)
- [onBeforeUserListing($paramBase, &amp;$extrafilters, &amp;$pageInfo, &amp;$filters, &amp;$tables, &amp;$searchMap, &amp;$select)](#onBeforeUserListing)
- [onBeforeHikaUserRegistration(&amp;$ret, $input\_data, $mode)](#onBeforeHikaUserRegistration)
- [onAfterHikaUserRegistration(&amp;$ret, $input\_data, $mode, &amp;$send\_email)](#onAfterHikaUserRegistration)

#### onBeforeUserCreate(&amp;$element, &amp;$do)

Triggered before a HikaShop user is created.

- `&$element`: The user object to be created.
- `&$do`: A boolean. Set it to `false` to cancel the creation.

#### onBeforeUserUpdate(&amp;$element, &amp;$do)

Triggered before a HikaShop user is updated.

- `&$element`: The user object with updated information.
- `&$do`: A boolean. Set it to `false` to cancel the update.

#### onAfterUserCreate(&amp;$element)

Triggered after a HikaShop user is successfully created.

- `&$element`: The created user object, including the `user_id`.

#### onAfterUserUpdate(&amp;$element)

Triggered after a HikaShop user is successfully updated.

- `&$element`: The updated user object.

#### onBeforeUserDelete(&amp;$ids, &amp;$do)

Triggered before one or more HikaShop users are deleted.

- `&$ids`: An array of HikaShop user IDs.
- `&$do`: A boolean. Set it to `false` to cancel the deletion.

#### onAfterUserDelete(&amp;$ids)

Triggered after one or more HikaShop users are successfully deleted.

- `&$ids`: An array of deleted user IDs.

#### onUserAccountDisplay(&amp;$buttons)

Triggered when displaying the user control panel. You can add or remove buttons from the `$buttons` array.

- `&$buttons`: An array of button objects.

#### onBeforeUserListing($paramBase, &amp;$extrafilters, &amp;$pageInfo, &amp;$filters, &amp;$tables, &amp;$searchMap, &amp;$select)

Triggered before HikaShop loads users for a listing.

- `$paramBase`: The base URL parameters.
- `&$extrafilters`: Extra filters (array).
- `&$pageInfo`: Pagination information.
- `&$filters`: Query filters (array).
- `&$tables`: Joins (array).
- `&$searchMap`: Search map (array).
- `&$select`: Select clauses (array).

#### onBeforeHikaUserRegistration(&amp;$ret, $input\_data, $mode)

Triggered during HikaShop user registration, before the CMS user is created. It allows plugins to perform additional validation or modify the registration data.

- `&$ret`: An associative array containing the status and messages of the registration. It also contains references to `registerData`, `userData`, `addressData`, and `shippingAddressData`.
- `$input_data`: The raw input data for user registration.
- `$mode`: The registration mode (0: Registration, 1: Simplified, 2: Guest, 3: Simplified with password).

#### onAfterHikaUserRegistration(&amp;$ret, $input\_data, $mode, &amp;$send\_email)

Triggered after the HikaShop user registration process is complete but before the confirmation email is sent.

- `&$ret`: The registration result array (same as `onBeforeHikaUserRegistration`).
- `$input_data`: The raw input data.
- `$mode`: The registration mode.
- `&$send_email`: A boolean indicating if a confirmation email should be sent.

### Fields API

This API allows you to customize custom fields behaviors.

Available events for the Fields API:

- [onFieldDateDisplay($field\_namekey, $field, &amp;$value, &amp;$map, &amp;$format, &amp;$size)](#onFieldDateDisplay)
- [onFieldDateCheckSelect(&amp;$values)](#onFieldDateCheckSelect)
- [onFieldsLoad(&amp;$externalValues, &amp;$externalOptions)](#onFieldsLoad)
- [onCustomfieldEdit(&amp;$field, &amp;$view)](#onCustomfieldEdit)
- [onTableFieldsLoad(&amp;$externalValues)](#onTableFieldsLoad)

#### onFieldDateDisplay($field\_namekey, $field, &amp;$value, &amp;$map, &amp;$format, &amp;$size)

Triggered when displaying a custom field of type "Date".

- `$field_namekey`: Internal name key of the field.
- `$field`: The field object.
- `&$value`: The current value of the field.
- `&$map`: A mapping object for the date picker.
- `&$format`: The date format string.
- `&$size`: Size of the input field.

#### onFieldDateCheckSelect(&amp;$values)

Triggered when a date field is selected.

#### onFieldsLoad(&amp;$externalValues, &amp;$externalOptions)

Triggered when custom fields are being loaded. Allows to inject external values for custom field selection.

- `&$externalValues`: An associative array where keys are field names and values are arrays of options.
- `&$externalOptions`: An associative array of extra options for those fields.

#### onCustomfieldEdit(&amp;$field, &amp;$view)

Triggered when a custom field is opened for edition in your backend, so that a plugin providing its own field type can add what it needs to the form.

- `&$field`: The custom field being edited.
- `&$view`: The view displaying the form.

#### onTableFieldsLoad(&amp;$externalValues)

Triggered when HikaShop builds the list of tables a custom field can be attached to. Add an entry to offer custom fields on a table of your own.

- `&$externalValues`: The extra tables, as an array of select options.

### Order Status API

This API allows you to customize the behavior of order statuses.

Available events for the Order Status API:

- [onBeforeOrderstatusCreate(&amp;$element, &amp;$do)](#onBeforeOrderstatusCreate)
- [onAfterOrderstatusCreate(&amp;$element)](#onAfterOrderstatusCreate)
- [onBeforeOrderstatusUpdate(&amp;$element, &amp;$do)](#onBeforeOrderstatusUpdate)
- [onAfterOrderstatusUpdate(&amp;$element)](#onAfterOrderstatusUpdate)
- [onBeforeOrderstatusDelete(&amp;$ids, &amp;$do)](#onBeforeOrderstatusDelete)
- [onAfterOrderstatusDelete(&amp;$ids)](#onAfterOrderstatusDelete)
- [onOrderStatusListingLoad(&amp;$orderstatus\_columns, &amp;$rows)](#onOrderStatusListingLoad)

#### onBeforeOrderstatusCreate(&amp;$element, &amp;$do)

Triggered before a new order status is created.

- `&$element`: The order status object.
- `&$do`: Boolean to allow or cancel.

#### onAfterOrderstatusCreate(&amp;$element)

Triggered after a new order status is successfully created.

- `&$element`: The created order status object.

#### onBeforeOrderstatusUpdate(&amp;$element, &amp;$do)

Triggered before an existing order status is updated.

- `&$element`: The order status object with new data. `$element->old` contains previous data.
- `&$do`: Boolean to allow or cancel.

#### onAfterOrderstatusUpdate(&amp;$element)

Triggered after an order status is successfully updated.

- `&$element`: The updated order status object.

#### onBeforeOrderstatusDelete(&amp;$ids, &amp;$do)

Triggered before one or more order statuses are deleted.

- `&$ids`: Array of order status IDs.
- `&$do`: Boolean to allow or cancel.

#### onAfterOrderstatusDelete(&amp;$ids)

Triggered after one or more order statuses are successfully deleted.

- `&$ids`: Array of deleted order status IDs.

#### onOrderStatusListingLoad(&amp;$orderstatus\_columns, &amp;$rows)

Triggered once the order status listing of your backend has been loaded, so that you can add your own column to it.

- `&$orderstatus_columns`: The columns of the listing. Add yours to display it.
- `&$rows`: The order status rows being displayed.

### Filter API

This API allows you to perform actions related to the HikaShop filtering system.

Available events for the Filter API:

- [onBeforeFilterCreate(&amp;$element, &amp;$do)](#onBeforeFilterCreate)
- [onAfterFilterCreate(&amp;$element)](#onAfterFilterCreate)
- [onBeforeFilterUpdate(&amp;$element, &amp;$do)](#onBeforeFilterUpdate)
- [onAfterFilterUpdate(&amp;$element)](#onAfterFilterUpdate)
- [onBeforeFilterDelete(&amp;$ids, &amp;$do)](#onBeforeFilterDelete)
- [onAfterFilterDelete(&amp;$ids)](#onAfterFilterDelete)
- [onFilterDisplay(&amp;$filter, &amp;$html, &amp;$divName, &amp;$parent, &amp;$datas)](#onFilterDisplay)
- [onFilterAdd(&amp;$filter, &amp;$filters, &amp;$select, &amp;$select2, &amp;$a, &amp;$b, &amp;$on, &amp;$order, &amp;$divName, &amp;$parent)](#onFilterAdd)
- [onFilterToLoad(&amp;$filter, &amp;$html, &amp;$divName, &amp;$parent)](#onFilterToLoad)
- [onFilterTypeDisplay(&amp;$allValues)](#onFilterTypeDisplay)
- [onInitFilterTypeClass($type)](#onInitFilterTypeClass)
- [onFilterTypeConfig(&amp;$element, &amp;$plgHtml)](#onFilterTypeConfig)
- [onFilterTypeSaveForm(&amp;$filter, &amp;$formData)](#onFilterTypeSaveForm)

#### onBeforeFilterCreate(&amp;$element, &amp;$do)

Triggered before a filter is created.

- `&$element`: The filter object.
- `&$do`: Boolean to allow or cancel.

#### onAfterFilterCreate(&amp;$element)

Triggered after a filter is successfully created.

- `&$element`: The created filter object.

#### onBeforeFilterUpdate(&amp;$element, &amp;$do)

Triggered before a filter is updated.

- `&$element`: The updated filter object.
- `&$do`: Boolean to allow or cancel.

#### onAfterFilterUpdate(&amp;$element)

Triggered after a filter is successfully updated.

- `&$element`: The updated filter object.

#### onBeforeFilterDelete(&amp;$ids, &amp;$do)

Triggered before one or more filters are deleted.

- `&$ids`: Array of filter IDs.
- `&$do`: Boolean to allow or cancel.

#### onAfterFilterDelete(&amp;$ids)

Triggered after one or more filters are successfully deleted.

- `&$ids`: Array of deleted filter IDs.

#### onFilterDisplay(&amp;$filter, &amp;$html, &amp;$divName, &amp;$parent, &amp;$datas)

Triggered when a filter is displayed. Use this for custom filter types.

- `&$filter`: The filter object.
- `&$html`: The HTML content to display.
- `&$divName`: The name of the div containing the filter.
- `&$parent`: The parent object (usually the product listing).
- `&$datas`: Data used by the filter.

#### onFilterAdd(&amp;$filter, &amp;$filters, &amp;$select, &amp;$select2, &amp;$a, &amp;$b, &amp;$on, &amp;$order, &amp;$divName, &amp;$parent)

Triggered when a filter needs to be added to the SQL query.

- `&$filter`: The filter object.
- `&$filters`: Array of WHERE clauses.
- `&$select`: Array of SELECT clauses.
- `&$select2`: Array of secondary SELECT clauses.
- `&$a`: Tables for joins.
- `&$b`: Tables for joins.
- `&$on`: JOIN conditions.
- `&$order`: The ORDER BY clause.
- `&$divName`: The div name.
- `&$parent`: The parent object.

#### onFilterToLoad(&amp;$filter, &amp;$html, &amp;$divName, &amp;$parent)

Triggered when loading the fields for a filter.

- `&$filter`: The filter object.
- `&$html`: The HTML content.
- `&$divName`: The div name.
- `&$parent`: The parent object.

#### onFilterTypeDisplay(&amp;$allValues)

Triggered when the display types of a filter are listed in your backend. Add an entry to offer a filter type of your own next to the dropdown, the cursor and the others.

- `&$allValues`: The display types, as an array of type key to label.

#### onInitFilterTypeClass($type)

Triggered when HikaShop needs the class of a filter type and cannot find it. Declare your class when $type is yours, so that the filter can be built.

- `$type`: The filter type being loaded.

#### onFilterTypeConfig(&amp;$element, &amp;$plgHtml)

Triggered when the options of a filter are displayed in your backend. Append the configuration of your own filter type to $plgHtml, wrapped in an element carrying a data-plg-filter-type attribute, which is how the page shows it only for the selected type.

- `&$element`: The filter being edited.
- `&$plgHtml`: The HTML of the configuration. Append yours to it.

#### onFilterTypeSaveForm(&amp;$filter, &amp;$formData)

Triggered when a filter whose type or data source belongs to a plugin is saved, so that the plugin stores what its own configuration needs. HikaShop only raises it for types prefixed with "plg.".

- `&$filter`: The filter being saved.
- `&$formData`: The data posted by the form.

### Currency and Taxation API

This API allows you to customize price rounding, currency conversion, and taxation rules.

Available events for the Currency and Taxation API:

- [onBeforeCurrencyCreate(&amp;$element, &amp;$do)](#onBeforeCurrencyCreate)
- [onAfterCurrencyCreate(&amp;$element)](#onAfterCurrencyCreate)
- [onBeforeCurrencyUpdate(&amp;$element, &amp;$do)](#onBeforeCurrencyUpdate)
- [onAfterCurrencyUpdate(&amp;$element)](#onAfterCurrencyUpdate)
- [onBeforeCurrencyDelete(&amp;$ids, &amp;$do)](#onBeforeCurrencyDelete)
- [onAfterCurrencyDelete(&amp;$ids)](#onAfterCurrencyDelete)
- [onBeforeTaxCreate(&amp;$element, &amp;$do)](#onBeforeTaxCreate)
- [onAfterTaxCreate(&amp;$element)](#onAfterTaxCreate)
- [onBeforeTaxUpdate(&amp;$element, &amp;$do)](#onBeforeTaxUpdate)
- [onAfterTaxUpdate(&amp;$element)](#onAfterTaxUpdate)
- [onBeforeTaxDelete(&amp;$ids, &amp;$do)](#onBeforeTaxDelete)
- [onAfterTaxDelete(&amp;$ids)](#onAfterTaxDelete)
- [onBeforeTaxationCreate(&amp;$element, &amp;$do)](#onBeforeTaxationCreate)
- [onAfterTaxationCreate(&amp;$element)](#onAfterTaxationCreate)
- [onBeforeTaxationUpdate(&amp;$element, &amp;$do)](#onBeforeTaxationUpdate)
- [onAfterTaxationUpdate(&amp;$element)](#onAfterTaxationUpdate)
- [onBeforeTaxationDelete(&amp;$ids, &amp;$do)](#onBeforeTaxationDelete)
- [onAfterTaxationDelete(&amp;$ids)](#onAfterTaxationDelete)
- [onHikashopGetTax(&amp;$obj, $zone\_id, $tax\_category\_id, $type, &amp;$matches, &amp;$taxPlans)](#onHikashopGetTax)

#### onBeforeCurrencyCreate(&amp;$element, &amp;$do)

Triggered before a currency is created.

- `&$element`: The currency object.
- `&$do`: Boolean to allow or cancel.

#### onAfterCurrencyCreate(&amp;$element)

Triggered after a currency is successfully created.

- `&$element`: The created currency object.

#### onBeforeCurrencyUpdate(&amp;$element, &amp;$do)

Triggered before a currency is updated.

- `&$element`: The currency object.
- `&$do`: Boolean to allow or cancel.

#### onAfterCurrencyUpdate(&amp;$element)

Triggered after a currency is successfully updated.

- `&$element`: The updated currency object.

#### onBeforeCurrencyDelete(&amp;$ids, &amp;$do)

Triggered before one or more currencies are deleted.

- `&$ids`: Array of currency IDs.
- `&$do`: Boolean to allow or cancel.

#### onAfterCurrencyDelete(&amp;$ids)

Triggered after one or more currencies are successfully deleted.

- `&$ids`: Array of deleted currency IDs.

#### onBeforeTaxCreate(&amp;$element, &amp;$do)

Triggered before a tax rate is created.

- `&$element`: The tax object.
- `&$do`: Boolean to allow or cancel.

#### onAfterTaxCreate(&amp;$element)

Triggered after a tax rate is successfully created.

- `&$element`: The created tax object.

#### onBeforeTaxUpdate(&amp;$element, &amp;$do)

Triggered before a tax rate is updated.

- `&$element`: The tax object.
- `&$do`: Boolean to allow or cancel.

#### onAfterTaxUpdate(&amp;$element)

Triggered after a tax rate is successfully updated.

- `&$element`: The updated tax object.

#### onBeforeTaxDelete(&amp;$ids, &amp;$do)

Triggered before one or more tax rates are deleted.

- `&$ids`: Array of tax IDs.
- `&$do`: Boolean to allow or cancel.

#### onAfterTaxDelete(&amp;$ids)

Triggered after one or more tax rates are successfully deleted.

- `&$ids`: Array of deleted tax IDs.

#### onBeforeTaxationCreate(&amp;$element, &amp;$do)

Triggered before a taxation rule (linking tax to zone/category) is created.

- `&$element`: The taxation object.
- `&$do`: Boolean to allow or cancel.

#### onAfterTaxationCreate(&amp;$element)

Triggered after a taxation rule is successfully created.

- `&$element`: The created taxation object.

#### onBeforeTaxationUpdate(&amp;$element, &amp;$do)

Triggered before a taxation rule is updated.

- `&$element`: The taxation object.
- `&$do`: Boolean to allow or cancel.

#### onAfterTaxationUpdate(&amp;$element)

Triggered after a taxation rule is successfully updated.

- `&$element`: The updated taxation object.

#### onBeforeTaxationDelete(&amp;$ids, &amp;$do)

Triggered before one or more taxation rules are deleted.

- `&$ids`: Array of taxation IDs.
- `&$do`: Boolean to allow or cancel.

#### onAfterTaxationDelete(&amp;$ids)

Triggered after one or more taxation rules are successfully deleted.

- `&$ids`: Array of deleted taxation IDs.

#### onHikashopGetTax(&amp;$obj, $zone\_id, $tax\_category\_id, $type, &amp;$matches, &amp;$taxPlans)

Triggered when HikaShop determines which taxes apply to a specific situation.

- `&$obj`: The currency helper instance.
- `$zone_id`: The zone ID (shipping or billing address).
- `$tax_category_id`: The product's tax category ID.
- `$type`: The type of tax.
- `&$matches`: The array of matching taxation rules found so far.
- `&$taxPlans`: The array of all available taxation rules.

### Waitlist API

This API allows you to perform actions related to the waitlist system.

Available events for the Waitlist API:

- [onBeforeWaitlistCreate(&amp;$element, &amp;$do)](#onBeforeWaitlistCreate)
- [onAfterWaitlistCreate(&amp;$element)](#onAfterWaitlistCreate)
- [onBeforeWaitlistUpdate(&amp;$element, &amp;$do)](#onBeforeWaitlistUpdate)
- [onAfterWaitlistUpdate(&amp;$element)](#onAfterWaitlistUpdate)
- [onBeforeWaitlistDelete(&amp;$ids, &amp;$do)](#onBeforeWaitlistDelete)
- [onAfterWaitlistDelete(&amp;$ids)](#onAfterWaitlistDelete)

#### onBeforeWaitlistCreate(&amp;$element, &amp;$do)

Triggered before a waitlist entry is created.

- `&$element`: The waitlist object.
- `&$do`: Boolean to allow or cancel.

#### onAfterWaitlistCreate(&amp;$element)

Triggered after a waitlist entry is successfully created.

- `&$element`: The created waitlist object.

#### onBeforeWaitlistUpdate(&amp;$element, &amp;$do)

Triggered before a waitlist entry is updated.

- `&$element`: The updated waitlist object.
- `&$do`: Boolean to allow or cancel.

#### onAfterWaitlistUpdate(&amp;$element)

Triggered after a waitlist entry is successfully updated.

- `&$element`: The updated waitlist object.

#### onBeforeWaitlistDelete(&amp;$ids, &amp;$do)

Triggered before one or more waitlist entries are deleted.

- `&$ids`: Array of waitlist IDs.
- `&$do`: Boolean to allow or cancel.

#### onAfterWaitlistDelete(&amp;$ids)

Triggered after one or more waitlist entries are successfully deleted.

- `&$ids`: Array of deleted waitlist IDs.

### File API

This API allows you to customize file handling and downloads.

Available events for the File API:

- [onBeforeDownloadFile(&amp;$filename, &amp;$do, &amp;$file, $options)](#onBeforeDownloadFile)
- [onBeforeFileCreate(&amp;$file, &amp;$do)](#onBeforeFileCreate)
- [onAfterFileCreate(&amp;$file)](#onAfterFileCreate)
- [onBeforeFileUpdate(&amp;$file, &amp;$do)](#onBeforeFileUpdate)
- [onAfterFileUpdate(&amp;$file)](#onAfterFileUpdate)
- [onBeforeFileDelete(&amp;$oldEntries, $ignoreFile)](#onBeforeFileDelete)
- [onAfterFileDelete(&amp;$oldEntries)](#onAfterFileDelete)
- [onHikaBeforeFileSave(&amp;$file, &amp;$do)](#onHikaBeforeFileSave)
- [onHikaAfterFileSave(&amp;$file)](#onHikaAfterFileSave)
- [onHikashopUploadStoreFile(&amp;$file, &amp;$file\_path, $uploaded\_file, $slice, $options)](#onHikashopUploadStoreFile)
- [onHikashopFieldFileInfo(&amp;$info, $value, $field)](#onHikashopFieldFileInfo)
- [onFieldFileDownload(&amp;$found, $name, $field\_table, $field\_namekey, $options)](#onFieldFileDownload)
- [onAfterDownloadFile(&amp;$filename, &amp;$file)](#onAfterDownloadFile)

#### onBeforeDownloadFile(&amp;$filename, &amp;$do, &amp;$file, $options)

Triggered before a file download.

- `&$filename`: The path to the file.
- `&$do`: A boolean. Set it to `false` to cancel the download.
- `&$file`: The file object from the database. Set `$file->download_name` to give the downloaded copy another name than the stored file, for example with its version number.
- `$options`: An array of options for the download.

#### onBeforeFileCreate(&amp;$file, &amp;$do)

Triggered before a file (image or download) is created in the database.

- `&$file`: The file object.
- `&$do`: Boolean to allow or cancel.

#### onAfterFileCreate(&amp;$file)

Triggered after a file is successfully created.

- `&$file`: The created file object.

#### onBeforeFileUpdate(&amp;$file, &amp;$do)

Triggered before a file is updated.

- `&$file`: The file object with updated data.
- `&$do`: Boolean to allow or cancel.

#### onAfterFileUpdate(&amp;$file)

Triggered after a file is successfully updated.

- `&$file`: The updated file object.

#### onBeforeFileDelete(&amp;$oldEntries, $ignoreFile)

Triggered before one or more files are deleted.

- `&$oldEntries`: Array of file objects to be deleted.
- `$ignoreFile`: True when only the records are removed and the files themselves are kept, so a plugin which stores them elsewhere should keep its copies too.

#### onAfterFileDelete(&amp;$oldEntries)

Triggered after one or more files are successfully deleted.

- `&$oldEntries`: Array of deleted file objects.

#### onHikaBeforeFileSave(&amp;$file, &amp;$do)

Triggered before a file is saved during product or category editing.

- `&$file`: The file object.
- `&$do`: Boolean to allow or cancel.

#### onHikaAfterFileSave(&amp;$file)

Triggered after a file is successfully saved during product or category editing.

- `&$file`: The saved file object.

#### onHikashopUploadStoreFile(&amp;$file, &amp;$file\_path, $uploaded\_file, $slice, $options)

Triggered while a file is being uploaded, after it has been validated but before HikaShop writes anything to the upload folder. It lets a plugin store the file somewhere else, for instance on a cloud storage. It is triggered for every kind of upload, images as well as product files, so a plugin must check `$options['type']` and ignore what it does not handle. A plugin takes over the storage of a file by **returning true**: HikaShop then writes nothing itself and the plugin becomes responsible for the whole storage, including the assembling of a sliced upload.

- `&$file`: The file being uploaded. A plugin which stores the file reports back on this object: `partial` set to true while more slices are expected, `resume` and `slice` to ask the browser to restart the upload at a given slice, `error` with a message on failure, and `file_path` and `size` once the file is complete. `file_path` is then recorded as the path of the file in place of the local name.
- `&$file_path`: The name the file is stored under. It can be changed to store the file under a different name.
- `$uploaded_file`: The temporary file of the slice being received.
- `$slice`: The index, the total number, the size of the slices and the total size of the file, or null when the file is not uploaded in slices. Large files are sent by the browser in several requests, so a plugin is called once per slice and only the last one completes the file.
- `$options`: The options of the upload, including `type` and the destination folder.

#### onHikashopFieldFileInfo(&amp;$info, $value, $field)

Triggered when HikaShop needs the fingerprint and the size of a file of a custom field of the type "AJAX file" or "AJAX image" whose value starts with "@" or "#", which means it is stored by a plugin rather than on the server. It is triggered when the field is displayed and again when it is saved.

- `&$info`: An object with `hash` and `size`, both empty. A plugin which recognises the value fills them in. `hash` takes the place of the checksum HikaShop computes for a file on the server: it is what proves that a value submitted with a form really is the file which was uploaded, so it must be something only the storage can give, and it must stay the same between the display and the save. A value left without a hash is refused when the form is saved.
- `$value`: The value of the field, the reference of the file.
- `$field`: The custom field the value belongs to.

#### onFieldFileDownload(&amp;$found, $name, $field\_table, $field\_namekey, $options)

Triggered when a file uploaded through a custom field is requested and HikaShop could not match it to a record of its own. Set $found to true if the file belongs to something of yours and the customer may download it.

- `&$found`: A boolean. Set it to true to allow the download.
- `$name`: The name of the file requested.
- `$field_table`: The table the custom field belongs to.
- `$field_namekey`: The name key of the custom field.
- `$options`: The options of the download.

#### onAfterDownloadFile(&amp;$filename, &amp;$file)

Triggered once a file has been sent to the customer, which is where a plugin records the download or applies its own counter.

- `&$filename`: The path of the file that was sent.
- `&$file`: The file object from the database.

### Email API

This API allows you to customize email preparation, sending and registration.

- [onBeforeMailPrepare(&amp;$mail, &amp;$mailer, &amp;$do)](#onBeforeMailPrepare)
- [onBeforeMailSend(&amp;$mail, &amp;$mailer)](#onBeforeMailSend)
- [onMailListing(&amp;$plugin\_files)](#onMailListing)
- [onMailTemplateListing(&amp;$external\_template\_files, $mail\_name)](#onMailTemplateListing)
- [onMailBlockListing(&amp;$blocks)](#onMailBlockListing)
- [onHkProcessMailTemplate(&amp;$mail, &amp;$data, &amp;$content, &amp;$vars, &amp;$texts, &amp;$templates)](#onHkProcessMailTemplate)

#### onBeforeMailPrepare(&amp;$mail, &amp;$mailer, &amp;$do)

Triggered before an email is prepared for sending. Allows to modify the mail content or cancel sending.

- `&$mail`: The mail object containing data (to, subject, body, options).
- `&$mailer`: The HikaShop mailer instance.
- `&$do`: A boolean. Set it to `false` to cancel the email preparation and sending.

#### onBeforeMailSend(&amp;$mail, &amp;$mailer)

Triggered just before an email is sent.

- `&$mail`: The mail object with its final content.
- `&$mailer`: The HikaShop mailer instance.

#### onMailListing(&amp;$plugin\_files)

Allows plugins to register custom emails in System &gt; Emails. Add your email metadata to `$plugin_files`.

- `&$plugin_files`: An array of email configuration objects.

#### onMailTemplateListing(&amp;$external\_template\_files, $mail\_name)

Triggered when HikaShop lists the templates available for an email. Add your own file to offer a template that does not live in the HikaShop folders.

- `&$external_template_files`: The extra templates, as an array of select options.
- `$mail_name`: The email the templates are listed for.

#### onMailBlockListing(&amp;$blocks)

Triggered when HikaShop lists the blocks an email can insert with a `{BLOCK:name}` tag. Add your own block to offer it to the emails and, later, to the email editor.

- `&$blocks`: The blocks, keyed by name. Each one is an array with `name`, `path` (the PHP file rendering the block), `override` (the .modified.php file, when there is one) and `label`. The file is included with `$mail`, `$data`, `$config`, `$tpl` (the design tokens of the template), `$vars` and `$texts` in scope, and its output goes through the usual tags replacement.

#### onHkProcessMailTemplate(&amp;$mail, &amp;$data, &amp;$content, &amp;$vars, &amp;$texts, &amp;$templates)

Triggered while an email is being built from its template, with everything that goes into it. Change $content to produce the body yourself, or add to $vars and $texts to make more data available to the template.

- `&$mail`: The email object.
- `&$data`: The data the email is about, an order for instance.
- `&$content`: The body produced so far.
- `&$vars`: The variables the template can use.
- `&$texts`: The texts the template can use.
- `&$templates`: The templates being applied.

### Configuration API

This API allows you to customize HikaShop settings loading and saving.

- [onAfterConfigLoad(&amp;$values)](#onAfterConfigLoad)
- [onBeforeConfigSave(&amp;$config, &amp;$do)](#onBeforeConfigSave)
- [onAfterConfigSave(&amp;$params)](#onAfterConfigSave)
- [onHikashopLanguageChange($locale)](#onHikashopLanguageChange)

#### onAfterConfigLoad(&amp;$values)

Triggered after HikaShop configuration is loaded from the database.

- `&$values`: Array of configuration objects.

#### onBeforeConfigSave(&amp;$config, &amp;$do)

Triggered before HikaShop configuration is saved.

- `&$config`: The configuration array.
- `&$do`: Boolean to allow or cancel.

#### onAfterConfigSave(&amp;$params)

Triggered after HikaShop configuration is saved.

- `&$params`: The parameters that were saved.

#### onHikashopLanguageChange($locale)

Triggered once HikaShop has switched to another language and loaded its translation files, so that a plugin can load its own for the same language.

- `$locale`: The language now in use, as its code, en-GB for instance.

### Mass Action API

This API allows you to create your own data tables, triggers, filters and actions for the HikaShop Mass Action system.

- [onMassactionTableLoad(&amp;$tables)](#onMassactionTableLoad)
- [onMassactionRelationLoad(&amp;$links, $tables)](#onMassactionRelationLoad)
- [onMassactionColumnSourceLoad(&amp;$sources, $tables)](#onMassactionColumnSourceLoad)
- [onMassactionTypeLoad(&amp;$types)](#onMassactionTypeLoad)
- [onMassactionActionLoad(&amp;$actions)](#onMassactionActionLoad)
- [onMassactionFieldTypeLoad(&amp;$fields)](#onMassactionFieldTypeLoad)
- [onMassactionTriggerLoad(&amp;$triggers)](#onMassactionTriggerLoad)
- [onMassactionTableFiltersLoad(&amp;$table, &amp;$filters, &amp;$filters\_html, &amp;$massaction)](#onMassactionTableFiltersLoad)
- [onMassactionTableActionsLoad(&amp;$table, &amp;$actions, &amp;$actions\_html, &amp;$massaction)](#onMassactionTableActionsLoad)
- [onAfterMassactionCreate(&amp;$element)](#onAfterMassactionCreate)
- [onAfterMassactionUpdate(&amp;$element)](#onAfterMassactionUpdate)
- [onBeforeMassactionProcess(&amp;$massaction, &amp;$elements, $report, &amp;$do)](#onBeforeMassactionProcess)
- [onAfterMassactionProcess(&amp;$massaction, &amp;$elements, $report)](#onAfterMassactionProcess)
- [onBeforeMassactionUpdate(&amp;$element)](#onBeforeMassactionUpdate)
- [onMassactionSpecialActions(&amp;$special)](#onMassactionSpecialActions)
- [onLoadDatatMassActionBeforeEdition($data, $data\_id, $table, $column, $type, $ids, &amp;$query, &amp;$view)](#onLoadDatatMassActionBeforeEdition)

#### onMassactionTableLoad(&amp;$tables)

Triggered to collect available data tables for mass actions.

- `&$tables`: An array of table objects. Each one carries `table` (the name of the table without its prefix), `value` (what a saved mass action stores, and the key everything else uses) and `text` (what the merchant reads). It may also carry `component` (the extension owning the table, `hikashop` when not said), `id` (the primary key column, `<table>_id` when not said) and `email` (the column holding an email address for one of its rows, when it has one). An extension declaring a table of its own has to give `component`, or its table will be looked for under HikaShop's prefix.
- What the table offers in the edit form: `filters`, the filters on a column of the table or of a table it reaches, keyed by the name a saved mass action stores; `types`, the filters of the register it offers beyond `limit`, `ordering` and `direction`, keyed by name, the value naming the type which answers (`'accessLevel' => 'userGroup'`); and `actions`, the names of the actions of the register which are not offered on every table.
- An entry of `filters` carries `label`, `table` (where its columns come from) and `widget` when the column is not picked from a plain list. With `apply` the register runs it: `column` compares a column of the element, `link` a column of the table reached through `link` (a link name, a path of links separated by dots, or a list of them), and `characteristic` the value of a characteristic of a product. Without `apply`, the filter is run by the events below.
- `date_columns`: the columns holding a date as a timestamp, where a filter understands a value such as `now` or `-2 days`. The date picker custom fields of the table are found on their own.
- `export_key`: set to `false` when the export of the table should not add the key of the element to the columns the merchant ticked.
- `emails`: the emails of the shop the "send an email" action can send about an element of the table, as an array of email name =&gt; loader. The loader is a callable receiving the element and the email name and returning the mail object ready for `sendMail()`, with its recipient set, or `null` to skip that element. The action lists them next to its own "Custom" email and, on the orders, writes a line in the history of each order whose customer received one.
- `lines`: the name of the link holding the lines of an element, `order_product` on the orders. The "send an email" action then offers to send one email per matching line: the lines each filter following that link matches, grouped by product with the variants of a product together, whose columns are tags of the email.
- `cells`: what the inline editing of the results listing does with a cell, as an array of table of the listing =&gt; entry. A cell of the table itself is saved through its class and read back by its id without an entry. An entry may give `save`, a callable receiving `$data_id, $column, $value, $id, $type` and writing the value; `load`, a callable receiving `$data_id, $column, $id, $value` and returning a query or the rows to redisplay; `select`, the columns read back after the edited one when a read by id is enough; and `reload`, the columns whose edit reloads the whole listing.
- `events`: the events of the rows of the table a mass action can be triggered by, as an array of event name =&gt; language key of the label, for instance `'onAfterOrderCreate' => 'AFTER_AN_ORDER_IS_CREATED'`. The class of the table raises them; the mass action runs on the rows they hand over.
- `results`: how the results listing, the display action and the CSV export show the tables around the elements of the table, as an array of callables and one list. `locks` receives `$table, $params` and fills `$params->lock` with the columns nobody may edit in the listing; `display` receives `$table, $params, $action` and attaches the rows of the other tables to each element of `$params->elements`; `load` receives `$other_table, $ids, $columns` and returns the query reading those rows, or the rows themselves; `export` receives `&$params, $other_table, &$columnsArrays` and adds the columns the CSV export writes for that table; `parent` receives an id and returns the query reading the name of its parent; `separators` gives, by other table, the character joining several values in one cell. A table declaring none of them shows its own columns and the column sources registered for it.
- `import`: offers the "Import from a CSV file" filter on the table, which it also has to name in its `types` (`'csvImport' => 'csvImport'`). It carries `key`, the column a file names a row by (the id when not said); `add`, `true` when a line naming no row may create one; `label`, `save_label` and `add_label`, the language keys of the name of the filter and of its two settings when the table wants its own; and `profile`, the name of a class `hikashopMassactionImport<Profile>Helper` reading files which hold more than the columns of the table, as products do. Without a profile the rows the file names are selected, with "save" the columns of the file are written to them, and with "add" a line naming no row creates one, all through the class of the table and leaving out the columns no mass action may write. HikaShop's orders and customers may be created this way, its categories and addresses may not.

A filter or an action nobody registered is run by the events `onProcess<Key>MassFilter<name>(&$elements, &$query, $filter, $num)`, `onCount<Key>MassFilter<name>(&$query, $filter, $num)` for the counter of the edit form, and `onProcess<Key>MassAction<name>(&$elements, &$action, $num)`. The key is the name of the table with a capital (`Product`) for a table of HikaShop, and the component followed by the name of the table (`HikamarketVendor`) for a table of another extension. Since HikaShop 6.7.0, HikaShop's own filters and actions are all in the registers, so its tables no longer answer these events: a plugin which called one of them to reuse a filter of HikaShop should ask the register instead, through `hikashop_get('helper.massaction-type')`.

#### onMassactionRelationLoad(&amp;$links, $tables)

Triggered after every table has been declared, to collect the links between them. It is a second pass on purpose: a link may be declared on a table the extension does not own, which is how an add-on says that a customer reaches one of its own rows, and no extension can assume it was loaded before the one owning the other side.

- `&$links`: An array of links keyed by the `value` of the table they start from. Each link carries `table` (the value of the table reached) and `via` (the column holding the reference). It may also carry `id` (the column the reference points at, the key of whichever side does not hold it when not said), `holder` (which of the two tables carries `via`, the one the link starts from when not said) and `name` (how a saved filter refers to it, the target table when not said, which is how an order reaches two different addresses). A link may also carry `list` set to `,` when `via` holds a list of ids between commas rather than one id, such as the products a discount is restricted to (`,3,8,`): the join then finds the id in the list, and the other table can hold several rows for one element.
- `$tables`: Every table already declared, keyed by value, so a link can be declared only when the table it points at exists.

#### onMassactionColumnSourceLoad(&amp;$sources, $tables)

Adds a table whose columns a mass action can display and export next to the ones its own table offers. It is how an extension puts its own data beside the results without knowing anything about how they are loaded: the serials of an order, the licences of a customer, the bookings of a product.

The event is fired once, after every table and every relation has been declared, so a source can be added to a table another extension declared.

- `$sources`: The list to add to, keyed by the table the source belongs to. Each entry is keyed by the name the form shows and a saved mass action stores its columns under, and holds:
- `table`: The table the rows come from, without its prefix.
- `via`: The column of that table holding the id of the element the row belongs to.
- `id`: Its own key. Defaults to `<table>_id`.
- `component`: Which extension owns the table. Defaults to `hikashop`.
- `order`: What to order the rows by. Defaults to the key.
- `$tables`: Every table already declared, by its stored name.

An element can have several rows of a source, so the export writes one set of columns per row, numbered: `1_serial_data`, `2_serial_data`, and so on.

Example, the serials of an order:

```
public function onMassactionColumnSourceLoad(&$sources, $tables) {
    $sources['order']['serial'] = array(
        'table' => 'serial',
        'component' => 'hikaserial',
        'via' => 'serial_order_id',
        'id' => 'serial_id',
    );
}
```

#### onMassactionTypeLoad(&amp;$types)

Triggered to collect the filters and actions which are implemented once for every table, rather than by one handler per table. A mass action asks this register before dispatching `onProcess<Table>MassFilter<name>`, so a name registered here answers for every table and the event is not dispatched for it; a name which is not registered goes to the event exactly as before.

- `&$types`: The types, keyed by the name a saved mass action stores (`limit`, `ordering`, `direction`). Registering an existing name replaces it, which is how an extension takes over one of HikaShop's on purpose. An entry is an object with `apply($table, &$elements, &$query, $filter, $num)`, and optionally `count($table, &$query, $filter, $num)` for what the counter of the edit form says and `universal()` returning `false` for a type offered only by the tables naming it in their `types`. Extending `hikashopMassactionFilterBaseHelper` gives the methods the edit form calls: `label()`, `defaults()` and `getHtml()`.

#### onMassactionActionLoad(&amp;$actions)

The same register as `onMassactionTypeLoad`, for the actions rather than for the filters. A mass action asks it before dispatching `onProcess<Table>MassAction<name>`, so a name registered here answers for every table and the event is not dispatched for it.

- `&$actions`: The actions, keyed by the name a saved mass action stores (`sendEmail`). Registering an existing name replaces it. An entry is an object with `act($table, &$elements, $action, $num)`, which returns a line for the report of the mass action or nothing, and optionally `universal()` returning `false` for an action offered only by the tables naming it in their `actions`. Extending `hikashopMassactionActionBaseHelper` gives the methods the edit form calls: `label()`, `defaults()` and `getHtml()`. An action registered without `act()` is still run by its event.

#### onMassactionFieldTypeLoad(&amp;$fields)

Triggered once per request to collect the kinds of field the results of a mass action can be edited with in place. The kind of a column (`text`, `price`, `status`, `yesno`, `custom_text`...) decides the rows the editor loads, the editor itself, whether the whole column can be edited at once, and how the posted value is written.

- `&$fields`: The kinds already registered, keyed by name. Each is an object with `query(&$view, $data, $table, $column, $type, $ids)` returning the statement loading the rows, `render(&$view, $id_td)` printing the editor of those rows, `hasColumn()` and `renderColumn(&$view, $id_td)` for the whole column, and `parse($value)` returning the value to write. Extending `hikashopMassactionFieldBaseHelper` gives all of them. The last registration of a name wins, so a plugin can replace a kind of HikaShop on purpose.

A kind nobody registered keeps working as before: its rows are loaded the generic way, `onLoadDatatMassActionBeforeEdition` still runs afterwards with the statement already written, and its editor is whatever answers `onDisplayEditionSquaredMassAction` followed by the name of the kind.

#### onMassactionTriggerLoad(&amp;$triggers)

The same register as `onMassactionTypeLoad`, for the triggers. HikaShop registers the scheduler periods, the HTTP endpoint, the MCP tool, and the events each table lists in its `events` key. A trigger extends `hikashopMassactionTriggerBaseHelper` and answers `names($origin)`, the events it offers on that table as name =&gt; label, and, when it has settings, `hasForm()`, `defaults()` and `getHtml()`.

- `&$triggers`: The triggers, keyed by a name of your choice. Add yours to it.

#### onMassactionTableFiltersLoad(&amp;$table, &amp;$filters, &amp;$filters\_html, &amp;$massaction)

Triggered to load filters for a specific table. Parameters are similar to triggers.

#### onMassactionTableActionsLoad(&amp;$table, &amp;$actions, &amp;$actions\_html, &amp;$massaction)

Triggered to load actions for a specific table. Parameters are similar to triggers.

#### onAfterMassactionCreate(&amp;$element)

Triggered after a mass action is created.

- `&$element`: The created mass action object.

#### onAfterMassactionUpdate(&amp;$element)

Triggered after a mass action is updated.

- `&$element`: The updated mass action object.

#### onBeforeMassactionProcess(&amp;$massaction, &amp;$elements, $report, &amp;$do)

Triggered before a mass action runs, once the elements it will act on have been selected.

- `&$massaction`: The mass action object.
- `&$elements`: The elements the mass action will act on.
- `$report`: The report of the mass action so far.
- `&$do`: A boolean. Set it to `false` to stop the mass action before its actions run.

#### onAfterMassactionProcess(&amp;$massaction, &amp;$elements, $report)

Triggered once every action of the mass action has run.

- `&$massaction`: The mass action object.
- `&$elements`: The elements the mass action acted on.
- `$report`: The report of the mass action.

#### onBeforeMassactionUpdate(&amp;$element)

Triggered before a mass action is saved from your backend, so that a plugin can complete or correct what is about to be stored.

- `&$element`: The mass action about to be saved.

#### onMassactionSpecialActions(&amp;$special)

Triggered when HikaShop lists the mass actions considered dangerous, the ones only a Super User may configure or run. Declare yours here when it can reach outside the shop.

- `&$special`: The names of the actions treated as special. Add yours to it.

#### onLoadDatatMassActionBeforeEdition($data, $data\_id, $table, $column, $type, $ids, &amp;$query, &amp;$view)

Triggered before such a cell is opened for edition, to load the value and the choices it should offer.

- `$data`: The kind of data being edited.
- `$data_id`: The id of that data.
- `$table`: The table of the listing.
- `$column`: The column being edited.
- `$type`: The type of the column.
- `$ids`: The records being edited.
- `&$query`: The query loading the current value.
- `&$view`: The view displaying the listing.

### Dashboard API

This API allows you to customize the HikaShop backend dashboard.

- [onBeforeStatisticsLoad(&amp;$dashboardStructure)](#onBeforeStatisticsLoad)

#### onBeforeStatisticsLoad(&amp;$dashboardStructure)

Triggered before displaying the backend dashboard. `$dashboardStructure` contains the layout, blocks, and queries. You can inject your own widgets here.

- `&$dashboardStructure`: The configuration object for the dashboard.

### Other Events

Miscellaneous events for various HikaShop functionalities.

- [onBeforeHikashopLoad($option)](#onBeforeHikashopLoad)
- [onAfterHikashopLoad()](#onAfterHikashopLoad)
- [onHikashopCronTrigger(&amp;$messages)](#onHikashopCronTrigger)
- [onHikashopBeforeCheckDB(&amp;$createTable, &amp;$custom\_fields, &amp;$structure, &amp;$helper)](#onHikashopBeforeCheckDB)
- [onHikashopAfterCheckDB(&amp;$messages)](#onHikashopAfterCheckDB)
- [onHikashopPluginController($ctrl)](#onHikashopPluginController)
- [onCheckSubscription($subscription\_level, &amp;$infos)](#onCheckSubscription)
- [onBeforeSendContactRequest(&amp;$element, &amp;$send)](#onBeforeSendContactRequest)
- [onBeforeWithdrawalRequest(&amp;$data, &amp;$do)](#onBeforeWithdrawalRequest)
- [onNameboxTypesLoad(&amp;$loaded\_types)](#onNameboxTypesLoad)
- [onHkContentParamsDisplay('menu', $name, &amp;$element, &amp;$extra\_blocks)](#onHkContentParamsDisplay)
- [onBeforeHikaPluginConfigurationListing($type, &amp;$filters, &amp;$order, &amp;$searchMap, &amp;$extrafilters, &amp;$view)](#onBeforeHikaPluginConfigurationListing)
- [onAfterHikaPluginConfigurationListing($type, &amp;$rows, &amp;$listing\_columns, &amp;$view)](#onAfterHikaPluginConfigurationListing)
- [onHikaPluginConfiguration($type, &amp;$plugin, &amp;$element, &amp;$extra\_config, &amp;$extra\_blocks)](#onHikaPluginConfiguration)
- [onBeforeCharacteristicListing($paramBase, &amp;$extrafilters, &amp;$pageInfo, &amp;$filters)](#onBeforeCharacteristicListing)
- [onNameboxCharacteristicsLoad($typeConfig, &amp;$fullLoad, $mode, $value, $search, $options, &amp;$ret)](#onNameboxCharacteristicsLoad)
- [onUploadControllerGet($controllerName, &amp;$controller)](#onUploadControllerGet)
- [onAfterHikaPluginConfigurationSelectionListing($type, &amp;$plugins, &amp;$view)](#onAfterHikaPluginConfigurationSelectionListing)
- [onBeforeHikaPluginCreate($type, &amp;$element, &amp;$do)](#onBeforeHikaPluginCreate)
- [onBeforeHikaPluginUpdate($type, &amp;$element, &amp;$do)](#onBeforeHikaPluginUpdate)
- [onAfterProductsImport(&amp;$view, &amp;$importProducts)](#onAfterProductsImport)
- [onGetImportSupportedColumns(&amp;$columns)](#onGetImportSupportedColumns)

#### onBeforeHikashopLoad($option)

Triggered early in HikaShop initialization.

- `$option`: The component option name (usually `com_hikashop`).

#### onAfterHikashopLoad()

Triggered after HikaShop initialization is complete.

#### onHikashopCronTrigger(&amp;$messages)

Triggered when a HikaShop cron job is executed. Add your logs to `$messages`.

- `&$messages`: An array of log messages (strings).

#### onHikashopBeforeCheckDB(&amp;$createTable, &amp;$custom\_fields, &amp;$structure, &amp;$helper)

Triggered during HikaShop's "Check Database" process. Use this to ensure your plugin's custom tables and columns are correctly defined and maintained.

- `&$createTable`: An array of CREATE TABLE SQL statements.
- `&$custom_fields`: An array of custom fields to be checked.
- `&$structure`: An object representing the database structure.
- `&$helper`: The HikaShop DB helper instance.

#### onHikashopAfterCheckDB(&amp;$messages)

Triggered after the database check is complete.

- `&$messages`: An array of success or error messages (strings) from the check.

#### onHikashopPluginController($ctrl)

Allows plugins to implement their own controllers within HikaShop. This lets you offer custom interfaces without creating a full CMS component. See `plg_hikashop_email_history` for a live example.

- `$ctrl`: The name of the controller being requested.

#### onCheckSubscription($subscription\_level, &amp;$infos)

Triggered when HikaShop checks the subscription level for special features or updates.

- `$subscription_level`: The requested level string.
- `&$infos`: An array where you can set the subscription status.

#### onBeforeSendContactRequest(&amp;$element, &amp;$send)

Triggered before a product contact request is sent.

- `&$element`: The object containing contact request data.
- `&$send`: A boolean. Set it to `false` to cancel sending the request.

#### onBeforeWithdrawalRequest(&amp;$data, &amp;$do)

Triggered when a customer sends the withdrawal form, before HikaShop looks the order up. The captcha plugins use it to check their answer, so the form cannot be used to guess order numbers.

- `&$data`: The array posted by the form: the order id, or the order number and the email address, the products and the reason.
- `&$do`: A boolean. Set it to `false` to refuse the request; the form is displayed again with what the customer typed, so enqueue a message saying why.

#### onNameboxTypesLoad(&amp;$loaded\_types)

Triggered when HikaShop loads the namebox types, the selectors used across the backend to pick a product, a category or a customer. Register a type of your own to be able to display it in your forms.

- `&$loaded_types`: The namebox types, keyed by type name.

#### onHkContentParamsDisplay('menu', $name, &amp;$element, &amp;$extra\_blocks)

Triggered when the parameters of a HikaShop menu item are displayed, so that a plugin can add its own settings to them. The blocks you add are displayed with the ones HikaShop provides.

- `'menu'`: The kind of content, always menu here.
- `$name`: The menu item type being edited.
- `&$element`: The content type and the parameters currently set.
- `&$extra_blocks`: An array with a products and a layouts key. Add your blocks to them.

#### onBeforeHikaPluginConfigurationListing($type, &amp;$filters, &amp;$order, &amp;$searchMap, &amp;$extrafilters, &amp;$view)

Triggered before the listing of the payment, shipping or plugin configurations is loaded in your backend. Change the query, or add a filter of your own to the listing.

- `$type`: The kind of listing: payment, shipping or plugin.
- `&$filters`: The WHERE clauses of the query.
- `&$order`: The ORDER BY clause of the query.
- `&$searchMap`: The columns the search box looks into.
- `&$extrafilters`: The extra filters displayed above the listing. Add yours to it.
- `&$view`: The view displaying the listing.

#### onAfterHikaPluginConfigurationListing($type, &amp;$rows, &amp;$listing\_columns, &amp;$view)

Triggered once that listing has loaded its rows, so that you can add your own column to it.

- `$type`: The kind of listing: payment, shipping or plugin.
- `&$rows`: The methods being displayed.
- `&$listing_columns`: The columns of the listing. Add yours to display it.
- `&$view`: The view displaying the listing.

#### onHikaPluginConfiguration($type, &amp;$plugin, &amp;$element, &amp;$extra\_config, &amp;$extra\_blocks)

Triggered when the configuration of a payment or shipping method is displayed, so that a plugin can add settings of its own to the form of another plugin.

- `$type`: The kind of method: payment, shipping or plugin.
- `&$plugin`: The plugin whose configuration is displayed.
- `&$element`: The method being configured.
- `&$extra_config`: The extra settings. Add yours to it.
- `&$extra_blocks`: The extra blocks displayed around the settings.

#### onBeforeCharacteristicListing($paramBase, &amp;$extrafilters, &amp;$pageInfo, &amp;$filters)

Triggered before the characteristic listing of your backend is loaded, so that you can add a filter of your own or change the query.

- `$paramBase`: The parameter prefix of the listing.
- `&$extrafilters`: The extra filters displayed above the listing.
- `&$pageInfo`: The pagination, the filters and the sort order.
- `&$filters`: The WHERE clauses of the query.

#### onNameboxCharacteristicsLoad($typeConfig, &amp;$fullLoad, $mode, $value, $search, $options, &amp;$ret)

Triggered when a characteristic selector is filled and the values do not come from HikaShop itself, so that a plugin can supply them.

- `$typeConfig`: The configuration of the selector.
- `&$fullLoad`: Whether every value is being loaded or only a search.
- `$mode`: The mode of the selector.
- `$value`: The value currently selected.
- `$search`: What the user typed.
- `$options`: The options of the selector.
- `&$ret`: The values to display. Fill it to supply your own.

#### onUploadControllerGet($controllerName, &amp;$controller)

Triggered when an upload is handled and HikaShop does not recognise the controller it is for. Set $controller to your own to take the upload over.

- `$controllerName`: The controller the upload was sent to.
- `&$controller`: The controller that will handle it. Set yours to take over.

#### onAfterHikaPluginConfigurationSelectionListing($type, &amp;$plugins, &amp;$view)

Triggered when the list of payment or shipping plugins you can add a method for is displayed, so that you can add an entry of your own to it.

- `$type`: The kind of listing: payment, shipping or plugin.
- `&$plugins`: The plugins offered. Add yours to it.
- `&$view`: The view displaying the listing.

#### onBeforeHikaPluginCreate($type, &amp;$element, &amp;$do)

Triggered before a payment or shipping method is created. Set $do to false to refuse the creation.

- `$type`: The kind of method: payment or shipping.
- `&$element`: The method about to be created.
- `&$do`: A boolean. Set it to false to cancel the creation.

#### onBeforeHikaPluginUpdate($type, &amp;$element, &amp;$do)

Triggered before a payment or shipping method is saved. Set $do to false to refuse the change.

- `$type`: The kind of method: payment or shipping.
- `&$element`: The method about to be saved.
- `&$do`: A boolean. Set it to false to cancel the update.

#### onAfterProductsImport(&amp;$view, &amp;$importProducts)

Triggered once a product import has finished, with everything it created or changed, which is where a plugin applies what it needs to the imported products.

- `&$view`: The import view, carrying its report.
- `&$importProducts`: The products that were imported.

#### onGetImportSupportedColumns(&amp;$columns)

Triggered when the import lists the columns it understands. Add yours so that a file carrying them can be matched to your own data.

- `&$columns`: The columns the import supports. Add yours to it.

### Assets Management

HikaShop provides helpers to manage JavaScript and CSS assets, ensuring compatibility and avoiding duplicate loading.

#### Loading HikaShop Libraries

Use `hikashop_loadJslib($name)` to load common libraries. This method handles both JS and CSS dependencies for each library.

```
hikashop_loadJslib('jquery');
hikashop_loadJslib('font-awesome');
hikashop_loadJslib('fancybox');
hikashop_loadJslib('owl-carousel');
```

Available libraries include: `jquery`, `font-awesome`, `fancybox`, `owl-carousel`, `tooltip`, `otree`, `opload`, `vex`, `notify`, `creditcard`, `dropdown`, `nouislider`, `swiper`, `drawer`.

#### Adding Custom Assets

For cross-platform compatibility, use HikaShop's asset loading functions. For platform-specific asset loading:

**On Joomla (J4+)**, use the **Web Asset Manager**:

```
if (defined('JVERSION') && version_compare(JVERSION, '4.0', '>=')) {
    $wa = JFactory::getDocument()->getWebAssetManager();
    $wa->registerAndUseStyle('plg_yourplugin.style', 'plugins/hikashop/yourplugin/style.css');
    $wa->registerAndUseScript('plg_yourplugin.script', 'plugins/hikashop/yourplugin/script.js', [], ['defer' => true], ['jquery']);
} elseif (defined('ABSPATH')) {
    // WordPress
    wp_enqueue_style('plg_yourplugin_style', plugins_url('yourplugin/style.css', __FILE__));
    wp_enqueue_script('plg_yourplugin_script', plugins_url('yourplugin/script.js', __FILE__), array('jquery'), false, true);
} else {
    // Fallback for legacy Joomla
    $doc = JFactory::getDocument();
    $doc->addStyleSheet(JURI::root() . 'plugins/hikashop/yourplugin/style.css');
    $doc->addScript(JURI::root() . 'plugins/hikashop/yourplugin/script.js');
}
```

For more details, see the [Joomla Web Asset Manager documentation](https://manual.joomla.org/docs/4.4/general-concepts/web-asset-manager/) or the [WordPress Plugin Developer documentation](https://developer.wordpress.org/plugins/wordpress-org/how-your-readme-txt-works/).

### Main Objects

Common objects passed as parameters to HikaShop events. Understanding their structure is key to effective development.

- **$order**: Contains the full order record. Important properties:
- `$order->products`: Array of product objects in the order.
- `$order->billing_address` / `$order->shipping_address`: Address objects.
- `$order->order_status`: Current status string.
- `$order->order_payment_params` / `$order->order_shipping_params`: Objects where custom metadata can be stored for third-party integrations.
- **$product**: Represents a catalog item. Important properties:
- `$product->product_code`: Unique SKU.
- `$product->prices`: Array of price objects.
- `$product->categories`: Array of category IDs.
- `$product->product_parent_id`: Used to link variants to their main product.
- **$cart**: The current shopping session. Properties include `$cart->products`, `$cart->cart_params`, and `$cart->cart_shipping_ids`.

### Overrides

HikaShop provides several ways to customize its behavior and appearance without modifying core files.

#### View Overrides

You can override any HikaShop view by using the **Display &gt; Views** menu in the HikaShop backend. This is the recommended way as HikaShop handles the file creation for you.

**Manual Override Path on Joomla:** `templates/YOUR_TEMPLATE/html/com_hikashop/VIEW_GROUP/VIEW_NAME.php`
For example, to override the product page: `templates/cassiopeia/html/com_hikashop/product/show.php`

**Manual Override Path on WordPress:** `wp-content/themes/YOUR_THEME/hikashop/VIEW_GROUP/VIEW_NAME.php`
For example: `wp-content/themes/flavor/hikashop/product/show.php`

For more details on layout customization, see the [Layout Customization Guide](https://www.hikashop.com/support/documentation/153-customize-the-display.html#layout).

**Developer Tip:** Enable the **"Display view files"** setting in *HikaShop Configuration &gt; Display &gt; General*. Once enabled, HikaShop will output a small comment in the HTML source before each view file it renders, making it easy to identify exactly which file you need to override.

#### Plugin View Overrides

If a plugin uses `$this->showPage('somepage')`, you can override its output at:
**Joomla:** `templates/YOUR_TEMPLATE/html/com_hikashop/PLUGIN_NAME/somepage.php`
**WordPress:** `wp-content/themes/YOUR_THEME/hikashop/PLUGIN_NAME/somepage.php`

#### Logic Overrides (Legacy)

**Note:** Most of these legacy override methods are deprecated in favor of PHP events or standard view overrides.

- **Images:** Override `product / show_block_img.php` instead of `hikashop_image.php`.
- **Characteristics:** Override `product / show_block_characteristic.php` instead of `hikashop_characteristics.php`.
- **Quantity Input:** Override `layouts / quantity.php` or use CSS.
- **Buttons:** Use CSS or override individual view files.

#### Class Overrides

You can override core HikaShop classes (classes, helpers, types, or controllers) by copying them to your template/theme folder and appending `Override` to the class name.

**Joomla path:** `templates/YOUR_TEMPLATE/html/com_hikashop/administrator/XXXX/yyy.override.php`
**WordPress path:** `wp-content/themes/YOUR_THEME/hikashop/administrator/XXXX/yyy.override.php`

```
class CategoryControllerOverride extends CategoryController {
    public function listing() {
        // Custom logic here
        return parent::listing();
    }
}
```

### Database Structure

HikaShop uses several tables to store its data. All table names are prefixed with your CMS database prefix (e.g. `jos_` on Joomla, `wp_` on WordPress) followed by `hikashop_`.

#### Product Catalog

- **hikashop\_product:** Stores the main product information (name, description, code, etc.). Products and Variants are both stored here, linked via `product_parent_id`.
- **hikashop\_category:** Stores the category tree using a nested set model (`category_left`, `category_right`). Used for products, zones, tax rates, etc.
- **hikashop\_product\_category:** Junction table for many-to-many relationship between products and categories.
- **hikashop\_characteristic:** Stores product characteristics (e.g., Color, Size) and their possible values.
- **hikashop\_variant:** Stores the relationship between products and characteristics.
- **hikashop\_file:** Stores metadata about images and downloadable files.

#### Sales &amp; Orders

- **hikashop\_order:** Main order header (status, customer, totals, payment/shipping methods).
- **hikashop\_order\_product:** Products included in each order, with snapshot data (price, tax) at the time of purchase.
- **hikashop\_history:** Detailed log of order status changes and history notes.
- **hikashop\_orderstatus:** Defines the available order statuses and their configurations.

#### Shopping Cart

- **hikashop\_cart:** Temporary cart headers for guest and registered users.
- **hikashop\_cart\_product:** Items currently held in users' carts.

#### Customer Data

- **hikashop\_user:** Links HikaShop customers to CMS users (Joomla or WordPress), stores affiliate data and user-specific shop settings.
- **hikashop\_address:** Stores billing and shipping addresses linked to users.

#### Logistics &amp; Commerce

- **hikashop\_shipping:** Configuration for shipping methods.
- **hikashop\_payment:** Configuration for payment methods.
- **hikashop\_warehouse:** Store warehouses for product stock management.
- **hikashop\_zone:** Geographical structure (Countries, States, Tax zones).
- **hikashop\_currency:** Currencies and exchange rates.

#### Pricing &amp; Taxes

- **hikashop\_price:** Product prices. Supports multiple currencies and quantity breaks.
- **hikashop\_tax:** Base tax rates.
- **hikashop\_taxation:** Taxation rules linking taxes, zones, and categories.

#### Marketing &amp; Promotions

- **hikashop\_discount:** Stores both automatic discounts and manual coupons (distinguished by `discount_type`).
- **hikashop\_badge:** Product labels ("New", "Sale").
- **hikashop\_banner:** Advertisement banners.
- **hikashop\_click:** Logs for affiliate link clicks.

#### Technical Tools

- **hikashop\_config:** Central HikaShop configuration.
- **hikashop\_field:** Custom fields definitions (Address, User, Product, Order).
- **hikashop\_filter:** Definitions for product filters.
- **hikashop\_massaction:** Saved mass action configurations.
- **hikashop\_waitlist:** Users waiting for stock notifications.
- **hikashop\_vote:** Product ratings and user reviews.

How the main tables reference each other. HikaShop declares no foreign keys, so these are the conventions the code follows, not constraints the database enforces. It is drawn in three parts rather than one, because a single graph of every relation came out too wide to read.

**Products, categories and variants**

```
erDiagram
    hikashop_category ||--o{ hikashop_product_category : "category_id"
    hikashop_product ||--o{ hikashop_product_category : "product_id"
    hikashop_product ||--o{ hikashop_variant : "variant_product_id"
    hikashop_characteristic ||--o{ hikashop_variant : "variant_characteristic_id"
```

*Three of these tables also point at themselves, which the diagram leaves out because the label has nowhere to sit: a category has a `category_parent_id`, a characteristic has a `characteristic_parent_id`, and a variant is a product whose `product_parent_id` points at the main one. The `hikashop_variant` rows say which characteristic values that variant stands for.*

**Prices, taxes and what hangs off a product**

```
erDiagram
    hikashop_currency ||--o{ hikashop_price : "price_currency_id"
    hikashop_product ||--o{ hikashop_price : "price_product_id"
    hikashop_category ||--o{ hikashop_product : "product_tax_id"
    hikashop_category ||--o{ hikashop_taxation : "category_namekey"
    hikashop_tax ||--o{ hikashop_taxation : "tax_namekey"
    hikashop_zone ||--o{ hikashop_taxation : "zone_namekey"
    hikashop_zone ||--o{ hikashop_zone_link : "zone_parent_namekey"
    hikashop_product ||--o{ hikashop_file : "file_ref_id"
    hikashop_product ||--o{ hikashop_vote : "vote_ref_id"
    hikashop_product ||--o{ hikashop_waitlist : "waitlist_product_id"
```

*The tax of a product is not a column but a category: `product_tax_id` names a category of the tax type, and `getTax()` joins that category to `hikashop_taxation` on `category_namekey` to find the rate for the customer zone. When no rule matches it walks up `category_parent_id` and tries again. `hikashop_file` and `hikashop_vote` are shared tables: their `file_type` and `vote_ref_type` say what the row belongs to, a product among others.*

**Customers, carts and orders**

```
erDiagram
    hikashop_user ||--o{ hikashop_address : "address_user_id"
    hikashop_user ||--o{ hikashop_cart : "user_id"
    hikashop_user ||--o{ hikashop_order : "order_user_id"
    hikashop_address ||--o{ hikashop_order : "billing and shipping"
    hikashop_cart ||--o{ hikashop_cart_product : "cart_id"
    hikashop_product ||--o{ hikashop_cart_product : "product_id"
    hikashop_order ||--o{ hikashop_order_product : "order_id"
    hikashop_product ||--o{ hikashop_order_product : "product_id"
    hikashop_order ||--o{ hikashop_history : "history_order_id"
    hikashop_currency ||--o{ hikashop_order : "order_currency_id"
```

*An order also points at another order through `order_parent_id`, which is how the terms of a subscription are linked to the one that started them. Every table above is listed with its purpose in the section just before. Scroll a diagram sideways if your screen cuts it off.*

### PHP Code Samples

To use HikaShop classes in your own scripts, you must first load the HikaShop helper:

```
if(!@include_once(JPATH_ADMINISTRATOR . '/components/com_hikashop/helpers/helper.php')) return false;
```

#### Get Configuration Settings

Use `hikashop_config()` to retrieve any setting from the HikaShop configuration.

```
$config = hikashop_config();
$roundPrices = $config->get('round_prices', 0);
```

#### Load a Product

```
$productClass = hikashop_get('class.product');
$product = $productClass->get($product_id);

if ($product) {
    echo $product->product_name;
}
```

#### Load a Category

```
$categoryClass = hikashop_get('class.category');
$category = $categoryClass->get($category_id);
```

#### Add to Cart

```
$cartClass = hikashop_get('class.cart');
$cartClass->update($product_id, $quantity);
```

#### Load Current Cart

```
$cartClass = hikashop_get('class.cart');
$cart = $cartClass->getFullCart();

foreach($cart->products as $product) {
    echo $product->product_name . '<br/>';
}
```

#### Load full Order

```
$orderClass = hikashop_get('class.order');
$order = $orderClass->loadFullOrder($order_id, true, false);

foreach($order->products as $product) {
    echo $product->product_name . '<br/>';
}
```

To create a new order programmatically:

```
$order = new stdClass();
$order->order_user_id = 42;
$order->order_status = 'created';
$order->order_currency_id = 1; // ID from hikashop_currency
$order->order_full_price = 120.50;

// Add a product to the order
$product = new stdClass();
$product->product_id = 10;
$product->order_product_quantity = 2;
$product->order_product_name = 'Example Product';
$product->order_product_code = 'PROD-10';
$product->order_product_price = 60.25;

// Important: Products must be assigned to $order->cart->products
$order->cart = new stdClass();
$order->cart->products = array($product);

$orderClass = hikashop_get('class.order');
$orderClass->save($order);
```

#### Update Order Status

```
$orderClass = hikashop_get('class.order');
$update = new stdClass();
$update->order_id = $order_id;
$update->order_status = 'shipped';

// Optionally add a history note and notify the customer
$update->history = new stdClass();
$update->history->history_notified = 1;
$update->history->history_reason = 'Your package has been picked up by the carrier.';

$orderClass->save($update);
```

To create a new product programmatically:

```
$product = new stdClass();
$product->product_name = 'API created product';
$product->product_code = 'PROD-001';
$product->categories = array(12, 15); // Category IDs

$productClass = hikashop_get('class.product');
$success = $productClass->save($product);

if ($success) {
    // These methods handle the related table updates (prices, categories, images)
    $productClass->updateCategories($product); // Saves to hikashop_product_category

    // Add a price
    $price = new stdClass();
    $price->price_value = 19.99;
    $price->price_currency_id = 1;
    $product->prices = array($price);
    $productClass->updatePrices($product);
}
```

#### Format a Price

Displays a price with the correct currency symbol and formatting based on HikaShop settings.

```
$currencyHelper = hikashop_get('helper.currency');
echo $currencyHelper->format(19.99, 1); // 19.99 is the value, 1 is the currency_id
```

### Javascript events

On the Javascript side of things, we implemented our own event mechanism in HikaShop. To use it, you just need to add a few lines of code, like so:

```
if(window.Oby) {
	window.Oby.registerAjax(["cart.updated","wishlist.updated"],function(params){
		// ... your javascript code ...
	});
}
```

This will run your javascript code when either the cart is modified or the wishlist of the user is modified on the current page. So as you can see `cart.updated` and `wishlist.updated` are the name of the events and HikaShop offers a wide range of these events on the frontend of the website. Also, the `params` parameter usually contains important information relative to the current event. So we recommend you first do a call to `console.log(params);` to check what you're being given. Here is the list of events:

- [cart.updated](#cart.updated)
- [wishlist.updated](#wishlist.updated)
- [cart.empty](#cart.empty)
- [checkout.step.completed](#checkout.step.completed)
- [hikashop.stateupdated](#hikashop.stateupdated)
- [checkout.user.updated](#checkout.user.updated)
- [checkout.address.updated](#checkout.address.updated)
- [checkout.cart.updated](#checkout.cart.updated)
- [checkout.coupon.updated](#checkout.coupon.updated)
- [checkout.shipping.updated](#checkout.shipping.updated)
- [checkout.payment.updated](#checkout.payment.updated)
- [checkoutBlockSubmit](#checkoutBlockSubmit)
- [checkoutBlockRefresh](#checkoutBlockRefresh)
- [checkoutFormSubmit](#checkoutFormSubmit)
- [compare.updated](#compare.updated)
- [quantity.checked](#quantity.checked)
- [hkContentChanged](#hkContentChanged)
- [hkAfterUpdateVariant](#hkAfterUpdateVariant)
- [hkAfterProductListingSwitch](#hkAfterProductListingSwitch)
- [filters.update](#filters.update)
- [filters.updated](#filters.updated)
- [order.placed](#order.placed)
- [vote.beforeListRefresh](#vote.beforeListRefresh)

#### cart.updated

Triggered whenever the current cart is being changed from an add to cart button or the HikaShop cart module. `params` will contain:

- params.type which will normally be "cart" for carts and "wishlist" for wishlists.
- params.notify which is normally undefined if HikaShop wants the user to be notified of the modification or not. For an add to cart event, this will be true or undefined. But when a product is removed from the cart (via the cart module for example), this will be set to false by HikaShop.
- params.resp will contain an object of the parsed json returned by the server after the AJAX request updating the cart. It can contain params.resp.product\_name and params.resp.image if a product is being added to the cart. It can also contain params.resp.products with a list objects, one per product currently in the cart with their "quantity", "product\_name" and "cart\_product\_id".
- If you need extra information that HikaShop doesn't provide by default in params.resp, you can implement the [onGetCartProductsInfo](https://www.hikashop.com/support/documentation/62-hikashop-developer-documentation.html#onGetCartProductsInfo) event of the Cart API in a plugin of the group "hikashop".

#### wishlist.updated

Triggered whenever the current wishlist is changed. Params are identical to `cart.updated`.

#### cart.empty

Triggered when the last product is removed from the cart. The system uses this to refresh the page or redirect based on settings.

#### checkout.step.completed

Triggered after an AJAX request completes a checkout step. The system uses this to transition to the next step.

#### hikashop.stateupdated

Triggered after a state selector is refreshed (e.g., after selecting a country). Params:

- `params.id`: The ID of the container element.
- `params.elem`: The actual `<select>` element.

#### checkout.user.updated

Triggered after user state changes (login, register, guest validation). Used to refresh address selection.

#### checkout.address.updated

Triggered after billing or shipping address changes.

#### checkout.cart.updated

Triggered after the cart is updated from the checkout cart view.

#### checkout.coupon.updated

Triggered after the coupon is updated (manually or via auto-load).

#### checkout.shipping.updated

Triggered when the available shipping methods list changes.

#### checkout.payment.updated

Triggered when the available payment methods list changes.

#### checkoutBlockRefresh

Triggered after a specific checkout view is refreshed. Params:

- `params.type`: View name (address, cart, etc.).
- `params.cid`: Step number.
- `params.pos`: View position.

#### checkoutBlockSubmit

Triggered just before an AJAX request is made for a specific checkout block. You can use `params.data` to override the submitted data.

#### checkoutFormSubmit

Triggered just before the entire checkout form is submitted (e.g., clicking "Next" or "Finish").

#### compare.updated

Triggered when a product is added or removed from the comparison list.

#### quantity.checked

Triggered when a quantity input value changes. Params:

- `params.el`: DOM element of the input.
- `params.value`: New value.
- `params.max`/`params.min`: Allowed limits.

#### hkContentChanged

Triggered after the product details page content changes (e.g., variant selection or option change).

#### hkAfterUpdateVariant

Triggered after a variant selection is processed. Params include `params.selection` (selected value IDs).

#### hkAfterProductListingSwitch

Triggered after switching between column and list views on a product listing.

#### filters.update

Triggered after filter data is sent to the server but before the UI is refreshed.

#### filters.updated

Triggered after the filters and product listing areas are updated.

#### order.placed

Triggered by the Order Notify plugin when a new order is received.

#### vote.beforeListRefresh

Triggered right after a comment / vote is saved on the product page, before the front-end tries to refresh the comment listing area. This lets a product display layout that conditionally renders the comment listing wrapper (for example the show\_tabular layout, which hides the Comments tab when the product has no comments yet) inject that wrapper on the fly so the newly posted comment can be shown without a full page reload. The handler should make sure an element with id `hikashop_vote_listing` (or `hikashop_product_vote_listing`) is present in the DOM, the front-end then sets its `innerHTML` with the refreshed listing returned by the server. If no handler creates the container, the front-end falls back to a full page reload so the comment is still visible.

Params:

- `params.ref_id`: the reviewed item id (the product id for a product comment).
- `params.type`: the vote type, normally `"product"`.
