# API Keys Reference CRUD operations for managing operator API keys. **Base path:** `/functions/v1/api-keys` **Authentication:** `Authorization: Bearer oh_live_...` or Supabase JWT (for listing and management) --- ## Create a key {#create} ``` POST /api-keys ``` Creates a new API key for an operator. The plaintext key is returned **once** in the response — store it securely. ### Request | Field | Type | Required | Description | |---|---|---|---| | `operatorId` | string | Yes | The operator ID to create the key for | | `label` | string | No | A descriptive label (e.g. "Production backend") | ### Example ```bash curl -X POST https://api.onehazel.com/api-keys \ -H "Content-Type: application/json" \ -d '{ "operatorId": "op_abc123", "label": "Production backend" }' ``` ### Response (201) ```json { "success": true, "data": { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "key": "oh_live_a1b2c3d4e5f6789012345678901234567890abcdef1234567890abcdef123456", "label": "Production backend", "createdAt": "2026-04-06T12:00:00.000Z" } } ``` ::: danger Store your key The `key` field is only returned in this response. It is stored as a SHA-256 hash and cannot be retrieved later. If you lose it, revoke the key and create a new one. ::: --- ## List keys {#list} ``` GET /api-keys ``` Lists all API keys for the authenticated operator. Keys are returned with hashed values — never in plaintext. Supports both API key auth (`oh_live_...`) and JWT auth (Supabase session). When authenticated, results are filtered to show only the operator's own keys. ### Example ```bash curl https://api.onehazel.com/api-keys \ -H "Authorization: Bearer oh_live_YOUR_API_KEY" ``` ### Response ```json { "success": true, "data": [ { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "operatorId": "op_abc123", "keyHash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "label": "Production backend", "createdAt": "2026-04-06T12:00:00.000Z", "lastUsedAt": "2026-04-06T14:30:00.000Z", "revoked": false }, { "id": "b2c3d4e5-f6a7-8901-bcde-f12345678901", "operatorId": "op_abc123", "keyHash": "d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592", "label": "Staging ETL", "createdAt": "2026-03-15T09:00:00.000Z", "lastUsedAt": null, "revoked": false } ] } ``` --- ## Rename a key {#rename} ``` PATCH /api-keys ``` Updates the label on an existing key. ### Request | Field | Type | Required | Description | |---|---|---|---| | `id` | string | Yes | The key ID | | `label` | string | Yes | The new label | ### Example ```bash curl -X PATCH https://api.onehazel.com/api-keys \ -H "Authorization: Bearer oh_live_YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "label": "Production v2" }' ``` ### Response ```json { "success": true, "message": "Key renamed" } ``` --- ## Revoke a key {#revoke} ``` DELETE /api-keys?id= ``` Soft-revokes an API key. The key remains in the database but can no longer be used for authentication. ### Query parameters | Parameter | Type | Required | Description | |---|---|---|---| | `id` | string | Yes | The key ID to revoke | ### Example ```bash curl -X DELETE "https://api.onehazel.com/api-keys?id=a1b2c3d4-e5f6-7890-abcd-ef1234567890" \ -H "Authorization: Bearer oh_live_YOUR_API_KEY" ``` ### Response ```json { "success": true, "message": "Key revoked" } ``` ### Last-key guard You cannot revoke your last active API key. If you try, the API returns: ```json { "success": false, "error": "Cannot revoke your last active API key — create a new one first" } ``` HTTP status: `400` --- ## Hard delete a key {#hard-delete} ``` DELETE /api-keys?id=&hard=true ``` Permanently removes a revoked key from the database. **Prerequisite:** The key must already be revoked. Attempting to hard-delete an active key returns an error. ### Example ```bash curl -X DELETE "https://api.onehazel.com/api-keys?id=a1b2c3d4-e5f6-7890-abcd-ef1234567890&hard=true" \ -H "Authorization: Bearer oh_live_YOUR_API_KEY" ``` ### Response ```json { "success": true, "message": "Key deleted" } ``` ### Error for active key ```json { "success": false, "error": "Cannot delete an active key — revoke it first" } ``` --- ## Error codes | HTTP Status | Error | Description | |---|---|---| | `400` | `operatorId is required` | Missing operatorId on create | | `400` | `id and label are required` | Missing fields on rename | | `400` | `Query parameter 'id' is required` | Missing key ID on delete | | `400` | `Cannot revoke your last active API key` | Last-key guard | | `400` | `Cannot delete an active key` | Must revoke before hard delete | | `405` | `Method not allowed` | Unsupported HTTP method | | `500` | `Failed to create key` | Database error on create | | `500` | `Failed to list keys` | Database error on list | | `500` | `Failed to rename key` | Database error on rename | | `500` | `Failed to revoke key` | Database error on revoke | | `500` | `Failed to delete key` | Database error on delete |