Records

Docs API reference

Records

The words your screens show. A template scene has blanks (title, speaker, …); a record fills them for one ref, and every scene that plays that ref shows its values. Change a record and open screens update within seconds. **How records are organized.** There are no collections to create: a workspace has one set of records and the ref is the address. The parts between slashes work like folders — your-event/session/b-14, your-event/room/hall-b, cafeteria/menu/monday — so pick a pattern and list one branch with GET /records?prefix=your-event/session/. A record has no fixed fields: its values are the blanks it fills. **Create a record** with POST /records, change it with PATCH /records/{ref}, and sync many at once with POST /records/batch.

List records

GET /records data

Sorted by ref. Use prefix to list one group, e.g. every session of an event.

Parameters

  • prefix string query

    Only refs starting with this text, e.g. your-event/session/.

  • limit integer query

    Page size, 1–200.

    1–200. Default 50

  • cursor string query

    The next_cursor of the previous page.

Responses

  • 200 A page of records.
  • 400 The request is invalid — details.field names the field when there is one.
  • 401 Missing or invalid API key.
  • 403 The key lacks the scope, or the role is read-only.
Response fields (200)
  • items object[] required
    6 fields in items
    • ref string required

      Your key for the record, e.g. your-event/session/b-14. Slashes group records.

      Pattern ^[A-Za-z0-9][A-Za-z0-9._:/-]{0,199}$

    • values map of string required

      Blank name → text. Blank names start with a letter, then letters, digits or _.

      Each value up to 2000 characters

    • origin string required

      Who wrote the values last: hand in the app, api through this API, source a connected data source, migration moved from a scene.

      One of hand, api, source, migration

    • stale boolean required

      The data source that owns the record no longer contains it.

    • created_at integer required

      Epoch ms.

    • updated_at integer required

      Epoch ms.

  • next_cursor string or null required

    Pass as cursor for the next page; null on the last page.

curl "https://www.wunderframe.com/api/v1/records?limit=50" \
  -H "Authorization: Bearer $WUNDERFRAME_API_KEY"
Response 200
{
  "items": [
    {
      "ref": "your-event/session/b-14",
      "values": {
        "title": "The AI-Native Startup",
        "speaker": "Ada Lovelace",
        "room": "Hall B"
      },
      "origin": "api",
      "stale": false,
      "created_at": 1789372800000,
      "updated_at": 1789376400000
    }
  ],
  "next_cursor": null
}
Error example
Response 400
{
  "error": {
    "code": "invalid",
    "message": "The request is invalid — `details.field` names the field when there is one."
  }
}

Create a record

POST /records data

Creates the record for a new ref with its values. Refused with 409 conflict when a record with that ref already exists — change it with PATCH /records/{ref} (merge) or PUT /records/{ref} (replace).

Every scene that plays this ref shows the values straight away. A ref no scene plays yet is fine: its values show as soon as a scene uses it.

Request body required

  • ref string required

    Your key for the record. Slashes group records: your-event/session/b-14.

    Pattern ^[A-Za-z0-9][A-Za-z0-9._:/-]{0,199}$

  • values map of string or null required

    Blank name → text. Blank names start with a letter, then letters, digits or _. null stores an empty value.

    Up to 200 entries. Each value up to 2000 characters

Responses

  • 201 Created.
  • 400 The request is invalid — details.field names the field when there is one.
  • 401 Missing or invalid API key.
  • 403 The key lacks the scope, or the role is read-only.
  • 409 Conflicts with the current state.
Response fields (201)
  • ref string required

    Your key for the record, e.g. your-event/session/b-14. Slashes group records.

    Pattern ^[A-Za-z0-9][A-Za-z0-9._:/-]{0,199}$

  • values map of string required

    Blank name → text. Blank names start with a letter, then letters, digits or _.

    Each value up to 2000 characters

  • origin string required

    Who wrote the values last: hand in the app, api through this API, source a connected data source, migration moved from a scene.

    One of hand, api, source, migration

  • stale boolean required

    The data source that owns the record no longer contains it.

  • created_at integer required

    Epoch ms.

  • updated_at integer required

    Epoch ms.

curl -X POST "https://www.wunderframe.com/api/v1/records" \
  -H "Authorization: Bearer $WUNDERFRAME_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "ref": "your-event/session/b-14",
  "values": {
    "title": "The AI-Native Startup",
    "speaker": "Ada Lovelace",
    "room": "Hall B"
  }
}'
Response 201
{
  "ref": "your-event/session/b-14",
  "values": {
    "title": "The AI-Native Startup",
    "speaker": "Ada Lovelace",
    "room": "Hall B"
  },
  "origin": "api",
  "stale": false,
  "created_at": 1789372800000,
  "updated_at": 1789376400000
}
Error example
Response 400
{
  "error": {
    "code": "invalid",
    "message": "The request is invalid — `details.field` names the field when there is one."
  }
}

Get a record

GET /records/{ref} data

Parameters

  • ref string required path

    The record ref. It may contain slashes and is used as-is: /records/your-event/session/b-14.

Responses

  • 200 The record.
  • 400 The request is invalid — details.field names the field when there is one.
  • 401 Missing or invalid API key.
  • 403 The key lacks the scope, or the role is read-only.
  • 404 Not found in this workspace.
Response fields (200)
  • ref string required

    Your key for the record, e.g. your-event/session/b-14. Slashes group records.

    Pattern ^[A-Za-z0-9][A-Za-z0-9._:/-]{0,199}$

  • values map of string required

    Blank name → text. Blank names start with a letter, then letters, digits or _.

    Each value up to 2000 characters

  • origin string required

    Who wrote the values last: hand in the app, api through this API, source a connected data source, migration moved from a scene.

    One of hand, api, source, migration

  • stale boolean required

    The data source that owns the record no longer contains it.

  • created_at integer required

    Epoch ms.

  • updated_at integer required

    Epoch ms.

curl "https://www.wunderframe.com/api/v1/records/your-event/session/b-14" \
  -H "Authorization: Bearer $WUNDERFRAME_API_KEY"
Response 200
{
  "ref": "your-event/session/b-14",
  "values": {
    "title": "The AI-Native Startup",
    "speaker": "Ada Lovelace",
    "room": "Hall B"
  },
  "origin": "api",
  "stale": false,
  "created_at": 1789372800000,
  "updated_at": 1789376400000
}
Error example
Response 400
{
  "error": {
    "code": "invalid",
    "message": "The request is invalid — `details.field` names the field when there is one."
  }
}

Create or replace a record

PUT /records/{ref} data

The record holds exactly the values you send; blanks you leave out are removed. Creates the record (201) when the ref has none yet, so it is safe to repeat.

Parameters

  • ref string required path

    The record ref. It may contain slashes and is used as-is: /records/your-event/session/b-14.

Request body required

  • values map of string or null required

    Blank name → text. null stores an empty value.

    Up to 200 entries. Each value up to 2000 characters

Responses

  • 200 Replaced.
  • 201 Created.
  • 400 The request is invalid — details.field names the field when there is one.
  • 401 Missing or invalid API key.
  • 403 The key lacks the scope, or the role is read-only.
Response fields (200)
  • ref string required

    Your key for the record, e.g. your-event/session/b-14. Slashes group records.

    Pattern ^[A-Za-z0-9][A-Za-z0-9._:/-]{0,199}$

  • values map of string required

    Blank name → text. Blank names start with a letter, then letters, digits or _.

    Each value up to 2000 characters

  • origin string required

    Who wrote the values last: hand in the app, api through this API, source a connected data source, migration moved from a scene.

    One of hand, api, source, migration

  • stale boolean required

    The data source that owns the record no longer contains it.

  • created_at integer required

    Epoch ms.

  • updated_at integer required

    Epoch ms.

Response fields (201)
  • ref string required

    Your key for the record, e.g. your-event/session/b-14. Slashes group records.

    Pattern ^[A-Za-z0-9][A-Za-z0-9._:/-]{0,199}$

  • values map of string required

    Blank name → text. Blank names start with a letter, then letters, digits or _.

    Each value up to 2000 characters

  • origin string required

    Who wrote the values last: hand in the app, api through this API, source a connected data source, migration moved from a scene.

    One of hand, api, source, migration

  • stale boolean required

    The data source that owns the record no longer contains it.

  • created_at integer required

    Epoch ms.

  • updated_at integer required

    Epoch ms.

curl -X PUT "https://www.wunderframe.com/api/v1/records/your-event/session/b-14" \
  -H "Authorization: Bearer $WUNDERFRAME_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "values": {
    "title": "The AI-Native Startup",
    "speaker": "Ada Lovelace",
    "room": "Hall B"
  }
}'
Response 200
{
  "ref": "your-event/session/b-14",
  "values": {
    "title": "The AI-Native Startup",
    "speaker": "Ada Lovelace",
    "room": "Hall B"
  },
  "origin": "api",
  "stale": false,
  "created_at": 1789372800000,
  "updated_at": 1789376400000
}
Error example
Response 400
{
  "error": {
    "code": "invalid",
    "message": "The request is invalid — `details.field` names the field when there is one."
  }
}

Create or update a record

PATCH /records/{ref} data

The values you send change; every other blank keeps its value. Creates the record (201) when the ref has none yet.

Parameters

  • ref string required path

    The record ref. It may contain slashes and is used as-is: /records/your-event/session/b-14.

Request body required

  • values map of string or null required

    Blank name → text. null stores an empty value.

    Up to 200 entries. Each value up to 2000 characters

Responses

  • 200 Updated.
  • 201 Created.
  • 400 The request is invalid — details.field names the field when there is one.
  • 401 Missing or invalid API key.
  • 403 The key lacks the scope, or the role is read-only.
Response fields (200)
  • ref string required

    Your key for the record, e.g. your-event/session/b-14. Slashes group records.

    Pattern ^[A-Za-z0-9][A-Za-z0-9._:/-]{0,199}$

  • values map of string required

    Blank name → text. Blank names start with a letter, then letters, digits or _.

    Each value up to 2000 characters

  • origin string required

    Who wrote the values last: hand in the app, api through this API, source a connected data source, migration moved from a scene.

    One of hand, api, source, migration

  • stale boolean required

    The data source that owns the record no longer contains it.

  • created_at integer required

    Epoch ms.

  • updated_at integer required

    Epoch ms.

Response fields (201)
  • ref string required

    Your key for the record, e.g. your-event/session/b-14. Slashes group records.

    Pattern ^[A-Za-z0-9][A-Za-z0-9._:/-]{0,199}$

  • values map of string required

    Blank name → text. Blank names start with a letter, then letters, digits or _.

    Each value up to 2000 characters

  • origin string required

    Who wrote the values last: hand in the app, api through this API, source a connected data source, migration moved from a scene.

    One of hand, api, source, migration

  • stale boolean required

    The data source that owns the record no longer contains it.

  • created_at integer required

    Epoch ms.

  • updated_at integer required

    Epoch ms.

curl -X PATCH "https://www.wunderframe.com/api/v1/records/your-event/session/b-14" \
  -H "Authorization: Bearer $WUNDERFRAME_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "values": {
    "speaker": "Grace Hopper"
  }
}'
Response 200
{
  "ref": "your-event/session/b-14",
  "values": {
    "title": "The AI-Native Startup",
    "speaker": "Ada Lovelace",
    "room": "Hall B"
  },
  "origin": "api",
  "stale": false,
  "created_at": 1789372800000,
  "updated_at": 1789376400000
}
Error example
Response 400
{
  "error": {
    "code": "invalid",
    "message": "The request is invalid — `details.field` names the field when there is one."
  }
}

Delete a record

DELETE /records/{ref} data

Scenes that played the record fall back to their own field values.

Parameters

  • ref string required path

    The record ref. It may contain slashes and is used as-is: /records/your-event/session/b-14.

Responses

  • 204 Deleted.
  • 400 The request is invalid — details.field names the field when there is one.
  • 401 Missing or invalid API key.
  • 403 The key lacks the scope, or the role is read-only.
  • 404 Not found in this workspace.
curl -X DELETE "https://www.wunderframe.com/api/v1/records/your-event/session/b-14" \
  -H "Authorization: Bearer $WUNDERFRAME_API_KEY"

204 — no body.

Error example
Response 400
{
  "error": {
    "code": "invalid",
    "message": "The request is invalid — `details.field` names the field when there is one."
  }
}

Update many records

POST /records/batch data

Up to 500 items in one call. Each item's fields are merged into the record for its ref. If no scene plays the ref yet and template names a template scene, a filled scene is created from it.

The whole call is refused with 400 if any item is invalid, naming the first bad one.

Use it for syncs; to create or change a single record, use POST /records or PUT/PATCH /records/{ref}.

Request body required

  • items object[] required

    Up to 500 items

    4 fields in items
    • ref string required

      Pattern ^[A-Za-z0-9][A-Za-z0-9._:/-]{0,199}$

    • fields map of string or number or boolean or null

      Blank name → value, merged into the record. Numbers and booleans are stored as text; values are cut at 2000 characters.

    • template string

      A template scene (its id or its ref). When no scene plays this ref yet, a filled scene is created from it.

    • title string

      The title of a scene created from template.

      Up to 200 characters

Responses

  • 200 What happened.
  • 400 The request is invalid — details.field names the field when there is one.
  • 401 Missing or invalid API key.
  • 403 The key lacks the scope, or the role is read-only.
Response fields (200)
  • updated integer required

    Items whose record already existed.

  • stored integer required

    Items whose record is new.

  • created integer required

    Filled scenes created from a template.

  • unknown string[] required

    Refs that no scene plays yet. Their values are stored all the same and show as soon as a scene uses the ref.

curl -X POST "https://www.wunderframe.com/api/v1/records/batch" \
  -H "Authorization: Bearer $WUNDERFRAME_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "items": [
    {
      "ref": "your-event/session/b-14",
      "fields": {
        "title": "The AI-Native Startup",
        "speaker": "Ada Lovelace"
      }
    },
    {
      "ref": "your-event/session/c-01",
      "fields": {
        "title": "Closing keynote",
        "speaker": "Grace Hopper"
      },
      "template": "your-event/session-template",
      "title": "17:00 · Closing keynote"
    }
  ]
}'
Response 200
{
  "updated": 12,
  "stored": 2,
  "created": 1,
  "unknown": [
    "your-event/session/c-01"
  ]
}
Error example
Response 400
{
  "error": {
    "code": "invalid",
    "message": "The request is invalid — `details.field` names the field when there is one."
  }
}