Your organization and key
One call that answers what this key may do, and why not — before you write a single retry-on-403.
TL;DRAI summary
This chapter explains what your Cypress API key can access in the platform and why certain actions might be restricted. It helps you understand your organization's features, limits, and the specific permissions tied to your key.
GET /api/v1/organizationAnswers any valid, unrevoked key — whatever your organization's status.
Every other route on both surfaces still requires an active organization;
this one exists so a key for an organization still onboarding (or between
plans) can learn why everything else is refused, instead of guessing from a
403.
What it returns
{
"organization": {
"id": "org_9f3a…",
"name": "Meridian Fleet Partners",
"slug": "meridian-fleet",
"status": "ACTIVE",
"profiles": ["SELLER"]
},
"account": {
"kind": "BUSINESS",
"features": { "team": true, "apps": true, "apiKeys": true, "campaigns": true, "listings": true, "valuations": true, "pricingRules": true },
"limits": { "listings": null, "valuations": null, "teamMembers": null, "campaignEmailsPerMonth": null, "cedarAnswersPerDay": null },
"used": { "listings": 0, "valuations": 0, "teamMembers": 4, "campaignEmailsPerMonth": 1250 }
},
"apiKey": {
"id": "key_2b71…",
"name": "ERP integration",
"scopes": ["vehicles", "listings", "webhooks", "planning:read"],
"createdAt": "2026-08-19T14:02:00.000Z"
},
"products": {
"remarketing": { "enabled": true },
"planning": { "enabled": true, "requestedAt": "2026-07-01T00:00:00.000Z" },
"buyPlanning": { "enabled": false, "requestedAt": null },
"automations": { "enabled": false }
},
"channels": [
{ "channel": "MARKETPLACE", "enabled": true },
{ "channel": "STOREFRONT", "enabled": true, "published": true },
{ "channel": "DIRECT_LINK", "enabled": false }
],
"billing": {
"standing": "CURRENT",
"autoPay": "ACH"
},
"delegation": {
"cypressMayActOnBehalf": false,
"cypressDecidesReviewOffers": true,
"cypressMayMakeBuyerOffers": false,
"expiresAt": "2026-11-02T13:00:00.000Z",
"expired": false
},
"accountManager": {
"id": "clx…",
"name": "Carla Reyes",
"email": "carla@getcypress.ai"
},
"capabilities": [
{ "capability": "vehicles.read", "allowed": true },
{ "capability": "vehicles.write", "allowed": true },
{ "capability": "listings.read", "allowed": true },
{ "capability": "listings.write", "allowed": true },
{ "capability": "listings.channel.MARKETPLACE", "allowed": true },
{ "capability": "listings.channel.STOREFRONT", "allowed": true },
{ "capability": "listings.channel.DIRECT_LINK", "allowed": false, "reason": "CHANNEL_NOT_GRANTED" },
{ "capability": "webhooks.manage", "allowed": true },
{ "capability": "planning.read", "allowed": true },
{ "capability": "planning.write", "allowed": false, "reason": "SCOPE_MISSING" },
{ "capability": "buy-planning.read", "allowed": false, "reason": "BUY_PLANNING_NOT_ENABLED" },
{ "capability": "buy-planning.write", "allowed": false, "reason": "BUY_PLANNING_NOT_ENABLED" }
],
"rateLimit": { "requestsPerMinute": 300 }
}No card numbers, no credit figures
billing.standing is the organization's billing status (e.g. CURRENT,
PAST_DUE); billing.autoPay says only which payment method type is on
file — ACH, CARD, or NONE. Discovery never returns a card brand,
last four digits, or a credit balance.
Individual and business accounts
account is your account's rules as they hold for your organization. Since 1.9.0.
kind:BUSINESS(a dealer or fleet) orINDIVIDUAL(a private person's account, from Grove's front door or the private-buyer sign-up). An individual works as a dealer does, within its caps, and can ask Cypress to become one.features: which features are on: the team, connecting apps, API keys, pricing rules, marketing campaigns, valuations and listings, and the rest. Planning, Buy planning, Automations, the channels, ACH and bank transfer keep their own switches (products,channels,billing).limits: the caps,nullfor none: cars listed and valuations in total (a car counts the first time it is listed), people in the account (owner included), campaign emails a month, Cedar's answers a day in Grove.used: what your organization used of them.
Cypress sets the rules for each kind of account and can change them for your organization. By default a business has
every feature and no caps; an individual lists 10 cars and runs 10 valuations in total, has a team of 3, and sends
campaigns once Cypress switches them on (500 emails a month). What they refuse answers ACCOUNT_RULES (403), on the
route and in capabilities alike; see Errors. An individual values, lists, invites people,
connects apps and makes API keys once its email is confirmed.
Your Cypress Manager
accountManager is the person at Cypress who looks after your organization:
their id, name and email, and nothing else. It is null while no one is
assigned. Any credential of your organization reads it, people's and agents'
alike, so an app can show who to contact. get_organization_profile
(GET /api/v1/organization/profile, scope organization:read) answers it
too. Since 1.9.0.
What Cypress may do for you, and until when
delegation is what your organization lets Cypress do, as it stands now. Your
admin sets it with set_cypress_delegation
(PATCH /api/v1/organization/delegation, scope organization:write): the
three switches and, since 1.9.0, an end date, expiresAt (a moment in the
future, or null for none). From that moment every switch reads as off
everywhere, and expired is true; the change is told as
ORGANIZATION.UPDATED with change: "DELEGATION", the switches' from and
to, and expiresAt.
curl -X PATCH "$BASE/api/v1/organization/delegation" \
-H "authorization: Bearer $TOKEN" -H "content-type: application/json" \
-d '{ "allowCMReviewOfferDecisions": true, "expiresAt": "2026-11-02T13:00:00Z" }'A switch granted again after its end date passed, with no new end date, is granted without one; the switches you leave out stay off. It is your admins' act, through an app acting for them: an API key, an agent and Cypress staff are refused.
Reading capabilities
Each entry names one thing this key could do, and — when it's refused — the
same reason code the refusing route would return. Switch on reason:
reason | Status the refusing route returns | What to do |
|---|---|---|
ORG_NOT_ACTIVE | 403 | Nothing you can fix — ask Cypress about your organization's status. |
PLANNING_NOT_ENABLED | 403 | Ask Cypress to turn on the Planning product for your organization. |
BUY_PLANNING_NOT_ENABLED | 403 | Ask Cypress to turn on the Buy planning product for your organization (a switch of its own, separate from Planning). |
SCOPE_MISSING | 403 | Ask your organization's admin to add the scope on the Integrations page — no need to rotate the key. |
CHANNEL_NOT_GRANTED | 422 | Ask Cypress for the channel grant. |
A capability with allowed: true carries no reason.
A PROVISIONAL organization sees the whole picture at once
When the organization isn't ACTIVE, every capability answers
allowed: false, reason: ORG_NOT_ACTIVE — discovery still returns 200,
so a partner mid-onboarding gets one clear answer instead of ten different
403s as they try each endpoint.
Live and test keys
A key's first characters say where it acts. Since 1.5.0.
| Prefix | Acts on | Reaches real people |
|---|---|---|
cyp_live_ | A live organization: your real fleet, dealers, buyers and contacts | Yes |
cyp_test_ | A sandbox: a demo organization with made-up data | Never: emails, campaign sends, reminders and signing links are recorded and answered as simulated |
cyp_cm_ | Cypress staff only: a CM token acts as the Cypress Manager who made it, for the organization each request names (Cypress-Organization) | As that person would |
Cypress holds a key to its environment: a test key on a live organization, or a
live key on a sandbox, answers 403 KEY_ENVIRONMENT and does nothing. Never
test with a live key: build against a sandbox's test key, and use the live key
only in the system that runs your integration.
A key is cyp_live_ or cyp_test_, then 32 letters and digits, an underscore,
and a 6-character checksum (the CRC-32 of everything before the underscore, in
base 62). A key whose checksum does not match is refused before Cypress looks
it up, and a secret scanner can recognize a real key with
cyp_(live|test)_[A-Za-z0-9]{32}_[A-Za-z0-9]{6}. Keys made before 1.5.0
(cyp_live_ and 32 characters, no checksum) keep working as they did; make a
new one to get the checksum. If a key is ever pasted anywhere it should not be,
revoke it in Organization → Integrations and make another.
Key scopes
| Scope | Grants |
|---|---|
vehicles | Read and write vehicles (vehicles.read, vehicles.write) |
listings | Read and write listings, and the channel checks (listings.*) |
webhooks | Manage subscriptions and read the delivery log (webhooks.manage) |
planning:read | Read planning stock together with vehicles — ?lifeStage=OPERATION,PLANNING and reads by id — and read the plan: /api/v1/planning/* reads, ownership, odometer readings and cost events (planning.read) — and subscribe to the PLAN.* webhooks, beside webhooks |
planning:write | Everything planning:read grants, plus every planning write: pushing planning stock, keeping it current, and driving the plan (planning.write implies planning.read) — see Planning API (Sell planning) |
buy-planning:read | Read the dealer's buy plan: the quarter, targets, their live matches and purchases — /api/v1/buy-planning/* reads (buy-planning.read) — and subscribe to the BUY.* webhooks, beside webhooks |
buy-planning:write | Everything buy-planning:read grants, plus every write: the quarter's goal, targets, hiding a match, purchases, and approving the quarter (buy-planning.write implies buy-planning.read) — see Planning API (Buy planning) |
offers:read | Read the offers on your vehicles and the offers your organization made (offers.read). Since 1.5.0 |
offers:write | Everything offers:read grants, plus accepting, declining and countering offers on your vehicles and withdrawing your own (offers.write). Accepting or countering below the floor is for a person: 403 PEOPLE_ONLY. Since 1.5.0 |
members:read | Read your members, people and agents (GET /api/v1/members), and the apps connected through Connect Cypress (GET /api/v1/connections) (members.read). Since 1.5.0 |
connections:write | Everything members:read grants, plus disconnecting an app (DELETE /api/v1/connections/{id}): every token ends and its agents are switched off (connections.write). API keys only. Since 1.5.0 |
tasks:read | Read your organization's CRM tasks, people's and agents' alike (tasks.read), and subscribe to the TASK.* webhooks, beside webhooks. Since 1.5.0 |
tasks:write | Everything tasks:read grants, plus creating, updating, completing, reassigning and deleting tasks (tasks.write). A task is given only to an active member of your organization, agents included. Since 1.5.0 |
crm:read | Read your organization's own CRM book: contacts, businesses and deals (crm.read) — see CRM. Since 1.5.0 |
crm:write | Everything crm:read grants, plus creating and changing contacts, businesses and deals, and moving deals by hand (crm.write). Since 1.5.0 |
mission-control:read | Read your organization's Mission Control board, what needs a person now (mission-control.read); with tasks:write, delegate an item to one of your agents — see Mission Control. Since 1.5.0 |
insights:read | Cedar's and Sequoia's insights on your vehicles and buy targets (insights.read), and include=insights on a single read — see Insights. Never a default. Since 1.5.0 |
notifications:read | What Cypress told your members, people and agents (notifications.read): GET /api/v1/notifications, and subscribing to NOTIFICATION.CREATED — see Notifications. Never a default. Since 1.5.0 |
notifications:write | Everything notifications:read grants, plus reading and setting your people's notification preferences (notifications.write) — see Notifications. Never a default. Since 1.5.0 |
closing:read | The closings of the cars you sold and bought, step by step, with deadlines and whose turn it is (closing.read) — see Closings. Never a default. Since 1.5.0 |
closing:write | Everything closing:read grants, plus reminding whoever's turn a step is, asking for a document and re-sending a signing link (closing.write) — see Closings. Never a default. Since 1.5.0 |
marketing:read | Your campaigns, their sends, the people they reached and the cars they brought people to, and your message templates (marketing.read) — see Marketing. Never a default. Since 1.5.0 |
marketing:write | Everything marketing:read grants, plus creating, editing, activating, pausing, sending now and deleting campaigns (marketing.write); an agent drafts and pauses but never activates or sends — see Marketing. Never a default. Since 1.5.0 |
automations:read | Your organization's own automations and their runs (automations.read). Needs the Automations product, which Cypress switches on per organization (403 AUTOMATIONS_NOT_ENABLED until then). Never a default. Since 1.5.0 |
automations:write | Everything automations:read grants, plus building, dry-running and submitting your organization's own automations for Cypress to publish (automations.write). Needs the Automations product. Never a default. Since 1.5.0 |
organization:read | Read your organization's settings: its profile, locations, preferences and what it asked Cypress for (organization.read). See The app's actions. Never a default. Since 1.5.0 |
organization:write | Everything organization:read grants, plus changing those settings and asking Cypress for a product (Planning, Buy planning) (organization.write). The switches that let Cypress act for you stay a person's. Never a default. Since 1.5.0 |
members:write | Everything members:read grants, plus inviting people, changing a member's role and removing a member (members.write). A person's through an app acting for them: an API key and an agent are refused, so a key never raises its own power. Never a default. Since 1.5.0 |
banking:read | Read your bank accounts and lenders (banking.read). They hold account numbers, so they have a scope of their own. Never a default. Since 1.5.0 |
banking:write | Everything banking:read grants, plus adding and changing bank accounts and lenders (banking.write). Never an agent's. Never a default. Since 1.5.0 |
billing:read | Read your plan, invoices, credit and what you owe (billing.read), and, on bank transfer, the transfers Cypress holds unapplied with the invoices they could pay (GET /api/v1/billing/bank-transfers: admins, billing admins and Cypress staff; since 1.9.0). Paying stays a person's, in Cypress. Never an agent's. Never a default. Since 1.5.0 |
analytics:read | Read your analytics: sales, engagement and market reports, as the Analytics pages show them (analytics.read). Never a default. Since 1.5.0 |
marketplace:read | The marketplace as a buyer: search the vehicles for sale, your saved vehicles and searches, and the offers your organization made (marketplace.read). Never a default. Since 1.5.0 |
marketplace:write | Everything marketplace:read grants, plus saving vehicles and searches, and making and answering offers as a buyer (marketplace.write). Making an offer commits money: a person's, never an agent's. Never a default. Since 1.5.0 |
documents:read | Read your organization's documents and document templates (documents.read). Never a default. Since 1.5.0 |
documents:write | Everything documents:read grants, plus uploading documents and editing templates (documents.write); publishing a template stays a person's. Never a default. Since 1.5.0 |
huddle:read | Read the conversations of the person or agent the token acts for: the rooms they are in, their messages and threads, and their Inbox (huddle.read) — see Huddle. Never an API key's: a conversation is always someone's. Never a default. Since 1.9.0 |
huddle:write | Everything huddle:read grants, plus posting, replying, reacting, editing and deleting their own messages, joining an open channel, opening a channel and adding people to one (huddle.write). Never an API key's. Never a default. Since 1.9.0 |
agent-quality:write | Send your agent's benchmark runs and flagged answers, and read Cypress's verdicts on them (agent-quality.write) — see Agent quality. For an app Cypress made (Grove) only: an API key cannot hold it, a partner app cannot be registered for it, and its routes refuse every other credential. Since 1.9.0 |
There are two planning products, and they are separate. products.planning,
the planning:read / planning:write scopes and the planning.* capabilities
mean Sell planning, the plan that hands vehicles to Sell.
products.buyPlanning, the buy-planning:read / buy-planning:write scopes and
the buy-planning.* capabilities mean Buy planning, the dealer's plan.
Each has its own switch: an organization with Buy planning but not Sell planning
answers 403 PLANNING_NOT_ENABLED on the Sell planning routes, and one with
Sell planning but not Buy planning answers 403 BUY_PLANNING_NOT_ENABLED on the
Buy planning routes. The scope strings never changed; since 1.4.0 the Integrations
page labels them "Sell planning (read)", "Sell planning (read and write)",
"Buy planning (read)" and "Buy planning (read and write)".
A key created without picking scopes gets the defaults — vehicles,
listings, webhooks — never a planning scope, sell or buy. Scopes are chosen at mint
and can be changed later from the Integrations page without rotating the
key; every existing key keeps exactly the scopes it already has.
planning:read alone doesn't get you the vehicle routes
planning:read alone reads the plan (/api/v1/planning/*), but reading
or listing vehicles — Sell stock or planning stock — goes through
GET /api/v1/vehicles, which the guard gates on the vehicles scope
first. A key holding only planning:read sees planning.read
allowed: true on discovery, but a call to GET /api/v1/vehicles (with or
without ?lifeStage=) answers 403 SCOPE_MISSING naming vehicles. Pair
planning:read with vehicles to read planning stock as vehicles.
An embedded listing on a vehicle push (POST /api/v1/vehicles, its bulk
form, and the Manheim-compatible offering on POST /api/compatible/v1/units)
needs the listings scope too — vehicles alone lets you push the vehicle
but not the listing riding along with it; without listings the push (or
that bulk item) answers 403 SCOPE_MISSING and creates nothing.
Which routes need vehicles too
The /api/v1/planning/* routes need only planning:read or
planning:write. Routes under /api/v1/vehicles — pushing planning
stock, PATCH, and a vehicle's ownership, odometer-readings,
cost-events and departure — are vehicle routes: they need vehicles
first, then the planning scope. A key for a fleet system that does both
holds vehicles and planning:write.
Call it at startup
Fetch /api/v1/organization once when your integration starts (and again
if you start seeing unexpected 403s). It's the fastest way to confirm a
new key is scoped the way you expect, and to catch a channel or product
change before it surprises a real push.
Pushing inventory
Send your vehicles one at a time or 500 at a time, map your feed's fields, attach an inspection report by its link, and keep the whole inventory in step.
Your own ids
Push and look up vehicles, listings, contacts, businesses, deals and tasks by the ids your own systems use, so a bridge keeps no mapping table of its own.