When to use
- An agent (MCP host, partner SDK, internal automation, third-party integration) is being onboarded against Closient for the first time.
- A developer wants the canonical “hello world” path before reading any per-app API docs.
- Token, scope, or rate-limit confusion needs to be reset to a known-good baseline.
closient-openapi-tour for a
breadth-first map of the 22 per-app APIs and individual skills like
local-product-search for depth on a specific workflow.
Environments
All endpoints in this doc are path-relative; prefix them with the env
URL of your choice. Examples use
https://www.closient.com.
Step 1 — Discover what’s available
Closient publishes machine-readable discovery surfaces under/.well-known/. Hit them first to enumerate APIs and capabilities
without grepping documentation:
service-desc pointing at that app’s OpenAPI document:
Step 2 — Pick a credential type
Closient accepts two authentication shapes on every per-app API:
Browser-based clients can also use the Django session cookie, but that
isn’t a useful agent path.
Quick rule: if your agent’s caller is a person who has a Closient
account, use OAuth. If your caller is another machine you own, use an
API key. Don’t share OAuth client credentials between operators.
2a — Get an API key (fastest path)
Sign in to Closient, open Settings → API Keys, and create a new key. The key is shown once; copy it then. Format:csb_<body>_<crc32>.
Verify by hitting the catalog search endpoint with no scope required:
200 OK with a JSON body containing items and total,
the key is alive and you can skip to Step 4. (Catalog search is one of
the few unauthenticated endpoints, so this also works without a key — a
401 here means the key string is malformed.)
2b — Register an OAuth client (RFC 7591 Dynamic Client Registration)
For agents that need to act on behalf of users, register a client dynamically — no human admin required:- The endpoint is rate-limited per IP (10 registrations/hour). Use a
stable
software_idso repeat runs deduplicate cleanly. client_secret_expires_at: 0means the secret never expires (RFC 7591 §3.2.1) — but you can rotate at any time via the connected-apps dashboard.- The redirect URI must use HTTPS in production;
http://localhostredirects are accepted in testing/local environments. - For a confidential server-to-server agent, use
client_credentialsin thegrant_typesarray; you’ll get tokens without a user in the loop.
Step 3 — Run the authorization_code + PKCE flow
Public clients (mobile, SPA, CLI tools) MUST use PKCE — Closient’s AS returnsinvalid_request if the code-verifier is missing.
3a — Mint the PKCE pair
code_verifier — you need it at the token exchange step.
3b — Redirect the user to the authorize endpoint
redirect_uri with code
and state in the query string.
If they click Deny, you’ll receive ?error=access_denied — surface
it as “the user declined” rather than retrying.
3c — Exchange the code for tokens
id_token is a signed OIDC JWT — verify against the JWKS URI from
/.well-known/openid-configuration before trusting the claims.
3d — Refresh when the access token expires
Step 4 — Make your first authenticated call
Pick any per-app endpoint. The search session endpoint is the canonical “hello world” for an agent because it returns local-first product results that exercise the geo-distance ranking pipeline:/search/session/{id}/refine) and an
array of items, each annotated with store, offer, and
distance_km.
For something even simpler that doesn’t require any auth at all:
Step 5 — Debug the common failures
401 Unauthorized
403 Forbidden
429 Too Many Requests
These are standard IETF
RateLimit-* headers (informed-governor). Use
RateLimit-Reset to schedule the next retry — don’t poll on 429 with no
backoff.
Legacy X-RateLimit-* aliases are also emitted; X-RateLimit-Reset
keeps the absolute Unix-timestamp shape for back-compat.
400 with error: invalid_grant on token exchange
codewas already redeemed (one-time-use).code_verifierdoesn’t match the originalcode_challenge.redirect_uridiffers from what you sent at/oauth/authorize/.
400 with RFC 7591 error: invalid_redirect_uri on registration
- HTTP redirect URI on production (HTTPS-only outside localhost).
- Loopback URI uses a hostname instead of
127.0.0.1/[::1].
Scopes you’ll actually use
Closient’s OAuth scope set is per-app — every NinjaAPI gets a:read
and a :write. The most common starter set:
The full canonical list is the
scopes_supported array in
/.well-known/openid-configuration. Always request the narrowest
scope set that lets you complete the workflow — agents asking for
write scope when they only read are flagged as suspicious in the consent
UI.
Related skills
closient-openapi-tour— bird’s-eye map of the 22 per-app APIs.decode-gs1-ai— once authenticated, parse GS1 AI strings into structured queries against/products/api/v1/.build-gs1-digital-link— inverse ofdecode-gs1-ai.local-product-search,resolve-gtin,check-product-availability— the most common workflows for an agent’s first useful call.claim-brand,onboard-retailer— onboarding-shaped workflows for authenticated org members.