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

# API Keys

> Manage your Developer API keys

## Endpoints

<CardGroup cols={3}>
  <Card title="GET" icon="download" color="#22c55e">
    List all keys
  </Card>

  <Card title="POST" icon="upload" color="#3b82f6">
    Create new key
  </Card>

  <Card title="DELETE" icon="trash" color="#ef4444">
    Revoke key
  </Card>
</CardGroup>

<Note>
  Developer API keys are self-service: while signed in to Omi, open **Developer → API Keys** to create,
  list, and revoke your keys. The lifecycle endpoints below use that signed-in Omi/Firebase session; an
  `omi_dev_...` key cannot create, list, or revoke keys itself.
</Note>

***

## Inspect the Calling Key

`GET /v1/dev/key` accepts any valid Developer API key, regardless of data scopes or memory readiness. It returns only that credential's metadata, never user content, the secret, or its hash. Use it to validate a key without reading memories.

```bash theme={null}
curl -H "Authorization: Bearer $OMI_API_KEY" \
  "https://api.omi.me/v1/dev/key"
```

```json theme={null}
{
  "id": "key_123abc",
  "name": "Task reader",
  "key_prefix": "omi_dev_abc123",
  "scopes": ["action_items:read"],
  "created_at": "2025-01-15T10:30:00Z",
  "last_used_at": "2025-01-20T14:22:00Z"
}
```

`scopes` reports effective permissions: legacy keys with missing scopes receive the read-only scopes; an explicit empty list stays empty. `last_used_at` is approximate: authentication updates it on cache misses, roughly hourly, so it is not an activity log and null does not prove a key has never been used. Invalid keys return `401`; the endpoint has its own rate-limit budget (see [Quick Start](/doc/developer/api/overview#rate-limits)).

## List API Keys

<Card title="GET /v1/dev/keys" icon="download" color="#22c55e" horizontal>
  Retrieve all your developer API keys
</Card>

<Note>
  This endpoint requires your signed-in Omi/Firebase session. The secret key values are not returned (only the prefix is shown).
</Note>

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    curl -H "Authorization: Bearer $FIREBASE_ID_TOKEN" \
      "https://api.omi.me/v1/dev/keys"
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    import requests

    response = requests.get(
        "https://api.omi.me/v1/dev/keys",
        headers={"Authorization": f"Bearer {firebase_id_token}"}
    )
    keys = response.json()
    ```
  </Tab>

  <Tab title="JavaScript">
    ```javascript theme={null}
    const response = await fetch(
      "https://api.omi.me/v1/dev/keys",
      { headers: { Authorization: `Bearer ${firebaseIdToken}` } }
    );
    const keys = await response.json();
    ```
  </Tab>
</Tabs>

<AccordionGroup>
  <Accordion title="Response Example" icon="code" defaultOpen={true}>
    ```json theme={null}
    [
      {
        "id": "key_123abc",
        "name": "My Analytics Dashboard",
        "key_prefix": "omi_dev_abc123",
        "created_at": "2025-01-15T10:30:00Z",
        "last_used_at": "2025-01-20T14:22:00Z",
        "scopes": ["conversations:read", "memories:read"]
      },
      {
        "id": "key_456def",
        "name": "Automation Script",
        "key_prefix": "omi_dev_def456",
        "created_at": "2025-01-18T09:00:00Z",
        "last_used_at": null,
        "scopes": ["memories:read"]
      }
    ]
    ```
  </Accordion>

  <Accordion title="Response Fields" icon="list">
    | Field | Type | Description |
    | - | - | - |
    | `id` | string | Unique key identifier (used for deletion) |
    | `name` | string | Descriptive name you gave the key |
    | `key_prefix` | string | First part of the key (for identification) |
    | `created_at` | datetime | When the key was created |
    | `last_used_at` | datetime | Approximate last authentication cache miss; may lag activity by about an hour (null if not recorded) |
    | `scopes` | array | Permissions assigned to the key |
  </Accordion>
</AccordionGroup>

***

## Create API Key

<Card title="POST /v1/dev/keys" icon="upload" color="#3b82f6" horizontal>
  Create a new developer API key
</Card>

<Note>
  Create keys from the signed-in Omi web app. The REST endpoint is the same self-service flow and requires a
  Firebase ID token, not an existing `omi_dev_...` key. The new secret is returned only once.
</Note>

<AccordionGroup>
  <Accordion title="Request Body" icon="code" defaultOpen={true}>
    | Parameter | Type | Required | Description |
    | - | - | - | - |
    | `name` | string | **Yes** | Descriptive name for the key |
    | `scopes` | array of strings | No | Permissions for the key. If omitted, the key receives the read-only scopes. |
  </Accordion>
</AccordionGroup>

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    curl -X POST "https://api.omi.me/v1/dev/keys" \
      -H "Authorization: Bearer $FIREBASE_ID_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{"name": "My New Integration", "scopes": ["memories:read"]}'
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    import requests

    response = requests.post(
        "https://api.omi.me/v1/dev/keys",
        headers={
            "Authorization": f"Bearer {firebase_id_token}",
            "Content-Type": "application/json"
        },
        json={"name": "My New Integration", "scopes": ["memories:read"]}
    )
    new_key = response.json()
    print(f"Store this key securely: {new_key['key']}")
    ```
  </Tab>

  <Tab title="JavaScript">
    ```javascript theme={null}
    const response = await fetch(
      "https://api.omi.me/v1/dev/keys",
      {
        method: "POST",
        headers: {
          Authorization: `Bearer ${firebaseIdToken}`,
          "Content-Type": "application/json"
        },
        body: JSON.stringify({ name: "My New Integration", scopes: ["memories:read"] })
      }
    );
    const newKey = await response.json();
    console.log(`Store this key securely: ${newKey.key}`);
    ```
  </Tab>
</Tabs>

<Accordion title="Response Example" icon="code" defaultOpen={true}>
  ```json theme={null}
  {
    "id": "key_789ghi",
    "name": "My New Integration",
    "key_prefix": "omi_dev_ghi789",
    "key": "omi_dev_ghi789_full_secret_key_here",
    "created_at": "2025-01-20T15:00:00Z",
    "last_used_at": null,
    "scopes": ["memories:read"]
  }
  ```
</Accordion>

<Warning>
  The full API key (`key` field) is only returned once during creation. Store it securely immediately - you won't be able to see it again!
</Warning>

### Scopes

Choose the least-privileged scopes needed by your integration:

* Read: `conversations:read`, `memories:read`, `action_items:read`, `goals:read`
* Write: `conversations:write`, `memories:write`, `action_items:write`, `goals:write`

Memory scopes authorize the key, but they do not bypass the account-level Developer Memory API readiness
gate. See [Memories](/doc/developer/api/memories) for that availability contract.

***

## Revoke API Key

<Card title="DELETE /v1/dev/keys/{key_id}" icon="trash" color="#ef4444" horizontal>
  Revoke (delete) a specific API key permanently
</Card>

<AccordionGroup>
  <Accordion title="Path Parameters" icon="route" defaultOpen={true}>
    | Parameter | Type | Description |
    | - | - | - |
    | `key_id` | string | The ID of the key to revoke |
  </Accordion>
</AccordionGroup>

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    curl -X DELETE "https://api.omi.me/v1/dev/keys/key_789ghi" \
      -H "Authorization: Bearer $FIREBASE_ID_TOKEN"
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    import requests

    response = requests.delete(
        f"https://api.omi.me/v1/dev/keys/key_789ghi",
        headers={"Authorization": f"Bearer {firebase_id_token}"}
    )
    if response.status_code == 204:
        print("Key revoked successfully")
    ```
  </Tab>

  <Tab title="JavaScript">
    ```javascript theme={null}
    const response = await fetch(
      "https://api.omi.me/v1/dev/keys/key_789ghi",
      {
        method: "DELETE",
        headers: { Authorization: `Bearer ${firebaseIdToken}` }
      }
    );
    if (response.status === 204) {
      console.log("Key revoked successfully");
    }
    ```
  </Tab>
</Tabs>

<Accordion title="Response" icon="check" defaultOpen={true}>
  ```
  204 No Content
  ```
</Accordion>

<Tip>
  If a key is compromised, revoke it immediately and create a new one.
</Tip>

***

## Best Practices

<CardGroup cols={2}>
  <Card title="Use Descriptive Names" icon="tag" color="#22c55e">
    Name keys after their purpose (e.g., "Analytics Dashboard", "Zapier Integration")
  </Card>

  <Card title="One Key Per Application" icon="key" color="#3b82f6">
    Create separate keys for different apps so you can revoke them independently
  </Card>

  <Card title="Monitor Usage" icon="chart-line" color="#a855f7">
    Check `last_used_at` to identify unused or potentially compromised keys
  </Card>

  <Card title="Rotate Regularly" icon="rotate" color="#f59e0b">
    Periodically create new keys and revoke old ones
  </Card>
</CardGroup>

***

## Use Case: Key Management Script

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    import requests

    FIREBASE_ID_TOKEN = "your_signed_in_firebase_id_token"
    headers = {
        "Authorization": f"Bearer {FIREBASE_ID_TOKEN}",
        "Content-Type": "application/json"
    }

    def list_keys():
        """List all API keys"""
        response = requests.get(
            "https://api.omi.me/v1/dev/keys",
            headers=headers
        )
        return response.json()

    def create_key(name):
        """Create a new API key"""
        response = requests.post(
            "https://api.omi.me/v1/dev/keys",
            headers=headers,
            json={"name": name}
        )
        return response.json()

    def revoke_key(key_id):
        """Revoke an API key"""
        response = requests.delete(
            f"https://api.omi.me/v1/dev/keys/{key_id}",
            headers=headers
        )
        return response.status_code == 204

    # List existing keys
    print("Current API keys:")
    for key in list_keys():
        last_used = key.get("last_used_at", "Never")
        print(f"  - {key['name']} ({key['key_prefix']}...) - Last used: {last_used}")

    # Create a new key
    print("\nCreating new key...")
    new_key = create_key("Test Integration")
    print(f"Created: {new_key['name']}")
    print(f"Key: {new_key['key']}")  # Store this securely!

    # Revoke a key (example)
    # if revoke_key("key_123abc"):
    #     print("Key revoked successfully")
    ```
  </Tab>

  <Tab title="JavaScript">
    ```javascript theme={null}
    const FIREBASE_ID_TOKEN = process.env.FIREBASE_ID_TOKEN;
    const headers = {
      Authorization: `Bearer ${FIREBASE_ID_TOKEN}`,
      "Content-Type": "application/json"
    };

    async function listKeys() {
      const response = await fetch("https://api.omi.me/v1/dev/keys", { headers });
      return response.json();
    }

    async function createKey(name) {
      const response = await fetch("https://api.omi.me/v1/dev/keys", {
        method: "POST",
        headers,
        body: JSON.stringify({ name })
      });
      return response.json();
    }

    async function revokeKey(keyId) {
      const response = await fetch(`https://api.omi.me/v1/dev/keys/${keyId}`, {
        method: "DELETE",
        headers
      });
      return response.status === 204;
    }

    // List existing keys
    console.log("Current API keys:");
    const keys = await listKeys();
    keys.forEach(key => {
      const lastUsed = key.last_used_at || "Never";
      console.log(`  - ${key.name} (${key.key_prefix}...) - Last used: ${lastUsed}`);
    });

    // Create a new key
    console.log("\nCreating new key...");
    const newKey = await createKey("Test Integration");
    console.log(`Created: ${newKey.name}`);
    console.log(`Key: ${newKey.key}`);  // Store this securely!

    // Revoke a key (example)
    // if (await revokeKey("key_123abc")) {
    //   console.log("Key revoked successfully");
    // }
    ```
  </Tab>
</Tabs>

***

## Managing Keys in the App

You can also manage API keys directly in the Omi app:

<Steps>
  <Step title="Open Omi App" icon="mobile">
    Launch the Omi app on your device
  </Step>

  <Step title="Navigate to Settings" icon="gear">
    Go to **Settings → Developer**
  </Step>

  <Step title="Manage Keys" icon="key">
    Under "Developer API Keys" you can:

    * View all your keys
    * Create new keys
    * Delete existing keys
  </Step>
</Steps>

<Info>
  Keys created in the app and via the API are the same - you can manage them from either place.
</Info>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.