Authentication

Every request carries a bearer token. There are two ways to get one, and the API cannot tell them apart once it has one — both resolve to a workspace and a scope set, and every downstream query is scoped to that workspace.

Which credential to use

  • API keys — for your own scripts, back-office jobs and internal integrations, where there is no user to send through a browser.
  • OAuth 2.0 — for anything a third party distributes. The user clicks a button, signs in to Chirply, approves, and never handles a credential.

Scopes are read and write. A token never exceeds the permissions of the workspace member behind it: if a screen is manager-only, so is its operation.

API keys

Create one in the app under Developers. A key looks like chp_live_<32 hex> and is displayed exactly once, at creation time — Chirply stores only its SHA-256 hash for lookup, plus a short display prefix so you can tell keys apart in the UI. A key acts with owner-level access for its workspace: treat it like a password, keep it server-side, and rotate it from the same screen whenever you want (revocation is immediate).

curl
curl https://app.chirply.io/api/v1 \
  -H "Authorization: Bearer chp_live_…"

That endpoint is the whoami read: it returns the workspace the credential acts for and the scopes it holds. It is the cheapest way to verify a connection — the quickstart starts there.

OAuth 2.0

Standard authorization-code grant, with PKCE and refresh-token rotation. Register your client (name, logo, redirect URIs, scopes) with Chirply first; redirect URIs are matched exactly — no prefixes and no wildcards.

Authorize   GET  https://app.chirply.io/oauth/authorize
              ?client_id=…&redirect_uri=…&response_type=code
              &scope=read%20write&state=…
              &code_challenge=…&code_challenge_method=S256   (PKCE)
Token       POST https://app.chirply.io/api/v1/oauth/token
              grant_type=authorization_code
              &code=…&redirect_uri=…&client_id=…&client_secret=…
              &code_verifier=…                               (PKCE)
Refresh     POST https://app.chirply.io/api/v1/oauth/token
              grant_type=refresh_token&refresh_token=…

The consent screen

The user signs in to Chirply, sees who is asking and what they get, and picks one workspace per connection — the way Stripe and Slack do it. Only workspaces the user can administer are offered, because connecting an integration is a workspace-level decision. The redirect back to you carries the authorization code (short-lived, single-use) and your state.

The token endpoint

POST https://app.chirply.io/api/v1/oauth/token accepts form-encoded or JSON bodies, and client credentials either in the body or as HTTP Basic (RFC 6749 §2.3.1) — use whichever your OAuth library prefers. A successful exchange answers:

Response
{
  "access_token": "chp_at_…",
  "refresh_token": "chp_rt_…",
  "token_type": "bearer",
  "expires_in": 28800,
  "scope": "read write"
}
PropertyBehavior
access_tokenA bearer credential (chp_at_…) valid for 8 hours (expires_in: 28800). Send it exactly like an API key: Authorization: Bearer chp_at_….
refresh_tokenRotates on every refresh: the token you sent is retired and a new one (chp_rt_…) comes back in the same response. Store the new one every time.
PKCES256 is the supported challenge method. Public clients (mobile, CLI, single-page) use PKCE in place of a client secret; confidential clients are welcome to send both.
redirect_uriMust byte-for-byte match one you registered, on the authorize request and again on the code exchange.
errorsThis endpoint speaks RFC 6749: a flat { "error", "error_description" } object your OAuth library already understands — see Errors.

Connections and revocation

Each connection is one workspace. Users list and revoke their connections in the app under Developers; revoking a connection retires its tokens immediately. Access tokens hold the same authority as an API key for their scopes — and the same rule applies: they never exceed what the approving user can do.

Token hygiene

Token responses are served with Cache-Control: no-store — keep them out of caches and logs on your side too. Authorization codes are single-use; refresh tokens are single-use by rotation. If a refresh ever fails with invalid_grant, send the user back through the authorize step.