Long-running work
Methods that answer before the work is done, and how to follow each one to the end.
On this page
Building a site, publishing it, taking a backup and restoring files take longer than one request should wait. The methods that start them answer as soon as the work is under way, and a second method reports how it is going. Your code calls the second one every few seconds until the work reaches an end.
| Work | Started by | Followed with | Finished when |
|---|---|---|---|
| A generation by the site agent | send_message, create_site |
get_job |
state is succeeded, failed or cancelled |
| A publish | publish_site, trigger_deploy_hook |
get_publish_status |
running is false |
| A storage archive | create_storage_backup |
list_storage_backups |
The row reads ready or failed |
| A database archive | create_database_backup |
list_database_backups |
The row reads ready or failed |
| A storage restore | restore_storage_backup |
get_storage_restore_status |
active is false and Status is completed or failed |
Wait a few seconds between calls. Each one spends from the token's per-minute budget, and asking more often does not make the work go faster. See Rate limits.
Generations
send_message hands a prompt to the site agent. When the site is free it starts at once and answers with queued: false and a jobId. When the agent is busy, the message joins the site's queue and the answer carries queued: true instead. create_site creates a site and starts its first build in one call, and answers with the new site and a jobId.
Follow a generation with get_job:
curl -X POST https://api.modulify.ai/v1/get_job \
-H "Authorization: Bearer YOUR_TOKEN" \
-d '{"projectId":"SITE_ID","jobId":"JOB_ID","cursor":0}'The answer carries the state and the events the run has produced, such as text, file changes and tool calls. Send the cursor from each answer back on the next call and you receive only the events that are new. count is the number of events in this answer, and limit asks for up to 500 at a time.
state |
What it means | What to do |
|---|---|---|
running |
The agent is working | Call again in a few seconds |
stalled |
No heartbeat for over a minute | Keep calling. It is not over: Modulify resumes or closes a run that has produced nothing for 15 minutes |
succeeded |
The run ended normally | Read the result. Check incomplete too |
failed |
The run ended with an error | error and errorCode say why |
cancelled |
Somebody stopped it | Nothing more will happen |
Four details matter:
incomplete: trueon a succeeded run means the agent stopped part way through the turn.incompleteReasonsays how. The run was billed and what it changed was kept, so send a follow-up asking it to continue rather than starting over.- Error code
SC-6001on a failed run means the workspace ran out of AI credits part way through. What it changed was kept and only what the balance covered was charged. reset: truemeans the run was retried from the start. Throw away the events you collected and carry on from the newcursor.- Leaving out
jobIdreads the most recent generation of the site, which is how you find a run your code did not start.
cancel_job stops a running generation and keeps whatever the agent had already written. See Building with prompts for the whole conversation, including questions the agent asks and plans waiting for approval.
Publishes
publish_site starts a publish and answers once it has started. If a publish is already running, the answer carries pending: true and the deploymentId of that run instead of starting a second one, so treat it as success and follow that one.
Call get_publish_status until running is false, then read status:
status |
What it means |
|---|---|
ready |
The new version is live |
failed |
The publish failed. error has the reason, and get_publish_logs has the build output |
cancelled |
The publish was stopped |
null |
The site has never been published |
Any other value, such as provisioning or deploying, is a step still in progress. get_publish_timeline shows each step with how long it took, and stop_publish abandons a publish that has not yet switched over. A publish started by trigger_deploy_hook is followed the same way.
Backups
create_storage_backup and create_database_backup answer as soon as the archive is reserved, with a row that reads pending. The archive itself is built later. Read list_storage_backups or list_database_backups until the row reads ready, or failed with the reason. Do not delete or move the files or rows it should hold until it is ready: anything removed before the archive reads it is left out.
create_backup and restore_backup work on the site's pages and components and answer when they are done.
Storage restores
restore_storage_backup is a two-step method, so nothing is overwritten by mistake. The first call, without confirm, changes nothing. It answers with a plan: how many files come back, how many are overwritten or deleted, and a confirm value. The second call sends the same arguments plus that confirm value and starts the restore.
The restore then runs in the background. Call get_storage_restore_status until active is false. Status reads pending, running, completed or failed, and counts such as FilesWritten and FilesFailed show progress. Only completed means the files are back. While a restore runs, the methods that change storage are refused and the ones that read it keep working.
Work that finishes in one call
Exports answer with everything at once. export_collection, export_site_analytics, export_site_crons, export_site_webhooks and export_deploy_hooks return their data in data, with nothing to follow.
Next
- Building with prompts for driving the site agent.
- Pagination for reading long lists.