Storefront-facing by design
The API exists to power a storefront — a shopper browsing a catalog, searching, managing their cart, checking out, paying, and tracking their own orders and returns. Merchant/admin operations (editing the catalog, moderating reviews, issuing refunds, changing store settings) happen in the Galactic Core admin, not through this API. The one exception is catalog ingestion, where a merchant syncs their own product feed in — see Catalog Ingestion. Key requirements follow from that boundary: catalog reads are open to a publishable key a browser can hold, while writes that a storefront’s server performs on a shopper’s behalf — creating an order, taking payment — require a secret key.Keys and sessions
Three identities combine depending on the call:
A storefront uses the publishable key for browsing, a customer session once the shopper signs in,
and routes sensitive writes (order creation, payment, ingestion) through a server holding the
secret key. Customer sessions come in two flavours — a GC-issued token, or a
bring-your-own-auth assertion if you run your own identity provider. See
Authentication and Customers & Auth.
Sensitive writes (orders, order updates, payments, ingestion) are additionally HMAC-signed so
the server can verify the request body wasn’t tampered with — the SDK computes and attaches the
signature for you.
Environments: production and sandbox
Every key carries an environment. A*_test_* key writes and reads sandbox data; a *_live_*
key writes and reads production data. They share the same endpoints and the same store, but the
data never mixes — you can build and exercise the full flow (orders, customers, carts, payments in
provider test mode) against sandbox without touching real records. Each authenticated response also
echoes the resolved environment in a Tybrite-Environment header.
Isolation
Your data is scoped to your store and never co-mingled with another store’s. Every key resolves to a singlestore_id, and the database enforces that boundary at the row level — each query is
constrained to your store’s rows by row-level security tied to the authenticated key, with no way for
one store to read or write another’s data even on a shared table. This holds for every endpoint, not
just the ones that take a store parameter.
For partners running a marketplace deployment, the boundary goes a step further: each operator’s
marketplace runs on its own dedicated backend — a separate database and API stack, not a shared
one — so an entire marketplace (and all its merchants) is isolated at the infrastructure level from
every other deployment. Within a deployment, individual stores are isolated from each other by the
row-level security described above.
Conventions that hold everywhere
- Errors — every error is
{ "error": { "code": "…", "message": "…", "details"?: … } }with a standard HTTP status. Codes are stable strings you can branch on. - Pagination — list endpoints are cursor-based: a response carries a
next_cursor; pass it back to fetch the next page. (The SDK exposes helpers for this.) - Sparse fieldsets — pass
fields=to fetch only the columns you need (lean catalog grids), orfull: true/ a detail call to get the complete object (SEO, media, specifications). - Idempotency — order creation takes an
Idempotency-Key; a retried call with the same key and body returns the original result instead of creating a duplicate.
Products and variants — which ID to send where
A product is the catalog entry a shopper browses (the “Cotton Hoodie”). A variant is a specific buyable SKU of it (the “Cotton Hoodie / Navy / M”). Every product has at least one variant, and one is marked the default. Two ID types follow from this —product_id and
variant_id — and which one an endpoint takes follows from what it acts on:
- Money and inventory are variant-grained. A shopper buys a specific SKU, so anything that
touches a cart, the stock count, or what gets charged uses
variant_id. - Catalog and discovery are product-grained. Browsing, recommendations, and reviews are about
the product, so they use
product_id.
variant_id you put in the cart all the way through to the order — don’t drop down to
product_id at checkout, or you may order the default variant instead of the one the shopper chose.
Gotcha —
product_specifications are keyed by variant. A product’s published specifications
are per-variant: each spec row references a variant_id (despite some internal column naming).
If a product has multiple variants, each can carry its own specifications. When you read specs off
a product detail, they belong to the specific variant, not the product as a whole.Performance & rate limits
Reads are served through a multi-tier edge cache, so catalog, pricing, and store-info calls return in tens of milliseconds globally and stay fast under load. The SDK retries transient failures automatically. There are two independent limits, and a429 tells you which one you hit by its error.code:
Rate-limit tiers (the abuse throttle): publishable keys are limited per-IP and per-key
(hourly + daily); secret keys per-key (hourly + daily); signed-in shoppers also get a per-session
cap. These are flat across plans — they protect a store from any single client monopolizing it.
Abuse-throttled traffic is never billed to the merchant, so a flood can’t deplete their monthly
quota. The monthly quota itself scales with the plan.
What an order does for you
Creating a paid order is a single call, but Galactic Core performs the operational work behind it automatically and atomically:- reduces stock for each line item (quantity- or barcode-tracked),
- redeems any gift cards applied,
- updates the customer’s purchase metrics,
- posts the double-entry accounting (revenue, tax, cost of goods), and
- records attribution for analytics.
post_processing_warnings array, so a partial failure is visible in the
response rather than inferred later from the ledger.
Currency
Every priced response already tells you its currency — you don’t fetch it separately. Product and pricing responses carry the currency inline:display_currency and currency_symbol on each
product (list and detail), plus base_currency and exchange_rate from the pricing endpoints. Both
are selectable via sparse fieldsets (fields=...,display_currency,currency_symbol). So a storefront
renders prices with the right symbol straight from the catalog read — no extra call. Store info’s
currencies list is configuration metadata (which currencies the store has enabled), not the
per-response source of truth. See Currency.
Where to go next
Quickstart
Your first authenticated call.
Authentication
Keys, sessions, and HMAC in depth.
TypeScript SDK
The typed client and every service.
API Reference
Every endpoint and schema.

