Skip to content

Postman Collection Guide

The Contio User API includes a Postman collection with a fully scripted OAuth 2.1 + PKCE flow that lets you test the API without writing any code — and without a browser round-trip. You log in with an email one-time code, and the collection handles PKCE, authorization, and token exchange for you.

Getting the Collection

Download the Postman collection from the OpenAPI page, or import it directly:

  1. Open Postman
  2. Click Import → Link
  3. Enter: https://docs.contio.ai/user-api/openapi/user_postman_collection.json

Key Differences from Partner API

The User API uses OAuth 2.1 with PKCE instead of the Partner API's OAuth 2.0 flow:

Feature User API Partner API
Flow type Authorization Code + PKCE Authorization Code + OTP
Client secret Not required Required
Authentication Email OTP (scripted, no browser) Email OTP
Consent screen None (first-party auto-approve) N/A
Redirect URI Loopback only (127.0.0.1/localhost) Any registered URI
Token prefix cto_at_v1_ / cto_rt_v1_ Standard JWT
Refresh tokens Rotating (new token each refresh), valid 30 days Non-rotating

Setting Up Variables

The collection comes pre-configured with sensible defaults. In most cases, you only need to set user_email to the account you want tokens for:

Variable Default Description
user_email (empty) Set this. Email of the Contio account to log in as
oauth_scopes meetings:read meetings:write action-items:read action-items:write calendar:read calendar:write canvases:read canvases:write Space-separated scopes to request (defaults to every scope first-party OAuth can issue)
client_id YOUR_CLIENT_ID First-party OAuth client ID. Replace with the client ID issued for your first-party application.
redirect_uri http://127.0.0.1:53123/callback Loopback redirect URI — never actually visited, but must be a valid loopback address
baseUrl https://api.contio.ai Base URL for all requests (change for dev/stage)
otp_code (empty) The 6-digit code from your login email (set during the flow)

The following variables are captured automatically as you run the flow; you normally don't touch them: otp_session, session_jwt, oauth_token, refresh_token, code_verifier, code_challenge, oauth_state, authorization_code.

To modify variables:

  1. Click on the collection name
  2. Go to the Variables tab
  3. Edit the Current Value column as needed
  4. Click Save

About the client_id

The User API uses first-party OAuth — a flow designed for Contio's own applications (desktop app, CLI tools, etc.) to obtain tokens on behalf of a signed-in user.

Set client_id to the client ID issued for your first-party application. If you do not have a first-party client ID, use a Personal Access Token instead — set oauth_token to your PAT and skip the OAuth flow entirely.

How authentication works

  • The collection logs you in for you. Steps 1-2 send an email one-time code and exchange it for a session — you only need to paste the 6-digit code from your inbox.
  • No consent screen. First-party OAuth auto-approves for the signed-in user, so the authorize step returns the code immediately (no browser).
  • The account must already exist. The email in user_email must belong to a Contio account. If not, sign up in the web app first.
  • Loopback redirect URI. redirect_uri must be http://127.0.0.1:PORT or http://localhost:PORT. It is never actually visited — the code is read from the redirect header.

If the OAuth flow doesn't work for your use case, use a Personal Access Token instead — set oauth_token to your PAT and skip the flow entirely.

Available Scopes

Scope Description
meetings:read Read meetings, participants, agenda items, context
meetings:write Create/update/delete meetings and related resources
action-items:read Read action items
action-items:write Create/update/delete action items
calendar:read Read calendar events
calendar:write Link meetings to calendar events and create meetings from events
canvases:read List, search and read canvases and their content
canvases:write Create, update, delete canvases and replace their content

The workspace scopes (workspace:read, workspace:write) cannot be requested through this OAuth flow; the authorize step rejects them. To call the Workspace endpoints, set oauth_token to a workspace API key instead.

Running the OAuth 2.1 + PKCE Flow

The collection includes a 🔐 OAuth 2.1 + PKCE Flow (Run in Order) folder with requests that walk you through the complete OAuth flow. Run them top to bottom.

Watch the Postman Console

Open the console (View → Show Postman Console) before you start. Every step logs what it captured and what to do next.

Step 1: Log In — Send OTP

Request: 1. Log In — Send OTP

Sends a 6-digit one-time code to user_email and starts a login session.

  • Before you run it: Set the user_email variable to your Contio account email
  • What happens: An OTP email is sent; the login session is captured into otp_session
  • Auto-captured: otp_session
  • If you get 404: That email has no Contio account — sign up in the web app first

Step 2: Log In — Verify OTP

Request: 2. Log In — Verify OTP

Verifies the code and completes login.

  • Before you run it: Set otp_code to the 6-digit code from your email
  • What happens: Returns your session JWT
  • Auto-captured: session_jwt (used as the Bearer token for the authorize step)

Already signed in?

If you already have a session JWT, set session_jwt directly and skip steps 1-2.

Step 3: Generate PKCE Parameters

Request: 3. Generate PKCE Parameters

Fetches the OIDC discovery document and generates the required PKCE parameters.

  • What happens:
  • Fetches the OpenID Connect discovery document
  • Generates a cryptographically secure code_verifier
  • Computes the S256 code_challenge
  • Generates a random state for CSRF protection
  • Auto-captured: code_verifier, code_challenge, oauth_state

Step 4: Authorize

Request: 4. Authorize (auto-captures code)

Calls /v1/oauth/authorize with your session JWT. Because first-party OAuth auto-approves, there is no consent screen — the endpoint returns a 302 redirect and the collection reads the authorization code straight from the Location header.

  • What happens:
  • Automatic redirect following is disabled so the 302 can be inspected
  • The code is captured into authorization_code
  • The returned state is verified against oauth_state
  • Auto-captured: authorization_code
  • If you get 401: Your session_jwt is missing or expired — re-run steps 1-2

Authorization codes expire quickly

Authorization codes typically expire within 10 minutes. Run the token exchange promptly.

Step 5: Exchange Token

Request: 5. Exchange Token (get access token)

Exchanges the authorization code + PKCE verifier for tokens.

  • What happens: Tokens are returned (no client secret needed!)
  • Auto-captured: oauth_token, refresh_token

OAuth flow complete!

After this step, you have valid tokens. The oauth_token variable is automatically used for all User API requests.

Step 6: Test API Call

Request: 6. Test API Call (verify token works)

Makes a sample API call to verify the token works.

  • What it does: Fetches your recent meetings
  • Expected result: 200 OK with meeting data (or empty array)

Step 7: Refresh Token (Optional)

Request: 7. Refresh Token (optional)

Use this to get a new access token when the current one expires.

  • When to use: Access tokens expire after 1 hour
  • Important: Refresh tokens rotate — each refresh returns a NEW refresh token and invalidates the old one
  • Lifetime: Refresh tokens are valid for 30 days, and each rotation resets that window — refreshing at least once every 30 days keeps the session alive
  • Auto-captured: New oauth_token and refresh_token

Step 8: Revoke Token (Optional)

Request: 8. Revoke Token (optional)

Revokes a token and its rotation chain.

  • What it does: Invalidates the specified token
  • Auth: Sends your session_jwt (this endpoint requires an authenticated user session)
  • Note: Always returns 200 per RFC 7009, even for unknown tokens

Using Personal Access Tokens (PAT)

For automation or when you don't want to use the OAuth flow, you can use a Personal Access Token:

  1. Generate a PAT from the Contio web app (Settings → API Tokens)
  2. In Postman, set the oauth_token variable to your PAT value
  3. Skip the OAuth flow and use any API endpoint directly

PATs are prefixed with cto_pat_v1_ and expire after a fixed period chosen at creation (30, 60, 90, 180, or 365 days), or when revoked.

See Personal Access Tokens for more details.

Troubleshooting

404 "Email not found" on Send OTP

The user_email has no Contio account. Sign up in the web app first, then re-run Step 1.

401 on Verify OTP

The code was wrong or expired. Re-run Step 1 to get a fresh code, then Verify with the new otp_code.

401 (no Location header) on Authorize

Your session_jwt is missing or expired. Re-run Steps 1-2 to log in again, then Step 3 and Step 4.

"Missing token parameter"

The oauth_token variable is empty. Run the OAuth flow first, or set a PAT.

"invalid_grant" on token exchange

  • The authorization code may have expired (codes expire quickly)
  • The PKCE verifier doesn't match the challenge
  • The redirect_uri doesn't match what was used in the authorize request

Solution: Re-run Steps 3-5 (generate fresh PKCE, authorize, exchange).

"invalid_request" on authorize

  • Check that redirect_uri is a loopback address (http://127.0.0.1:PORT or http://localhost:PORT)
  • Ensure you ran Step 3 first so code_challenge and oauth_state are populated
  • Verify response_type is code

"insufficient_scope"

The token doesn't have the required scopes. This usually means:

  • The requested scopes in oauth_scopes don't include what the endpoint needs
  • The user didn't approve all requested scopes

Solution: Re-run the OAuth flow with the correct scopes.

"401 Unauthorized" on API calls

  • The access token may have expired (1 hour lifetime)
  • Use the Refresh Token request to get a new access token
  • Or re-run the full OAuth flow

Tips

  • Run requests in order — Each step depends on the previous one
  • Check the Console — Postman logs helpful messages (View → Show Postman Console)
  • No browser needed — Login and authorization are fully scripted; you only paste the emailed OTP code
  • Variables are auto-saved — Tokens and codes are captured automatically by test scripts
  • Reuse your session — Steps 3-5 can be re-run without logging in again, as long as session_jwt is still valid
  • Use environments — Create separate environments for dev/staging/production (update baseUrl)
  • No client secret — PKCE replaces the need for a client secret

Optional Parameters and Request Bodies

Requests ship ready to send without leaving placeholder values in the request:

  • Optional query parameters and headers are disabled. For example, q, limit and offset on List or search canvases, and Idempotency-Key on create requests. Tick the checkbox next to a parameter or header and set its value to send it. Required parameters (such as start_date/end_date on List calendar events) stay enabled.
  • Example bodies include only required fields and enum examples. Optional fields such as template_id, due_date or is_instant are left out. Add any field you need from the API reference. Replace the remaining <string> placeholders before sending. A request whose fields are all optional, such as Update workspace settings, ships with an empty {} body. Add the fields you want to change, because the API rejects an update with no fields (400).

API Endpoints Overview

The collection includes all User API endpoints organized by category:

Category Endpoints Required Scope
OAuth 2.1 + PKCE Flow Log In (Send OTP, Verify OTP), Generate PKCE Parameters, Authorize, Exchange Token, Test API Call, Refresh Token, Revoke Token None to log in; session JWT to authorize and revoke; the test call needs meetings:read
Action Items List, Get, Create, Update, Delete action-items:read / action-items:write
Agenda Items List, Get, Create, Update, Delete meetings:read / meetings:write
Auth Introspect token (/v1/auth/introspect) (any valid token)
Backlog Items List, Get, History, Create, Update, Delete, Assign to Meeting meetings:read / meetings:write
Calendar List Events, Get Event / Create Meeting from Event calendar:read / calendar:write
Canvases List/Search, Get, Get Content / Create, Update, Delete, Replace Content canvases:read / canvases:write
Me Get Current User (/v1/me) (any valid token)
Meeting Templates List meetings:read
Meetings List, Search, Upcoming, Get / Create, Update, Delete meetings:read / meetings:write
Meeting Attachments List, Get, Download / Upload, Delete meetings:read / meetings:write
Meeting Calendar Link Link, Unlink meetings:write or calendar:write
Meeting Contacts List meetings:write
Meeting Context List, Get, Download / Upload, Delete meetings:read / meetings:write
Meeting Participants List / Add, Remove, Update Role meetings:read / meetings:write
Meeting Transcript Export meetings:read
OAuth Discovery (OIDC, Authorization Server Metadata), JWKS, Token Exchange None
OAuth Authorize, Consent Decision, Revoke Session JWT
OAuth Client Registration Register / Read, Update, Delete Registered Client None to register; registration access token to manage
User Tokens List, Delete (any valid token)
User Events (SSE) Stream workspace events Any of meetings:read, action-items:read, calendar:read, workspace:read
Workspace Get, List Members / Update, Update Member Role, Remove Member workspace:read / workspace:write (admin or owner)
Workspace API Keys List, Delete workspace:write (admin or owner)
Workspace Webhooks List, Create, Delete, Rotate Secret, Re-enable, Re-send Verification workspace:write

Next Steps