NinjaAPI instance, mounted at /{app}/api/v1/, with its own OpenAPI
3.1 document at /{app}/api/v1/openapi.json. This skill is the map
that gets an agent from “which app owns this concept?” to “this is
the endpoint I want to hit” without grepping templates.
When to use
- An agent knows what data it needs but not which Closient app owns that data.
- A developer is writing an SDK or MCP server and needs to enumerate every API surface.
- The agent hit a
404 Not Foundand wants to confirm the endpoint path before assuming the API is broken.
closient-api-quickstart first.
Discover everything from the API catalog
The canonical enumeration is the RFC 9727 linkset at/.well-known/api-catalog:
anchor— the API’s base URL (e.g.https://www.closient.com/products/api/v1/).service-desc[0].href— the OpenAPI document URL.service-desc[0].type—application/openapi+json.
APP_API_REGISTRY in
backend/apps/core/api/factory.py — that’s the source of truth if you’re
inside the monorepo.
App-by-app — what each API owns
| Mount | Label | Owns |
|---|---|---|
/account/api/v1/ | Account | Users, organizations, API keys, RBAC, OAuth-connected apps, whoami. Start here to identify the caller. |
/agent/api/v1/ | Agent | LLM-powered conversational endpoints (chat, search refinement, tool-use orchestration). |
/advertising/api/v1/ | Advertising | Sponsored placements, impressions, revenue-share reporting. |
/analytics/api/v1/ | Analytics | Scan events, search performance snapshots, brand engagement summaries. Read-heavy. |
/billing/api/v1/ | Billing | Stripe subscription state, usage metrics, plan + tier endpoints. Read-only for non-owners. |
/brands/api/v1/ | Brands | Brand records, ownership/claim flow, brand-level analytics. Write requires brands:write. |
/byos/ | BYOS | ”Bring your own search” — embedded search widget endpoints (not v1 prefixed by convention). |
/certifications/api/v1/ | Certifications | Product certifications (organic, gluten-free, Fair Trade, …). |
/compliance/api/v1/ | Compliance | Recalls, safety notices, FSMA 204 traceability (sibling to /epcis/api/2.0/). |
/content/api/v1/ | Content | Wagtail-backed pages, blog posts, feeds, legal pages. |
/dashboard/api/v1/ | Dashboard | Aggregated views consumed by the Closient web UI. Not a public-facing API. |
/epcis/api/2.0/ | EPCIS 2.0 | GS1 EPCIS 2.0 event capture + query. Path mounted at /api/2.0/ per spec, not /v1/. |
/integrations/api/v1/ | Integrations | POS connections (Shopify, Square, Clover, Lightspeed), webhooks. |
/locations/api/v1/ | Locations | Physical store/service locations with PostGIS geometry. |
/notifications/api/v1/ | Notifications | Multi-channel notification delivery (email, Slack, SMS). |
/products/api/v1/ | Products | Products (GTINs), images, validators, catalog API, categories, QR rendering. |
/resolver/api/v1/ | Resolver | GS1 Digital Link resolution + linkset queries + serial verification. |
/retailers/api/v1/ | Retailers | Offers (in-store + online), inventory sources, online-retailer integrations. |
/scanner/api/v1/ | Scanner | Barcode + product scanning, vision-extracted attributes. |
/search/api/v1/ | Search | Catalog search, session-based local-first search, refinement. |
/sustainability/api/v1/ | Sustainability | Sustainability certifications + impact tracking. |
/voice-feedback/api/v1/ | Voice Feedback | Speech-to-text user feedback + reproducer playback. |
backend/apps/core/api/factory.py:APP_API_REGISTRY.
When that list changes, the catalog updates automatically; you don’t
need to re-grep.
Find an endpoint across the 22 APIs
Three strategies, fastest first:1. Browse Mintlify docs
Interactive HTML docs aggregate every per-app OpenAPI spec athttps://docs.closient.com. Search the sidebar by resource name —
“product”, “brand”, “offer”, “recall” — and you’ll get the canonical
endpoint URL with auth, parameters, and response schemas.
2. Fetch the OpenAPI doc directly
For machine consumption (SDK generation, MCP tool registration), grab the per-app spec straight from the catalog and parse it:3. Search the linkset
The catalog itself is linkset-shaped, so you can grep throughanchor and service-desc.href to find candidate apps before fetching
their specs. Useful in an MCP / tool-use context where dropping every
spec into a prompt is wasteful.
Cross-cutting conventions (apply to every per-app API)
Authentication
Every API accepts the same three auth mechanisms; pick one:| Mechanism | Header / cookie |
|---|---|
| API key | X-API-Key: csb_<body>_<crc32> |
| OAuth 2.0 access token | Authorization: Bearer <token> |
| Session (browser only) | Django sessionid cookie |
auth=None in the OpenAPI spec and accept anonymous
calls subject to a tighter IP-based throttle.
Pagination
List endpoints use limit/offset pagination (cursor pagination is NOT in use):limit=25, max limit=100. Implemented by the shared
apps.core.api.pagination.LimitOffsetPagination.
Error envelope (RFC 9457 Problem Details)
All errors returnapplication/problem+json:
type is a stable URI (you can build clients that switch on it);
title is human-readable; detail may include user-context
information. Wired by apps.core.api.exceptions.register_error_handlers.
Rate-limit headers
Every response carries IETFRateLimit-* headers:
| Header | Value |
|---|---|
RateLimit-Policy | All active windows, e.g. 300;w=60, 10000;w=86400. |
RateLimit-Limit | Quota for the most-restrictive currently-active window. |
RateLimit-Remaining | Requests left in that window. |
RateLimit-Reset | Seconds until that window resets (relative; clock-skew safe). |
X-RateLimit-* aliases are also emitted; X-RateLimit-Reset
keeps the absolute Unix-timestamp shape for back-compat. Implemented in
apps.core.api.throttling. Default: 300/min, 10k/day per key.
Idempotency
Mutating endpoints acceptIdempotency-Key headers where the operation
is naturally idempotent (POSTs that look like upserts, batch ingest
endpoints). The key is opaque to Closient; same key + same body returns
the original response. Check the per-endpoint OpenAPI description for
the explicit Idempotency-Key parameter declaration before relying on
it — not every POST is idempotent.
Empathy contract
EveryField() in every per-app schema carries a description= (or
auto-pipes from the model’s help_text via ModelDocumentedSchema),
and enum-shaped names are typed as StrEnums with the values declared
on the schema. SDK generators get a real enum constraint instead of a
bare string. See backend/apps/core/CLAUDE.md “API Empathy” for the
internal contract.
OpenAPI specs are versioned per app
When an app evolves a breaking change, expect a/api/v2/ mount
alongside /api/v1/. Today only EPCIS 2.0 lives outside the v1
convention (it sits at /api/2.0/ to match the GS1 EPCIS spec naming).
There is no global /v1/.
Cross-app patterns to recognise
”List then detail”
For most resources, list endpoints return a slim representation; detail endpoints return the full one:Short IDs in URLs
Public-facing resources use a 22-characterShortUUIDField for both
PKs and URL paths (see apps.core.fields.ShortUUIDField):
Scoped to organization
Resources owned by an organization (Products, Brands, Offers, Locations, EPCIS events, …) are filtered by the caller’s organization membership. Cross-org reads return404 Not Found rather than 403, to avoid
leaking existence.
Webhooks vs polling
Closient prefers webhooks over polling for state changes. Subscribe via/notifications/api/v1/webhooks (signed with HMAC-SHA256). Endpoints
that emit events are documented in each per-app OpenAPI spec; common
ones: scanner events, recall notices, offer changes, EPCIS captures.
Putting it all together
A typical agent boot sequence:- Hit
/.well-known/api-catalogto learn what’s available. - Hit
/.well-known/openid-configurationto learn how to auth. - Run
closient-api-quickstartto register / authenticate. GET /account/api/v1/whoamito confirm the token’s identity.- Walk per-app OpenAPI specs from the catalog to bind tools.
local-product-search,
resolve-gtin, claim-brand, capture-epcis-event, …) tell the
agent what to do with them.
Related skills
closient-api-quickstart— auth, scopes, first call.decode-gs1-ai,build-gs1-digital-link— GS1 identifier mechanics.local-product-search,resolve-gtin,check-product-availability— search + product depth.claim-brand,onboard-retailer— onboarding workflows.capture-epcis-event,query-epcis-events,manage-recall,check-fsma-204-readiness— supply-chain and compliance.brand-scan-summary,brand-search-demand,brand-retail-footprint— brand analytics.
Authoritative references
- RFC 9727 — API Catalog / Linkset.
https://datatracker.ietf.org/doc/html/rfc9727 - RFC 9457 — Problem Details for HTTP APIs.
- IETF
RateLimit-*headers (informed governor draft). - OpenAPI 3.1 spec — generated docs at
https://docs.closient.com. - Closient internal:
backend/apps/core/api/factory.py,backend/apps/core/api/pagination.py,backend/apps/core/api/throttling.py,backend/apps/core/api/exceptions.py.