Partner API
Live inventory and Certificates of Analysis from a real manufacturer; holds and orders for fulfilment partners. Contract: /openapi.json · For agents: /llms.txt
Authentication
Authorization: Bearer pk_XXXXX:sk_YYYYYYYY
Keys are issued by the manufacturer’s operator, carry scopes, and may be bound to one brand. A sandbox key behaves identically but touches only rehearsal stock that can never ship.
Versioning
Pharmagistic-Version: 2026-09-06
Optional; omit it for the current version. A date newer than this deployment is a 400 unsupported_version. Dates are added, never rewritten: a shape that exists on a date keeps that shape on that date.
Start here: inventory + COA, read only
Most partners begin with the read-only feed: show our live availability and our Certificates of Analysis on your own site. No pricing (prices are yours), no holds, no orders. A read-only key carries atp.products, atp.inventory and atp.check; every other endpoint answers 403.
GET /api/v1/products— every SKU you may sell, with availability.GET /api/v1/inventory?sku=…— the live count for one SKU.- The COA feed below — the certificate for each product.
- Map each product on your site to exactly one of our SKUs. Unmapped = not sellable.
- Refresh counts at least every 5 minutes. Our number is the truth; yours is a mirror.
- The count is “available as of our last sync”. Orders you ship through us reach our system via ShipStation and draw the count down; you never post an order.
- A 401 or 403 means stop showing stock and alert a human. Never treat it as zero.
Certificates of Analysis
The COA feed is served by our storefront platform and accepts the same key:
GET https://usamadepeptides.us/api/partner/v1/coa
GET https://usamadepeptides.us/api/partner/v1/coa/lot/{lot}Query: ?status=current|archived|retired|all (default current), ?product=<slug> (repeatable), ?updated_since=<ISO 8601> for incremental sync, ?format=json|csv, ?limit=1..500&cursor=. Each record carries product{slug,name}, batch_number, vial_size, tested_on, lab_name, purity_pct, status, certificate_url (PDF), verify_url and updated_at. A retired lot is a tombstone with an empty certificate_url: take it down. Match COAs to products by product.slug; your operator sends the slug ↔ SKU map with your key. Anyone can verify one lot without a key at https://usamadepeptides.us/coa/lookup?lot=<LOT>.
Go-live
Build against a sandbox key first. When the checks below pass, tell your operator; we read your sandbox traffic, then issue a production key bound to your brand and revoke the sandbox key 30 days later.
- Your mirror shows the same count as
GET /api/v1/inventoryfor every mapped SKU. - Every listed product shows its current COA and links the PDF.
- With your key revoked (we do this for ten minutes), your site hides stock and COAs and alerts you. It does not show stale or zero counts as if they were true.
- You stay under 60 requests a minute.
The flow (fulfilment keys only)
- Reserve the units. You get a
reservation_token, good for 30 minutes. - Charge the customer — your gateway, your rules.
- Place or consume.
POST /api/v1/ordershands us the order and we ship it;POST /api/v1/consumekeeps the units and you ship them.
Reserve before you charge. /check is advisory and can be stale; the reserve is the only answer that holds physical vials. A short reserve means do not take the money.
Endpoints
POST /api/v1/check | Available-to-promise for one or more SKUs (no hold) |
POST /api/v1/reserve | Hold inventory (brand pool first, then shared per access) |
POST /api/v1/release | Release a hold |
POST /api/v1/consume | Consume a hold WITHOUT creating an OMS order |
POST /api/v1/consume/reverse | Give back the units a consume took, when the sale is reversed |
GET /api/v1/inventory | ATP for one SKU by brand plus totals |
GET /api/v1/products | Every sellable SKU, with availability for this key |
POST /api/v1/orders | Place the pickable OMS order from a hold (one transaction) |
GET /api/v1/orders/{ref} | An order this key placed, by order id or Idempotency-Key |
POST /api/v1/orders/{ref}/cancel | Cancel an order this key placed, before it is picked |
POST /api/v1/shipments/combine | Ship several of this key's orders in one box (combined shipments) |
POST /api/v1/keys/introspect | Is this token a live OMS key, and what may it do? |
GET /api/v1/shipments | This key's brand's ShipStation queue, by modification time |
POST /api/v1/reserve-cache | Push the console's prepaid-reserve mirror for one brand |
POST /api/v1/confirm deprecated | Legacy: place an OMS order from a hold (use POST /api/v1/orders) |
Errors
{ "error": { "code": "reservation_gone", "message": "..." } }Codes are stable strings. Match on code, never on message.
no_inventory | Not enough stock for those lines. Do not charge. |
reservation_gone | The hold is over (expired or released). Reserve again. |
reservation_expired | The hold aged out of its 30-minute window. |
reservation_used | Already consumed or placed. You have been served once already. |
idempotency_mismatch | That Idempotency-Key was used with a different hold. |
order_not_cancellable | The order is picked or shipped. It needs a return authorization. |
brand_mismatch | This key may only act for its own brand. |
rate_limited | 429. Retry-After carries the seconds. |
unsupported_version | The version date is newer than this deployment. |
Webhooks
We send order.shipped and order.held to the URL you register, signed in Svix format: svix-id, svix-timestamp (Unix seconds) and svix-signature = v1,<base64 HMAC-SHA256 of "id.timestamp.body">keyed by your whsec_ secret.
- Reject anything more than five minutes old.
- Dedupe on
svix-id— a retry carries the same one. - During a secret rotation both signatures arrive, space separated. Any match is valid.
- Answer 2xx to stop the retries; answer 410 and we deactivate the endpoint.
Sandbox
A sandbox key draws on the SANDBOX brand: fake units, no shared-pool access, nothing that can ship. Same endpoints, same errors, same shapes. Rehearse reserve → charge → order there before you touch real stock.
Status
Beta. The endpoints and error codes on this page are stable and versioned by date. A breaking change gets a new version date and ninety days of overlap, and the old date keeps working for that whole window.