# API リファレンス

> DocRelay の公開 API のリファレンス。帳票の発行、テンプレート、レイアウト、完了通知（Webhook）、保存期間、改ざん検知、スコープ、レート制限。

Source: https://docrelay.jp/docs/api/

DocRelay は提供開始に向けて準備中です。仕様は提供開始までに変更する場合があります。ベース URL は `https://api.docrelay.jp` です。

## 帳票の発行

`POST /v1/renders` で帳票を発行します。`wait` 秒（0〜25、既定 25）以内に完了すれば帳票をその場で返却し（`200`）、完了しない場合は `202` で `Render` を返して、完了時に Webhook で通知します。`wait` に 0 を指定した場合と、50 件を超える一括発行は、非同期で処理します。

**curl**

```bash
curl https://api.docrelay.jp/v1/renders \
  -H "Authorization: Bearer $DOCRELAY_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: inv_88" \
  -d '{
    "template": "請求書",
    "format": "pdf",
    "data": { "customer": { "name": "株式会社サンプル" }, "total": 128000 },
    "wait": 10
  }' \
  -o 請求書.pdf
```

**Node.js**

```js
const res = await fetch('https://api.docrelay.jp/v1/renders', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.DOCRELAY_API_KEY}`,
    'Content-Type': 'application/json',
    'Idempotency-Key': 'inv_88',
  },
  body: JSON.stringify({
    template: '請求書',
    format: 'pdf',
    data: { customer: { name: '株式会社サンプル' }, total: 128000 },
    wait: 10,
  }),
});
if (res.status === 200) {
  const pdf = Buffer.from(await res.arrayBuffer()); // x-render-id・x-content-sha256 ヘッダーも返却
} else if (res.status === 202) {
  const render = await res.json(); // { id: 'rnd_…', status: 'queued', … } → 完了時に render.succeeded を Webhook で通知
}
```

| メソッド | パス | 内容 |
| --- | --- | --- |
| POST | `/v1/renders` | 帳票を発行。完了すれば帳票本体（`200`）。`Accept: application/json` または `link` の指定時は `Render`。完了しなければ `202` と `Render` |
| GET | `/v1/renders` | 発行履歴（`template_id`・`status`・`since` で絞り込み。新しい順） |
| GET | `/v1/renders/:id` | 1 件の `Render` |
| GET | `/v1/renders/:id/file` | 帳票本体。保存期間を過ぎて削除した後は `410 gone`、未完了の場合は `409` |
| POST | `/v1/renders/:id/links` | 有効期限付き URL を発行（`expires_in`・`max_downloads`。省略時は 24 時間・回数制限なし） |
| GET | `/d/:token` | 有効期限付き URL による取得（API キー不要）。期限切れ・回数超過の場合は `404`、保存期間を過ぎて帳票を削除した後は `410` |

**リクエストとレスポンス**

```
type RenderRequest = {
  template: string;          // テンプレートの ID または名前
  version?: number;          // 省略時は本番環境で公開中、テスト環境で最新
  format?: 'pdf' | 'xlsx' | 'docx' | 'csv';  // 省略時は先頭の形式
  data?: object;             // 1 件分のデータ
  items?: object[];          // 1〜1,000 件。zip で返却
  merge?: boolean;           // レイアウトのみ: 1 つの PDF に結合
  wait?: number;             // 秒。0〜25（既定 25）
  keep_for?: number;         // 保存期間（秒。既定 86,400）
  link?: true | { expires_in?: number; max_downloads?: number };  // 有効期限付き URL
  metadata?: Record<string, string>;  // 20 個まで。Webhook にも含める
  csv?: {                    // CSV の書き出し方（format が csv のときだけ）
    newline?: 'crlf' | 'lf';  // 既定 crlf
    trailing_newline?: boolean;  // 最後の行のあとの改行（既定 true）
    bom?: boolean;           // UTF-8 の BOM（既定 true）
    encoding?: 'utf-8' | 'shift_jis';  // 既定 utf-8
    quote?: 'minimal' | 'all';  // minimal は必要なときだけ、all はすべて囲む
  };
};

type Render = {
  id: string;                // rnd_…
  status: 'queued' | 'rendering' | 'succeeded' | 'failed' | 'expired';
  template_id: string; version: number; format: string;
  filename: string; size: number | null; sha256: string | null; item_count: number;
  error: { code: string; message: string } | null;
  ledger: { seq: number } | null;
  link: { url: string; expires_at: number } | null;
  metadata: Record<string, string>;
  created_at: number; completed_at: number | null; expires_at: number | null;
};
```

- その場で返却するときのヘッダー: `content-type`、`content-disposition`（日本語のファイル名に対応）、`x-render-id`、`x-content-sha256`。
- `Idempotency-Key` ヘッダー（任意）を指定すると、24 時間以内の同じキーによる再送には同じ発行結果を返します。
- リクエスト本文は 5MB までです。
- 本番環境の発行は、帳票 1 件ごとに月間発行数に含みます（一括発行は件数分）。テスト環境の発行とプレビューは含みません。
- 応答には `Server-Timing`（認証・テンプレートの読み込み・フォント・描画などの段ごとの ms）を付けます。`X-DocRelay-Timing: cpu` を付けると、描画の CPU 時間 `cpu` も返します。

## テンプレート

| メソッド | パス | 内容 |
| --- | --- | --- |
| GET | `/v1/templates` | テンプレートの一覧 |
| POST | `/v1/templates` | JSON の `{ name, layout? }` でレイアウトのテンプレートを作成（`layout` 省略時は空の A4）。または multipart の `file`（xlsx・docx）と `name` でアップロード |
| GET・PATCH・DELETE | `/v1/templates/:id` | 取得・変更（名前・ファイル名・サンプルデータ）・削除。`:id` には ID またはテンプレート名を指定。削除しても発行履歴と改ざん検知ログは残ります |
| PUT | `/v1/templates/:id/layout` | レイアウトを保存。最新バージョンが下書きの場合は上書きし、公開済みの場合は新しい下書きのバージョンを作成 |
| POST | `/v1/templates/:id/versions` | 同じ種類の xlsx・docx をアップロードして、新しい下書きのバージョンを作成 |
| POST | `/v1/templates/:id/versions/:v/publish` | バージョンを公開。以後、本番環境の API キーはこのバージョンで発行 |
| POST | `/v1/templates/:id/preview` | プレビュー。`data` 省略時はサンプルデータを使用。発行履歴に残さず、月間発行数にも含みません。不足している差し込み項目を `x-missing-fields` ヘッダーで返却 |

## レイアウト

テンプレートエディターで作成するレイアウトは JSON で表し、`PUT /v1/templates/:id/layout` で保存できます。長さの単位は mm、原点は用紙の左上です。書き方の説明とサンプルは、MCP の `get_layout_guide` でも取得できます。

| 要素 | 内容 |
| --- | --- |
| `text` | 文字。折り返し・縮小・切り取り、枠線・背景、`rotate`（回転）・`opacity`（不透明度） |
| `line` | 線（太さ・色・破線） |
| `rect` | 矩形（枠線・背景・角丸） |
| `image` | 画像（`data:` または https の URL。差し込み項目で渡すこともできます） |
| `table` | 明細テーブル。データの配列の件数だけ行を増やし、入りきらない行は次のページに続けます（見出しをくり返す） |
| `flow` | 本文。枠から書き始め、入りきらない分を次のページに流します。中身は Markdown か、データのブロック（見出し・段落・箇条書き・表・横線・改ページ） |

### 明細テーブルと本文の表

- `wrap: true` でセルの文字を列の幅で折り返し、行の高さを最も高いセルに合わせます。ページに入らない行は、セルの中の行の単位で次のページに分けます。
- 行のデータの `_span`（列をまたぐ）・`_align`（寄せ）・`_bold`（太字）で、行ごとに見た目を変えられます。
- 列の `rich` に指定した項目（`[{ text, bold?, color?, underline? }]`）で、一部の文字だけ太字・色・下線を変えられます。本文の Markdown では `**太字**`・`<u>下線</u>` を使えます。
- `headerBold`（見出しの行の太字）・`padding`（セルの内側の余白）・`lineHeight`（セルの行の高さ）を指定できます。
- 本文の表のセルには、段落・箇条書き・表を 1 段まで入れ子にできます（データのブロックのみ）。

### そのほかの指定

- `follow: { id, gap? }`: 表・本文の実際の終わりに合わせて、合計欄などの要素を詰めて置きます。入りきらなければ次のページに送ります。
- `repeat`: 表と本文以外の要素を、最初のページ・すべてのページ・最後のページのどれに描くかを指定します。
- `watermark: { text, size?, color?, opacity?, angle?, tile?, gap? }`: すべてのページに半透明の文字を重ねます。`tile: true` でページ全体にくり返します。
- 差し込み項目: `{{a.b}}`・`{{x | number}}`・`{{d | date:YYYY年M月D日}}`・`{{#list}}…{{/list}}`・`{{^x}}…{{/x}}`・`{{_page}}`・`{{_pages}}`。
- レイアウトの形式の誤りは `422 invalid` で、`fields` に `elements[3].w` のような項目ごとの説明を返します。

## 完了通知（Webhook）

イベントは `render.succeeded`・`render.failed` の 2 種類です。本文は `{ type, data: Render }` です。送信先の登録方法は、提供開始時にご案内します。

**本文の例**

```
{
  "type": "render.succeeded",
  "data": {
    "id": "rnd_…", "status": "succeeded", "filename": "invoice_1024.pdf",
    "sha256": "a3f9…", "item_count": 1, "link": null, …
  }
}
```

## 保存期間

帳票の保存期間は `keep_for`（秒）で指定します。既定は 86,400 秒（24 時間）で、上限はプランの保存期間です。保存期間を過ぎた帳票は削除し、発行の記録（ハッシュ値・サイズ・ファイル名）と改ざん検知ログだけを残します。

## 改ざん検知ログ

ブロックチェーン技術を応用した改ざん検知です。発行した帳票の SHA-256・発行 ID・テンプレートとバージョン・日時を、1 つ前の記録と連結して記録します。差し込んだデータは記録しません。日次ハッシュ（UTC の日単位）を公開します。

| メソッド | パス | 内容 |
| --- | --- | --- |
| GET | `/v1/ledger/:render_id` | その帳票の改ざん検知ログと、その日の日次ハッシュまでの連結（日次ハッシュの確定前は `head` が `null`） |
| POST | `/v1/ledger/verify` | 帳票ファイルまたは `{ sha256 }` を送信し、この環境で発行した帳票かを検証 |
| GET | `/ledger/heads` | 公開中の日次ハッシュ（API キー不要。`date` 省略時は直近 30 日） |

```
type LedgerEntry = {
  seq: number;               // 通し番号
  render_id: string; sha256: string; template_id: string; version: number;
  at: number;
  prev_hash: string;         // 1 つ前の記録の entry_hash
  // prev_hash・seq・sha256・render_id・at を "\n" でつないだ SHA-256
  entry_hash: string;
};
type DailyHead = { date: string; seq: number; entry_hash: string; published_at: number };
```

## API キーのスコープ

| スコープ | 操作 |
| --- | --- |
| `templates:read` | テンプレートの取得・プレビュー |
| `templates:write` | テンプレートの作成・変更・削除・公開 |
| `renders:create` | 帳票の発行 |
| `renders:read` | 発行履歴・帳票ファイル・有効期限付き URL・改ざん検知ログの取得と検証 |

`GET /v1/whoami` は、どのスコープでも呼び出せます。API キーの環境・プロジェクト・組織を返します。

## レート制限とエラー

- レート制限は環境単位で、1 分あたりの上限はプランによって異なります（Free 60 回・Starter 300 回・Pro 1,200 回・Business 3,000 回）。すべてのレスポンスに `x-ratelimit-limit`・`x-ratelimit-remaining`・`x-ratelimit-reset` を付けます。上限を超えると `429 rate_limited` と `retry-after` を返します。
- エラーは `{ error, message, fields?, request_id }` の形式で返します。入力の誤りは `422 invalid` で、`fields` に項目ごとの説明を含みます。
- 失敗したリクエストは、管理画面の API ログで 30 日間確認できます。
