Skip to content
v1
Get an API key

Authentication

Every request that is not from a person in the Funnel One app carries a credential. Whatever the credential, one rule holds: it can never do more than the person accountable for it can do in that workspace.

Credential Looks like Acts as Use it for Status
API key amp_… The scopes ticked on the key Server-to-server REST calls Live
Service key f1_sk_… Its owner, narrowed to the key’s role and scopes Server-to-server REST calls Preview
OAuth access token f1_at_… The person who signed in Claude, ChatGPT, Cursor and other MCP clients Preview
Personal token f1_pat_… You Scripts and agent SDKs that cannot open a browser Coming soon
Connection secret f1x_… Another company’s agent, capped by its sponsor External agents Coming soon

The prefixes exist so a secret scanner can recognize a leaked credential. Funnel One stores every credential only as a hash, so it cannot show you one again after it is created.

In the preview, new API keys start with f1_sk_, every key has an owner (the person who created it), and an existing amp_ key keeps working.

Send it in the Authorization header as a bearer token, from a server:

Authorization: Bearer <credential>

Never in a query string, a form field or browser code. A credential in a URL ends up in logs, proxies and Referer headers.

A credential carries scopes, the same permission names the app’s roles use.

  • API key (live): the scopes ticked when the key was created. An admin creates keys in Settings, then Integrations, then API Keys.
  • Service key (preview): only admins create keys. A key can do what its owner’s role allows right now, narrowed to the key’s own role and scopes. If the owner’s role is narrowed, the key is narrowed on its next request. If the owner leaves the workspace, the key is suspended and stops working.
  • OAuth token (preview): what the person’s role allows right now, narrowed to what they allowed on the consent page. If they leave the workspace, everything they connected stops working.

Effective scopes are worked out again on every request, never at the moment the credential was issued. A request that lacks a scope is refused with 403, naming every missing scope at once. See forbidden_scope.

A credential belongs to exactly one workspace. The workspace comes from the credential itself, never from anything in the request.

Funnel One is its own OAuth 2.1 authorization server, on the same host as the MCP server. An MCP client sets itself up from the server’s replies, so the person only pastes one URL.

  1. The client calls https://app.funnelone.ai/mcp without a token and gets 401 with a WWW-Authenticate header that points at /.well-known/oauth-protected-resource/mcp.
  2. From there it reads the authorization server’s metadata at /.well-known/oauth-authorization-server.
  3. It identifies itself, either with a client metadata document (a URL it hosts) or by registering at /oauth/register. Registered clients are public clients: there is no client secret. A registered client has no access to anything until a person consents.
  4. It opens /oauth/authorize in the person’s browser, with PKCE (S256 only) and resource=https://app.funnelone.ai/mcp.
  5. The person signs in and sees the consent page (below).
  6. The client exchanges the code at /oauth/token, sending application/x-www-form-urlencoded, and receives tokens.
  7. It calls /mcp with Authorization: Bearer f1_at_….
  • the app that is asking, labeled Unverified unless Funnel One recognizes it (Claude, Claude Code, ChatGPT and Cursor’s web sign-in are recognized);
  • where the app will be sent back to, marked Loopback when that is your own computer (localhost);
  • a workspace picker when you belong to more than one: a sign-in grants access to one workspace only;
  • each permission the app asked for, grouped by area. Anything your role does not include is shown as unavailable and cannot be granted.
Token Lifetime
Authorization code f1_code_… 60 seconds, used once
Access token f1_at_… 1 hour
Refresh token f1_rt_… Replaced on every use; expires after 30 days unused, or 90 days in all

A refresh token works once. Presenting one that was already used revokes the whole sign-in, because that is what a stolen token looks like. A client can revoke its own tokens at /oauth/revoke.

A token is bound to the resource it was issued for. A token for https://app.funnelone.ai/mcp is refused by the REST API at https://app.funnelone.ai/api/v1, and the reverse.