Validating build configurations
POST /riddle-builder/validate dry-runs build configurations: every item is validated exactly as the real call would validate it, against a scratch Riddle that is discarded before the response. Nothing is created, changed, published or queued, and no Riddle appears in your library.
Use it to check a configuration you are still writing, to find out why one would be rejected without spending a real create or edit on it, and to pre-flight a whole set of similar Riddles in a single request.
Needed subscription plan: Business or Enterprise.
Request
| Property | Required | Type | Description | Default |
|---|---|---|---|---|
builds | ✓ | array | The configurations to check, 1 to 20 entries. See below | |
projectId | integer | The project a creating item would be created in. Defaults to your personal project, and is checked for the same permission a real create needs. Ignored by editing items, which are checked against their own Riddle | ||
strictProperties | boolean | Request-wide default for strict properties; can be overridden per item, exactly as on the batch endpoint |
Each entry of builds is either
{"type": ..., "build": {...}}- a would-be creation, the shape ofPOST /riddle-builderand of a batch item, or{"UUID": ..., "build": {...}}- a would-be edit, the shape ofPUT /riddle-builder/{UUID}(see Editing Riddles).
Exactly one of type/UUID per item; creations and edits can be mixed in one call. An item may carry its own strictProperties, and a per-item publish is accepted and ignored - nothing is built here.
To check a single configuration, send a one-item builds array and read items[0].
{
"builds": [
{
"type": "Poll",
"build": {
"title": "My new poll",
"blocks": [
{
"type": "SingleChoice",
"title": "Which city do you like most?",
"items": [
{ "title": "Berlin" },
{ "title": "Madrid" },
{ "title": "Paris" }
]
}
]
}
},
{
"UUID": "abcdef12",
"build": {
"title": "A new title for an existing Riddle"
}
}
]
}
Response
| Property | Type | Description | Default |
|---|---|---|---|
valid | boolean | Whether every item would be accepted as-is | |
summary | object | Counts over all items: {total, valid, invalid} | |
items | array | One entry per item of builds, in the order you sent them |
Every item entry carries its index, the type it names (or the type of the Riddle an editing item addressed), the UUID for editing items, and valid. Beyond that:
| Property | When | Description | Default |
|---|---|---|---|
build | valid: true | The build configuration the Riddle would end up with, read back the way GET /riddle-builder/{UUID} reports one | |
errors | valid: false | Why the item would be rejected, as a {message, code} list - the same codes exception handling documents. An entry that came from property validation additionally names its property | |
wouldBeRejectedByRequest | only when true | The item is malformed at request level (neither or both of type/UUID, no build, or an undeclared property under strictProperties) rather than at build-configuration level: a real call would reject the whole request over it, not just this item | |
internalError | only when true | Checking this item ran into an error on our side rather than into a rejection: its outcome is unknown (and has been reported to us), the other items are unaffected. A real call with that configuration would answer a 500 |
Every item is answered on its own. One item being rejected - or hitting an internalError - never changes what the others report, and the response is a 200 either way: read valid, not the status code.
{
"success": true,
"code": 200,
"valid": false,
"summary": { "total": 2, "valid": 1, "invalid": 1 },
"items": [
{
"index": 0,
"type": "Poll",
"valid": true,
"build": { "title": "My new poll", "blocks": [ ... ] }
},
{
"index": 1,
"type": "Quiz",
"UUID": "abcdef12",
"valid": false,
"errors": [
{
"message": "QuizSingleChoiceBlock: Property \"items\" is required but not set",
"code": "REQUIRED"
}
]
}
]
}
What it can catch
- Permissions are enforced as they would be for a real call: the project permission a create needs (resolved only if the request contains a creating item, so an edit-only call does not need create permission), and per editing item the edit permission plus the same origin rule
PUT /riddle-builder/{UUID}applies - only Riddles built via the API or generated by the Riddle AI can be edited. - Media URLs are checked. A media URL in the configuration is verified with a live request for reachability, content type and redirect limit, exactly as a real call would - so an unreachable URL is rejected here too. The file itself is never downloaded or stored; see Use media.
Two things worth knowing
errors is not necessarily the complete list. Validation reports the first class of problem it runs into for an item: a rejection that aborts the build - overlapping result percentages, an unusable logic tree, a reference that cannot be resolved - is reported on its own, and the block-level property errors of the very same configuration are only reported once that rejection is gone. So an item that comes back with one error can still come back with further ones after you fixed it. Re-validate after every fix until valid is true; that final true is conclusive.
Send projectId whenever the configuration references another Riddle. A creating item is validated in the project you name, and in your personal project if you name none - exactly where a real create would put it. References to other Riddles (a Placeholder condition, a leaderboard UUID, a FormSelect target) are authorization-checked against that location, so validating a configuration without projectId while the Riddle it points at lives in a team project is rejected with You are not authorized to access <Type> <UUID> - not because the configuration is wrong, but because it was checked in the wrong place. Name the project you actually intend to build in. Editing items are unaffected: they are always checked against their own Riddle's project.
This is also the only way to check the items of POST /riddle-builder/batch beforehand: a batch only enqueues its builds and therefore answers 200 long before any of them is validated - see Batch & asynchronous processing.

