TurfAITurfAI Developers

Authentication

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

TurfAI uses different credentials for different callers. Pick the one that matches who is calling and what they're calling.

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: <ag_…>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. Obtain one by logging in with email and password:

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

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. The secret is returned 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:

  • ag_ / 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