# フォーム

> Kanorioフォームを独自のフロントエンドに配置しましょう。ボット保護、ファイルアップロード、同意確認、連絡先収集を自動的に処理します。

> Markdown version of https://kanorio.com/ja/developers/guides/forms. Append `.md` to any developer docs URL for this format. Index: https://kanorio.com/llms.txt · MCP: https://app.kanorio.com/api/mcp
>
> Translated from the English original: https://kanorio.com/en/developers/guides/forms.md

管理画面の**マーケティング › オンラインフォーム**でフォームを作成し、フロントエンドに表示します。Kanorioはボットやスパムのチェックを行い、回答を保存し、連絡先の作成や更新、確認メールやチームへの通知メールの送信、そして `customers.form.submitted` ウェブフックをトリガーします。

開始する前に、管理画面からフォームIDをコピーしてください。ブラウザから独自のドメインでAPIを呼び出す場合は、[サイト設定 › 開発者](https://app.kanorio.com/settings/developer) の **許可されたオリジン** にそのドメインを追加してください。`localhost` は常に許可されています。

## オプション1: フォーム要素の使用

`<KanorioForm>` は、あらゆる質問タイプ、ファイルアップロード、同意チェックボックスをレンダリングし、ボット保護を実行します。最も迅速な方法であり、アップグレードなしで新しい保護ルールが適用されます。

```tsx
import { KanorioProvider, KanorioForm } from "@kanorio/elements";
import "@kanorio/elements/elements.css";

export function ContactSection() {
  return (
    <KanorioProvider siteUrl="https://s-xxxxxxxxxxxx.kanorio.com">
      <KanorioForm formId="cform12345678901234567890" siteName="Sourdough Studio" />
    </KanorioProvider>
  );
}
```

Reactを使用しない場合は、`<kanorio-form site-url="…" form-id="…">` を使用してください。[Elements](https://kanorio.com/ja/developers/elements) を参照してください。

## オプション2: 独自のマークアップの使用

HTMLを完全に制御したい場合は、Content Delivery APIを直接使用します。

### 1. フォームの読み込み

`GET /api/v1/forms/{id}` は、質問、同意設定、フォームが回答を受け付けているかどうかを返します。`availability.accepting` が `false` の場合、入力欄の代わりに終了メッセージを表示してください。

### 2. フォーム表示時のボットチェックの取得

`GET /api/v1/forms/{id}/challenge` は、この送信に対するボットチェックを返します。その `provider` は、サイト所有者が **サイト設定 › ボット保護** で設定します。

- `kanorio` (デフォルト): `altcha` に組み込まれたプルーフ・オブ・ワークのチャレンジです。SDKが自動的に解決し（中程度の性能のスマートフォンで約0.5秒）、結果を `_tk` として送信します。
- `turnstile`, `recaptcha`, `hcaptcha`: 所有者自身のキーです。そのプロバイダーのウィジェットを `siteKey` と `action`（Turnstileの場合は `cData` も）でレンダリングし、トークンを `captchaToken` として渡します。サーバーはサイト設定から検証するプロバイダーを決定するため、他のプロバイダーからのトークンは拒否されます。

送信ごとに新しいチャレンジを取得してください。チャレンジとウィジェットトークンは使い捨てです。

### 3. 送信

質問IDをキーとした回答を、保護フィールドと共に送信します。ハニーポットフィールドは空である必要があります。

```ts
import { forms } from "@kanorio/sdk/forms";

const SITE_URL = "https://s-xxxxxxxxxxxx.kanorio.com";
const FORM_ID = "cform12345678901234567890";
const client = forms.client({ siteUrl: SITE_URL });

// when the form is shown
const renderedAt = Date.now();
const challenge = await client.challenge(FORM_ID);

// when the visitor submits
// built-in: the SDK solves the challenge; third-party: pass the widget token
const protection = await forms.protectionFromChallenge(FORM_ID, challenge, renderedAt, {
  captchaToken: challenge.provider === "kanorio" ? undefined : widgetToken,
});

const result = await client.submit(FORM_ID, {
  answers: { name: "Ada", email: "ada@example.com", message: "Do you ship?" },
  consent: "checked",
  pagePath: window.location.pathname,
  protection,
});

if (!result.ok) {
  // result.error.code, and result.error.issues for INVALID_ANSWERS
}
```

SDKを使用しない場合、以下のボディで `POST /api/v1/forms/{id}/submit` を実行します（組み込みチェックの場合。サードパーティプロバイダーの場合は `_tk` の代わりに `captchaToken` を送信してください）：

```json
{
  "answers": { "name": "Ada", "email": "ada@example.com" },
  "consent": "checked",
  "pagePath": "/contact",
  "_hp": "",
  "_ts": 1793520000000,
  "_tk": "<solved ALTCHA payload>",
  "_ctx": "cform12345678901234567890"
}
```

送信に成功すると `200` と `{}` が返されます。その間にフォームが終了していた場合、ボディは `{ "state": "closed" }`、`"not_open"`、または `"full"` となります。

| エラーコード | 対処方法 |
|---|---|
| `INVALID_ANSWERS` | `details.issues` に含まれるメッセージを質問IDごとに表示します |
| `VERIFICATION_EXPIRED` | 新しいチャレンジを取得（ウィジェットをリセット）し、再度送信します |
| `DUPLICATE_SUBMISSION` | フォームはすでに送信済みであることを訪問者に伝えます |
| `RATE_LIMITED` | `Retry-After` の時間まで待機してから再試行します |

### ファイルアップロード

ファイルに関する質問の場合、まず `POST /api/v1/forms/{id}/upload-request` でアップロードチケットを要求します。その際、質問ID、ファイル名、タイプ、サイズを `forms.uploadProtectionFromChallenge(FORM_ID, challenge, renderedAt, solved)` からの保護フィールドと共に送信します。組み込みチェックの場合、これは送信時に使用する解決済みのチャレンジと同じです。サードパーティプロバイダーの場合は、チャレンジの `uploadToken` を使用します（ウィジェットトークンは使い捨てであり、送信時にチェックされるため）。返された `headers` を使用して `PUT` で `uploadUrl` にファイルをアップロードし、その後 `uploadId` をその質問の回答として送信します。質問の制限を超えるファイルは `413 FILE_TOO_LARGE` エラーとなります。

## 送信後

- 送信内容は管理画面およびManagement APIの `submissions` に表示されます。
- メールまたは電話番号の回答に基づいて連絡先が作成または更新されます。
- フォームの設定に従って、確認メールとチームへの通知メールが送信されます。
- ウェブフックの購読者に `customers.form.submitted` が通知されます。

## サーバーからの転送

Next.jsのサーバーアクションなど、独自のサーバーから送信することも可能です。レート制限は訪問者ごとに適用されるため、ブラウザから直接送信する方がクォータを保護できます。転送する場合は、ブラウザの保護フィールドを変更しないでください。
