API クイックスタート
このページを完了すると、API キーを bearer トークンに交換し、認証情報が操作できる組織とチームを確認して、スレッドを作成し、そのイベント履歴とともに読み戻せるようになります。
以下の各言語の手順は、どちらも完全かつ独立しています。すべての要素は使用前に定義されており、もう一方の手順を参照する必要はありません。タブを 1 つ選び、そのまま進めてください。
次のものが必要です。
- Service Account API キー。組織管理者が発行します。個人用 API キーは存在しません。まだキーがない場合は、認証と API キーを参照してください。
- Service Account が書き込み先チームのメンバーであること。 スレッドを作成するには、選択したチームの現在のメンバーである必要があります。どのチームにも所属していない組織レベルの認証情報は、
/api/v1/meを読み取れますが、記録は作成できません。手順 3 で403 FORBIDDENが返された場合は、管理者にチームへの追加を依頼してください。 - curl の手順:
curlとjq(例では JSON の解析に使用します。jqをインストールしない場合は、レスポンスから値を手動でコピーしてください)。 - TypeScript の手順: TypeScript を直接実行でき、グローバルな
fetchを備えたランタイム。Node.js 22.18 以降、Bun、または Deno を使用できます。Node.js 18 または 20 では、代わりにtsxなどのローダーを使ってファイルを実行してください。パッケージをインストールする必要はありません。例では標準のfetchのみを使用します。型付きクライアントも別途利用できます。TypeScript クライアントを参照してください。
すべてのリクエストは https://apid.dustid.io に送信します。その他のサービス URL については、環境を参照してください。
-
環境を設定する
Section titled “環境を設定する”Terminal window export APID_URL="https://apid.dustid.io"export DUST_API_KEY="your-service-account-key" # read this from your secrets manager以下のファイルを
quickstart.tsとして保存し、node quickstart.ts、bun quickstart.ts、またはdeno run --allow-net --allow-env quickstart.tsで実行します。各手順では、同じファイルにコードを追加していきます。quickstart.ts // Makes the file an ES module, which is what lets the top-level `await`s// below run. (A `.mts` extension, or "type": "module" in package.json,// does the same job.)export {};const apidUrl = "https://apid.dustid.io";const apiKey = process.env.DUST_API_KEY;if (!apiKey) throw new Error("Set DUST_API_KEY in the environment."); -
API キーを bearer トークンに交換する
Section titled “API キーを bearer トークンに交換する”API キーを
/api/v1/*エンドポイントに送信することはありません。x-api-keyヘッダーでキーを渡して、GET /api/auth/tokenで一度トークンに交換します。その後のすべての呼び出しでは、取得した JWT をAuthorization: Bearer <token>として送信します。Terminal window curl -fsS "$APID_URL/api/auth/token" -H "x-api-key: $DUST_API_KEY"{ "token": "eyJhbGciOi...", "expiresIn": 900, "expiresAt": "2026-09-20T22:40:00.000Z" }Terminal window export DUST_TOKEN="$(curl -fsS "$APID_URL/api/auth/token" -H "x-api-key: $DUST_API_KEY" | jq -r '.token')"quickstart.ts type TokenResponse = { token: string; expiresIn?: number; expiresAt?: string };async function exchangeToken(): Promise<TokenResponse> {const response = await fetch(`${apidUrl}/api/auth/token`, {headers: { "x-api-key": apiKey! },});if (!response.ok) {throw new Error(`Token exchange failed: ${response.status} ${await response.text()}`);}return (await response.json()) as TokenResponse;}const { token, expiresIn, expiresAt } = await exchangeToken();console.log(`Token valid for ${expiresIn ?? "unknown"}s (until ${expiresAt ?? "unknown"})`);レスポンスには
tokenが含まれます。また、JWT 自体に有効期限のクレームがある場合は、expiresIn(残り秒数)とexpiresAt(ISO 8601)も含まれます。有効期間をハードコードせず、レスポンスから読み取ってください。現在、トークンの有効期間は短く(約 15 分)、リフレッシュトークンはありません。そのため、長時間実行するジョブでは、実行中にキーを再交換する必要があります。有効期間に関する完全な仕様、キャッシュの実装、および401時に一度だけ更新するパターンについては、認証 → トークンの有効期限と更新を参照してください。 -
組織を確認する
Section titled “組織を確認する”GET /api/v1/meは、コンテキストヘッダーが不要な数少ないエンドポイントの 1 つです。プリンシパル、所属する組織、アクティブな組織など、認証情報そのものについての情報を返します。Terminal window curl -fsS "$APID_URL/api/v1/me" -H "Authorization: Bearer $DUST_TOKEN"{"userId": "6a1f…","email": "sap-connector@example.com","name": "SAP Connector","activeOrganizationId": "b2c7…","organizations": [{ "id": "b2c7…", "name": "Anchor Electronics", "slug": "anchor-electronics", "roles": ["member"] }]}Terminal window # Prefer the active organization; fall back to the first membership.export DUST_ORG_ID="$(curl -fsS "$APID_URL/api/v1/me" -H "Authorization: Bearer $DUST_TOKEN" \| jq -er '.activeOrganizationId // .organizations[0].id')"echo "Organization: $DUST_ORG_ID"quickstart.ts type Organization = { id: string; name: string; slug: string; roles: string[] };type MeResponse = {userId: string;email: string;activeOrganizationId?: string | null;organizations: Organization[];};const auth = { Authorization: `Bearer ${token}` };const meResponse = await fetch(`${apidUrl}/api/v1/me`, { headers: auth });if (!meResponse.ok) {throw new Error(`/me failed: ${meResponse.status} ${await meResponse.text()}`);}const me = (await meResponse.json()) as MeResponse;const organizationId =me.activeOrganizationId ?? me.organizations[0]?.id;if (!organizationId) {throw new Error("This credential belongs to no organization — ask your admin.");}console.log(`Organization: ${organizationId}`); -
チームを選択する(任意)
Section titled “チームを選択する(任意)”記録は、組織内のチームに属します。サポートされている選択肢は 2 つあります。
- 何もしない。
Dust-Ctx-Team-Idを省略すると、API は組織のルートチームで動作します。チームが 1 つだけの組織では、これで手順 4 は完了です。手順 5 の例もこの方法を使用します。 - チームを指定する。
GET /api/v1/teamsは、認証情報がメンバーになっているチームを{ "teams": [ … ], "total": n }の形式で一覧表示します。各チームにはteamId、orgId、nameが含まれます。使用するチームをDust-Ctx-Team-Idとして送信してください。
Terminal window curl -fsS "$APID_URL/api/v1/teams?pageSize=50" \-H "Authorization: Bearer $DUST_TOKEN" \-H "Dust-Ctx-Org-Id: $DUST_ORG_ID" \| jq '.teams[] | { teamId, name }'{ "teamId": "b2c7…", "name": "Anchor Electronics" }{ "teamId": "4e90…", "name": "Line 3 Receiving" }Terminal window # Optional. Leave DUST_TEAM_ID unset to use the organization's root Team.export DUST_TEAM_ID="4e90…"以下のすべてのリクエストでは、
-H "Dust-Ctx-Team-Id: ${DUST_TEAM_ID:-}"を渡します。空の値は、ヘッダーを省略した場合とまったく同じように扱われ、組織のルートチームが使用されます。そのため、この変数を設定した場合も設定しない場合も、同じスクリプトを実行できます。quickstart.ts type Team = { teamId: string; orgId: string; name: string | null };const teamsResponse = await fetch(`${apidUrl}/api/v1/teams?pageSize=50`, {headers: { ...auth, "Dust-Ctx-Org-Id": organizationId },});if (!teamsResponse.ok) {throw new Error(`/teams failed: ${teamsResponse.status} ${await teamsResponse.text()}`);}const { teams } = (await teamsResponse.json()) as { teams: Team[]; total: number };for (const team of teams) console.log(`${team.teamId} ${team.name ?? "(unnamed)"}`);// Optional. Leave DUST_TEAM_ID unset to act in the organization's root Team.const teamId = process.env.DUST_TEAM_ID;// Context headers for every call from here on. The Team header is present// only when a Team was chosen — an undefined value must not be sent.const context: Record<string, string> = {...auth,"Dust-Ctx-Org-Id": organizationId,...(teamId ? { "Dust-Ctx-Team-Id": teamId } : {}),}; - 何もしない。
-
スレッドを作成する
Section titled “スレッドを作成する”スレッドは、1 つのアセットまたはアイテムに対応する記録です。
type: "single"を指定してPOST /api/v1/threadsを呼び出すと、スレッドが 1 つ作成されます。必須フィールドはthread.nameのみで、任意のdata配列には型付きフィールドを格納します。Terminal window curl -fsS "$APID_URL/api/v1/threads" \-H "Authorization: Bearer $DUST_TOKEN" \-H "Dust-Ctx-Org-Id: $DUST_ORG_ID" \-H "Dust-Ctx-Team-Id: ${DUST_TEAM_ID:-}" \-H "Content-Type: application/json" \-d '{"type": "single","thread": {"name": "Tire SZ3J-11-ZJ17","description": "Production asset"},"data": [{ "name": "Serial Number", "type": "text", "value": { "text": "SZ3J-11-ZJ17" } },{ "name": "Max PSI", "type": "number", "value": { "number": 51 } }]}' | tee /tmp/created.json | jq '.created[0] | { threadId, name }'{ "threadId": "0f13c0de-2f1a-4a2e-9f60-6d2f7b9f0a11", "name": "Tire SZ3J-11-ZJ17" }Terminal window export THREAD_ID="$(jq -r '.created[0].threadId' /tmp/created.json)"quickstart.ts type ThreadRecord = { threadId: string; name: string | null };const createResponse = await fetch(`${apidUrl}/api/v1/threads`, {method: "POST",headers: { ...context, "Content-Type": "application/json" },body: JSON.stringify({type: "single",thread: { name: "Tire SZ3J-11-ZJ17", description: "Production asset" },data: [{ name: "Serial Number", type: "text", value: { text: "SZ3J-11-ZJ17" } },{ name: "Max PSI", type: "number", value: { number: 51 } },],}),});if (!createResponse.ok) {const error = await createResponse.json();throw new Error(`create failed: ${error.code} — ${error.message}`);}const { created } = (await createResponse.json()) as { created: ThreadRecord[] };const threadId = created[0]?.threadId;if (!threadId) throw new Error("The server created no Thread.");console.log(`Created ${threadId}`);ステータスは
201 Createdで、ボディーは{ "created": [ … ], "uploadResponses": [] }です。同じエンドポイントではtype: "list"またはtype: "raw"を指定して複数のスレッドを一度に作成できるため、バッチ形式になっています。createdの各エントリーは、生成されたthreadIdを含む完全なスレッド記録です。フィールドのエントリーには
typeとvalueが必要です。valueの形式は型に従い、textの場合は{ "text": "…" }、numberの場合は{ "number": 51 }となります。nameはフィールドのラベルです。フィールド型の完全な一覧については、スレッドガイドを参照してください。 -
GET /api/v1/threads/{thread_id}は、スレッドとそのイベント履歴を返します。すべての書き込みが記録されるため、監査証跡は作成時点から始まります。Terminal window curl -fsS "$APID_URL/api/v1/threads/$THREAD_ID" \-H "Authorization: Bearer $DUST_TOKEN" \-H "Dust-Ctx-Org-Id: $DUST_ORG_ID" \-H "Dust-Ctx-Team-Id: ${DUST_TEAM_ID:-}" \| jq '{ name: .thread.name, fields: [.thread.data[]?.name], events: (.events | length) }'{ "name": "Tire SZ3J-11-ZJ17", "fields": ["Serial Number", "Max PSI"], "events": 1 }quickstart.ts const getResponse = await fetch(`${apidUrl}/api/v1/threads/${threadId}`, {headers: context,});if (!getResponse.ok) {const error = await getResponse.json();throw new Error(`read failed: ${error.code} — ${error.message}`);}const record = (await getResponse.json()) as {thread: { name: string | null };events: unknown[];};console.log(record.thread.name); // "Tire SZ3J-11-ZJ17"console.log(record.events.length); // at least 1 — creation is an eventレスポンスの形式は
{ "thread": { … }, "events": [ … ] }です。正確なイベント数は仕様として保証されません。少なくとも 1 件あることを前提にしてください。
正常に動作しなかった場合
Section titled “正常に動作しなかった場合”| 表示された内容 | 意味 |
|---|---|
交換時の 401 UNAUTHORIZED | API キーが誤っている、取り消されている、または Service Account キーではありません。個人用キーでは認証できません。 |
/api/v1/* 呼び出し時の 401 UNAUTHORIZED | bearer トークンの有効期限が切れています(有効期間は短く設定されています)。再交換して、一度だけ再試行してください。 |
400 ORG_ID_REQUIRED | 組織を範囲とするエンドポイントで Dust-Ctx-Org-Id を省略しています。 |
ヘッダーを示す 400 INVALID_REQUEST | コンテキストヘッダーが UUID ではありません。ヘッダーはエンドポイントが実行される前に検証されます。 |
作成時の 403 FORBIDDEN | Service Account が選択したチームのメンバーではありません。管理者に追加を依頼してください。 |
読み戻し時の 404 | 通常は記録が存在しないのではなく、コンテキストが誤っています。スレッドは、そのスレッドを所有している、または共有された組織とチームでのみ表示できます。 |
すべてのエラーボディーは { code, message, status, detail? } 形式です。また、すべてのレスポンスには、ログに記録する価値のある x-request-id ヘッダーが含まれます。完全なコード一覧、スキャン結果の表、再試行に関するガイダンスについては、エラーとスキャン結果を参照してください。
次に読むページ
Section titled “次に読むページ”- リクエスト規則 — コンテキストヘッダー、ページネーション、ローカライズ。
- エラーとスキャン結果 — エラー仕様の全体。
- スレッド — フィールド型、更新、アーカイブ、一覧表示、検索。
- 識別子 — 物理的な識別子をスレッドにバインドして検証する方法(
/api/v1/tags/*エンドポイント)。 - ファイル — 証拠ファイルをスレッドに添付する方法。
- チームと共有 — チーム間のアクセス。
- TypeScript クライアント — 標準の
fetchに代わる型付きの方法。 - 完全な API リファレンス — OpenAPI 仕様から生成されたすべてのエンドポイント。API サーバーは、
https://apid.dustid.io/api/docsでインタラクティブなリファレンスを、/api/openapi.jsonで未加工の仕様も提供しています。