Write files to a site
write_file
Writes one or more source files straight into the running preview of a site, replacing whatever was at each path.
It takes up to 20 files per call. Each one replaces the whole file rather than patching it, so read the file first with read_file, and a path that does not exist yet is created.
The preview has to be running: with nothing to write to, the call is refused rather than queued, so open the preview first. Each file is confirmed individually by the preview, and the response lists the paths that were written in written and the ones that failed, with the reason, in failed, so read that rather than assuming a success means everything landed.
It is also refused, with the same message send_message and publish_site give, while the site code is being moved into GitHub or back to Modulify, when Modulify has lost access to the GitHub repository that holds the site or that repository was archived or deleted, and when the code lives in the workspace's own GitHub but the workspace is on the Free plan. See Move your code to GitHub.
This does not go through the site AI, so nothing about the change is explained or reviewed, and no code backup is taken when it is written. It only reaches the code backup history, as a Preview sync entry, once the preview is next saved: when the editor opens, just before a publish, or after a chat run is stopped or fails.
Take a backup with create_backup first for anything beyond a small edit. Use send_message instead when someone described what they want rather than exactly what to write, because the AI reads the surrounding code and this does not. See Backups.
Request
Call it with a POST to https://api.modulify.ai/v1/write_file, sending the inputs below as a JSON object. The token needs the code:write scope.
This method is marked destructive: it deletes or overwrites data. Check the inputs before you call it, and send an Idempotency-Key header whenever you might retry it.
curl -X POST https://api.modulify.ai/v1/write_file \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"projectId":"PROJECT_ID","files":[]}'Over MCP, the same method is the write_file tool.
Inputs
| Input | Type | Required | Description |
|---|---|---|---|
projectId |
string | Yes | The site id. |
files |
array of objects | Yes | The files to write, at most 20 per call. Each object has Path, such as app/page.tsx, Content with the complete new contents, and an optional Encoding, utf8 by default or base64 for a binary file. A leading slash in Path is stripped, and a path stepping outside the site is refused. |
Response
Every call answers with the JSON envelope of success, message, data, code and version. data holds the result described above, and on a method that returns a total, count carries it. The response headers carry the call's X-Request-Id and what is left of your per-minute budget in X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset. Errors explains every status code a call can answer with.