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:
- Go to 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.
- Under Personal Access Tokens, create a new token: pick the scopes you need (see Token scopes below) and an expiry.
- Copy the token — it’s shown once.
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
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, 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:
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:
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_tokengrant 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:
{
"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 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 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:
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 (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:
{
"_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 (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:
{
"_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:
{
"_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.
https://api.onbolder.com/v2Root
API entry point — embeds sellers, shops, and navigation links to every resource
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.
Catalog
Customers
Shop customers. Includes customer authentication and password-reset flows.
- GETList customer tags
/customer_tags - GETList customer tags
/shops/{shop_id}/customer_tags - GETList contact groups (flat)
/contact_groups - POSTCreate a contact group (flat)
/contact_groups - GETList contact groups (legacy shop-nested)
/shops/{shop_id}/customer_groups - POSTCreate a contact group (legacy shop-nested)
/shops/{shop_id}/customer_groups - GETGet a contact group
/contact_groups/{id} - PUTUpdate a contact group
/contact_groups/{id} - DELETEDelete a contact group
/contact_groups/{id} - GETList contacts in a group
/contact_groups/{id}/contacts - GETList customers
/customers - POSTCreate a customer
/customers - GETGet a customer
/customers/{id} - PUTUpdate a customer
/customers/{id} - GETGet last ordered products
/customers/{id}/last_ordered_products - POSTStart contact activation
/customers/{id}/activations - POSTStart phone validation
/customers/{id}/phone_validations - DELETEDemote a contact
/customers/{id}/activation - POSTAuthenticate a customer
/customers/sessions - POSTRequest a password reset
/customers/reset_password - PUTActivate a customer account
/customers/activations/{token}
Orders
Shop orders. Supports batch status updates and per-order document management.
- GETList order tags
/order_tags - GETList orders
/orders - POSTCreate an order
/orders - POSTBatch update orders
/orders/updaters - GETGet an order
/orders/{id} - PUTUpdate an order
/orders/{id} - POSTRefund an order
/orders/{id}/refund - POSTSplit an order
/orders/{id}/split - GETList order documents
/orders/{order_id}/documents - POSTCreate an order document
/orders/{order_id}/documents - GETGet an order document
/orders/{order_id}/documents/{id} - DELETEDelete an order document
/orders/{order_id}/documents/{id} - POSTAdd a line item to an order
/orders/{order_id}/items - PUTUpdate an order line item
/orders/{order_id}/items/{id} - DELETERemove a line item from an order
/orders/{order_id}/items/{id} - POSTRecord a manual payment on an order
/orders/{order_id}/payments - POSTStart (or resume) checkout for an order
/orders/{order_id}/checkout_session - GETGet a checkout session
/checkout_sessions/{id} - POSTMark a checkout session as viewed
/checkout_sessions/{id}/view
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.
- GETList product tags
/product_tags - GETList products
/products - POSTCreate a product
/products - POSTBatch update products
/products/updaters - GETGet a product
/products/{id} - PUTUpdate a product
/products/{id} - DELETEDelete a product
/products/{id} - GETList product price items
/products/{id}/price_items - POSTCreate a product asset
/products/{product_id}/assets - DELETEDelete a product asset
/products/{product_id}/assets/{id} - POSTCreate a product relation
/products/{product_id}/relations - GETList product tags
/shops/{shop_id}/product_tags - GETList vendors
/shops/{shop_id}/vendors - GETList custom product attributes
/shops/{shop_id}/custom_product_attributes - GETList product sets
/shops/{shop_id}/product_sets
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.
- GETList events
/events - GETList exchange rates
/exchange_rates - GETList payment methods
/payment_methods - GETList shipping tables
/shipping_tables - GETGet a shipping table
/shipping_tables/{id} - GETList shops
/shops - GETGet a shop
/shops/{id} - GETGet shop settings
/shops/{id}/settings - GETList shop admins
/shops/{shop_id}/admins - GETGet a shop admin
/shops/{shop_id}/admins/{id} - GETList shop events
/shops/{shop_id}/events - GETList payment methods
/shops/{shop_id}/payment_methods - GETList exchange rates
/shops/{shop_id}/exchange_rates - GETList order tags
/shops/{shop_id}/order_tags - GETList shipping tables
/shops/{shop_id}/shipping_tables - GETGet a shipping table
/shops/{shop_id}/shipping_tables/{id}
Webhooks
Event webhooks. Subscribe to events such as orders.created, products.updated, etc.
Inactive subscriptions can be reactivated and their delivery history inspected.
- GETList webhooks
/webhooks - POSTCreate a webhook
/webhooks - GETGet a webhook
/webhooks/{id} - DELETEDelete a webhook
/webhooks/{id} - PUTReactivate a failed webhook
/webhooks/{id}/reactivate - GETGet webhook delivery history
/webhooks/{id}/history - GETList webhooks for a seller
/sellers/{seller_id}/webhooks - POSTCreate a webhook for a seller
/sellers/{seller_id}/webhooks
Store
Collections
Curated product collections (manually or rule-based). Products can belong to multiple collections.
- GETList collections
/collections - GETGet a collection
/collections/{id} - DELETEDelete a collection
/collections/{id}
Product Types
Product type definitions used to group and filter catalog products.
- GETList product types
/product_types - POSTCreate a product type
/product_types - PUTUpdate or upsert a product type
/product_types/{id}
Variants
Product variants (size, colour, etc.). Nested under /products/{product_id}/variants.
Each variant holds its own SKU, price, stock level, and images.
- GETList variants
/products/{product_id}/variants - POSTCreate a variant
/products/{product_id}/variants - GETGet a variant
/products/{product_id}/variants/{id} - PUTUpdate a variant
/products/{product_id}/variants/{id} - DELETEDelete a variant
/products/{product_id}/variants/{id} - POSTBatch update variants
/products/{product_id}/variants/updaters
Themes
Hosted-storefront themes, templates, and assets. Applies only to shops with a
hosted storefront (store: namespace); absent for headless shops.
- GETList themes for a shop
/shops/{id}/themes - POSTCreate a dev theme
/shops/{id}/themes - GETGet a theme
/themes/{id} - PUTUpdate a theme
/themes/{id} - DELETEDelete a dev theme
/themes/{id} - PUTPublish a dev theme
/themes/{id}/publication - POSTCreate a template
/themes/{theme_id}/templates - PUTUpdate theme settings
/themes/{theme_id}/templates/settings - GETGet a template
/themes/{theme_id}/templates/{id} - PUTUpdate a template
/themes/{theme_id}/templates/{id} - DELETEDelete a template
/themes/{theme_id}/templates/{id} - POSTUpload a theme asset
/themes/{theme_id}/assets - DELETEDelete a theme asset
/themes/{theme_id}/assets/{id}
Content
CMS-style content for a shop’s storefront — blog posts, static pages, and contact/lead-capture forms.
- GETList shop posts
/shops/{shop_id}/posts - POSTCreate a post
/shops/{shop_id}/posts - GETGet a post
/posts/{id} - PUTUpdate a post
/posts/{id} - DELETEDelete a post
/posts/{id} - GETList pages
/shops/{shop_id}/pages - POSTCreate a page
/shops/{shop_id}/pages - GETGet a page
/pages/{id} - PUTUpdate a page
/pages/{id} - DELETEDelete a page
/pages/{id} - GETList forms
/shops/{shop_id}/forms - POSTCreate a form
/shops/{shop_id}/forms - GETGet a form
/forms/{id} - PUTUpdate a form
/forms/{id} - DELETEDelete a form
/forms/{id}
Price Lists
Named price lists for B2B / wholesale pricing. Products can have per-variant price overrides within a price list.
- GETList price lists
/price_lists - POSTCreate a price list
/price_lists - GETGet a price list
/price_lists/{id} - PUTUpdate a price list
/price_lists/{id} - DELETEDelete a price list
/price_lists/{id} - GETList products in a price list
/price_lists/{id}/products - GETList price items
/price_lists/{price_list_id}/items - PUTUpdate a price item
/price_lists/{price_list_id}/items/{id} - DELETEDelete a price item
/price_lists/{price_list_id}/items/{id}
Promotions
Promotional discount codes and automatic discounts applied at checkout.
- GETList promotions
/promotions - POSTCreate a promotion
/promotions - GETGet a promotion
/promotions/{id} - PUTUpdate a promotion
/promotions/{id} - DELETEDelete a promotion
/promotions/{id}
Volume Discounts
Quantity-based discount rules (tiered pricing by units purchased).
- GETList volume discounts
/volume_discounts - POSTCreate a volume discount
/volume_discounts - GETGet a volume discount
/volume_discounts/{id} - PUTUpdate a volume discount
/volume_discounts/{id} - DELETEDelete a volume discount
/volume_discounts/{id}
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.
- GETList subscription purchases
/subscription_purchases - GETGet a subscription purchase
/subscription_purchases/{id} - PUTUpdate a subscription purchase
/subscription_purchases/{id} - PUTRecord a manual renewal
/subscription_purchases/{id}/renew - GETList subscription fees
/subscription_fees - POSTCreate a subscription fee
/subscription_fees - GETGet a subscription fee
/subscription_fees/{id} - PUTUpdate a subscription fee
/subscription_fees/{id} - DELETEDelete a subscription fee
/subscription_fees/{id}