# Validate commands

`POST https://api.vidmoat.com/v1/projects/{id}/validate`

- Scope: `projects.read`
- Cost: Free

Dry-run a command batch against the current document and get back per-command results and layout lint, without saving anything. Needs only a read scope.

> **Note.** Read the lint. Numeric x/y/fontSize choices routinely overlap on the real canvas, and this is cheaper than a render to find out.

### Path parameters

- `id` (string, required): The project id.

### Body

- `commands` (array of objects, required): One to 200 commands, applied in order. Each is an object with a string `op` and that op's parameters, exactly as listed by `GET /v1/schema/commands`.

## Response

Returns `200`.

### Response fields

- `projectId` (string): The project.
- `valid` (boolean): Every command would succeed.
- `results` (array): One entry per command: `{ op, ok, error?, data? }`. A failed command is reported here, not as an HTTP error.
- `blocked` (array of strings): Plan-gated features that would be dropped.
- `lint` (array): Layout warnings: `{ severity: "warn" | "note", time, message }`.
- `suggestedPreviewTimes` (array of numbers): Timestamps worth looking at with the preview endpoint before you render.
- `applied` (boolean): Always `false`.

## Errors

Besides the errors any request can get ([authentication](https://developer.vidmoat.com/developer/docs/authentication#when-a-request-is-refused), [rate limits](https://developer.vidmoat.com/developer/docs/rate-limits)):

| Status | Code | When |
| --- | --- | --- |
| 404 | [`not_found`](https://developer.vidmoat.com/developer/docs/errors#not_found) | No such project, or it is not yours. The two are indistinguishable on purpose. |
| 400 | [`invalid_request`](https://developer.vidmoat.com/developer/docs/errors#invalid_request) | The command list is malformed. |

## Request examples

```bash curl
curl -X POST https://api.vidmoat.com/v1/projects/$ID/validate \
  -H "Authorization: Bearer $VIDMOAT_KEY" \
  -H "Content-Type: application/json" \
  -d '{"commands":[{"op":"addTextClip","text":"Hi","start":0,"duration":2}]}'
```

```js Node
const ID = 'YOUR_PROJECT_ID';

const res = await fetch(`https://api.vidmoat.com/v1/projects/${ID}/validate`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.VIDMOAT_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    commands: [
      {
        op: 'addTextClip',
        text: 'Hi',
        start: 0,
        duration: 2,
      },
    ],
  }),
});
const data = await res.json();
if (!res.ok) throw new Error(data.error?.message ?? `HTTP ${res.status}`);
console.log(data);
```

```python Python
import os
import requests

ID = "YOUR_PROJECT_ID"

res = requests.post(
    f"https://api.vidmoat.com/v1/projects/{ID}/validate",
    headers={"Authorization": f"Bearer {os.environ['VIDMOAT_KEY']}"},
    json={
      "commands": [
        {
          "op": "addTextClip",
          "text": "Hi",
          "start": 0,
          "duration": 2,
        },
      ],
    },
    timeout=60,
)
res.raise_for_status()
print(res.json())
```

## Example response

```json
{
  "projectId": "cm1abc",
  "valid": true,
  "results": [{ "op": "addTextClip", "ok": true }],
  "blocked": [],
  "lint": [],
  "suggestedPreviewTimes": [1],
  "applied": false
}
```

---

Source: https://developer.vidmoat.com/developer/docs/api/projects/validate-commands
Previous: [Apply commands](https://developer.vidmoat.com/developer/docs/api/projects/apply-commands.md)
Next: [List workspaces](https://developer.vidmoat.com/developer/docs/api/workspaces/list-workspaces.md)
All documentation: https://developer.vidmoat.com/llms-full.txt
