# Manage and edit a hosted site's files

A hosted site is a folder of files: pages, styles, scripts, images and a `config.json`. You can change any of them from the dashboard file manager, or let an AI agent do it through the API with its own key. Every change is checked, versioned and logged.

Available

## Two ways to change a site

| Who | How | Needs |
| --- | --- | --- |
| A person | Open the site in your dashboard and use the file manager: upload, edit, rename, delete, restore an earlier version. | Access to the site's Space through the dashboard. |
| An AI agent | The file endpoints below, with an agent key. | A key with `read:site-files` and, to change files, `write:site-files`. |

Both use the same rules and the same publish path, so a change made by an agent looks exactly like one made by a person, and a person can undo it from the file manager.

## Give an agent access

1. Create an [agent key](https://bynefit.com/docs/agent-keys). It starts in test mode.
2. The agent asks for the permission with `POST /dash/api/v1/agent/access-requests` and a `reason`.
3. The key owner, a manager or admin of the Space, approves it on the key page. It takes effect at once. Bynefit staff do not review it, because the Space is only changing its own site.
4. To let the agent write for real, the owner moves the key from test mode to live. In test mode every write is a dry run.

If the owner stops being a manager or admin, the whole key switches off.

## The calls

All calls are under `/dash/api/v1` and take the key as a Bearer token.

| Call | Permission | What it does |
| --- | --- | --- |
| `GET /sites` | read | The Space's sites: id, name, slug, and whether writes are allowed right now. |
| `GET /sites/{id}/files?prefix=&cursor=` | read | Files under a folder, 100 a page, with size and type. Pass `next_cursor` back as `cursor`. |
| `GET /sites/{id}/files/{path}` | read | One file: text as `content`, binary as `content_base64`, and its `sha256`. |
| `GET /sites/{id}/versions/{path}` | read | The saved versions of a file. |
| `PUT /sites/{id}/files/{path}` | write | Create or replace a file. |
| `DELETE /sites/{id}/files/{path}?base_sha256=` | write | Move a file to the trash. |

`PUT` takes `content` for text or `content_base64` for binary, `base_sha256` (required when the file already exists) and an optional `dry_run`. `config.json` is a file like any other: change a site's header, footer and modules by replacing it, and it is refused if it is not valid JSON.

## Change a file safely

An agent must read a file before it replaces it. The hash from the read proves it saw the current version.

**Read, then replace (bash)**

```
# 1. find the site
curl -H "Authorization: Bearer $BYNEFIT_API_KEY" https://bynefit.com/dash/api/v1/sites

# 2. read the file; keep its sha256
curl -H "Authorization: Bearer $BYNEFIT_API_KEY" https://bynefit.com/dash/api/v1/sites/SITE_ID/files/index.html

# 3. replace it, sending that sha256 back
curl -X PUT -H "Authorization: Bearer $BYNEFIT_API_KEY" -H "Content-Type: application/json" \
  -d '{"content": "<!doctype html>...", "base_sha256": "SHA_FROM_STEP_2"}' \
  https://bynefit.com/dash/api/v1/sites/SITE_ID/files/index.html
```

Add `"dry_run": true` to a `PUT` to check a change without writing it. A dry run is validated, scanned for secrets and checked against storage. It writes nothing, uses none of the daily ceiling and leaves no log entry. A key in test mode gets a dry run from every `PUT` and `DELETE` without asking.

A successful write answers `200`. If the file was saved but the live site could not be updated, it answers `202` with `"published": false` and a `warning`: the file is safe in the site source, so check `published` and retry or tell the owner.

## What is checked on every write

- **Path.** A relative path, with no `..`, no backslashes, no control characters and at most 500 characters. Any segment that starts with a dot (so `.htaccess`, `.env` and `.htpasswd`), any top-level folder that starts with an underscore (such as `_bynli/`) and files Bynefit manages are refused with `protected_path`.
- **File type.** Only site file types. No PHP, shell scripts or executables.
- **Secrets.** Every text file is scanned for keys and tokens. A finding blocks the write, and an agent cannot override it. See [keeping keys safe](https://bynefit.com/docs/site-secrets) for where a key belongs.
- **Size.** 2 MB a file, text or binary. The site's storage quota applies, and an agent stops at the quota instead of running into overage.
- **The site.** An archived, scheduled-for-deletion or deleted site refuses writes.
- **Overwrites.** Replacing or deleting needs the current `base_sha256`, so an agent cannot overwrite an edit a person made after it read the file.
- **Ceiling.** 1,000 live writes (replaces and deletes) a day per key by default, which the key's owner can raise to 10,000. It is a safety ceiling against a runaway agent; each write also costs units. It comes back at midnight, server time.

A version is saved before every replace and delete. A delete moves the file to the trash and never removes it for good; purging stays with a person. Every live write and delete is recorded in the Space activity log with the key, path, size and hash. Dry runs are not logged. File content is never logged.

## Errors

| Status | `error` | What to do |
| --- | --- | --- |
| 404 | `site_not_found`, `file_not_found` | Check the id from `GET /sites` and the path from the file list. |
| 409 | `base_sha256_required` | The file exists. Read it and send its hash. |
| 409 | `file_changed` | Someone changed it after your read. The answer carries `current_sha256`. Read it again and re-apply your change. |
| 409 | `site_not_writable` | The site is archived, scheduled for deletion or deleted. The message says which. |
| 400 | `invalid_cursor` | Use the `next_cursor` the last page returned. |
| 413 | `body_too_large`, `quota_exceeded` | Shrink the file, or free storage. Also `file_too_large` on a `GET` of a file over the size limit. |
| 422 | `invalid_path`, `protected_path`, `invalid_type`, `file_too_large`, `invalid_body`, `invalid_config_json` | Fix the path, file type, size, body or JSON. Nothing was written. |
| 429, 503 | `agent_limits_unavailable` | The write limits could not be checked, so nothing was changed. Try again in a minute. |
| 500 | `read_failed`, `version_failed`, `write_failed`, `delete_failed` | Nothing was changed. Try again, and quote the `request_id` if it repeats. |
| 405 | `method_not_allowed` | Use the method in the calls table. |
| 422 | `secret_blocked` | The file contains something that looks like a key. Remove it and use a secure request instead. `findings` says where. |
| 429 | `agent_write_budget_spent` | Wait for midnight, server time. |
| 403 | `insufficient_scope` | The key lacks the permission. Request it and have the owner approve. |

Quote the `request_id` from any error when you contact support.

## What an agent cannot do

- Delete a file for good, or empty the trash.
- Change the site's plan, domain, publish state or secrets. Those stay in the dashboard.
- Write to a site outside its own Space.

## What exists and what does not

- [Read community resources](https://bynefit.com/docs/resources-read) - List and filter community resources with a developer key. JSON, cursor paging. (Available)
- [Submit a resource for review](https://bynefit.com/docs/resources-submit) - Propose a new entry. A moderator reviews it before it goes live. (Available)
- [Partner events](https://bynefit.com/docs/partner-events) - Partners send their own product events from a page, a server or an app, and read the totals back. Bynefit turns it on per partner. (By approval)
- [Hosted sites runtime](https://bynefit.com/docs/sites-runtime-api) - Events, resources, media, forms and page views for a hosted site, with no key. (Available)
- [Read and edit hosted site files](https://bynefit.com/docs/manage-site-files) - An agent key lists a Space's sites and reads, replaces and deletes their files, with versions, secret scanning and a daily write ceiling. The key owner approves the permission. (Available)
- [Create and manage forms](https://bynefit.com/docs/manage-forms) - An agent key creates forms for a Space, changes their settings and fields, pauses them and deletes unanswered ones, with a daily write ceiling and a test mode. Registration forms and submissions stay out of reach. The key owner approves the permission. (Available)
- [Engagement types and stages](https://bynefit.com/docs/manage-engagement-types) - A Space defines its own kinds of client work with ordered stages inside the existing statuses. Managers edit them on the Engagements page, and an agent key reads and manages them with a daily write budget and a test mode. The key owner approves the permissions. (Available)
- [Client portal API](https://bynefit.com/docs/client-portal-api) - A signed-in client reads their own engagements, documents and messages; a practice manager runs the pipeline. (Available)
- Engagements through an API key or a webhook - Read engagements from your own server, or hear about a change, without a person signed in. (Planned)
- [Every docs page as Markdown](https://bynefit.com/docs/ai-agents) - Add ?format=md to any docs page, or send Accept: text/markdown. (Available)
- [llms.txt index](https://bynefit.com/docs/ai-agents) - A short index of the docs for tools that read llms.txt, at /docs?format=llms. (Available)
- [OpenAPI spec](https://bynefit.com/docs/ai-agents) - An OpenAPI 3.1 description of the v1 API, with the error envelope and security schemes, at /docs?format=openapi. (Available)
- [Agent skill and integration brief](https://bynefit.com/docs/agent-skill) - An installable SKILL.md and a paste-in brief, generated from the same code as the spec. (Available)
- [Agent keys](https://bynefit.com/docs/agent-keys) - A key made for an AI agent: read-only to start, short-lived, test mode first, every call logged, and the owner approves anything more. (Available)
- Request id and docs link on every error - Every error body carries an id to quote to support and a link to the page that explains it. (Planned)
- [Test keys and a sandbox](https://bynefit.com/docs/test-mode) - Keys that only touch sample data, ready at once with no review, so a first attempt cannot break anything. (Available)
- [Idempotency-Key on writes](https://bynefit.com/docs/authentication) - Retry a v1 write without doing it twice: the first answer is replayed for 24 hours, per key. (Available)
- [Status page](https://bynefit.com/docs/status) - Live state, 90-day uptime and incident history for the API, sign-in, webhook delivery, the widget, hosted sites and email. Atom and JSON feeds. (Available)
- [Docs MCP server](https://bynefit.com/docs/docs-mcp) - Read-only search of these docs from an AI tool. (Available)

---

Source: https://bynefit.com/docs/manage-site-files
Checked against the live API on October 18, 2026.
