Skip to content
Heads up — these docs cover Voice Monkey API v3, the current version. If you signed up before the v3 launch, your account is still on API v2 for a limited transition period and the examples below will not work against your account.

Variables API

Read and write variables over HTTP. Use it to plug Voice Monkey into automations that need to share state — sensor readings, occupancy flags, counters, dynamic announcement text — between systems.

GET/POST/PUT/DELETE https://api-v3.voicemonkey.io/variables

The method picks the operation:

  • GET — read one, several, or all variables.
  • POST or PUT — upsert a variable by name (interchangeable).
  • DELETE — remove a variable by name.
Terminal window
curl "https://api-v3.voicemonkey.io/variables?token=YOUR_TOKEN&variable=FIRST_NAME"
{ "name": "FIRST_NAME", "value": "Joe" }

Returns 404 with { "error": "VARIABLE_NOT_FOUND" } if the variable doesn’t exist.

Terminal window
curl "https://api-v3.voicemonkey.io/variables?token=YOUR_TOKEN&variables=FIRST_NAME,CAMERA_STATUS"
{ "FIRST_NAME": "Joe", "CAMERA_STATUS": "motion" }

Variables that don’t exist come back as null rather than producing a 404, so a single call always returns the full requested map.

Terminal window
curl "https://api-v3.voicemonkey.io/variables?token=YOUR_TOKEN"
{ "variables": [
{ "name": "FIRST_NAME", "value": "Joe" },
{ "name": "CAMERA_STATUS", "value": "motion" }
] }

POST and PUT behave identically — both upsert the variable by name. Use whichever fits your tooling.

Terminal window
curl -X PUT https://api-v3.voicemonkey.io/variables \
-H "Content-Type: application/json" \
-d '{
"token": "YOUR_TOKEN",
"variable": "CAMERA_STATUS",
"value": "motion"
}'
{ "name": "CAMERA_STATUS", "value": "motion", "created": false }

Returns 201 (with created: true) the first time a variable is created, then 200 (with created: false) on every subsequent update.

Terminal window
curl -X DELETE https://api-v3.voicemonkey.io/variables \
-H "Content-Type: application/json" \
-d '{ "token": "YOUR_TOKEN", "variable": "CAMERA_STATUS" }'
{ "success": true, "name": "CAMERA_STATUS" }

Setting variables alongside any other API call

Section titled “Setting variables alongside any other API call”

Every public endpoint (/announce, /trigger, /flow, /variables) accepts a var-<NAME> parameter shorthand. Any parameter whose name starts with var- is upserted as a variable before the main action runs, so the new value is visible to placeholders, conditions and webhook chains in the same request.

Terminal window
curl -X POST https://api-v3.voicemonkey.io/announce \
-H "Content-Type: application/json" \
-d '{
"token": "YOUR_TOKEN",
"device": "YOUR_SPEAKER_DEVICE_ID",
"speech": "Hello {NAME}, you have {UNREAD} unread messages.",
"var-NAME": "Joe",
"var-UNREAD": "3"
}'

{NAME} and {UNREAD} are resolved against the values you just sent — no extra round-trip needed.

The same shorthand works on the query string for GET-style calls:

Terminal window
curl "https://api-v3.voicemonkey.io/trigger?token=YOUR_TOKEN&device=DEV&var-CAMERA_STATUS=motion"

When one or more var- updates are applied the response includes a variableUpdates summary so you can verify what landed. For example, calling /announce with two var- params returns:

{
"success": true,
"data": "OK",
"variableUpdates": [
{ "name": "NAME", "created": false, "updated": true },
{ "name": "UNREAD", "created": true, "updated": false }
]
}

Each entry has one of three shapes:

  • { name, created: true, updated: false } — brand-new variable.
  • { name, created: false, updated: true } — existing variable’s value was overwritten.
  • { name, error: "RESERVED_NAME" | "UPSERT_FAILED" | … } — the update was skipped. Reserved names (built-in placeholders like WEBHOOK) are surfaced this way so you can see why the update didn’t apply, without failing the primary action.

If you call POST/PUT /variables with only var-… shorthand parameters and no variable field, the response is { "success": true, "variableUpdates": [...] } instead of the usual MISSING_VARIABLE error — the request is treated as a pure batch upsert.

  • Names are normalised to upper-case (var-name and var-NAME both target NAME).
  • Names must match [A-Z][A-Z0-9_]* — anything else (e.g. var-1bad, var-foo!) is silently dropped.
  • Reserved names (WEBHOOK, WEB_RESPONSE) are rejected and reported via the variableUpdates array as error: "RESERVED_NAME".
  • Object/array values are JSON-stringified, so structured payloads survive intact: "var-PAYLOAD": { "temp": 72 } stores {"temp":72}. Reference fields with the dotted-path syntax inside Flow nodes — {PAYLOAD.temp}.
  • Plan limits only apply when creating a new variable. Updates to existing variables always succeed, even after a plan downgrade.

Errors return a JSON body with an error field and an HTTP status code:

StatusResponse bodyMeaning
400{ "error": "MISSING_VARIABLE" }No variable provided on a write/delete (and no var-… sidecars to fall back on).
400{ "error": "MISSING_VALUE" }No value provided on a write.
400{ "error": "INVALID_VARIABLE_NAME" }Name doesn’t match [A-Z][A-Z0-9_]*.
400{ "error": "RESERVED_VARIABLE_NAME", "message": "<details>" }Name collides with a built-in placeholder (WEBHOOK, WEB_RESPONSE).
401{ "error": "UNAUTHORIZED" }No token supplied.
401{ "error": "INVALID_TOKEN" }Token doesn’t match an active token.
403{ "error": "Variable limit reached for your plan", "upgrade": true }Plan cap hit on a brand-new variable; existing ones can still be updated.
404{ "error": "VARIABLE_NOT_FOUND" }Read or delete of a name that doesn’t exist.
429{ "error": "THROTTLED", "lockoutUntil": "<ISO>" }Per-user safety lockout — back off until the timestamp.
500{ "error": "Failed to upsert variable" }Generic upstream failure on a write — retry with backoff.