API の使い方
サーバー間の API です。セッション・Cookie はなく、すべてのリクエストに Authorization: Bearer <token> を付けます。サービス画面の使い方は はじめに をご覧ください。/api/* の応答は、エラーも含めてすべて JSON で、Cache-Control: private, no-store です。
トークン
クライアントはトークンの SHA-256 ハッシュで登録します。サービス画面の「API クライアント」で発行する(発行したアカウントのクライアントになります)か、クライアント側で作ったトークンのハッシュを php artisan api-clients:register {name} {sha256} [--days=N] で登録します。トークンがない・形が違う・未登録・期限切れ・失効済みの場合は 401 {"message": "Unauthenticated."} と WWW-Authenticate: Bearer を返します。
1 クライアントあたり毎分 600 リクエストまでです。応答には X-RateLimit-Limit と X-RateLimit-Remaining が付き、超えると 429 と Retry-After を返します。
納品(コーディングの依頼)
CANVAS と原稿を渡して、HTML/CSS の納品を依頼します。画面で発行したクライアントは、発行したアカウントの納品を扱います(サービス画面で依頼したものも見えます)。コマンドで登録したクライアントは、自分で依頼した納品だけを扱います。生成は裏で進むので、依頼は 202 で受け付け、status が completed か failed になるまで読み直します。
| リクエスト | 内容 |
|---|---|
GET /api/v1/templates | 依頼できる媒体(preset。media-contract の媒体 ID)と、CANVAS の枚数・順・制作枠。 |
GET /api/v1/templates/{preset} | その媒体の原稿の記入例(manuscript、原稿の契約 magic://schemas/manuscript/v1 の形)と、その媒体の原稿のスキーマ(manuscript_schema)。記入例の値をすべて書き換えてから送ります。 |
POST /api/v1/deliveries | multipart/form-data で manuscript(原稿の JSON)・canvases[](PNG・JPEG・WebP、原稿の構成の面・ページ・スライドの順に 1 枚ずつ。ランディングページは PC、SP の順)・任意の preset(省略すると原稿の media.id)・任意の title。202 と Location。原稿が JSON でない・原稿の契約に合わない・媒体が違う・まだ作れないもの(フォーム・QR コード・添付ファイル)がある・CANVAS の枚数が面・ページの数と違う場合は 422。 |
GET /api/v1/deliveries | 納品の一覧(新しい順、20 件ずつ、?page=)。 |
GET /api/v1/deliveries/{id} | 状態(queued・generating・completed・failed)、検査の結果 check、error、download_url。 |
PATCH /api/v1/deliveries/{id} | JSON の title だけなら 200。manuscript(JSON のオブジェクトか、その文字列。同じ媒体で同じ面・ページの数)か "generate": true は新しい版として描き直し、202。生成中は 409。 |
DELETE /api/v1/deliveries/{id} | 納品と、その CANVAS・納品物を消します(204)。 |
GET /api/v1/deliveries/{id}/project.zip | 今の版のプロジェクトフォルダの ZIP。検査に通らなかったときも、最後に書いたものを取れます。まだなければ 404。 |
curl -sS https://coder.magichtml.dev/api/v1/deliveries \ -H "Authorization: Bearer $TOKEN" -H 'Accept: application/json' \ -F preset=banner -F title='灯台珈琲のバナー' \ -F manuscript=@manuscript.json -F 'canvases[]=@canvas.png'
{
"data": {
"id": "01k…", "title": "灯台珈琲のバナー", "preset": "banner", "status": "completed", "revision": 1, "turns": 2,
"pages": 1, "canvases": [{"position": 1, "label": "バナー", "viewport": null, "width": 960, "height": 800, "sha256": "…"}],
"manuscript": {"schema_version": 1, "kind": "publication-manuscript", "media": {"id": "banner", "version": 1}, …}, "check": {"valid": true, "checks": {…}, "violations": [], "warnings": []}, "error": null,
"download_url": "https://coder.magichtml.dev/api/v1/deliveries/01k…/project.zip", "created_at": "…", "started_at": "…", "completed_at": "…"
}
}
原稿は、原稿の契約(magic://schemas/manuscript/v1)の JSON です。content.items が載せる項目、structure が面・ページ・セクションの構成で、AI は各ページにその構成の部分が指す項目をすべて、原稿の値のまま載せます。納品物の m-field のキーは掲載項目のキー(部分に分けたときは「キー-部分」)で、リンク先は原稿にあるものだけです。画像の項目は CANVAS から切り出します(原稿の src のファイルは使いません)。
依頼できる媒体:landing、html-email、business-card、business-card-vertical、flyer、flyer-a4-landscape、flyer-a3、flyer-a3-landscape、flyer-b5、flyer-b5-landscape、book-cover、slide、slide-4x3、banner、banner-336x280、banner-160x600、banner-300x600、banner-728x90、banner-970x90、banner-970x250、banner-300x50、banner-320x50、banner-320x100、banner-1200x628、banner-1200x1200、banner-900x1600、youtube-thumbnail、x-post、x-profile、x-header、line-rich-message、instagram-story、instagram-post、instagram-carousel、note-cover、ogp
POST /api/v1/projects/check
multipart/form-data の zip に、プロジェクトフォルダの ZIP(アーカイブの直下に project.json)を送ります。合否にかかわらず 200 で、成果物の契約の project:check の結果に、違反ごとの修正指示 repair を足した JSON を返します(php artisan coder:check と同じ)。repair.scope は直す場所で、html(ページの HTML・CSS)、contract(project.json・page.json などの定義)、content(保存された値)、environment(送り方・検査の環境)、folder(フォルダの構成・ファイル名・ファイルの有無)のどれかです。専用の指示がない違反は "repair": null です。ページの HTML で見つけた違反には、そのページ ID(page)が付き、repair.selector にその要素の XPath(結果の anchors から)が入ります。HTML の中の参照(外部の画像など)やスタイルの目印についてのフォルダの違反も、repair.selector にその要素の XPath が入ります。警告(warnings)は違反と同じ形で、"repair": null です。受け付けるのは magic://schemas/project/v2(schema_version: 2)のフォルダだけです。
{
"path": "site.zip",
"valid": false,
"schema": "magic://schemas/project/v2",
"checks": {"read": "passed", "layout": "failed", ...},
"violations": [{
"code": "binding.field", "path": "...", "target": "...", "expected": "...", "actual": "...", "message": "...",
"page": "pages:<uuid>",
"repair": {"scope": "html", "candidates": ["summary"], "selector": "/*/*[2]/*/*/*[4]/*[2]", "instruction": "...", "steps": ["..."]}
}],
"warnings": [],
"html_checked_pages": [], "contract_checked_pages": [], "html_compared_pages": [],
"anchors": {"pages:<uuid>": {"<target>": "<XPath>"}},
"source_sha256": "..."
}
ZIP は 42.0 MiB まで受け付けます。422 は読める ZIP がなかったことを表します(zip がない、アップロードの失敗、上限超え、ZIP として開けない)。ファイル数や展開後の大きさの上限超え、安全でない名前やパスは 200 の違反として返します。アップロードは検査の間だけ非公開の作業ディレクトリに置き、終わったら消します。
curl -sS https://coder.magichtml.dev/api/v1/projects/check \ -H "Authorization: Bearer $TOKEN" -H 'Accept: application/json' \ -F zip=@my-project.zip
POST /api/v1/pages/check
書いている途中のページを 1 枚ずつ検査します。JSON の本文に、ページの html、その page(UUID か pages:UUID)、検査に要るプロジェクトの文脈 project(Project の契約データ)と pages(全ページの定義)を送ります。HTML と値は送られたとおりに検査します(前後の空白も変えません)。合否にかかわらず 200 で、projects/check と同じ形の結果(scope は page、違反ごとに repair か null)を返します(php artisan coder:check-page と同じ)。本文が形に合わなければ 422 です。
curl -sS https://coder.magichtml.dev/api/v1/pages/check \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"project": {...}, "pages": [...], "page": "<uuid>", "html": "<!doctype html>..."}'
GET /api/v1/schemas/project/v2/{file}
プロジェクトフォルダの契約の JSON Schema(draft 2020-12)を application/schema+json で返します。ほかの名前は 404 です。
canvases.schema.jsoncollection.schema.jsoncomponent.schema.jsoncontent-schema.schema.jsoncontent.schema.jsonform.schema.jsonpage.schema.jsonproject.schema.jsonprovenance.schema.json
GET /api/v1/schemas/{names|media}/v{n}
プロジェクトのスキーマが $ref で参照する、media-contract のスキーマです(キー・パス・URL の名前の規則と、媒体の一覧)。スキーマの $id は、magic://schemas/ を https://coder.magichtml.dev/api/v1/schemas/ に置き換えると、ここの URL になります。検証するときは、この対応で $ref を解決してください。
magic://schemas/media/v1→/api/v1/schemas/media/v1magic://schemas/names/v1→/api/v1/schemas/names/v1
そのほか
GET /up はヘルスチェックです。GET / は Accept: application/json のときサービス名と版を JSON で返します。