cypress.DOCS
Log inRegister
Cypress Docs

Connect Cypress

Let an organization's admin connect your app to Cypress, get tokens that act for that admin or for the agents your app adds, and sign people in with their Cypress login.

TL;DRAI summary

This chapter explains how your app can securely connect to Cypress using OAuth 2.1, allowing fleet managers or dealers to approve your app and grant it access to their organization's data. You'll learn how to register your app, manage agents, and use tokens to interact with the Cypress API.

Dive deeper:

An API key belongs to one organization and acts as that organization. Connect Cypress is for an app that many organizations use: an organization's admin approves your app once, on a Cypress screen, and your app gets tokens for that organization. It is OAuth 2.1 with PKCE. Since 1.5.0.

Your app can also ask to add agents to the organization's team. An agent is a member of the organization with its own name and the role AGENT. Every action it takes is recorded under its own name, and it works under the same rules as everyone else, plus a few of its own (see What agents may not do).

Register your app

Apps are registered by Cypress. Send us:

FieldWhat it is
Name and descriptionWhat the admin reads on the consent screen
Redirect addressesWhere Cypress sends the admin back. https only (http only for localhost), matched exactly; an http address on the person's own computer matches on any port
ScopesThe most your app will ever ask for, from the key scopes
AgentsOptional. The agents your app may add, each with a key, a name and its scopes, for example sell, "Cedar Sell", offers:write

You receive a client_id (cyp_app_…) and, for an app that runs on a server, a client_secret (cyp_cs_…), shown once. An app without a secret (a browser or mobile app) uses PKCE alone and cannot add agents.

The server's settings are published at /.well-known/oauth-authorization-server.

Without registering: a client ID metadata document

An MCP client, or any app that runs on a person's own computer, can connect without registering. Its client_id is the https address of a JSON document it publishes about itself, as the MCP authorization flow (2026-07-28) has it. The server's settings say client_id_metadata_document_supported: true.

{
  "client_id": "https://desk.example.com/oauth/client.json",
  "client_name": "Fleet Desk",
  "client_uri": "https://desk.example.com",
  "redirect_uris": ["http://127.0.0.1/callback", "https://desk.example.com/oauth/callback"],
  "token_endpoint_auth_method": "none",
  "grant_types": ["authorization_code", "refresh_token"],
  "response_types": ["code"]
}
  • The address is https, names a document (a path, not a whole site), carries no user name, password or fragment, and is written in its plain form. The document's client_id is that address, exactly.
  • Cypress reads it when an authorization starts, again after five minutes at most. It must be served at the address itself (a redirect is not followed), from a public address, as JSON of at most 5 KB, within five seconds.
  • It is a public app: no secret (token_endpoint_auth_method is none or left out), PKCE always, and no agents. Its token acts for the admin who approved it, with the scopes they approved.
  • Redirect addresses are https, or http on the person's own computer (127.0.0.1, localhost, [::1]). An address on the computer matches on any port, so a desktop client lists http://127.0.0.1/callback and listens on the port it picks.
  • The admin sees the address. The consent screen shows it beside the name, marks the app Not registered with Cypress and says where the browser returns; Settings → Connected apps shows it too. Cypress can switch an app off, and it then stays off whatever its document says.

The flow below is the same: send client_id (the address) and no secret when you exchange the code.

Registering itself: dynamic client registration

An app that registers itself (RFC 7591), as Microsoft Copilot Studio's automatic OAuth does, posts its settings to POST /api/oauth/register, the server settings' registration_endpoint, and gets its client_id at once:

{
  "client_name": "Fleet Desk",
  "redirect_uris": ["https://desk.example.com/oauth/callback"],
  "token_endpoint_auth_method": "none",
  "grant_types": ["authorization_code", "refresh_token"],
  "scope": "offers:read crm:read"
}
  • It answers 201 with the client_id (cyp_dyn_…), and for an app that asks for client_secret_basic or client_secret_post (the default) a client_secret (cyp_cs_…), shown once and never expiring.
  • What it may ask for: the authorization_code grant, with refresh_token; response_types code; any of the scopes (all of them when scope is left out), of which an admin approves a part. It never adds agents.
  • Redirect addresses follow the same rule as above: https, or http on the person's own computer, without a fragment.
  • A refusal answers 400 with invalid_redirect_uri or invalid_client_metadata and says why. Twenty registrations an hour per caller.
  • The admin sees it as unregistered. The consent screen marks it Not registered with Cypress, says it registered itself and where the browser returns; Settings → Connected apps shows where it returns too.

The flow

1. Send the admin to Cypress.

GET /api/oauth/authorize
  ?response_type=code
  &client_id=cyp_app_…
  &redirect_uri=https://your.app/callback
  &scope=offers:write webhooks
  &agents=sell
  &state=<your value>
  &code_challenge=<base64url(SHA-256(verifier))>
  &code_challenge_method=S256

PKCE with S256 is required. agents is a comma list of your agent keys and may be left out. Every scope an agent has must also be in scope.

2. The admin approves. Cypress shows the app, the organization, what the app will be able to do and the agents it will add. An admin of the organization approves, or Cypress staff acting for it (on its behalf, and the audit log says so). A connection staff approve creates the agents, but your person token acts for nobody, since staff are not members of the organization: an app that must act as a person is connected by one of its people. Approving again later updates the same connection.

3. Cypress sends the admin back to your redirect address with code and your state. A refusal comes back as error=access_denied. A code works once, for 10 minutes.

4. Exchange the code.

curl -X POST https://app.getcypress.ai/api/oauth/token \
  -u "cyp_app_…:cyp_cs_…" \
  -d grant_type=authorization_code \
  -d code=cyp_ac_… \
  -d redirect_uri=https://your.app/callback \
  -d code_verifier=<the verifier>
{
  "access_token": "cyp_at_…",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "cyp_rt_…",
  "scope": "offers:write webhooks",
  "connection_id": "…",
  "organization_id": "…",
  "agents": [{ "id": "…", "key": "sell", "name": "Cedar Sell", "scopes": ["offers:write"] }]
}

This token acts for the admin who approved, while they remain a member of the organization.

5. Get a token for an agent. Agent tokens are never handed out in step 4. Ask for one with your secret and the agent's id:

curl -X POST https://app.getcypress.ai/api/oauth/token \
  -u "cyp_app_…:cyp_cs_…" \
  -d grant_type=client_credentials \
  -d agent_id=<agent id>

The token is bound to that agent and lasts an hour. There is no refresh token: ask again.

6. Refresh. grant_type=refresh_token returns a new access token and a new refresh token; the old refresh token stops working. Presenting a used refresh token again is treated as a leak: every token for that person on that connection is revoked.

7. Revoke a token you no longer need at POST /api/oauth/revoke with token=… and your client credentials.

Calling the API with a token

Send Authorization: Bearer cyp_at_…. A token works on the app's actions, the MCP servers and most of the API, under the scope rules for API keys, applied to the scopes the organization approved. A few routes belong to the system that runs an integration and take an API key only (webhook subscriptions, the delivery log, disconnecting an app, and pushing vehicle data): they answer a token 401, "This endpoint accepts API keys only; app and agent tokens are not accepted here". The list is in Keys and tokens.

A token stops working at once when the connection is revoked, when the person it acts for leaves the organization, or when the agent is switched off.

What agents may not do

An agent works under the app's rules with a fleet manager's authority, and some decisions are never its own: accepting or countering below the floor, setting the floor, emailing a contact, sending a campaign, approving a quarter, confirming that money arrived, and switching an automation back on. Each answers 403 PEOPLE_ONLY (on Cypress Operate, a decision with a link for a person). An agent never signs a document, accepts terms, changes billing or manages the team; those endpoints do not accept agent tokens at all. Area by area, with what the agent is told: What an agent can and cannot do.

Disconnecting

The organization's admin disconnects your app in Settings › Connected apps. An integration of the organization can do it too, with an API key holding connections:write: DELETE /api/v1/connections/{id}. Either way every token ends at once and every agent your app added is switched off. Its actions stay in the organization's activity log.

Sign in with Cypress

To know who is using your app, call GET /api/oauth/userinfo with the app's token:

{
  "sub": "…",
  "kind": "PERSON",
  "name": "Ana Ruiz",
  "email": "ana@fleet.example",
  "role": "ADMIN",
  "organization": { "id": "…", "name": "Fox Fleet" },
  "scope": "offers:write webhooks"
}

With an agent's token it answers kind: AGENT, the agent's name and its organization, and no address.

For a full OpenID Connect sign-in, where your app signs people in with their Cypress login and receives an ID token, ask Cypress to register your app with Cypress's identity provider as well. That registration is separate from the one above.