# Key/value storage API reference

> Canonical HTML: https://screenrig.ai/docs/api/owner-kv
> Source SHA-256: e0c997a2ab813502f0d99a41d2ed1d3d6b26dbaf1a3d7e514c1cce0278ff8422

Application key/value storage. This group has 9 operations, each with its authentication, parameters, request body fields, request template and responses. The [API overview](https://screenrig.ai/docs/api.md) covers services, authentication, requests and retries, problem codes and versioning.

Replace uppercase placeholders. Save a schema-valid JSON body in request.json when required. Cookie examples use a local cookie jar from an authenticated session.

## Application key/value storage

### GET /api/applications/{application_id}/kv

**List KV**

Returns at most 200 entries in ascending key order. next_cursor is the last returned key; pass it back as after to fetch the next page. next_cursor is null when there are no more entries. A dashboard session reads its project's entries here for the web app preview; the dashboard has no KV write.


Operation: listKV.

- Authentication: projectBearer OR dashboardSession
- Request body: none

#### Parameters

| Name | Send in | Required? | Description |
| --- | --- | --- | --- |
| ScreenRig-Project | header | optional | Deprecated for one release. Must be consistent with the JWT projects grants; adds Deprecation and Warning headers. No token exchange. |
| application_id | path | required |  |
| after | query | optional |  |

#### Request template

~~~sh
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --cookie cookies.txt --cookie-jar cookies.txt 'https://api.screenrig.ai/api/applications/APPLICATION_ID/kv'
~~~

#### Responses

| Status | Meaning | Body and headers |
| --- | --- | --- |
| 200 | KV entries | KVList (application/json) |
| default | Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value. | Problem (application/problem+json) |

### GET /api/applications/{application_id}/kv/{key}

**Get KV**


Operation: getKV.

- Authentication: projectBearer OR dashboardSession
- Request body: none

#### Parameters

| Name | Send in | Required? | Description |
| --- | --- | --- | --- |
| ScreenRig-Project | header | optional | Deprecated for one release. Must be consistent with the JWT projects grants; adds Deprecation and Warning headers. No token exchange. |
| application_id | path | required |  |
| key | path | required |  |

#### Request template

~~~sh
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --cookie cookies.txt --cookie-jar cookies.txt 'https://api.screenrig.ai/api/applications/APPLICATION_ID/kv/KEY'
~~~

#### Responses

| Status | Meaning | Body and headers |
| --- | --- | --- |
| 200 | KV entry | KVEntry (application/json) |
| default | Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value. | Problem (application/problem+json) |

### PUT /api/applications/{application_id}/kv/{key}

**Put KV**


Operation: putKV.

- Authentication: projectBearer
- Request body: KVWrite

#### Parameters

| Name | Send in | Required? | Description |
| --- | --- | --- | --- |
| ScreenRig-Project | header | optional | Deprecated for one release. Must be consistent with the JWT projects grants; adds Deprecation and Warning headers. No token exchange. |
| application_id | path | required |  |
| key | path | required |  |
| If-Match | header | optional | Optional positive resource revision. Omit to create or overwrite a key; a supplied stale revision is revision_conflict. |
| Idempotency-Key | header | optional | Omit for a fresh operation. Supply and reuse a key to deduplicate retries; the CLI manages keys automatically. |

#### Request body fields

| Field | Required? | Type | Description |
| --- | --- | --- | --- |
| value_base64 | required | string | maxLength: 1398104 |
| content_type | optional | string | default: "application/octet-stream" minLength: 1 maxLength: 127 |

#### Request template

~~~sh
curl --request PUT --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --header 'Content-Type: application/json' --data '@request.json' 'https://api.screenrig.ai/api/applications/APPLICATION_ID/kv/KEY'
~~~

#### Responses

| Status | Meaning | Body and headers |
| --- | --- | --- |
| 200 | KV entry | KVEntry (application/json) |
| 429 | Stable rate_limited problem. Retry only after the authoritative Retry-After interval. Fixed-window denials also include the applicable RateLimit-Policy and RateLimit members; concurrency and byte-budget denials omit those optional disclosures. | Problem (application/problem+json); headers: Retry-After, RateLimit-Policy, RateLimit |
| default | Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value. | Problem (application/problem+json) |

### DELETE /api/applications/{application_id}/kv/{key}

**Delete KV**


Operation: deleteKV.

- Authentication: projectBearer
- Request body: none

#### Parameters

| Name | Send in | Required? | Description |
| --- | --- | --- | --- |
| ScreenRig-Project | header | optional | Deprecated for one release. Must be consistent with the JWT projects grants; adds Deprecation and Warning headers. No token exchange. |
| application_id | path | required |  |
| key | path | required |  |
| If-Match | header | optional | Optional positive resource revision. Omit to write the current resource; a supplied stale revision is revision_conflict. |
| Idempotency-Key | header | optional | Omit for a fresh operation. Supply and reuse a key to deduplicate retries; the CLI manages keys automatically. |

#### Request template

~~~sh
curl --request DELETE --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/applications/APPLICATION_ID/kv/KEY'
~~~

#### Responses

| Status | Meaning | Body and headers |
| --- | --- | --- |
| 204 | Deleted | no body |
| default | Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value. | Problem (application/problem+json) |

### GET /api/applications/{application_id}/kv-webhooks

**List KVWebhooks**

Lists the application's incoming key/value webhooks, oldest first (at most 20), each with the key it writes, its ingest url and last_used_at once it has written. The secret is never returned here.


Operation: listKVWebhooks.

- Authentication: projectBearer
- Request body: none

#### Parameters

| Name | Send in | Required? | Description |
| --- | --- | --- | --- |
| ScreenRig-Project | header | optional | Deprecated for one release. Must be consistent with the JWT projects grants; adds Deprecation and Warning headers. No token exchange. |
| application_id | path | required |  |

#### Request template

~~~sh
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/applications/APPLICATION_ID/kv-webhooks'
~~~

#### Responses

| Status | Meaning | Body and headers |
| --- | --- | --- |
| 200 | The application's key/value webhooks. | KVWebhookList (application/json) |
| default | Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value. | Problem (application/problem+json) |

### POST /api/applications/{application_id}/kv-webhooks

**Create KVWebhook**

Creates an incoming key/value webhook: one URL that writes one key of this application, so an outside system (Zapier, Make, a point of sale, a cron job, curl) pushes data to screens with one HTTP POST; see POST /api/applications/{application_id}/kv-webhooks/{webhook_id}/write. The key need not exist yet.

The answer is the only place the secret appears (with the rotate answer): store it in the sending system at once; the server keeps a digest. An application has at most 20 webhooks (kv_webhook_limit_reached). Appends kv_webhook.created. An exact retry with the same Idempotency-Key returns this same answer, secret included, for twenty-four hours.


Operation: createKVWebhook.

- Authentication: projectBearer
- Request body: KVWebhookCreate

#### Parameters

| Name | Send in | Required? | Description |
| --- | --- | --- | --- |
| ScreenRig-Project | header | optional | Deprecated for one release. Must be consistent with the JWT projects grants; adds Deprecation and Warning headers. No token exchange. |
| application_id | path | required |  |
| Idempotency-Key | header | optional | Omit for a fresh operation. Supply and reuse a key to deduplicate retries; the CLI manages keys automatically. |

#### Request body fields

| Field | Required? | Type | Description |
| --- | --- | --- | --- |
| key | required | string | minLength: 1 maxLength: 256 pattern: "^[A-Za-z0-9][A-Za-z0-9._:/-]{0,255}$" |
| description | optional | string | What sends to it, for the people reading the list. Trimmed; it must not hold a credential. maxLength: 200 |

#### Request template

~~~sh
curl --request POST --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --header 'Content-Type: application/json' --data '@request.json' 'https://api.screenrig.ai/api/applications/APPLICATION_ID/kv-webhooks'
~~~

#### Responses

| Status | Meaning | Body and headers |
| --- | --- | --- |
| 201 | Created, with its url and secret. | KVWebhookWithSecret (application/json); headers: Cache-Control |
| 400 | invalid_request, including a malformed key or a description that holds a credential. | Problem (application/problem+json) |
| 404 | not_found — the application is not in this project. | Problem (application/problem+json) |
| 409 | kv_webhook_limit_reached or idempotency_mismatch. | Problem (application/problem+json) |
| default | Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value. | Problem (application/problem+json) |

### DELETE /api/applications/{application_id}/kv-webhooks/{webhook_id}

**Delete KVWebhook**

Deletes the webhook. Its URL stops working at once; the key it wrote keeps its value. Appends kv_webhook.deleted.


Operation: deleteKVWebhook.

- Authentication: projectBearer
- Request body: none

#### Parameters

| Name | Send in | Required? | Description |
| --- | --- | --- | --- |
| ScreenRig-Project | header | optional | Deprecated for one release. Must be consistent with the JWT projects grants; adds Deprecation and Warning headers. No token exchange. |
| application_id | path | required |  |
| webhook_id | path | required | The id of one of the application's key/value webhooks. |
| Idempotency-Key | header | optional | Omit for a fresh operation. Supply and reuse a key to deduplicate retries; the CLI manages keys automatically. |

#### Request template

~~~sh
curl --request DELETE --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/applications/APPLICATION_ID/kv-webhooks/WEBHOOK_ID'
~~~

#### Responses

| Status | Meaning | Body and headers |
| --- | --- | --- |
| 204 | Deleted. | no body |
| 404 | not_found — the webhook is not on this application. | Problem (application/problem+json) |
| default | Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value. | Problem (application/problem+json) |

### POST /api/applications/{application_id}/kv-webhooks/{webhook_id}/rotate-secret

**Rotate KVWebhook Secret**

Replaces the webhook's secret and returns the new one, once. The old secret stops working at once; update the sending system. Appends kv_webhook.secret_rotated. An exact retry with the same Idempotency-Key returns this same answer, secret included, for twenty-four hours.


Operation: rotateKVWebhookSecret.

- Authentication: projectBearer
- Request body: none

#### Parameters

| Name | Send in | Required? | Description |
| --- | --- | --- | --- |
| ScreenRig-Project | header | optional | Deprecated for one release. Must be consistent with the JWT projects grants; adds Deprecation and Warning headers. No token exchange. |
| application_id | path | required |  |
| webhook_id | path | required | The id of one of the application's key/value webhooks. |
| Idempotency-Key | header | optional | Omit for a fresh operation. Supply and reuse a key to deduplicate retries; the CLI manages keys automatically. |

#### Request template

~~~sh
curl --request POST --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/applications/APPLICATION_ID/kv-webhooks/WEBHOOK_ID/rotate-secret'
~~~

#### Responses

| Status | Meaning | Body and headers |
| --- | --- | --- |
| 200 | The webhook with its new secret. | KVWebhookWithSecret (application/json); headers: Cache-Control |
| 404 | not_found — the webhook is not on this application. | Problem (application/problem+json) |
| default | Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value. | Problem (application/problem+json) |

### POST /api/applications/{application_id}/kv-webhooks/{webhook_id}/write

**Receive KVWebhook**

The URL an outside system posts one key's new value to. It authenticates with the webhook's own secret in the Authorization header only: Bearer <secret>, or HTTP Basic with the webhook id as the username and the secret as the password. A secret in the URL or query is never accepted.

An unknown webhook, one of another application and a wrong secret all answer the same 401. The raw body, at most 1 MiB, becomes the value of the webhook's key, and the Content-Type header its content_type (application/octet-stream when absent; a header that is not one media type is invalid_request).

The write is PUT /api/applications/{application_id}/kv/{key} without If-Match: it replaces the value, increments the revision, is metered and quota-checked like any K/V write, is one billed API request that is never refused for balance, and appends kv.updated.

Idempotency-Key (8 to 200 characters) deduplicates a sender's retries of one write for twenty-four hours, and the same key with another body or content type is idempotency_mismatch; without it every post is a new write. The answer is the key's new metadata, never its value.

At most 120 writes per minute per webhook; each also counts toward the organization's and the key's write rates (PUT /api/card-data/{key}).


Operation: receiveKVWebhook.

- Authentication: kvWebhookBearer OR kvWebhookBasic
- Request body: string

#### Parameters

| Name | Send in | Required? | Description |
| --- | --- | --- | --- |
| application_id | path | required |  |
| webhook_id | path | required | The id of one of the application's key/value webhooks. |
| Idempotency-Key | header | optional | Omit for a fresh operation. Supply and reuse a key to deduplicate retries; the CLI manages keys automatically. |

#### Request template

~~~sh
curl --request POST --header 'Content-Type: */*' --data-binary '@request.bin' 'https://api.screenrig.ai/api/applications/APPLICATION_ID/kv-webhooks/WEBHOOK_ID/write'
~~~

#### Responses

| Status | Meaning | Body and headers |
| --- | --- | --- |
| 200 | The key's new metadata. | KVWebhookWriteResult (application/json); headers: RateLimit-Policy, RateLimit, Cache-Control |
| 400 | invalid_request — the body is larger than 1 MiB, the Content-Type is not one media type, or the Idempotency-Key is malformed. | Problem (application/problem+json) |
| 401 | unauthorized — missing or wrong credentials, or an unknown webhook. WWW-Authenticate names the Bearer and Basic realms. | Problem (application/problem+json) |
| 409 | idempotency_mismatch — the Idempotency-Key was used for another body or content type. | Problem (application/problem+json) |
| 429 | Stable rate_limited problem. Retry only after the authoritative Retry-After interval. Fixed-window denials also include the applicable RateLimit-Policy and RateLimit members; concurrency and byte-budget denials omit those optional disclosures. | Problem (application/problem+json); headers: Retry-After, RateLimit-Policy, RateLimit |
| default | Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value. | Problem (application/problem+json) |


## Sitemap

See the [public documentation sitemap](https://screenrig.ai/sitemap.md).
