API
画面でできることは、すべて /api/v1 でもできます。プロジェクトフォルダを開き、ページを操作で編集し、保存して、フォルダを持ち出します。
認証
- ログインして「アカウント」→「APIトークン」でトークンを発行します。トークンは発行した画面で一度だけ表示されます。有効期間は 90 日です。
- 要求に
Authorization: Bearer <トークン>を付けます。
トークンは発行したアカウントのものです。そのアカウントが開けるプロジェクトだけを扱え、権限(編集できる・見るだけ)もアカウントと同じです。いらなくなったトークンは同じ画面で失効させます。
応答はすべて JSON(フォルダのダウンロードは ZIP)で、Cache-Control: private, no-store です。
export EDITOR=https://editor.magichtml.dev
export TOKEN=... # 発行したトークン
curl -H "Authorization: Bearer $TOKEN" $EDITOR/api/v1/projects
プロジェクト
| 要求 | すること |
|---|---|
GET /api/v1/projects |
開けるプロジェクトの一覧 |
POST /api/v1/projects/folder |
プロジェクトフォルダか素のサイト(multipart の zip)を開いて、新しいプロジェクトにする(201) |
GET /api/v1/projects/{id} |
1 つのプロジェクト |
PATCH /api/v1/projects/{id} |
名前を変える({"title": "..."})。履歴に残り、元に戻せる |
DELETE /api/v1/projects/{id} |
削除する。オーナーだけ |
GET /api/v1/projects/{id}/folder |
保存版をプロジェクトフォルダ(ZIP)で持ち出す |
GET /api/v1/projects/{id}/folder/{version} |
過去の版のフォルダ |
POST /api/v1/projects/{id}/folder |
フォルダで中身を置き換える。1 つの変更として履歴に残る |
GET /api/v1/projects/{id}/pages |
ページの一覧 |
プロジェクトは次の形で返ります。
{
"id": "0f8c…",
"title": "灯台珈琲",
"media": {"id": "web", "version": 1},
"medium": "Webサイト",
"role": "editor",
"owner": true,
"pages": 3,
"revision": 12,
"created_at": "2026-10-10T09:00:00+00:00",
"updated_at": "2026-10-10T09:30:00+00:00",
"url": "/projects/0f8c…",
"editor_url": "https://editor.magichtml.dev/projects/0f8c…",
"folder_url": "https://editor.magichtml.dev/api/v1/projects/0f8c…/folder"
}
role は呼び出したアカウントの権限(owner・editor・viewer)で、owner はオーナーのとき true です。editor_url を人に渡すと、そのプロジェクトが編集画面で開きます(その人がメンバーのとき)。
メンバー
| 要求 | すること |
|---|---|
GET /api/v1/projects/{id}/members |
メンバーの一覧(id・name・email・role)。メンバーなら誰でも |
PUT /api/v1/projects/{id}/members |
{"email": "...", "role": "editor"} で、アカウントをメンバーにする、または権限を変える。オーナーだけ |
DELETE /api/v1/projects/{id}/members/{user} |
メンバーを外す。オーナーは誰でも、ほかのメンバーは自分だけ(抜けると応答の members は null) |
- 権限は
owner(編集・メンバーの管理・削除)、editor(編集)、viewer(見る・持ち出す)です。 - メンバーにできるのは、すでにアカウントがある人だけです。ない人は 422 で、アカウントは事務局が発行します。
- オーナーは 1 人以上必要です。最後のオーナーの権限を下げる・外すと 422 になります。
- フォルダを開いてプロジェクトを作ったアカウントが、最初のオーナーです。
# 依頼者をオーナーにして、編集画面の URL を渡す
curl -X PUT -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"email": "person@example.com", "role": "owner"}' $EDITOR/api/v1/projects/<id>/members
# フォルダを開く
curl -H "Authorization: Bearer $TOKEN" -F zip=@site.zip $EDITOR/api/v1/projects/folder
# 編集したフォルダを持ち出す
curl -H "Authorization: Bearer $TOKEN" -o edited.zip $EDITOR/api/v1/projects/<id>/folder
フォルダが契約に合わないときは 422 で、どの検査で何が問題だったか(checks・violations)を返します。
project.json がなく index.html がある ZIP は、素のサイトとして Web のプロジェクトフォルダに変換してから開きます(サービス画面の使い方の「手元のサイトを開く」と同じ規則)。応答には site が加わります。
"site": {
"pages": [{"file": "index.html", "public_url": "/"}, {"file": "about.html", "public_url": "/about/"}],
"ignored": ["README.md"],
"warnings": [{"code": "site.link_removed", "path": "index.html", "target": "link[href]", "actual": "favicon.ico", "message": "…"}]
}
サイトを変換できないときは 422 で、checks.site が failed、violations のコードは site.external・site.missing・site.file_type・site.page_url・site.read・site.limit のどれかです。
ページを編集する
編集は「ロックを取る → 下書きを開く → 操作する → 保存する → ロックを手放す」の順に行います。
PUT /api/v1/projects/{id}/lock ロックを取る(60 秒以内に繰り返して保つ)
GET /api/v1/pages/{page}/draft 下書きを開く(draft_token を受け取る)
POST /api/v1/pages/{page}/operations 操作する(新しい draft_token が返る)
POST /api/v1/pages/{page}/draft/undo サーバー側で 1 つ戻す(redo でやり直す)
PUT /api/v1/pages/{page}/operations 保存する(ここで検査する)
DELETE /api/v1/projects/{id}/lock ロックを手放す
- 書き込みの要求には
X-Editor-Client: <クライアントID>を付けます。クライアント ID は、実行ごとに作る英数字と._:-の 64 文字までの文字列(UUID でかまいません)です。 - ほかのクライアントがロックを持っているあいだ、書き込みは
423 Lockedになります。応答のlockに、相手の種類と期限が入っています。 - ロックを取るときは
{"kind": "agent", "label": "my-script"}を送ります。labelは、締め出された画面に「編集中」として表示されます。
操作
POST /api/v1/pages/{page}/operations に、直前の draft_token と操作を 1 つ送ります。
{
"draft_token": "…",
"operation": {"kind": "replace", "target": "#hero-title", "html": "<h1 id=\"hero-title\">春の新メニュー</h1>"},
"outline": true
}
kind |
すること | 必要な項目 |
|---|---|---|
insert |
要素を足す | parent、html、任意で before |
move |
要素を動かす | target、parent、任意で before |
remove |
要素を消す | target |
duplicate |
要素を複製する | target |
replace |
要素を置き換える | target、html |
swap |
要素を入れ替える | target、html |
要素は id(#hero-title)か、下書きのアウトラインでの位置(@12)で指定します。"outline": true を付けると、応答の outline に <body> の中の要素が順に並びます(node・tag・id・classes・先頭の text)。@n はその下書きでの番号なので、同じ下書きの draft_token と一緒に使ってください。
操作は検査せずに進みます(速く返すため)。検査は保存のときに一度だけ行います。
保存
PUT /api/v1/pages/{page}/operations に draft_token と、要求ごとに作る commit_id(UUID)を送ります。検査に通ると保存版になり、履歴に 1 つ積まれます。通らないと 422 で、violations に理由が入ります。保存版がほかで変わっていたときは 409 です。
確定した版
人が編集画面で「確定」した版を読み出します。保存(自動保存を含む)とは別です。連携先は、確定した版だけを取り込んでください。
| 要求 | すること |
|---|---|
GET /api/v1/projects/{id}/confirmations/latest |
最新の確定。まだなければ 404 |
GET /api/v1/projects/{id}/confirmations |
確定の一覧(新しい順。per_page、next_page_url でページ送り) |
GET /api/v1/projects/{id}/folder/{version} |
その版の ZIP。X-Content-SHA256 と ETag に ZIP の SHA-256 が入る |
{
"id": "9b1f…",
"version": 42,
"revision": 12,
"sha256": "3a7c…",
"note": null,
"confirmed_at": "2026-10-10T10:00:00+00:00",
"confirmed_by": {"name": "山田"},
"download_url": "https://editor.magichtml.dev/api/v1/projects/0f8c…/folder/42",
"has_unconfirmed_changes": false
}
- 取り込む側は、
download_urlから ZIP を取り、sha256と照らし合わせます。同じsha256は取り込み済みとして扱えます。 has_unconfirmed_changesは、確定のあとに確定と違う状態が保存されているかどうかです。- 確定(
POST /api/v1/projects/{id}/confirmations)は、編集画面から人が行う操作です。API トークンでは 403 になります。
履歴
| 要求 | すること |
|---|---|
GET /api/v1/projects/{id}/history |
履歴と、戻せるか・やり直せるか |
PUT /api/v1/projects/{id}/history |
{"direction": "undo"} または "redo" と、今の revision を送って、保存版を戻す・やり直す |
エラー
| 状態 | 意味 |
|---|---|
| 401 | トークンがない、期限切れ、または失効した |
| 403 | 見るだけの権限で書き込もうとした、またはオーナーでないのにメンバーを変えた・削除しようとした |
| 404 | プロジェクトやページがない、または開く権限がない |
| 409 | ほかで保存されて、手元の版が古い |
| 422 | 入力や契約の違反。errors か violations に理由が入る |
| 423 | ほかのクライアントが編集中(ロックを持っている) |
| 429 | 要求が多すぎる。少し待ってからやり直す |