# Authentication

The public API is served from `https://api.flownally.com/v1` and uses bearer API keys for server-to-server integrations.

Flownally keeps customer communication flowing across WhatsApp, Messenger, and Instagram. API credentials are for backend systems that support that flow: contact imports, inbox synchronization, reporting, and automation setup. Keep the signed-in app session separate from programmatic API access.

```bash
export FLOWNALLY_API_BASE_URL="https://api.flownally.com/v1"
export FLOWNALLY_API_TOKEN="fln_live_replace_with_secret_value"
```

## Bearer tokens

Send the token in the `Authorization` header on every request. Include `Accept: application/json`, and send `Content-Type: application/json` whenever the request has a JSON body.

- Use `Authorization: Bearer $FLOWNALLY_API_TOKEN`.
- Keep tokens out of browsers, client-side bundles, logs, screenshots, and tickets.
- Use separate credentials for development, staging, and production tenants.

```bash
curl -G "$FLOWNALLY_API_BASE_URL/contacts" \
  -H "Authorization: Bearer $FLOWNALLY_API_TOKEN" \
  -H "Accept: application/json"
```

## Service accounts

Service accounts represent backend systems, automations, and other machine actors that need stable API credentials. Use a service account when an integration needs to act without a signed-in person.

Good service-account use cases include CRM sync jobs, reporting pipelines, internal tools, channel setup automation, and workers that prepare data used by the Flownally inbox.

Human operators should use their own Flownally user accounts in the app. Service accounts should represent software, and each API key should belong to one clear job.

Give each service account a name that describes the system and environment:

- `production-crm-sync`
- `staging-reporting-export`
- `support-tools-contact-import`

Avoid names like `backend`, `api`, or `test` in production. Clear names make it easier to audit access when communication workflows grow across teams.

## API keys

A service account is the identity. An API key is the bearer credential. Create the service account first, then [create an API key](/reference/api-keys#create-api-key) for the system that needs to act as that account.

API keys are backend-only secrets. Treat the plaintext key carefully because it is shown once. Use this model for integrations that keep Flownally in sync with the rest of your customer operations: importing contacts, updating tags, reading inbox data, or connecting internal tools to journeys and chatbots.

Key handling rules:

- Use one API key per backend service or automation.
- Use separate keys for development, staging, and production.
- Store keys in a secret manager, not in source code or browser storage.
- Never send API keys to client-side applications.
- Record the service, owner, and rotation schedule outside Flownally so your team knows what each key controls.

Copy the plaintext key directly into your secret manager. Avoid pasting it into tickets, chat messages, screenshots, or logs.

```bash
export FLOWNALLY_API_TOKEN="fln_live_replace_with_secret_value"
```

Use the token as a bearer credential when calling the API.

```bash
curl -X POST "$FLOWNALLY_API_BASE_URL/service-accounts" \
  -H "Authorization: Bearer $FLOWNALLY_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "production-crm-sync"
  }'

curl -X POST "$FLOWNALLY_API_BASE_URL/service-accounts/$SERVICE_ACCOUNT_ID/api-keys" \
  -H "Authorization: Bearer $FLOWNALLY_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "sync-worker"
  }'
```

## Rotate safely

Create a replacement key before revoking the old one. Deploy the new secret, verify that the job can still reach the API, then revoke the previous key.

Recommended rotation flow:

1. Create a new API key on the same service account.
2. Update the secret in your runtime environment.
3. Restart or redeploy the job that uses the secret.
4. Confirm successful API calls.
5. Revoke the old key.

Use [revoke API key](/reference/api-keys#revoke-api-key) immediately when a key is leaked, unused, owned by a decommissioned service, or no longer tied to a clear business purpose.

## Least privilege in practice

The OpenAPI reference describes which endpoints require bearer authentication. Use the narrowest operational design even when a credential can reach multiple endpoints:

- Give each backend job its own key.
- Keep development and production credentials separate.
- Do not share one key across unrelated systems.
- Remove credentials for retired automations.

This keeps customer communication infrastructure easier to reason about. If one job fails or leaks a key, you can rotate that job without interrupting every integration.

## Keep app sessions in the browser

People sign in to the Flownally app to manage conversations, channels, journeys, chatbots, billing, and settings. Do not copy app cookies into scripts or backend jobs. If an integration needs to run without a person present, create a service account and use a bearer token.

## Scopes and roles

API keys authenticate the caller. Each operation also documents the permission scopes it requires and the workspace roles that usually receive those permissions.

Use operation-level authorization details when choosing which service account should own an integration. A contact sync job should use endpoints with contact scopes. A webhook setup job should use the Webhooks endpoints and their webhook scopes.

On each endpoint page:

- Authentication names the credential scheme, usually `bearerAuth`.
- Required scopes list the permissions the request must satisfy.
- Allowed roles show which workspace roles grant those permissions.

Treat scopes as endpoint requirements, not as text to place in the bearer token. Send the API key as the bearer token and use `403` responses to detect credentials that are valid but not allowed to perform the requested action.

## Webhook signatures

Webhook receiver endpoints use [Standard Webhooks](https://www.standardwebhooks.com/) signatures instead of bearer tokens. Flownally sends `webhook-id`, `webhook-timestamp`, and `webhook-signature` headers with each delivery.

Verify the signature against the exact raw request body before processing the event. Use `webhook-id` as the dedupe key, and reject stale `webhook-timestamp` values to limit replay.

## Tenant scope and failures

Credentials are scoped to the authenticated tenant and user context. A missing, malformed, expired, or revoked token returns `401`. A valid credential without permission for the requested action returns `403`.

Use these responses to separate authentication problems from permission problems:

- `401` means the request did not prove who it is. Check the token value, header format, and environment secret.
- `403` means the credential is valid but does not have the required permission scope or role for that action in the current tenant.
- `404` can mean the object does not exist or is not visible to the credential.
