/api/v1 and use the publishable key (or the store domain).
Amounts as strings. The decimal fields of products, cart, checkout, and orders
(
price, unit_price, subtotal, total…) arrive as strings ("1199.00").
Convert them before doing math: in JavaScript "10.00" + "5.00" concatenates instead of
adding. For money, use a decimal library or work in cents.1. Catalog & search
- The
min_priceandmax_pricefilters and thesort=price/sort=-priceordering work on the effective price (active sale and special price), andmeta.totalalways matches the filtered rows.in_stock=truekeeps only products with a purchasable variant. - In the list,
sale_priceis the variant’s active sale or the special price, whichever is lower;nullwhen no discount is active.
GET /products/{slug}) has two new fields:
sale_price is null outside the sale window (sale_start–sale_end). A
variant with track_inventory: false can be bought even at zero stock.
2. Cart
The cart works for guests (with a session token) and for logged-in customers.Cross-origin / headless cart. The guest cart is keyed by a session token, returned in the
response’s
session_token field. If your storefront runs on a different origin than the API
(e.g. xxxx.com → api.vellaro.io), the cx_cart cookie (SameSite=Lax) is not sent
cross-site: store session_token client-side (e.g. localStorage) and send it back on
every cart call and at checkout as the X-Cart-Token header. The cart then persists
anywhere and is restored on the shopper’s return (7-day TTL). Same-origin? The cookie is
enough and the header is optional.The cart at sign-in
When the guest signs in, their cart merges into the account’s cart on the first authenticated cart call, or checkout, that still carries the guest token (X-Cart-Token or the
cx_cart cookie):
- the same item adds up, but never beyond the available stock;
- items no longer for sale stay behind;
- the guest cart is then deleted, and the same token never merges twice.
- keep sending
X-Cart-Tokenafter the login; - reload the cart right after signing in (password, social login or registration), so the badge and the drawer show the merged items;
- once the cart response has
user_idset, stop using the guest token; - on sign-out, clear the account’s cart from the screen.
The price to show is unit_price
Each line carries the price actually applied, which already accounts for sale, special
price, quantity discount, and the customer’s group: unit_price, with
line_total = unit_price × quantity. Show that one. variant.price and variant.sale_price
are list prices and must not be used for lines and totals.
Store rules
The cart exposes the rules the checkout enforces, so you can show them before payment:min_order_total: minimum order on thesubtotal(zero = no minimum). Below the threshold, show how much is missing and disable the payment button.guest_checkout_enabled: withfalsethe store accepts orders only from registered customers. Ask for login or sign-up before checkout.
3. Checkout & payment
Always take the payment methods from the public list: the checkout accepts only those. Each method is a stablecode (stripe, paypal, pokpay, paysera, bank_transfer,
cod) to translate in the client.
client_secret/redirect to complete
client-side, others confirm immediately. An online order that was never paid can be reopened
with POST /orders/{order_id}/pay (“Pay now”): same response as the checkout, same order.
See the API Reference for the exact schema of POST /checkout.
Store rule errors
A coupon’s discount never exceeds the subtotal, and a “free shipping” coupon zeroes the
shipping cost.
Gift voucher
The customer enters the voucher code and you send it invoucher_code. The balance pays the
total after the coupon, shipping included.
- The balance is reserved when the order is created and becomes final on payment: two checkouts can’t spend the same balance.
- The balance goes back to the voucher when the payment attempt is really closed (payment canceled, attempt replaced by a new checkout, order canceled by the store) and, for a paid order, with a full refund or a cancellation. A declined card does not release the voucher, because the same payment can be retried.
- If the voucher covers the whole total, the response has
payment_method: "voucher"and no gateway data: the order is already paid, go to the confirmation page. - The response carries
voucher_code,voucher_amount(amount used), andvoucher_remaining(balance left, to show to the customer). - A voucher can’t pay for a subscription.
4. Orders & tracking
history) the customer sees is filtered:
- it contains only status changes (
event_type: "status_change") and public notes (event_type: "note"); payments, refunds, shipments, and emails stay with the staff; - a status row written by the system has
comment: null: translate thestatusin the client. The comment stays only when a staff member wrote it and made it public; - a note has
status: null.
payment_status can also be partially_refunded; payment_method can be voucher.
5. Subscriptions
A product can have recurring plans (recurrings in the product detail). The customer
subscribes at checkout with subscribe_recurring_id (login and payment_method: "stripe"
are required).
- At purchase the customer pays the product price; renewals are charged at the plan price
(
price). - The “trial” only moves the first renewal: it comes after
trial_lengthunits oftrial_frequencyinstead of after one interval.trial_priceis not applied. billing_intervalsays every how manyfrequencyunits it renews;billing_chargesis the total number of charges, purchase included (0= until canceled).
GET /account/subscriptions the status can be active, trialing, past_due,
paused, canceled, or completed: finished, every installment charged and
next_billing_date: null. On a completed subscription hide the cancel button:
POST /account/subscriptions/{id}/cancel answers 409 subscription.already_completed.
Quick tip: the full list of parameters, request bodies, and responses is in the
API Reference, generated from the live OpenAPI schema — so it’s always
aligned with production.
Campaigns
A campaign link looks likehttps://<store>/…?cmp=<code>. When the storefront finds the cmp
parameter, it calls once per browser:
counted: false for the following ones) and an
unknown code answers 200 with counted: false. Limit: 30 requests per minute per IP.
Appearance & configuration
GET /settings/store-info— name, contacts, social, appearance (logo, colors) to brand your frontend like the store. It also contains:catalog.items_per_page(products per page,null= your choice) andcatalog.default_sort(default category ordering, already in theGET /products?sort=syntax, ornull);seo.meta_title_defaultandseo.meta_description_default: title and description for pages without their own meta (empty string = not set).
GET /banners,GET /information/<slug>— CMS content and hero.GET /languages,GET /currencies— for language/currency selectors.