Skip to content

Edit through REST

Every change the graphics builder makes to a working Rive graphic is one REST operation. Each operation locks the graphic for the request, validates the whole configuration, saves, and publishes a live update to open builder tabs.

All routes sit under /rest/v2/themes/{themeId}/rive-graphics/{graphicId}. Write routes need themes:write. Each write returns updatedAt, entityId, and the full stateMachine.

Send ifUnchangedSince with the updatedAt you last read. A changed draft answers 409 TARGET_CHANGED. Opening a graphic in the dashboard Graphics Builder takes its edit lock. While that builder tab is open, every REST write answers 409 LOCKED. Close the builder tab, then retry.

The ligr-graphic CLI sends ifUnchangedSince for you and retries once. See Command line.

An error body has message and code. A 4xx answer can also have details, an array with one entry for each problem.

FieldContent
codeThe error code, for example INVALID_CONFIGURATION, UNKNOWN_REFERENCE or INVALID_EXPRESSION.
details[].fieldThe path of the value that failed. The path points into the request body or into the graphic configuration, for example controlVariables[stage].defaultValue or dataBindings[Main.homeScore].expression.
details[].reasonWhat is wrong with the value, for example must be a JSON number.
422 response
{
"message": "INVALID_CONFIGURATION",
"code": "INVALID_CONFIGURATION",
"details": [{ "field": "controlVariables[stage].defaultValue", "reason": "must be a JSON number" }]
}

A 500 answer has only message. The ligr-graphic CLI prints each detail on its own line as field: reason.

Terminal
api POST "themes/$THEME_ID/rive-graphics/$GRAPHIC_ID/control-variables" \
--data '{"name":"stage","type":"enum","options":["GROUP A","FINAL"],"defaultValue":"GROUP A"}'
api PATCH "themes/$THEME_ID/rive-graphics/$GRAPHIC_ID/control-variables/$CONTROL_ID" --data '{"defaultValue":"FINAL"}'
api DELETE "themes/$THEME_ID/rive-graphics/$GRAPHIC_ID/control-variables/$CONTROL_ID?force=true"

Types: string, number, boolean, enum, and the entity types team, player, match, fact, stat, teamStat, period, set, round, court. Entity types carry a server-derived dataSchema in the response. hide is reserved. A control variable default must have the JSON type of the variable. Send 0, not "0". Removing a variable that an expression references answers 422 UNKNOWN_REFERENCE; force=true blanks those expressions.

Binding ids contain dots, so URL-encode them.

Terminal
B="themes/$THEME_ID/rive-graphics/$GRAPHIC_ID/data-bindings"
api PATCH "$B/Main.homeScore" --data '{"expression":"$d.1.score"}'
api PUT "$B/Main.badge/exposure" --data '{"name":"Home badge","expression":"$d.1.id","required":true,"entityType":"team"}'
api PUT "$B/Main.badge/image-transform" --data '{"fit":"cover","outWidth":256,"outHeight":256}'
api PUT "$B/Main.players%5B%5D/source-array" --data '{"arrayPath":"1.lineup"}'
api POST "$B/Main.players%5B%5D/elements"
api DELETE "$B/Main.players%5B%5D/elements/0"
api PUT "$B/Main.players%5B%5D/elements/order" --data '{"order":[1,0]}'

Exposure and image transforms apply to image bindings only. A source array applies to one list binding per graphic. A source array is a path into the match data without the $d prefix, for example 1.lineup for team one’s lineup.

Inputs, assets, user expressions, schemas, settings

Section titled “Inputs, assets, user expressions, schemas, settings”
Terminal
G="themes/$THEME_ID/rive-graphics/$GRAPHIC_ID"
api PATCH "$G/inputs/$INPUT_ID" --data '{"expression":"!$v.hide.value"}'
api PATCH "$G/assets/crest.png" --data '{"expression":"$d.1.logo.url"}'
api PUT "$G/assets/crest.png/exposure" --data '{"name":"Crest","required":true,"entityType":"team"}'
api POST "$G/user-expressions" --data '{"name":"leader","expression":"$d.1.score > $d.2.score ? 1 : 2"}'
api PUT "$G/schemas/tennisRankings"
api PATCH "$G/settings" --data '{"renderer":"canvas","scale":0.5,"name":"Scorebug","sports":["football"]}'
Terminal
api GET "themes/$THEME_ID/rive-graphics"
api POST "$G/duplicate" --data '{"name":"Scorebug copy"}'
api DELETE "$G"

Delete is refused with 409 TARGET_NOT_EMPTY while the active theme version pins a published version of the graphic. Publish, theme snapshots and activation are unchanged; read Import through REST step 6.