Metadata
metadata is a set of your own key-value pairs on an object: the ID of the record in your CRM, the team that owns
it, the run of the sync that wrote it. Sursa stores it, returns it with the object and in events, and lets you filter
the lists of cards, collections and folders by it. It does not interpret it in any way.
{
"id": "3f2c9a7e-5b1d-4c8e-9f0a-1b2c3d4e5f60",
"title": "Refund policy",
"metadata": {"crm_id": "A-1042", "team": "support"}
}
Objects with metadata: cards, collections and folders. A document of a
custom source carries metadata too; it becomes the metadata of the
document's card.
Limits
| Limit | Value |
|---|---|
| Pairs per object | 50 |
| Key | 1 to 40 characters from A-Z, a-z, 0-9, _, . and -, starting with a letter or a digit |
| Value | A string of up to 500 characters |
| The whole object | Up to 8 KiB as JSON |
A request that breaks a limit returns 400 with the code api.metadata_invalid.
error.details.key names the key, and error.details.reason says what is wrong: too_many_keys, key_invalid,
value_too_long, too_large or value_invalid (the value is not a string).
Values are strings. Store numbers and dates as strings too, for example "2026-10-24".
Set metadata
When you create or replace an object (POST, PUT), metadata is set as a whole:
curl -X PUT https://api.sursa.com/v1/cards-by-external-id/policy-refunds \
-H "Authorization: Bearer $SURSA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "Refund policy",
"body": "Refunds are processed within 14 days.",
"metadata": {"crm_id": "A-1042", "team": "support"}
}'In a multipart/form-data request, such as a file upload, send metadata as a form field whose value is the JSON
object: metadata={"crm_id":"A-1042"}.
Update metadata
PATCH merges the keys you send into the existing ones. A key with the value "" or null is removed; keys you do
not send stay as they are:
curl -X PATCH https://api.sursa.com/v1/cards/3f2c9a7e-5b1d-4c8e-9f0a-1b2c3d4e5f60 \
-H "Authorization: Bearer $SURSA_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"metadata": {"team": "billing", "legacy_flag": null}}'{"id": "3f2c9a7e-5b1d-4c8e-9f0a-1b2c3d4e5f60", "title": "Refund policy", "metadata": {"crm_id": "A-1042", "team": "billing"}}
"metadata": {} changes nothing. To remove all pairs, send each key with null.
Filter by metadata
These lists accept metadata[<key>]=<value>:
- cards:
GET /v1/cardsandGET /v1/cards/count; - collections:
GET /v1/collections; - folders:
GET /v1/foldersandGET /v1/collections/{name}/folders.
It matches the value exactly. You can combine up to 3 conditions, and an object must match all of them:
curl -G https://api.sursa.com/v1/cards \
-H "Authorization: Bearer $SURSA_API_KEY" \
--data-urlencode "metadata[team]=support" \
--data-urlencode "metadata[crm_id]=A-1042"With a filter, a folder tree comes as a flat list: folders of each collection holds the matching folders with
empty children, and parent_id tells where each one sits. GET /v1/folders then leaves out the collections without
matching folders. More than 3 conditions or an invalid key returns 400 with the code
api.metadata_invalid.
What metadata is not
- It is not content. Search and the assistant's answers do not use it. Put what people should find into the text of the card, its title or its tags.
- It is not private. Everyone who can see the object can see its metadata. Never store secrets, tokens or personal data that the object's readers should not see.
- It is not a substitute for
external_id. To find a card by the ID of your record, give the card anexternal_id; it is unique, while metadata values are not.