If you're using Claude Code, Cursor, or a similar tool to build your integration, paste the block below as your opening prompt. It gives the assistant the API's ground rules up front so it doesn't have to infer them — and, just as importantly, tells it what the API doesn't do, so it doesn't invent endpoints that don't exist.
Fill in the last line with what you want built.
Don't paste your API token into the prompt — tell the assistant to read it from an environment variable and add it yourself.
You are building an integration against the CartGenie Public API.
REFERENCE
Docs: https://api.cartgenie.com/public-api-docs
OpenAPI spec: https://api.cartgenie.com/public-api-docs.openapi
Fetch the spec before writing code. Do not invent endpoints — if
something isn't in the spec, say so instead of assuming it exists.
BASICS
Base URL: https://api.cartgenie.com, all endpoints under /public/v1/
Auth: every request needs `Authorization: Bearer <token>`
Read the token from an environment variable. Never hardcode it and
never expose it to a browser or any client-side code.
Sanity check: GET /public/v1/store returns 200 when the token is
valid and the API is enabled for the store.
WHAT EXISTS
Read: store, products, product by id, variants, orders, order by
name, webhooks
Write: variant inventory, order tracking, order fulfill/unfulfill/
cancel, webhook create/update/delete/test
WHAT DOES NOT EXIST
There is no endpoint to create or update products, create orders,
issue refunds, or read customers, discounts, or subscriptions.
Some webhook events reference those resources, but there is no REST
endpoint to read them back. Do not write code that assumes otherwise.
RULES THAT WILL BREAK NAIVE CODE
1. Strict validation. Any field an endpoint doesn't define returns
422 rather than being ignored. Never read an object, modify it,
and POST the whole thing back. Build request bodies from scratch
with only the fields being changed.
2. Cursor pagination. Pass `limit` (1-250) and send `meta.next_cursor`
back as `cursor`. Stop when `meta.has_more` is false. Cursors are
opaque — never construct or parse them.
3. Incremental sync. products, variants and orders accept
`updated_since` (ISO-8601). Persist the timestamp of each
successful run and use it to start the next.
4. Inventory writes are absolute, not increments. PUT
/variants/{id}/inventory with `stock` sets the level. Always send
`expected_stock` so the write is conditional; on 409 the response
carries `actual_stock`, so retry from that without re-reading.
The variant must be published with tracking enabled.
5. SKUs are not unique within a store. GET /variants?sku= always
returns an array. Never take [0] and assume it's correct.
6. Product deletions are polymorphic. Check `deleted_at` before
touching any other field. A permanently deleted product carries
only id, name, slug, status, deleted_at and updated_at — no
price, stock, variants, images or url. Code that reads those
first will crash. Archived products keep the full shape but also
carry `deleted_at`.
7. Order shapes are conditionally complete. `shipment` is an object
on shippable orders and an empty ARRAY on digital-only orders.
`refunds` is absent unless the order was refunded — treat absence
as "nothing refunded", not an error. payment.method and
transaction_id are null until the gateway records them.
8. Orders are addressed by merchant-visible name, not database id.
URL-encode it.
9. Tracking routing. With zero fulfillments, tracking goes to the
order's shipment. With exactly one, omit fulfillment_id. With
more than one, or a partially fulfilled order, fulfillment_id is
required. Once any fulfillment exists, shipment.tracking_* always
reads back null — read tracking from fulfillments[].
10. Cancel is a status change only. It does not refund, restock,
remove fulfillments, or cancel subscriptions.
11. Money is in the smallest currency unit. 4900 is $49.00. Never do
float math on it.
12. Rate limits: 120 req/min and 4 req/sec per token. Respect
X-RateLimit-Remaining and back off on 429 with retry.
WEBHOOKS
Body arrives as {"type": "<event>", "payload": {...}} with a
`Signature` header holding an HMAC-SHA256 of the RAW body, keyed
with the store's webhook secret. Hash the raw bytes exactly as
received — re-serializing the JSON produces a different digest.
Deliveries retry up to 3 times with a 10s timeout, so the handler
must be idempotent and respond fast. Endpoints must be public HTTPS.
ERROR HANDLING
401 bad token, 403 missing scope, 404 not found or API not enabled
for the store, 409 state conflict, 422 validation, 429 rate limit.
Handle each distinctly; don't collapse them into a generic retry.
HOW TO WORK
Ask before assuming anything not covered above. State your
assumptions explicitly. Write the sync/state logic so a partial
failure can be resumed rather than restarted.
WHAT I WANT YOU TO BUILD
[describe your integration here]