---
seo:
  description: >-
    The Bolder API provides programmatic access to your Bolder Shop data through
    a hypermedia-driven REST interface.
sidebar:
  label: Overview
title: Bolder API v2
---
### Getting Started

The Bolder API provides programmatic access to your Bolder Shop data through a
hypermedia-driven REST interface.

#### Fastest path — Personal Access Token

For scripts, CLI tools, and personal automation, skip the OAuth grant dance entirely:

1. Go to [https://auth.onbolder.com/dev/credentials](https://auth.onbolder.com/dev/credentials)
   and sign in. The first visit auto-creates a default developer application for your
   account — there's nothing to register.
2. Under **Personal Access Tokens**, create a new token: pick the scopes you need (see
   [Token scopes](#token-scopes) below) and an expiry.
3. Copy the token — it's shown **once**.

```bash
export BOLDER_TOKEN=PASTE_YOUR_TOKEN_HERE

curl -H "Authorization: Bearer $BOLDER_TOKEN" https://api.onbolder.com/v2
```

All `curl` examples in this documentation use `$BOLDER_TOKEN`. Set it once in your
shell and every example works immediately. See [Personal Access Tokens](#personal-access-tokens-pats)
below for details on expiry and revocation.

#### Building a real integration — register an OAuth application

If you're building something you'll distribute to other Bolder merchants (rather than
automating your own account), register a dedicated application instead of using a PAT:

Go to [https://auth.onbolder.com](https://auth.onbolder.com), sign in, and create a new
application. You'll receive a `CLIENT_ID` and `CLIENT_SECRET`. The fastest way to get a
token from a terminal is the **Client Credentials** grant:

```bash
export BOLDER_TOKEN=$(curl -s \
  -X POST https://auth.onbolder.com/oauth/token \
  -d "grant_type=client_credentials&client_id=CLIENT_ID&client_secret=CLIENT_SECRET&scope=products.read,orders.read,orders.write" \
  | jq -r .access_token)
```

No `jq`? Use Python instead:

```bash
export BOLDER_TOKEN=$(curl -s \
  -X POST https://auth.onbolder.com/oauth/token \
  -d "grant_type=client_credentials&client_id=CLIENT_ID&client_secret=CLIENT_SECRET&scope=products.read,orders.read,orders.write" \
  | python3 -c "import sys,json; print(json.load(sys.stdin)['access_token'])")
```

> **Note:** Unlike PATs, these tokens are temporary. Re-run the request above when your
> token expires, or use the `refresh_token` grant described in the Authentication section
> below.

---

### Authentication

The Bolder API uses **OAuth 2.0**. The token **must** be sent in the
`Authorization` header — query-parameter tokens are not accepted by v2.

Five grant types are supported:

#### 1. Authorization Code (recommended for web apps)

Redirect the user to the authorization endpoint and exchange the returned `code`
for tokens on your server.

```
GET https://auth.onbolder.com/oauth/authorize
  ?client_id=YOUR_CLIENT_ID
  &redirect_uri=https://yourapp.com/callback
  &response_type=code
  &scope=products.read,orders.read,orders.write
```

Then exchange the code:

```
POST https://auth.onbolder.com/oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code
&client_id=YOUR_CLIENT_ID
&client_secret=YOUR_CLIENT_SECRET
&redirect_uri=https://yourapp.com/callback
&code=RETURNED_CODE
```

#### 2. Implicit Grant (for client-side JavaScript apps)

```
GET https://auth.onbolder.com/oauth/authorize
  ?client_id=YOUR_CLIENT_ID
  &redirect_uri=https://yourapp.com/callback
  &response_type=token
  &scope=products.read
```

The access token is returned in the URL fragment after the redirect.

#### 3. Client Credentials (for server-to-server / automated scripts)

No user involved — the application authenticates as itself.

```
POST https://auth.onbolder.com/oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials
&client_id=YOUR_CLIENT_ID
&client_secret=YOUR_CLIENT_SECRET
&scope=products.read,orders.read,orders.write
```

#### 4. Resource Owner Password Credentials (trusted apps only)

```
POST https://auth.onbolder.com/oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=password
&client_id=YOUR_CLIENT_ID
&client_secret=YOUR_CLIENT_SECRET
&username=USER_EMAIL
&password=USER_PASSWORD
&scope=products.read,orders.read,orders.write
```

#### 5. JWT Bearer (refreshing expired tokens)

Exchange a `refresh_token` for a new access token:

```
POST https://auth.onbolder.com/oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=refresh_token
&client_id=YOUR_CLIENT_ID
&client_secret=YOUR_CLIENT_SECRET
&refresh_token=YOUR_REFRESH_TOKEN
```

#### Token response

All flows return a JSON token response:

```json
{
  "access_token":  "eyJ...",
  "token_type":    "bearer",
  "expires_in":    7200,
  "refresh_token": "abc123...",
  "scope":         "products.read,orders.read,orders.write"
}
```

Access tokens are **temporary**. Implement refresh-token logic to obtain new
tokens before they expire.

#### Token scopes

v2 uses **granular scopes**: request access to individual resource namespaces using
`{namespace}.read` / `{namespace}.write` scopes. This lets an integration ask for only
what it needs — e.g. an order-fulfillment tool can request `orders.read,orders.write`
without also getting product or customer write access.

| Namespace   | Read scope        | Write scope         | Covers |
|-------------|--------------------|-----------------------|--------|
| `products`  | `products.read`   | `products.write`    | Products, variants, collections |
| `orders`    | `orders.read`     | `orders.write`       | Orders, documents, tracking |
| `customers` | `customers.read`  | `customers.write`    | Customer profiles |
| `shops`     | `shops.read`      | `shops.write`        | Shop configuration |
| `hub`       | `hub.read`        | `hub.write`           | Content (posts, pages) |
| `store`     | `store.read`      | `store.write`        | Themes and assets |
| `sellers`   | `sellers.read`    | — (read-only)         | Seller information |
| `batches`   | `batches.read`    | `batches.write`      | Batch job status |

Request them the same way as any other scope, comma-separated:

```
&scope=products.read,orders.read,orders.write
```

#### Personal Access Tokens (PATs)

For scripts and CLI tools where the standard OAuth grants (which require redirect flows or
a client secret exchange per session) are overkill, you can issue a **Personal Access
Token**: a long-lived Bearer JWT tied to your user account and a specific application,
created from the developer credentials page — see
[Fastest path — Personal Access Token](#fastest-path--personal-access-token) above for the
step-by-step. A few more details:

- Give the token a name, choose an expiry (30 days, 90 days, 1 year, or no expiry), and
  select the scopes to grant — you can only grant scopes your own user role already has
  (see [Token scopes](#token-scopes) above).
- The raw token is shown **once**, immediately after creation. Copy it then — it cannot be
  retrieved again afterwards.

Use it exactly like any other access token:

```bash
curl -H "Authorization: Bearer $PERSONAL_ACCESS_TOKEN" https://api.onbolder.com/v2
```

PATs do not expire on a fixed short TTL like regular access tokens, so there is no
refresh-token flow — the token is valid until its chosen expiry (if any) or until revoked.
Revoke a PAT at any time from the same credentials page; revocation takes effect
immediately.

---

### Hypermedia (HAL)

All responses follow the [HAL](https://stateless.group/hal_specification.html)
(Hypertext Application Language) format. Every response contains:

- **`_links`** — navigation links to related resources and available actions.
- **`_embedded`** — inline sub-resources (e.g. variants inside a product).
- **`_class`** — array of type strings (e.g. `["results", "products"]`).
- **Properties** — the resource's own data fields at the top level.

#### CURIEs

Link relation types use **service-namespaced CURIEs** so clients can
resolve documentation for any relation:

```json
{
  "_links": {
    "curies": [
      { "name": "products", "href": "https://api.onbolder.com/docs/v2#products:{rel}", "templated": true },
      { "name": "orders",   "href": "https://api.onbolder.com/docs/v2#orders:{rel}",   "templated": true }
    ],
    "self":             { "href": "https://api.onbolder.com/v2/products/123" },
    "products:update":  { "href": "https://api.onbolder.com/v2/products/123", "method": "put" },
    "products:variants":{ "href": "https://api.onbolder.com/v2/products/123/variants" }
  }
}
```

**Clients should follow links rather than constructing URLs.** If a link is absent
from a response, the action is either unavailable or not permitted for the current
token. The presence of a link is itself an affordance.

#### URI Templates

Some links are [URI templates](https://www.rfc-editor.org/rfc/rfc6570) (marked
`"templated": true`). Expand them with the parameters shown in the template before
making a request:

```
products:list → https://api.onbolder.com/v2/products{?q,status,page,per_page,...}

Expanded:       https://api.onbolder.com/v2/products?status=visible&page=2
```

---

### Pagination

List endpoints return a standard pagination envelope:

```json
{
  "_class":      ["results", "products"],
  "total_items": 142,
  "per_page":    20,
  "page":        1,
  "_links": {
    "self": { "href": "https://api.onbolder.com/v2/products?page=1" },
    "next": { "href": "https://api.onbolder.com/v2/products?page=2" },
    "prev": { "href": "https://api.onbolder.com/v2/products?page=0" }
  },
  "_embedded": {
    "items": [...]
  }
}
```

Default page size is **20**, maximum is **200** (use `per_page` to override).

---

### Errors

| HTTP Status | Meaning |
|-------------|---------|
| `400` | Bad request — malformed JSON or missing required field |
| `401` | Unauthorized — missing or invalid access token |
| `403` | Forbidden — valid token but insufficient permissions |
| `404` | Not found |
| `422` | Unprocessable — validation failed; see `_embedded.errors` |
| `429` | Too many requests — rate limit exceeded |
| `500` | Server error |

Validation errors (`422`) embed a structured error list:

```json
{
  "_embedded": {
    "errors": [
      { "field": "name", "messages": ["can't be blank"] }
    ]
  }
}
```

---

### HTTP caching

The API emits standard `ETag` and `Last-Modified` headers. Clients may send
`If-None-Match` / `If-Modified-Since` on subsequent requests; unchanged
resources return `304 Not Modified` with no body.

Version 2.0

Base URL: `https://api.onbolder.com/v2`

## Root

API entry point — embeds sellers, shops, and navigation links to every resource

- [`GET /`](/api/v2/root/get-root) — API root.

## Sellers

Seller entities — the business layer between an account and its shops.
An account can have multiple sellers, each owning one or more shops and their product catalog.

- [`GET /sellers`](/api/v2/sellers/list-sellers) — List sellers.
- [`GET /sellers/{id}`](/api/v2/sellers/get-seller) — Get a seller.

## Shops

Shops owned by the authenticated account. A shop is the customer-facing storefront
that belongs to a seller. Settings, admins, shipping tables, payment methods,
exchange rates, and other shop-level configuration are anchored to a specific shop.

- [`GET /events`](/api/v2/shops/list-events-flattened) — List events.
- [`GET /exchange_rates`](/api/v2/shops/list-exchange-rates-flattened) — List exchange rates.
- [`GET /payment_methods`](/api/v2/shops/list-payment-methods-flattened) — List payment methods.
- [`GET /shipping_tables`](/api/v2/shops/list-shipping-tables-flattened) — List shipping tables.
- [`POST /shipping_tables`](/api/v2/shops/create-shipping-table) — Create a shipping table.
- [`GET /shipping_tables/{id}`](/api/v2/shops/get-shipping-table-flattened) — Get a shipping table.
- [`PUT /shipping_tables/{id}`](/api/v2/shops/update-shipping-table) — Update a shipping table.
- [`GET /shipping_tables/{shipping_table_id}/shipping_options`](/api/v2/shops/list-shipping-options) — List shipping options (shipping costs).
- [`POST /shipping_tables/{shipping_table_id}/shipping_options`](/api/v2/shops/create-shipping-option) — Create a shipping option (shipping cost).
- [`GET /shipping_options/{id}`](/api/v2/shops/get-shipping-option) — Get a shipping option.
- [`PUT /shipping_options/{id}`](/api/v2/shops/update-shipping-option) — Update a shipping option.
- [`DELETE /shipping_options/{id}`](/api/v2/shops/delete-shipping-option) — Delete a shipping option.
- [`GET /shops`](/api/v2/shops/list-shops) — List shops.
- [`GET /shops/{id}`](/api/v2/shops/get-shop) — Get a shop.
- [`GET /shops/{id}/settings`](/api/v2/shops/get-shop-settings) — Get shop settings.
- [`GET /shops/{shop_id}/admins`](/api/v2/shops/list-shop-admins) — List shop admins.
- [`GET /shops/{shop_id}/admins/{id}`](/api/v2/shops/get-shop-admin) — Get a shop admin.
- [`GET /shops/{shop_id}/events`](/api/v2/shops/list-shop-events) — List shop events.
- [`GET /shops/{shop_id}/payment_methods`](/api/v2/shops/list-payment-methods) — List payment methods for a shop.
- [`GET /shops/{shop_id}/exchange_rates`](/api/v2/shops/list-exchange-rates) — List exchange rates for a shop.
- [`GET /shops/{shop_id}/order_tags`](/api/v2/shops/list-order-tags) — List order tags.
- [`GET /shops/{shop_id}/shipping_tables`](/api/v2/shops/list-shipping-tables) — List shipping tables for a shop.
- [`GET /shops/{shop_id}/shipping_tables/{id}`](/api/v2/shops/get-shipping-table) — Get a shipping table for a shop.

## Content

CMS-style content for a shop's storefront — blogs and their posts, static pages, and
contact/lead-capture forms. A shop can have several blogs, each with its own language;
a post in one language can point at the post it translates.

- [`GET /shops/{shop_id}/posts`](/api/v2/content/list-shop-posts) — List shop posts.
- [`POST /shops/{shop_id}/posts`](/api/v2/content/create-post) — Create a post.
- [`GET /posts/{id}`](/api/v2/content/get-post) — Get a post.
- [`PUT /posts/{id}`](/api/v2/content/update-post) — Update a post.
- [`DELETE /posts/{id}`](/api/v2/content/delete-post) — Delete a post.
- [`GET /shops/{shop_id}/blogs`](/api/v2/content/list-shop-blogs) — List shop blogs.
- [`GET /blogs/{id}`](/api/v2/content/get-blog) — Get a blog.
- [`GET /shops/{shop_id}/pages`](/api/v2/content/list-shop-pages) — List pages.
- [`POST /shops/{shop_id}/pages`](/api/v2/content/create-page) — Create a page.
- [`GET /pages/{id}`](/api/v2/content/get-page) — Get a page.
- [`PUT /pages/{id}`](/api/v2/content/update-page) — Update a page.
- [`DELETE /pages/{id}`](/api/v2/content/delete-page) — Delete a page.
- [`GET /shops/{shop_id}/forms`](/api/v2/content/list-shop-forms) — List forms.
- [`POST /shops/{shop_id}/forms`](/api/v2/content/create-form) — Create a form.
- [`GET /forms/{id}`](/api/v2/content/get-form) — Get a form.
- [`PUT /forms/{id}`](/api/v2/content/update-form) — Update a form.
- [`DELETE /forms/{id}`](/api/v2/content/delete-form) — Delete a form.

## Products

Catalog products, automatically scoped to the authenticated account's sellers.
Account-scoped tokens need no extra parameters; tokens without an account/seller
scope must supply `shop_subdomains`.

- [`GET /product_tags`](/api/v2/products/list-product-tags-flattened) — List product tags.
- [`GET /products`](/api/v2/products/list-products) — List products.
- [`POST /products`](/api/v2/products/create-product) — Create a product.
- [`POST /products/updaters`](/api/v2/products/batch-update-products) — Batch update products.
- [`GET /products/{id}`](/api/v2/products/get-product) — Get a product.
- [`PUT /products/{id}`](/api/v2/products/update-product) — Update a product.
- [`DELETE /products/{id}`](/api/v2/products/delete-product) — Delete a product.
- [`GET /products/{id}/price_items`](/api/v2/products/get-product-price-items) — List product price items.
- [`POST /products/{product_id}/assets`](/api/v2/products/create-product-asset) — Create a product asset.
- [`DELETE /products/{product_id}/assets/{id}`](/api/v2/products/delete-product-asset) — Delete a product asset.
- [`POST /products/{product_id}/relations`](/api/v2/products/create-product-relation) — Create a product relation.
- [`GET /shops/{shop_id}/product_tags`](/api/v2/products/list-product-tags) — List product tags for a shop.
- [`GET /shops/{shop_id}/vendors`](/api/v2/products/list-shop-vendors) — List vendors.
- [`GET /shops/{shop_id}/custom_product_attributes`](/api/v2/products/list-custom-product-attributes) — List custom product attributes.
- [`GET /shops/{shop_id}/product_sets`](/api/v2/products/list-shop-product-sets) — List product sets.

## Variants

Product variants (size, colour, etc.). Nested under `/products/{product_id}/variants`.
Each variant holds its own SKU, price, stock level, and images.

- [`GET /products/{product_id}/variants`](/api/v2/variants/list-variants) — List variants.
- [`POST /products/{product_id}/variants`](/api/v2/variants/create-variant) — Create a variant.
- [`GET /products/{product_id}/variants/{id}`](/api/v2/variants/get-variant) — Get a variant.
- [`PUT /products/{product_id}/variants/{id}`](/api/v2/variants/update-variant) — Update a variant.
- [`DELETE /products/{product_id}/variants/{id}`](/api/v2/variants/delete-variant) — Delete a variant.
- [`POST /variants/updaters`](/api/v2/variants/batch-update-variants) — Batch update variants.

## Price Lists

Named price lists for B2B / wholesale pricing. Products can have per-variant price
overrides within a price list.

- [`GET /price_lists`](/api/v2/price-lists/list-price-lists) — List price lists.
- [`POST /price_lists`](/api/v2/price-lists/create-price-list) — Create a price list.
- [`GET /price_lists/{id}`](/api/v2/price-lists/get-price-list) — Get a price list.
- [`PUT /price_lists/{id}`](/api/v2/price-lists/update-price-list) — Update a price list.
- [`DELETE /price_lists/{id}`](/api/v2/price-lists/delete-price-list) — Delete a price list.
- [`GET /price_lists/{id}/products`](/api/v2/price-lists/get-price-list-products) — List products in a price list.
- [`GET /price_lists/{price_list_id}/items`](/api/v2/price-lists/list-price-items) — List price items.
- [`PUT /price_lists/{price_list_id}/items/{id}`](/api/v2/price-lists/update-price-item) — Update a price item.
- [`DELETE /price_lists/{price_list_id}/items/{id}`](/api/v2/price-lists/delete-price-item) — Delete a price item.

## Product Types

Product type definitions used to group and filter catalog products.

- [`GET /product_types`](/api/v2/product-types/list-product-types) — List product types.
- [`POST /product_types`](/api/v2/product-types/create-product-type) — Create a product type.
- [`PUT /product_types/{id}`](/api/v2/product-types/update-product-type) — Update or upsert a product type.

## Collections

Curated product collections (manually or rule-based). Products can belong to
multiple collections.

- [`GET /collections`](/api/v2/collections/list-collections) — List collections.
- [`GET /collections/{id}`](/api/v2/collections/get-collections-id) — Get a collection.
- [`DELETE /collections/{id}`](/api/v2/collections/delete-collection) — Delete a collection.

## Orders

Shop orders. Supports batch status updates and per-order document management.

- [`GET /order_tags`](/api/v2/orders/list-order-tags-flattened) — List order tags.
- [`GET /orders`](/api/v2/orders/list-orders) — List orders.
- [`POST /orders`](/api/v2/orders/create-order) — Create an order.
- [`POST /orders/updaters`](/api/v2/orders/batch-update-orders) — Batch update orders.
- [`GET /orders/{id}`](/api/v2/orders/get-order) — Get an order.
- [`PUT /orders/{id}`](/api/v2/orders/update-order) — Update an order.
- [`POST /orders/{id}/refund`](/api/v2/orders/refund-order) — Refund an order.
- [`POST /orders/{id}/split`](/api/v2/orders/split-order) — Split an order.
- [`GET /orders/{order_id}/documents`](/api/v2/orders/list-order-documents) — List order documents.
- [`POST /orders/{order_id}/documents`](/api/v2/orders/create-order-document) — Create an order document.
- [`GET /orders/{order_id}/documents/{id}`](/api/v2/orders/get-order-document) — Get an order document.
- [`DELETE /orders/{order_id}/documents/{id}`](/api/v2/orders/delete-order-document) — Delete an order document.
- [`POST /orders/{order_id}/items`](/api/v2/orders/create-order-item) — Add a line item to an order.
- [`PUT /orders/{order_id}/items/{id}`](/api/v2/orders/update-order-item) — Update an order line item.
- [`DELETE /orders/{order_id}/items/{id}`](/api/v2/orders/delete-order-item) — Remove a line item from an order.
- [`POST /orders/{order_id}/payments`](/api/v2/orders/create-order-payment) — Record a manual payment on an order.
- [`POST /orders/{order_id}/checkout_session`](/api/v2/orders/create-checkout-session) — Start (or resume) checkout for an order.
- [`GET /checkout_sessions/{id}`](/api/v2/orders/get-checkout-session) — Get a checkout session.
- [`POST /checkout_sessions/{id}/view`](/api/v2/orders/view-checkout-session) — Mark a checkout session as viewed.

## Customers

Shop customers. Includes customer authentication and password-reset flows.

- [`GET /customer_tags`](/api/v2/customers/list-customer-tags) — List customer tags.
- [`GET /shops/{shop_id}/customer_tags`](/api/v2/customers/list-contact-tags) — List customer tags for a shop.
- [`GET /contact_groups`](/api/v2/customers/list-contact-groups-flat) — List contact groups (flat).
- [`POST /contact_groups`](/api/v2/customers/create-contact-group-flat) — Create a contact group (flat).
- [`GET /shops/{shop_id}/customer_groups`](/api/v2/customers/list-contact-groups) — List contact groups (legacy shop-nested).
- [`POST /shops/{shop_id}/customer_groups`](/api/v2/customers/create-contact-group) — Create a contact group (legacy shop-nested).
- [`GET /contact_groups/{id}`](/api/v2/customers/get-contact-group) — Get a contact group.
- [`PUT /contact_groups/{id}`](/api/v2/customers/update-contact-group) — Update a contact group.
- [`DELETE /contact_groups/{id}`](/api/v2/customers/delete-contact-group) — Delete a contact group.
- [`GET /contact_groups/{id}/contacts`](/api/v2/customers/list-contact-group-contacts) — List contacts in a group.
- [`GET /customers`](/api/v2/customers/list-customers) — List customers.
- [`POST /customers`](/api/v2/customers/create-customer) — Create a customer.
- [`GET /customers/{id}`](/api/v2/customers/get-customer) — Get a customer.
- [`PUT /customers/{id}`](/api/v2/customers/update-customer) — Update a customer.
- [`GET /customers/{id}/last_ordered_products`](/api/v2/customers/get-customer-last-ordered-products) — Get last ordered products.
- [`POST /customers/{id}/activations`](/api/v2/customers/start-contact-activation) — Start contact activation.
- [`POST /customers/{id}/phone_validations`](/api/v2/customers/start-phone-validation) — Start phone validation.
- [`DELETE /customers/{id}/activation`](/api/v2/customers/demote-contact) — Demote a contact.
- [`POST /customers/sessions`](/api/v2/customers/authenticate-customer) — Authenticate a customer.
- [`POST /customers/reset_password`](/api/v2/customers/reset-customer-password) — Request a password reset.
- [`PUT /customers/activations/{token}`](/api/v2/customers/activate-customer) — Activate a customer account.

## Promotions

Promotional discount codes and automatic discounts applied at checkout.

- [`GET /promotions`](/api/v2/promotions/list-promotions) — List promotions.
- [`POST /promotions`](/api/v2/promotions/create-promotion) — Create a promotion.
- [`GET /promotions/{id}`](/api/v2/promotions/get-promotion) — Get a promotion.
- [`PUT /promotions/{id}`](/api/v2/promotions/update-promotion) — Update a promotion.
- [`DELETE /promotions/{id}`](/api/v2/promotions/delete-promotion) — Delete a promotion.

## Volume Discounts

Quantity-based discount rules (tiered pricing by units purchased).

- [`GET /volume_discounts`](/api/v2/volume-discounts/list-volume-discounts) — List volume discounts.
- [`POST /volume_discounts`](/api/v2/volume-discounts/create-volume-discount) — Create a volume discount.
- [`GET /volume_discounts/{id}`](/api/v2/volume-discounts/get-volume-discount) — Get a volume discount.
- [`PUT /volume_discounts/{id}`](/api/v2/volume-discounts/update-volume-discount) — Update a volume discount.
- [`DELETE /volume_discounts/{id}`](/api/v2/volume-discounts/delete-volume-discount) — Delete a volume discount.

## Themes

Hosted-storefront themes, templates, and assets. Applies only to shops with a
hosted storefront (`store:` namespace); absent for headless shops.

- [`GET /shops/{id}/themes`](/api/v2/themes/list-shop-themes) — List themes for a shop.
- [`POST /shops/{id}/themes`](/api/v2/themes/create-shop-theme) — Create a dev theme.
- [`GET /themes/{id}`](/api/v2/themes/get-theme) — Get a theme.
- [`PUT /themes/{id}`](/api/v2/themes/update-theme) — Update a theme.
- [`DELETE /themes/{id}`](/api/v2/themes/delete-theme) — Delete a dev theme.
- [`PUT /themes/{id}/publication`](/api/v2/themes/publish-theme) — Publish a dev theme.
- [`POST /themes/{theme_id}/templates`](/api/v2/themes/create-template) — Create a template.
- [`PUT /themes/{theme_id}/templates/settings`](/api/v2/themes/update-theme-settings) — Update theme settings.
- [`GET /themes/{theme_id}/templates/{id}`](/api/v2/themes/get-template) — Get a template.
- [`PUT /themes/{theme_id}/templates/{id}`](/api/v2/themes/update-template) — Update a template.
- [`DELETE /themes/{theme_id}/templates/{id}`](/api/v2/themes/delete-template) — Delete a template.
- [`POST /themes/{theme_id}/assets`](/api/v2/themes/create-theme-asset) — Upload a theme asset.
- [`DELETE /themes/{theme_id}/assets/{id}`](/api/v2/themes/delete-theme-asset) — Delete a theme asset.

## Webhooks

Event webhooks. Subscribe to events such as `order.created`, `product.updated`,
`customer.created`, etc.
Inactive subscriptions can be reactivated and their delivery history inspected.

###### Topic spelling

The v2 API spells topics in the **singular**: `customer.created`, `order.updated.item.added`,
`product.updated.variant.sold_out`. Only the nouns change; verbs and states
(`updated`, `sold_out`, `opted_out`) stay as they are. The singular spelling is used
everywhere in v2: the `topic` of a subscription, the `topic` of the notifications it
receives, and the `topic` of events returned by `/events`.

On input the plural spelling (`customers.created`) is accepted too, in the `topic` of a
new subscription and in the `topic` filter of `/events`. A subscription created through v2
always receives the singular spelling, whichever one you sent. Subscriptions created before
this change, and those created through the v1 API, keep receiving the plural spelling so
their consumers are not affected: every subscription reports the spelling it receives in
`topic_style` (`singular` or `plural`).

###### Topic hierarchy

Topics are dot-separated and hierarchical. A subscription to a topic also receives every
topic below it: `order` receives all order events, `order.updated` receives
`order.updated.placed`, `order.updated.closed`, and so on, while `order.updated.closed`
receives only that one. Sibling topics are independent.

###### Customer events

Customer event topics use the singular `customer`:

| Topic | Sent when |
|---|---|
| `customer.created` | A customer is created, whichever way it happens: the API, a storefront sign-up, a newsletter or contact form, checkout, social login, or the admin. |
| `customer.updated` | A customer's profile data changes (name, email, phone, company, custom fields, opt-in, ...). Automatic bookkeeping does not count: order totals and counts, last login, timestamps and integration sync state never trigger it. |
| `customer.opted_in` | An **existing** customer opts in to email marketing. Sent together with `customer.updated`. |
| `customer.opted_out` | An **existing** customer opts out of email marketing. Sent together with `customer.updated`. |
| `customer.deleted` | A customer is permanently deleted. The payload is minimal (the customer's `id`, since the record no longer exists). |

Customer payloads never include the customer's activation token or the links that embed it.

A brand-new customer who opts in at sign-up only produces `customer.created`; check
`opt_in` in its payload. Internal placeholder customers (for example the shared
"Venta Presencial" customer used for point-of-sale sales without an identified buyer)
never produce events.

The payload of a `customer.*` webhook is the customer representation, the same one
returned by `GET /customers/{id}` (see the `Contact` schema). Events are delivered
asynchronously, usually within seconds of the change, and delivery order between
different changes is not guaranteed: use `updated_on` to order updates to the same
customer.

Subscribe to `customer` to receive all customer events, or to a specific topic to
receive only that one. `customer.updated` does not include `customer.opted_in` or
`customer.opted_out`, which are separate topics; a subscription to `customer` receives
both events for an opt-in change.

**Change to existing `customers.created` / `customers.updated` webhooks:** their payload
now uses the v2 customer representation. The deprecated `company` property is gone
(use `company_name`) and links point to v2 URLs (`/v2/customers/{id}`). Their topic keeps
the plural spelling unless the subscription was created through v2 (see Topic spelling).

###### Product stock and price events

| Topic | Sent when |
|---|---|
| `product.sold_out` | A product is no longer available in a stock location (its last available variant ran out there). |
| `product.restocked` | A product is available again in a stock location. |
| `product.updated.variant.sold_out` | A single variant ran out in a stock location. |
| `product.updated.variant.restocked` | A single variant is available again in a stock location. |
| `product.updated.variant.low_stock` | A variant's stock fell to the account's minimum (`critical_stock_amount`) or below, without being sold out. Also sent when a sold out variant comes back with that little stock. |
| `product.updated.variant.replenished` | A variant's stock went back above the account's minimum. |
| `product.price_dropped` | A product's final price went down (its sale price if it has one, otherwise its regular price). |
| `product.price_raised` | A product's final price went up. |
| `product.updated.variant.price_dropped` | A variant's final price went down. |
| `product.updated.variant.price_raised` | A variant's final price went up. |

The old and new price are in the event's `changes`: `{"price": [1000, 800], "sale_price": [1000, 800]}`,
in the currency's smallest unit (for CLP, whole pesos). A change that leaves the final price
as it was, such as raising the regular price while a sale price applies, sends nothing.

A product's price derives from its variants, so one price change can produce both a variant
event and a product event. Which of the two you receive depends on how the change was made,
and a change made through the product form of a single-variant product may only produce one of them:
subscribe to both `product.price_dropped` and `product.updated.variant.price_dropped` (and the `raised`
pair) if you must not miss a price change.

###### Refund events

| Topic | Sent when |
|---|---|
| `refund.created` | A refund was accepted by the payment gateway (successful). A refund that failed first and later succeeded is announced when it succeeds. |
| `refund.updated` | A successful refund changed afterwards (for example its description). |
| `refund.failed` | The payment gateway rejected a refund. Sent once per attempt; a later `refund.created` for the same order is the retry succeeding. |

The payload is the refund transaction (`order_id`, negative `amount`, `absolute_amount`, `payment_method_type`,
`transaction_id`, ...). The raw gateway reply is never included. Refund topics are not part of the `order`
family: subscribe to `refund`. A token needs `orders.read`.

###### Webhook events

| Topic | Sent when |
|---|---|
| `webhook.disabled` | One of your webhooks stopped being delivered: the receiver answered 410 Gone, or too many deliveries failed. The payload names the host only. |
| `webhook.reactivated` | A stopped webhook was reactivated (`PUT /webhooks/:id/reactivate`) or subscribed again. |

###### Cart events

| Topic | Sent when |
|---|---|
| `cart.updated` | The cart of an identified customer changed: items, quantities or total. |
| `cart.deleted` | That cart was emptied. |

A cart is a draft order, so the payload is the order representation. Cart events are only sent for
carts that belong to an identified customer (a logged-in customer on the storefront), and only when
something actually changed. Cart topics are not part of the `order` family: subscribing to `order`
does not include them, subscribe to `cart`. A token needs `orders.read` to subscribe.

###### Collection events

| Topic | Sent when |
|---|---|
| `collection.created` | A collection is created. |
| `collection.updated` | A collection's title, slug, description, visibility or other data changes. Adding or removing products (the product counter) does not count. |
| `collection.deleted` | A collection is permanently deleted. The payload is minimal (the `id`). |

Collections belong to the whole account, not to one shop, so these events are recorded under the
account's main shop. A token needs `products.read` to subscribe.

###### Integration events

| Topic | Sent when |
|---|---|
| `integration.misconfigured` | A shop's integration (an add-on such as a mailing list, analytics or Facebook) stopped working on the merchant's side: a required option is missing, or the provider rejected its credentials. Sent once per breakage, not once per failed call. |
| `integration.recovered` | That integration worked again after being misconfigured. |

The payload has no body; the event's `payload` carries the add-on key (`integration`, eg. `google_analytics`) and, for `integration.misconfigured`, the `reason` (`options` or `credentials`). Subscribe to `integration`
for both. Only an admin token can subscribe.

- [`GET /webhooks`](/api/v2/webhooks/list-webhooks-flattened) — List webhooks.
- [`POST /webhooks`](/api/v2/webhooks/create-webhook-flattened) — Create a webhook.
- [`GET /webhooks/{id}`](/api/v2/webhooks/get-webhook-flattened) — Get a webhook.
- [`DELETE /webhooks/{id}`](/api/v2/webhooks/delete-webhook-flattened) — Delete a webhook.
- [`PUT /webhooks/{id}/reactivate`](/api/v2/webhooks/reactivate-webhook-flattened) — Reactivate a failed webhook.
- [`GET /webhooks/{id}/history`](/api/v2/webhooks/webhook-history-flattened) — Get webhook delivery history.
- [`GET /sellers/{seller_id}/webhooks`](/api/v2/webhooks/list-seller-webhooks) — List webhooks for a seller.
- [`POST /sellers/{seller_id}/webhooks`](/api/v2/webhooks/create-seller-webhook) — Create a webhook for a seller.

## Alerts

The notification feed of the admin (the bell): things a merchant should look at or act on. The kinds are
defined by the platform, they are not configured per account. Each one is raised by a webhook topic:

| `topic` | Raised when | Leaves the feed when |
|---|---|---|
| `product.sold_out` | A product is no longer available. | It is restocked (`product.restocked`). |
| `integration.misconfigured` | An integration (add-on) stopped working on the merchant's side: a required option is missing, or the provider rejected its credentials. | The integration works again (`integration.recovered`). |

Every open alert is in the feed for every user who can see the seller. **Seen and read are per user**, like
a bell: opening the feed marks what it shows as *seen* (the badge, `unseen_count`), reading an alert is
explicit and can be undone. One user reading an alert does not change it for the others. Alerts are open
or resolved: only open ones are listed. Who is *emailed* about an alert is decided by the notification
profile of each recipient, which opts in to the topics it wants (`GET /alerts/topics` lists the ones it can opt in
to). Every endpoint needs `shops.read`; all but `/alerts/topics` also need a token issued to a user.

- [`GET /alerts`](/api/v2/alerts/list-alerts) — List the alert feed.
- [`GET /alerts/topics`](/api/v2/alerts/list-alert-topics) — List the alert topics a notification profile can opt in to.
- [`POST /alerts/seen`](/api/v2/alerts/mark-alerts-seen) — Mark the feed as seen.
- [`POST /alerts/{id}/read`](/api/v2/alerts/mark-alert-read) — Mark an alert as read.
- [`DELETE /alerts/{id}/read`](/api/v2/alerts/mark-alert-unread) — Mark an alert as unread.

## Subscriptions

Recurring product subscriptions. `SubscriptionFee` defines the recurring
payment terms attached to a product/variant; `SubscriptionPurchase` is a
customer's active subscription created from a recurring order.

- [`GET /subscription_purchases`](/api/v2/subscriptions/list-subscription-purchases) — List subscription purchases.
- [`GET /subscription_purchases/{id}`](/api/v2/subscriptions/get-subscription-purchase) — Get a subscription purchase.
- [`PUT /subscription_purchases/{id}`](/api/v2/subscriptions/update-subscription-purchase) — Update a subscription purchase.
- [`PUT /subscription_purchases/{id}/renew`](/api/v2/subscriptions/renew-subscription-purchase) — Record a manual renewal.
- [`GET /subscription_fees`](/api/v2/subscriptions/list-subscription-fees) — List subscription fees.
- [`POST /subscription_fees`](/api/v2/subscriptions/create-subscription-fee) — Create a subscription fee.
- [`GET /subscription_fees/{id}`](/api/v2/subscriptions/get-subscription-fee) — Get a subscription fee.
- [`PUT /subscription_fees/{id}`](/api/v2/subscriptions/update-subscription-fee) — Update a subscription fee.
- [`DELETE /subscription_fees/{id}`](/api/v2/subscriptions/delete-subscription-fee) — Delete a subscription fee.

## Wallets

Points and store-credit wallets, one per contact per program. A seller runs
at most one active `PointsProgram` and one active `CreditProgram`, each
covering every shop under the seller. Use `register_purchase` /
`unregister_purchase` to award or reverse points for completed orders.
Credit wallets carry a spending limit and accrue payments toward it.

- [`GET /wallet_programs`](/api/v2/wallets/list-wallet-programs) — List wallet programs.
- [`GET /wallet_programs/{id}`](/api/v2/wallets/get-wallet-program) — Get a wallet program.
- [`PUT /wallet_programs/{id}`](/api/v2/wallets/update-wallet-program) — Update a wallet program's settings.
- [`GET /wallets`](/api/v2/wallets/list-wallets) — List wallets.
- [`POST /wallets`](/api/v2/wallets/create-wallet) — Create (or find) a wallet for a contact.
- [`GET /wallets/{id}`](/api/v2/wallets/get-wallet) — Get a wallet.
- [`GET /wallets/{wallet_id}/transfers`](/api/v2/wallets/list-wallet-transfers) — List transfers for a wallet.
- [`POST /wallets/{wallet_id}/transfers`](/api/v2/wallets/add-wallet-transfer) — Add a balance or payment transfer.
- [`POST /wallets/{id}/register_purchase`](/api/v2/wallets/register-wallet-purchase) — Register points earned from a completed purchase.
- [`POST /wallets/{id}/unregister_purchase`](/api/v2/wallets/unregister-wallet-purchase) — Reverse points earned from a purchase (e.g. on order cancellation).

## Catalog

- [`GET /vendors`](/api/v2/catalog/list-vendors) — List vendors.
- [`GET /product_sets`](/api/v2/catalog/list-product-sets) — List product sets.
- [`GET /product_groups`](/api/v2/catalog/list-product-groups) — List product groups.

## Store

- [`GET /themes`](/api/v2/store/list-themes-flattened) — List themes.
