factqlDocs
Get an API key
Get started

Authentication

Every request carries your API key in the X-API-Keyheader. Keys don't expire; they work until you revoke them.

curl "https://api.factql.ai/whoami" -H "X-API-Key: $FACTQL_API_KEY"

Your keys

  • Keys start with fl_live_ or fl_test_. The prefix is a label only; both reach the same data and count towards the same usage.
  • The full key is shown once. FactQL stores only a hash, so a lost key can't be recovered: revoke it and create a new one under API keys in the app.
  • The key from signup is bound to one tenant and one workspace. On any other tenant it gets 403.
Call FactQL from your server with a full-access key. A key in browser or mobile code can be read by anyone who uses your app; if your app must call FactQL directly, use an ask-only key.

Full-access and ask-only keys

Choose the access when you create a key under API keys in the app, or send "scope": "query" when creating one through POST /accounts/api-keys. The new key comes back once, in api_key (the same field signup uses); raw_key carries the same value for older integrations. A key created with a workspace-bound key is bound to the same workspace.

Full accessAsk only
Use it fromYour serverA browser or mobile app
Ask and stream answersYesYes
Chats, result pages, CSV exportYesYes, for the end user in X-End-User-Id
Upload or delete files, change settingsYesNo (403)
Manage keys, tenants and webhooksYesNo (403)
X-End-User-IdOptionalRequired on every call except /query and /whoami

Access limits what a key can do; the workspace it belongs to limits which data it reaches. Create a browser key on the API keys page of the workspace your app uses, so it can't reach your other workspaces. An ask-only key still spends your account's usage, and anyone who copies it can send any X-End-User-Id. Keep full-access keys on your server, and revoke an ask-only key if it is misused. GET /whoami reports a key's scope.

Calling FactQL from a browser

Browsers only let a page call another site's API when that API allows the page's origin (CORS). Calls from your server aren't affected, so the simplest setup is to proxy questions through your own backend with a full-access key. To call FactQL straight from your web app, list the app's websites on its ask-only key.

  1. Create an ask-only key with Allowed websites under API keys in the app, or send them when creating the key:
curl -X POST "https://api.factql.ai/accounts/api-keys" \
  -H "X-API-Key: $FACTQL_API_KEY" -H "Content-Type: application/json" \
  -d '{"name": "Web app", "scope": "query",
       "allowed_origins": ["https://app.example.com", "http://localhost:3000"]}'
  1. Use that key from those websites, with X-End-User-Id on every call. Change the list any time with PATCH /accounts/api-keys/{key_id} and {"allowed_origins": [...]}; an empty list removes the restriction. Changes can take up to a minute to reach every server.
Allowed websites
formstring
Scheme and host, with a port if it isn't the default: https://app.example.com, https://app.example.com:8443. No paths or wildcards.
httpsrule
Required, except http://localhost and http://127.0.0.1 for development.
limitrule
Up to 10 websites per key, ask-only keys only.

A browser call with that key from any other website gets 403, so another site can't reuse your key from a browser. Allowing a website never replaces the key: anyone who copies an ask-only key can still call the API from a script, which is why it can only ask questions. Calls from FactQL's own sites, such as the Try it panels here, are always accepted.

Check a key

GET /whoami returns what a key is and where it points, so you never have to copy IDs out of the app.

curl "https://api.factql.ai/whoami" -H "X-API-Key: $FACTQL_API_KEY"
Response fields
keyobject
The key's prefix, name and environment. Never the key itself.
accountobject
Account type and plan.
client_idstring | null
The tenant the key is bound to. Null for an account-level key, which lists tenants instead.
workspace_idstring | null
The workspace the key is bound to. When null, workspaces lists the tenant's workspaces.
plan_limitsobject | null
The free plan's limits, or null on other plans.
sampleboolean
True for the public sample-data key.
Errors
401The header is missing, or the key is invalid or revoked (Invalid or revoked API key).

One key, many people

A key belongs to your account, not to a person. When your app serves many people, send X-End-User-Id with a stable id for the person asking, so each gets their own conversations. See Serving many users.

Sample data

The Try it panels can use a public, read-only key for a demo shop with customers, products and orders. It comes from GET /sample, which needs no key. The sample key:

  • can ask questions (POST /query, /ask, /ask/stream) and check schema status. Anything else gets 403.
  • needs X-End-User-Id on tenant routes. Try it sets a random id for your browser.
  • is limited per IP address: 5 requests a minute and 30 questions an hour, then 429 with Retry-After.