> ## Documentation Index
> Fetch the complete documentation index at: https://getfloo.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# App API keys and request history

> Give a program access to selected app routes, inspect its requests, and revoke its key.

Give a program an app API key to call selected routes while the browser UI stays behind sign-in.

App keys grant no floo administration access. They belong to one app, not to a
workspace or environment. The same key can work in dev and production wherever
that app's deployed route policy accepts its scopes.

## Declare the API path

For a multi-service app, add these entries to `floo.app.toml`. This example assumes
your declared services are named `web` and `api`, both with public ingress.

```toml theme={null}
[[routes]]
path = "/"
service = "web"
access = "accounts"

[[routes]]
path = "/api"
service = "api"
access = "accounts"

[[routes]]
path = "/integrations/v1"
service = "api"
access = "api_key"
scope = "reports.access"
```

The API service must implement `/integrations/v1` and its endpoints. floo forwards
the full path unchanged. For a fixture in a FastAPI service:

```python theme={null}
@app.get("/integrations/v1/status")
def integration_status():
    return {"ok": True}
```

Commit and push the declaration. A new app can establish this policy on its
first deploy; wait for that deploy to be LIVE. For an existing protected dev app, adding machine access broadens the allowed callers and the
deployment guard requires floo org-admin authority. After pushing, an org admin
or their authorized agent can run `floo redeploy --app <name> --rebuild` with an
admin-scoped floo credential. This reads the current GitHub default-branch HEAD
and applies the access change without dashboard approval. Any separately
configured infrastructure-review policy still applies. Rebuilding dev does not
apply a production broadening; release and promote currently reject that transition.

Explicit multi-service routes replace the default path table on the app host,
service aliases, and verified custom domains. See [Multi-service routing](/docs/guides/multi-service-routing).

## Create a consumer and a scoped key

Create a named consumer and a key scoped to the declared route:

```bash theme={null}
floo apps consumers create daily-report
floo apps keys create daily-report --consumer daily-report --scope reports.access --rate-limit-rpm 60
```

These commands use the app in your local config. Pass `--app <name>` to select
another app. `--consumer` accepts an ID or a case-insensitive name. The CLI uses
your floo operator credential; keep it separate from the app key you give the program.

Human mode prints only the **one-time raw key** on stdout. The shown-once notice,
key ID, prefix, and scopes go to stderr. Store the raw value directly in the
program's secret store. It cannot be retrieved again. Do not paste it into a
chat or prompt, print it in logs, or put it in a URL or repository. Keep the
key ID for request-history queries and revocation.

To store a new key in another floo app without displaying it in the terminal
or an agent transcript, pipe it directly to the environment command. Replace
`report-worker` with the app that will call the API:

```bash theme={null}
floo apps keys create reader --consumer daily-report --scope reports.access | floo env set REPORTS_KEY --stdin --app report-worker
```

With `--json`, `raw_key` is redacted unless you pass the global
`--reveal-secrets` flag. The output sets `contains_secrets: true` in either case.

Always set scopes explicitly: `--scope` is required and repeatable. Use
`--scope '*'` only to grant every scope. Scopes are exact-match labels, not
HTTP-method permissions: GET and POST under the same scoped route use the
same gate. Your application still owns operation and record-level permissions.

List consumers and key metadata without redisclosing the key:

```bash theme={null}
floo apps consumers list
floo apps keys list --consumer daily-report
```

## Call the app

Have the program send the app key in its `Authorization: Bearer` header to the
app's public URL, for example `/integrations/v1/status`. Use no browser cookie.

The fixture returns `{"ok": true}` with status 200. Missing, malformed, revoked,
and wrong-app keys return 401. A valid key without the required scope returns
403; a per-key rate-limit rejection returns 429. floo strips the raw key before
forwarding the request and supplies verified consumer identity headers instead.
Sending an app key to the `/` browser route does not sign the caller in.

## Inspect requests by key

Use the operator credential, not the app key:

```http theme={null}
GET /v1/apps/{app_id}/requests?api_key_id={key_id}&since=1h&limit=100
```

Each row includes the timestamp, key ID, routed host, HTTP method, path, status,
and latency. To page through results, pass the returned `next_cursor` as `cursor`
and keep the same filters. `total` counts this page, not all matching requests.
The maximum page size is 500.

For a fixed interval, use timezone-aware ISO 8601 `since` and `until` values;
`until` is exclusive. URL-encode query values. The `host` filter distinguishes
app hostnames and environments. An expired or invalid cursor returns
`REQUESTS_QUERY_ERROR`; restart the query with the intended time range.

Verified keys remain attributable on scope and per-key rate-limit failures.
Unknown or invalid credentials are not assigned a key identity. Request bodies,
authorization headers, cookies, and query strings are not part of this history.

History is asynchronously buffered and retained for about seven days. Allow
time for a request to appear. Buffer overflow or a process crash can lose
events. This is request visibility, not a lossless business-change audit log.

## Revoke access

Revoke a key by its ID:

```bash theme={null}
floo apps keys revoke KEY_ID
```

Revocation is idempotent: revoking an already-revoked key succeeds.
Revocation is published to gateway instances; the validation cache limits
propagation to 30 seconds if that signal is missed. Retry the fixture after
that window and confirm it returns 401. Creation and revocation use floo's
existing key lifecycle audit.

Delete a consumer to revoke all its active keys:

```bash theme={null}
floo apps consumers delete daily-report
```

Deletion requires typed confirmation. In non-interactive or JSON mode, pass
the explicit confirmation flag:

```bash theme={null}
floo apps consumers delete daily-report --yes-i-know-this-destroys-data
```

Next, use [Logs and debugging](/docs/guides/logs) to investigate application errors
behind a failed request.

## HTTP reference

Use the management API at `https://api.getfloo.com` with your authorized floo
operator credential. Keep that credential separate from the app key you give
the program. Substitute your app and record IDs in these routes.

Create a named consumer:

```http theme={null}
POST /v1/apps/{app_id}/consumers
Content-Type: application/json

{"name": "daily-report"}
```

Use the returned consumer `id` to create its key:

```http theme={null}
POST /v1/apps/{app_id}/consumers/{consumer_id}/keys
Content-Type: application/json

{"name": "daily-report", "scopes": ["reports.access"], "rate_limit_rpm": 60}
```

The response contains a non-secret key `id` and a one-time `raw_key`. Always
set `scopes` explicitly in HTTP requests; omitting them grants the wildcard default.

Inventory endpoints return metadata without redisclosing the key:

```http theme={null}
GET /v1/apps/{app_id}/consumers
GET /v1/apps/{app_id}/consumers/{consumer_id}/keys
```

Revoke a key:

```http theme={null}
DELETE /v1/apps/{app_id}/api-keys/{key_id}
```

A successful response is 204, including when the key was already revoked.

Delete a consumer and revoke all its active keys:

```http theme={null}
DELETE /v1/apps/{app_id}/consumers/{consumer_id}
```
