TurfAI Developer Docs

Authentication

JWT, API key prefixes, polling tokens, service keys, and Google OAuth2.

Choose the credential that matches who is calling and what they're calling. TurfAI uses a different credential for each kind of caller.

CredentialHeaderWho uses itScope
JWTAuthorization: Bearer <jwt>A logged-in user / your backendAll authenticated endpoints, owner-scoped
Polling tokenAuthorization: Bearer <token>External trigger callersOne execution's status, ~1 hour
Webhook secretX-Webhook-Secret: <secret>Whoever triggers a webhookTriggering that one webhook
Agent keyX-Agent-Key: <ak_…>Public agent chat clientsOne agent's public chat
Chatbot keyX-Chatbot-Key: <cb_…>Embedded widget / public chatOne chatbot's public chat
Service keyX-Service-Key: <key>Internal services onlyInternal endpoints (not for app developers)

JWT (user authentication)

Most endpoints require a user JWT. To get one, log in with your email and password:

curl -X POST https://apisandbox.turfai.in/api/auth/local \
  -H "Content-Type: application/json" \
  -d '{ "identifier": "[email protected]", "password": "yourpassword" }'
{
  "jwt": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "user": { "id": 1, "username": "user", "email": "[email protected]" }
}

Send it on every authenticated call:

curl https://apisandbox.turfai.in/api/agents \
  -H "Authorization: Bearer $TURFAI_JWT"

JWTs are owner-scoped: you only see and act on resources you own. Tokens are long-lived (default 30 days, configurable) and are blacklisted immediately on logout (POST /auth/logout).

Polling tokens

Triggering a webhook returns a polling_token — a short-lived JWT (~1 hour) that can only read that one execution's status. Use it as a Bearer token. It exists so an external caller can follow a run to completion without holding a full user JWT. Don't store it long-term.

curl https://apisandbox.turfai.in/api/workflow-executions/456 \
  -H "Authorization: Bearer $POLLING_TOKEN"

Webhook secrets

Each webhook has a 64-character hex secret_key (256 bits). The public trigger endpoint authenticates with it via the X-Webhook-Secret header — no JWT required, so external systems (forms, SaaS apps) can trigger workflows without TurfAI credentials. TurfAI returns the secret only on create and on POST /webhooks/:id/regenerate-secret, which invalidates the old one immediately. Validation is timing-safe.

API key prefixes

Public chat surfaces are protected by prefixed API keys rather than user JWTs, so you can embed them in clients without exposing a user account:

  • ak_ / agent key — sent as X-Agent-Key to POST /agents/:slug/public-chat.
  • cb_ / chatbot key — sent as X-Chatbot-Key to POST /chatbots/:slug/chat (48 hex chars).

Both keys are owner-bound: a public chat request runs under the resource owner's context (the owner's documents are searched, the owner's quota is charged). Rotate either key via its POST /…/:id/regenerate-key endpoint; rotation invalidates the previous key. Regenerating an agent key requires step-up verification (see below).

Treat agent and chatbot keys as public-client credentials, not secrets — anyone with the embed snippet can see them. Lock them down with allowed_origins and per-key rate limits (default 60 requests/minute), and rotate if abused.

Step-up authentication

Sensitive operations require a second factor on top of a valid JWT. Request an OTP, verify it, then retry the protected call with X-Step-Up-Verified: true:

# 1. Send a 6-digit code to the user's email
curl -X POST https://apisandbox.turfai.in/api/auth/step-up \
  -H "Authorization: Bearer $TURFAI_JWT"

# 2. Verify it (grants a step-up flag for ~5 minutes)
curl -X POST https://apisandbox.turfai.in/api/auth/step-up/verify \
  -H "Authorization: Bearer $TURFAI_JWT" \
  -H "Content-Type: application/json" \
  -d '{ "code": "123456" }'

Operations that require step-up include deleting a credential (DELETE /credentials/:id) and regenerating an agent key (POST /agents/:id/regenerate-key), sent with the X-Step-Up-Verified: true header.

Google OAuth2

TurfAI supports two distinct Google OAuth flows — don't confuse them:

  1. Sign in with Google — authenticate a user. The browser hits GET /api/connect/google, Google redirects back to GET /api/connect/google/callback, and TurfAI returns a normal user JWT. Use this for login/signup; you then call the rest of the API with that JWT.
  2. Delegated Google access — let a workflow act on a user's Drive/Gmail. Start with GET /google/oauth/authorize (returns an authUrl to redirect the user to), handle the callback, then check GET /google/oauth/status. Once connected, tasks like google_drive_fetch and Drive event sources can read the user's files. Revoke with POST /google/oauth/revoke. Requested scopes are limited to what the feature needs.

Credentials for integrations

For non-Google integrations (e.g. a third-party REST API your workflow calls), store secrets as credentials rather than hardcoding them. Fields are encrypted at rest (AES-256-GCM) and never returned by the API — list/get return metadata and field_names only. Reference them from rest_api tasks via {{variable}} templates. See the custom REST integration guide.

Error responses

Auth failures use the platform's standard error shape:

{ "error": "Unauthorized", "message": "Authentication required or invalid token" }

Common codes: 401 (missing/invalid credential), 403 (valid credential, no permission — e.g. an inactive webhook or a resource you don't own), 429 (rate limit; check retryAfter).

On this page