*Overview › Get started*

# Quickstart

> Create an API key in the API and MCP section of the Filmo settings, then call `GET /api/v1/account`. The response tells you the timezone, currency, add-ons and scopes to build with.

## Requirements

- A Filmo account whose environment has the API and MCP switched on by Filmo; an administrator of the account cannot switch it on. The API and MCP are included in any paid plan and are not an add-on, and a free trial (14 days, no card) can create keys too.
- An administrator of the account to create the key. If that is not you, read the next section first.
- The add-ons for the resources you plan to use. A free trial unlocks all of them, and when it ends the endpoints behind an add-on answer 402 [`addon_required`](https://docs.filmo.io/rest-api/errors/addon_required).
- For the examples: cURL, Windows PowerShell 5.1 or later, Node 22 or later, or Python 3 with `requests`.

The base URL is `https://app.filmo.io/api/v1`. [Plans and add-ons](https://docs.filmo.io/concepts/plans-and-add-ons) explains what each add-on opens.

## Not an admin?

Only an administrator can create a key, and the key acts as that person ([Permissions](https://docs.filmo.io/concepts/permissions)). Ask an administrator for a key and tell them:

- The exact scopes your integration needs. Always include [`account:read`](https://docs.filmo.io/rest-api/guides/scopes#account:read): the first call needs it, and without it you get 403 [`insufficient_scope`](https://docs.filmo.io/rest-api/errors/insufficient_scope).
- To name the key after the integration, so it can be found and revoked later.
- To send you the key through a shared secrets manager, never by email or chat. It is shown once and gives programmatic access to the company's data.

Who owns a key and what happens when that person leaves is explained in [Authentication](https://docs.filmo.io/rest-api/guides/authentication).

## Create a key

1. **Open the API and MCP settings** In the Filmo app, as an administrator, open the section of the settings for the API and MCP. In the Spanish interface it reads Ajustes → API y MCP.
2. **Add a key** Give it a name that says what it is for and choose its scopes. Include [`account:read`](https://docs.filmo.io/rest-api/guides/scopes#account:read), and add only what the integration needs. Set an expiry date if the form offers one and you rotate keys on a schedule; a key without a date never expires.
3. **Copy the key now** The key starts with `fk_live_` and is shown only once; Filmo keeps only a hash of it. Store it in a secrets manager or an environment variable, not in your code or your repository.

For the same steps without the API vocabulary, see [Generate an API key](https://www.filmo.io/help/reference/integrations-and-api/create-an-api-key) in the help center.

## Make the first call

Set the key in an environment variable and call [`GET /api/v1/account`](https://docs.filmo.io/rest-api/endpoint-reference/account/get-the-account). The examples read `FILMO_API_KEY` and, if set, `FILMO_BASE_URL`; the default base URL is `https://app.filmo.io`.

*GET /api/v1/account*

**cURL**

```bash
# Paste the key when asked; it stays out of your shell history. Works in bash and zsh.
printf 'Filmo API key: '; stty -echo; read -r FILMO_API_KEY; stty echo; echo; export FILMO_API_KEY

FILMO_BASE_URL="${FILMO_BASE_URL:-https://app.filmo.io}"

curl -sS "$FILMO_BASE_URL/api/v1/account" \
  -H "Authorization: Bearer $FILMO_API_KEY" \
  -H "Accept-Language: en-US"
```

**PowerShell**

```text
# Windows PowerShell 5.1 and PowerShell 7. Paste the key when asked.
$secure = Read-Host "Filmo API key" -AsSecureString
$env:FILMO_API_KEY = [System.Net.NetworkCredential]::new("", $secure).Password
$base = if ($env:FILMO_BASE_URL) { $env:FILMO_BASE_URL } else { "https://app.filmo.io" }

try {
  $response = Invoke-RestMethod -Uri "$base/api/v1/account" `
    -Headers @{ Authorization = "Bearer $env:FILMO_API_KEY"; "Accept-Language" = "en-US" }
  $response.data | ConvertTo-Json -Depth 5
} catch {
  # The body of the problem is in ErrorDetails; the status is in the exception.
  Write-Error $_.ErrorDetails.Message
  exit 1
}

# Alternative with curl.exe (the .exe matters: plain curl is an alias in Windows PowerShell 5.1):
# curl.exe -sS "$base/api/v1/account" -H "Authorization: Bearer $env:FILMO_API_KEY"
```

**Node**

```javascript
const base = process.env.FILMO_BASE_URL ?? "https://app.filmo.io";

const res = await fetch(`${base}/api/v1/account`, {
  headers: {
    Authorization: `Bearer ${process.env.FILMO_API_KEY}`,
    "Accept-Language": "en-US",
  },
});

// Check the status before parsing: a platform error may not be JSON.
if (!res.ok) {
  console.error(res.status, res.headers.get("content-type"), await res.text());
  process.exit(1);
}

const { data } = await res.json();
console.log(data.timezone, data.currency, data.addons, data.apiKey.scopes);
```

**Python**

```python
import os
import sys

import requests

base = os.environ.get("FILMO_BASE_URL", "https://app.filmo.io")

res = requests.get(
    f"{base}/api/v1/account",
    headers={"Authorization": f"Bearer {os.environ['FILMO_API_KEY']}", "Accept-Language": "en-US"},
    timeout=30,
)

# Check the status before parsing: a platform error may not be JSON.
if not res.ok:
    print(res.status_code, res.headers.get("content-type"), res.text, file=sys.stderr)
    sys.exit(1)

account = res.json()["data"]
print(account["timezone"], account["currency"], account["addons"], account["apiKey"]["scopes"])
```

The cURL tab is for macOS and Linux shells. On Windows PowerShell 5.1, `curl` is an alias of `Invoke-WebRequest` and the `-H` flag fails: use `Invoke-RestMethod` as above, or call `curl.exe`. In Command Prompt, variables are written `%FILMO_API_KEY%`, not `$FILMO_API_KEY`:

*Command Prompt (cmd.exe)*

```text
rem Command Prompt (cmd.exe): variables are %NAME%, not $NAME.
rem cmd.exe shows the key while you type it: use PowerShell if anyone can see your screen.
set /p FILMO_API_KEY=Filmo API key: 
curl.exe -sS "https://app.filmo.io/api/v1/account" -H "Authorization: Bearer %FILMO_API_KEY%"
```

A successful call returns 200 with the account inside the usual `data` envelope (the values below are fictitious):

*200 OK*

```json
{
  "data": {
    "name": "Acme Rentals",
    "timezone": "Europe/Madrid",
    "currency": "EUR",
    "country": "ES",
    "language": "en-US",
    "addons": ["crm"],
    "trial": { "active": false, "endsAt": null },
    "apiKey": {
      "id": "example-key-id",
      "name": "Inventory sync",
      "scopes": ["account:read", "items:read", "orders:read"]
    },
    "rateLimits": {
      "global": { "perMinute": 120 },
      "availability": { "perMinute": 30 }
    },
    "api": {
      "version": "1.0.0",
      "docsUrl": "https://docs.filmo.io"
    }
  }
}
```

## Read the response

| Field | What to do with it |
| --- | --- |
| `timezone` | The business timezone. A bare day such as 2026-10-17 in a filter is read in it. When you write, send instants with an offset. |
| `currency` | The currency of the account. Amounts are decimal strings with two decimals, and a document may carry its own currency. |
| `language` | The default language of error messages for this key, unless `Accept-Language` says otherwise. Never branch on message text. |
| `addons` | The add-ons the account has today. A resource behind an add-on that is not listed answers 402. While the trial is active every add-on is unlocked, so do not decide from this list until the trial has ended. |
| `trial` | While `active` is true every add-on is unlocked; `endsAt` is when that stops. |
| `apiKey` | The key that made the call: its name and its `scopes`. The secret is never returned. |
| `rateLimits` | Requests per minute: the global quota and the separate quota of the availability queries. |
| `api` | The version of the contract this account is served with, and where its documentation lives. |

## If the first call fails

Find the symptom, then the cause. Errors are RFC 9457 problems: branch on `code`, never on `detail`. Quote `requestId` to support ([Support](https://docs.filmo.io/further-reading/support)).

| Symptom | Cause and fix | Error |
| --- | --- | --- |
| 401 and the detail says the Authorization header is missing or malformed | The header must be exactly `Authorization: Bearer <key>`, with the word `Bearer` and a space. A bare key, `Token` or `Basic` is rejected. | `unauthorized` |
| 401 for a key that was working | The key is wrong, was revoked or has expired. Check how it reached your shell, and issue a new one if needed. | `api_key_invalid`, `api_key_revoked`, `api_key_expired` |
| 404, or a response that is not a Filmo problem body | Every path starts with `/api/v1`, not `/v1`. Use `https://app.filmo.io/api/v1/account`. | None |
| 401 after the key owner changes role or leaves | The person who created the key is no longer an administrator, or is deactivated. The key is fine; reissue it from an account that is still an administrator. | `api_key_owner_not_admin`, `api_key_owner_inactive` |
| 403 on the first call | The key does not carry `account:read`. `requiredScope` in the body names it. Create a key that includes it. | `insufficient_scope` |
| 400 on a later write that carries a date | A date and time in a write needs an offset: 2026-10-17T09:00:00+02:00, not 2026-10-17T09:00:00. Only a field that is a plain date, such as `invoiceDate` in `PUT /api/v1/invoices/external/{originSystem}/{originExternalId}`, takes a bare day. `errors[].path` points at the field. | `validation_error` |
| 402 instead of 403 | A 402 is about an add-on: the account does not have the add-on of the module that resource belongs to, and no role bypasses it. A 403 is about the key or its owner. See Permissions. | `addon_required`, `forbidden` |
| The browser blocks the call (CORS) | Do not call the API from a web page. In production the API allows cross-origin browser calls only from https://docs.filmo.io, so a browser blocks the call from any other origin; and keys are for servers, because a key in a browser is exposed. | None: the browser stops it |
| The `detail` is in Spanish | Without `Accept-Language`, a 401 for a missing or unknown key comes back in Spanish, because there is no owner to ask; every other error uses the preferred language of the key owner. Always send `Accept-Language: en-US` (`es-ES` and `en-US` are guaranteed), and do not base logic on `detail`. | Any |
| The response is not `application/problem+json`, for example a 413 or a 504 | The platform in front of the API answered, not the API. Check the status and `Content-Type` before parsing; do not assume a JSON body. Retry a 504 after a pause. | Not a Filmo code. Server faults of the API are `internal_error` and `service_unavailable` |
| PowerShell 5.1: `curl` fails on `-H` | `curl` is an alias of `Invoke-WebRequest`. Use `Invoke-RestMethod`, or `curl.exe`. | None: the shell fails first |
| cmd: the key is not sent | `$FILMO_API_KEY` is not expanded in Command Prompt, so the header carries that literal text and the key is rejected. Write `%FILMO_API_KEY%`. | `api_key_invalid` |
| In a cURL command, `Idempotency-Key` goes out empty | `uuidgen` does not exist on Windows or on minimal Debian and Alpine images, so `$(uuidgen)` in a `-H` option expands to nothing. Generate the id in your language: `crypto.randomUUID()` in Node, `uuid.uuid4()` in Python, `[guid]::NewGuid()` in PowerShell. | None: the retry is unprotected |

## Next steps

- [Capabilities and limits](https://docs.filmo.io/further-reading/capabilities-and-limits): what v1 covers, its hard limits and what it does not do.
- [Syncing data](https://docs.filmo.io/rest-api/guides/syncing-data): keep your system in step with Filmo by polling for changes.
- [Going live](https://docs.filmo.io/rest-api/guides/going-live): the checklist before production.
- [MCP quickstart](https://docs.filmo.io/mcp/quickstart): give an AI assistant the same access.

---

Canonical URL: https://docs.filmo.io/quickstart  
Last updated: 2026-10-09