OAuth
Integrate your app
Add 'Sign in with Teamcast' using the authorization_code grant with mandatory PKCE.
POST /admin/oauth-clients), which issues a client_id (and a client_secret for confidential clients — public/browser clients get none and authenticate with PKCE alone).1. Generate a PKCE pair and redirect
Generate a random code_verifier, derive code_challenge = BASE64URL(SHA256(code_verifier)), and send the recruiter's browser to GET /oauth/authorize. Only S256 is accepted — plain is rejected.
GET https://devapi.teamcast.ai/api/v2/oauth/authorize
?response_type=code
&client_id=oauth_client_9f3a1c...
&redirect_uri=https://yourapp.example.com/callback
&scope=interview:read+interview:create
&state=8f14e45fceea167a5a36dedd4bea2543
&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
&code_challenge_method=S2562. Recruiter consents on tc-web
Teamcast validates the request, mints a short-lived signed pending-request token (PRT), and 302s the browser to tc-web's consent screen. If the recruiter isn't logged in, they authenticate first (return URL preserved); if they've already consented to these exact scopes for this client, the screen is skipped. Otherwise they see your client's name and the requested scopes, and choose Allow or Deny.
3. Receive the authorization code
On Allow, Teamcast redirects to your redirect_uri (exact-match against the registered value — no wildcards) with a single-use code.
https://yourapp.example.com/callback
?code=a1f9c2b7e6d4...
&state=8f14e45fceea167a5a36dedd4bea2543Verify state matches what you sent before continuing — this is your CSRF protection on the redirect.
4. Exchange the code for tokens
curl -X POST https://devapi.teamcast.ai/api/v2/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d grant_type=authorization_code \
-d client_id=oauth_client_9f3a1c... \
-d client_secret=oauth_secret_... \
-d code=a1f9c2b7e6d4... \
-d redirect_uri=https://yourapp.example.com/callback \
-d code_verifier=<the_original_code_verifier>
# → {
# "access_token": "eyJhbGciOiJSUzI1NiIs...",
# "token_type": "Bearer",
# "expires_in": 900,
# "scope": "interview:read interview:create",
# "refresh_token": "8f3a...c2"
# }Public clients (mobile/SPA, no client_secret) omit client_secret and rely entirely on code_verifier — the code is bound to the original challenge, so a stolen code is useless without it.
5. Call the API, then refresh
Use the access token as a normal bearer token against any endpoint your granted scopes cover (mapped 1:1 onto Teamcast permission keys, e.g. interview:create). When it expires, rotate it:
curl -X POST https://devapi.teamcast.ai/api/v2/oauth/token \
-d grant_type=refresh_token \
-d client_id=oauth_client_9f3a1c... \
-d client_secret=oauth_secret_... \
-d refresh_token=8f3a...c2invalid_grant on refresh as a signal to restart the authorization flow.