Check a change of one kind and sign a plan for it, without writing anything.
POST/ai-builder-api/projects/:projectId/changes/plan
The caller's AI writes a change of one kind; the server validates it
against that kind's schema and against what exists now (CRM, modules,
saved customization) and answers what applying it would do. Nothing is
written and no model is called. planId is a signed token over
{projectId, locationId, kind, changeHash} that expires at expiresAt;
it is null when ok is false. The location is the session's, never
the body's. Kinds: records, modules, appearance, mobile,
assets, domain; any other kind is 400 unsupported_change_kind
naming the supported ones. assets plans also return upload: PUT the
image bytes to upload.url with upload.headers, then apply (apply is
409 customizer_image_not_uploaded until they land, and the plan stays
open). domain apply returns the DNS records to add in
result.dnsRecords; GET /custom-domains reports when it is active.
Request
The API version.
v3The project's id.
Possible values: Value must match regular expression ^prj_[A-Za-z0-9_-]+$
- application/json
- Body
- Example
Bodyrequired
records, modules, appearance, mobile, assets or domain.
Possible values: Value must match regular expression ^[a-z][a-z_]{0,39}$
The change, in the shape GET /changes/schema gives for kind.
{
"kind": "modules",
"change": {
"enable": [
"courses"
],
"disable": []
}
}
The checked plan, or the problems to fix first.
- application/json
- Schema
- Example (auto)
- Example
Schema
Signed, expiring plan id; null when ok is false.
True when the change is valid and can be applied.
The change, in one line.
What apply would do, one line per step, in order.
Why the change cannot be applied, when ok is false.
Things to know before applying; they do not block it.
When planId stops working; null when ok is false.
Where to upload the file the change needs, for a change that needs one.
{
"planId": "cp1.eyJwIjoicHJqXzVmMGMyYTNlIn0.c2lnbmF0dXJl",
"ok": true,
"summary": "Turns off Communities",
"diff": [
"Turn off the Communities module"
],
"errors": [
{
"path": "change.disable.0",
"message": "Unknown module \"forum\"",
"fix": "Send one of: courses, communities"
}
],
"warnings": [
"Members lose access to their community posts"
],
"expiresAt": "2026-10-15T10:30:00.000Z",
"upload": {
"method": "PUT",
"url": "https://storage.example.com/uploads/asset-1.png?signature=abc123",
"headers": {
"Content-Type": "image/png"
},
"assetId": "ast_7b2e91",
"publicUrl": "https://assets.example.com/asset-1.png",
"expiresAt": "2026-10-15T10:15:00.000Z"
}
}
1 modules step(s) ready to apply.
{
"planId": "cp1.WyJwcmpfMSIsImxvY18xIiwibW9kdWxlcyIsImFiYyIsMTc2MDAwMDAwMDAwMF0.c2ln",
"ok": true,
"summary": "1 modules step(s) ready to apply.",
"diff": [
"Turn on Courses"
],
"errors": [],
"warnings": [],
"expiresAt": "2026-10-07T12:30:00.000Z"
}