API ドキュメント / hanamii REST API
REST API を使う
hanamii のワークスペース、プロジェクト、デプロイ、ログ、環境変数、オブジェクトストレージ、API トークンを HTTP リクエストから操作できます。
API の基本
リクエストは HTTPS の REST endpoint に送信します。JSON body を送る POST / PATCH では Content-Type: application/json を指定してください。
GET / DELETE と multipart/form-data の ZIP アップロードでは不要です。
Base URL: https://hanamii.jp Authorization: Bearer <API_TOKEN> Content-Type: application/json # JSON body の場合のみ
認証
すべての公開 API リクエストで Authorization: Bearer <TOKEN> が必要です。
API トークン
トークンはアカウント設定で作成します。平文トークンの表示は作成時のみです。
レート制限
認証入口では IP guard を適用します。認証後は endpoint ごとに制限されます。
認証
すべての公開 API リクエストで Authorization header が必要です。API トークンは hnm_ から始まる Bearer token です。
平文トークンの表示は作成時のみのため、作成後に再表示できません。
Authorization: Bearer <TOKEN>ワークスペースのリソース操作
scopeType=full_account のトークンは、トークン所有ユーザーが所属しているワークスペースを対象にします。scopeType=workspace のトークンは対象ワークスペース内のみ操作でき、実行できる操作はそのワークスペースにおけるユーザー role によって制限されます。
workspaceId は GET /api/v1/workspaces で確認できます。
curl -H "Authorization: Bearer $HANAMII_TOKEN" \ "$BASE_URL/api/v1/workspaces"
操作
owner
admin
developer
viewer
ストレージのバケット・ファイル一覧・閲覧URL・利用量
可
可
可
可
ストレージのバケット作成・削除・キー管理
可
可
不可
不可
プロジェクト一覧・詳細
可
可
可
可
ログ取得
可
可
可
可
環境変数の取得
可
可
可
不可
プロジェクト作成・デプロイ・再デプロイ
可
可
可
不可
環境変数の追加・更新
可
可
可
不可
プロジェクト削除
可
可
不可
不可
データベースの取得
可
可
可
可
データベースの作成・削除・接続トークン・データ閲覧・エクスポート・インポート
可
可
不可
不可
ページネーション
一覧取得では limit で取得件数を指定できます。limit を省略した場合は 20 件、最大は 100 件です。続きがある場合はレスポンスの pagination.next に値が入るため、その値をそのまま until に指定して同じ endpoint を再度呼び出します。pagination.next が null の場合、続きはありません。
このlimit・until・sinceはプロジェクト等の一覧用です。ストレージはcursor/nextCursorを使用し、件数はバケット100・キーとファイル50で固定です。ストレージではlimit・until・sinceは反映されません。
query
用途
limit
取得件数。省略時は 20、最大 100
until
pagination.next の値をそのまま指定して続きの一覧を取得
since
pagination.prev の値をそのまま指定して前方向の一覧を取得
# まず一覧を取得 curl -H "Authorization: Bearer $HANAMII_TOKEN" \ "$BASE_URL/api/v1/projects?workspaceId=$WORKSPACE_ID&limit=20" # 返ってきた JSON の pagination.next を確認 { "pagination": { "count": 20, "next": 1777622400000, "prev": 1777623000000 } } # pagination.next の値をそのまま until に指定 curl -H "Authorization: Bearer $HANAMII_TOKEN" \ "$BASE_URL/api/v1/projects?workspaceId=$WORKSPACE_ID&limit=20&until=1777622400000"
レート制限
レート制限を超過した場合、API は 429 rate_limited を返します。詳しい上限は以下の表を参照してください。レスポンスには X-RateLimit-* ヘッダーが含まれます。
operation
scope
limit
補足
ストレージの一覧・利用量
ワークスペース
500 / 60秒
バケット・ファイル一覧・利用量で共通
ストレージバケット作成
ワークスペース
30 / 3600秒
POST /api/v1/workspaces/:workspaceId/storage/buckets
ストレージバケット削除
ワークスペース
30 / 300秒
DELETE /api/v1/workspaces/:workspaceId/storage/buckets/:bucketId
ストレージキー一覧
ワークスペース
120 / 60秒
GET /api/v1/workspaces/:workspaceId/storage/buckets/:bucketId/access-keys
ストレージキー発行
ワークスペース
32 / 3600秒
POST /api/v1/workspaces/:workspaceId/storage/buckets/:bucketId/access-keys
ストレージキー無効化
ワークスペース
50 / 300秒
DELETE /api/v1/workspaces/:workspaceId/storage/buckets/:bucketId/access-keys/:keyId
ストレージ閲覧URL発行
ワークスペース
120 / 60秒
POST /api/v1/workspaces/:workspaceId/storage/buckets/:bucketId/files/:fileId/view-url
認証試行
同一 IP
60 / 60秒
トークン確認前に適用
認証失敗
同一 IP
30 / 300秒
未認証、不正な Bearer、無効なトークン
トークン一覧 / 取得
ユーザー
120 / 60秒
GET /api/v1/user/tokens 系
トークン作成
ユーザー
32 / 3600秒
POST /api/v1/user/tokens
トークン失効
ユーザー
50 / 300秒
DELETE /api/v1/user/tokens/:id
ワークスペース一覧
ユーザー
120 / 60秒
GET /api/v1/workspaces
プロジェクト一覧 / 取得
ユーザー
500 / 60秒
GET /api/v1/projects 系
プロジェクト作成
ワークスペース
60 / 3600秒
POST /api/v1/projects
プロジェクト削除
プロジェクト
30 / 300秒
DELETE /api/v1/projects/:id
デプロイ / 再デプロイ
プロジェクト
120 / 300秒
POST /api/v1/projects/:id/deploy
AppRun設定反映
プロジェクト
120 / 300秒
POST /api/v1/projects/:id/restart
ZIP uploadUrl / 検証
トークン
120 / 60秒
POST /api/v1/uploads 系
ログ取得
プロジェクト
500 / 60秒
GET /api/v1/projects/:id/logs
環境変数取得
プロジェクト
500 / 60秒
GET /api/v1/projects/:id/env
環境変数更新
プロジェクト
120 / 60秒
PATCH /api/v1/projects/:id/env
ヘルスチェック取得
プロジェクト
500 / 60秒
GET /api/v1/projects/:id/health-check
ヘルスチェック更新
プロジェクト
120 / 60秒
PUT /api/v1/projects/:id/health-check
データベース取得
プロジェクト
500 / 60秒
GET /api/v1/projects/:id/database
データベース作成
プロジェクト
30 / 3600秒
POST /api/v1/projects/:id/database
データベース削除
プロジェクト
30 / 300秒
DELETE /api/v1/projects/:id/database
接続トークン一覧
プロジェクト
120 / 60秒
GET /api/v1/projects/:id/database/auth-tokens
接続トークン発行
プロジェクト
32 / 3600秒
POST /api/v1/projects/:id/database/auth-tokens
接続トークン失効
プロジェクト
50 / 300秒
DELETE /api/v1/projects/:id/database/auth-tokens/:tokenId
テーブル / 行の読取
プロジェクト
500 / 60秒
GET /api/v1/projects/:id/database/tables 系
エクスポート開始
プロジェクト
10 / 3600秒
POST /api/v1/projects/:id/database/exports
エクスポート照会 / URL 発行
プロジェクト
120 / 60秒
GET /api/v1/projects/:id/database/exports/:exportJobId 系
インポート(アップロード先発行 / 取込開始)
プロジェクト
20 / 3600秒
POST /api/v1/projects/:id/database/import-session / import-start
エラー
エラーレスポンスは JSON で返します。
400
validation_error
リクエスト body、query、path parameter が不正
401
unauthorized
認証失敗、message は 認証に失敗しました に統一
403
forbidden
トークン scope または workspace / project 権限不足、またはプランの利用上限到達
404
not_found
対象リソースが存在しない、または参照できない
409
conflict
同じワークスペース内でプロジェクト名が重複
413
payload_too_large
request body または chunk size の上限超過
415
unsupported_media_type
JSON body で Content-Type が application/json ではない
410
gone
保持期限切れなど、期限が過ぎて取り出せなくなったリソース(エクスポート)
429
rate_limited
レート制限超過。X-RateLimit-* header を返却
500
internal_error
内部 message を外部へ返さず固定 message を返却
502
external_api_error
連携先サービスとの操作に失敗した。作成・発行は結果不明の場合あり
503
service_unavailable
連携先サービスが未設定または一時的に利用できない
ストレージをAPIから使う
バケット・アクセスキー・利用量の管理は、他機能と同じHanamii APIトークンで操作できます。バケット・ファイルの一覧と閲覧URL・利用量はメンバー全員、バケット作成・削除とキー管理はowner/adminが利用できます。
ファイルのアップロード・削除・共有URLは、バケット一覧のapiOriginを接続先とし、発行したストレージ専用キーで呼びます。Hanamii APIトークンや内部連携鍵はファイルAPIへ送らないでください。
export BASE_URL="https://hanamii.jp" export WORKSPACE_ID="<対象のワークスペースID>" # HANAMII_TOKENにはAPIトークン画面で発行した値を設定します curl -sS "$BASE_URL/api/v1/workspaces/$WORKSPACE_ID/storage/buckets" \ -H "Authorization: Bearer $HANAMII_TOKEN"
ストレージの一覧はitemsとnextCursor(不透明な文字列。最大1024文字の表示可能なASCII)、日時はISO 8601で返します。すべての応答はno-storeです。作成・発行の応答を受け取れなかったときは、自動で再送せず一覧で結果を確認してください。
ファイルAPIのPOST /v1/files/uploadsでは、name・sizeBytes・contentType・contentMd5がすべて必須です。contentMd5はファイル全体のMD5(16バイト)を標準Base64で表した24文字(末尾は==)で、省略・形式不正は400(VALIDATION_ERROR)になります。計算例と各項目の条件は、ファイル操作の使い方ガイドを参照してください。
閲覧用URLの発行やファイルの完了連絡など、本文のないPOSTをcurlで呼ぶときはContent-Length: 0を付けてください。未指定だと実行環境によって411(No Content Length)で拒否されます。
TypeScript例はサーバーで実行し、HANAMII_TOKENをサーバー環境変数に設定します。Next.js例はserver-onlyの内部関数で、Server Actionではありません。HTTPルート等から呼ぶ前に、アプリ側で利用者の認証と対象ワークスペースの権限を確認してください。キー発行では、サーバー内の秘密情報保管処理をstoreKeyとして渡します。平文キーをログ・ブラウザ・Server Componentのpropsへ渡さないでください。閲覧URLも認可済みの表示だけに使います。
以下は主な応答です。共通のエラー節も参照してください。5xxのmessageは固定文言で、内部の失敗理由は公開しません。キー一覧のcreatedByは発行者ID、creatorEmailは現在もメンバーの場合だけ返し、それ以外はnullです。URLの応答例は例示で、ファイルAPIの実際の接続先はバケット一覧のapiOriginを使います。
エンドポイント一覧
利用できる REST API endpoint の一覧です。各 endpoint の詳細は下のリファレンスを参照してください。
API トークン
/api/v1/user/tokens
有効な API トークンの一覧を取得します。
/api/v1/user/tokens
新しい API トークンを作成します。(トークンの表示は作成時のみ)
/api/v1/user/tokens/:id
指定した API トークンの情報を取得します。 :id に current を指定すると、このリクエストの認証に使用している API トークン自身の情報を取得します。
/api/v1/user/tokens/:id
指定した API トークンを失効します。 :id に current を指定すると、このリクエストの認証に使用している API トークン自身を失効します。
ワークスペース
/api/v1/workspaces
トークンの scope 内で参照できるワークスペース一覧を取得します。 full_account token はトークン所有ユーザーが所属しているワークスペース、workspace scope token は対象ワークスペースのみを返します。
プロジェクト
/api/v1/projects
参照可能なプロジェクト一覧を取得します。
/api/v1/projects
Git または ZIP から project を作成し、初回 deployment を開始します。
/api/v1/projects/:id
project 情報、公開URL、直近 deployment 試行の状態を取得します。
/api/v1/projects/:id/deploy
既存 project の再デプロイを開始します。
/api/v1/projects/:id
指定したプロジェクトを削除します。 トークン所有ユーザーが、そのプロジェクトのワークスペースで owner または admin の場合のみ実行できます。外部リソース削除が継続する場合は、削除完了とせず 202 accepted を返します。
/api/v1/projects/:id/logs
project の runtime logs を JSON または text で取得します。
/api/v1/projects/:id/health-check
AppRun health check 設定を取得または保存します。
/api/v1/projects/:id/restart
保存済みの環境変数とヘルスチェック設定を AppRun に反映します。
環境変数
/api/v1/projects/:id/env
project の環境変数を取得または key 単位で更新します。
データベース
/api/v1/projects/:id/database
project の SQLite 互換データベースを取得、作成、削除します。
/api/v1/projects/:id/database/auth-tokens
データベースへ接続するためのトークンを一覧・発行します。
/api/v1/projects/:id/database/auth-tokens/:tokenId
接続トークンを失効します。即座に接続できなくなります。
/api/v1/projects/:id/database/tables
テーブルと列定義の一覧を取得します(読み取り専用)。
/api/v1/projects/:id/database/tables/:table/rows
指定テーブルの行を offset ページングで取得します(読み取り専用)。
/api/v1/projects/:id/database/exports
データベースを単一の SQLite .db ファイルとしてエクスポートします。
/api/v1/projects/:id/database/exports/:exportJobId
エクスポート job の進行状態を取得します。
/api/v1/projects/:id/database/exports/:exportJobId/download
完成したエクスポートの署名付きダウンロード URL を発行します。
/api/v1/projects/:id/database/import-session
SQLite ファイルからデータベースを作る手順 1/2。分割アップロード用の署名付き URL を発行します。
/api/v1/projects/:id/database/import-start
SQLite ファイルからデータベースを作る手順 2/2。アップロード済みパートの ETag を送って取込を開始します。
オブジェクトストレージ
/api/v1/workspaces/:workspaceId/storage/buckets
ワークスペースのバケット一覧と、ファイルAPIの接続先apiOriginを返します。メンバー全員が利用できます。ストレージの一覧はcursorによるページ送りで、最大100件です。件数は固定で、limit・until・sinceは使用しません。createdAtなどの日時はISO 8601文字列です。
/api/v1/workspaces/:workspaceId/storage/buckets
owner/adminがバケットを作成します。同名のバケットがある場合は409です。公開設定は作成後に変更できません。無料プランは非公開だけ作成できます。作成直前にその時点のプラン上限をストレージへ同期します。プランを判定できない場合は503で作成を止めます。応答を受け取れなかった場合は、自動で再作成せず一覧を確認してください。
/api/v1/workspaces/:workspaceId/storage/buckets/:bucketId
owner/adminがバケットを削除します。ファイルとキーは使えなくなり、画面から元には戻せません。ファイルが残る場合は202で処理を継続し、空なら204を返します。削除済みへの再送も202または204で、存在しないIDの404とは異なります。公開URLの配信停止には、後処理とキャッシュの時間がかかります。
/api/v1/workspaces/:workspaceId/storage/buckets/:bucketId/access-keys
owner/adminがバケットの有効なアクセスキーを取得します。キーの平文は含まれません。1ページ50件です。
/api/v1/workspaces/:workspaceId/storage/buckets/:bucketId/access-keys
owner/adminがバケット専用のキーを発行します。keyの平文はこの応答で一度だけ返します。作成者はAPIトークンの所有者になります。応答を受け取れなかった場合は、一覧から発行結果を確認し、不要なキーを無効化してください。Hanamii APIトークンとストレージキーは用途が異なります。
/api/v1/workspaces/:workspaceId/storage/buckets/:bucketId/access-keys/:keyId
owner/adminがアクセスキーを無効化します。既に無効なキーへの再送も204です。既発行の署名PUT URL・非公開配信URLは期限まで残り、キャッシュも即時には失効しません。
/api/v1/workspaces/:workspaceId/storage/buckets/:bucketId/files
メンバー全員がファイル一覧を取得できます。1ページ50件で、日時はISO 8601、sizeBytesは10進文字列です。URLは一覧には含めず、開くときに閲覧用URLを発行してください。
/api/v1/workspaces/:workspaceId/storage/buckets/:bucketId/files/:fileId/view-url
メンバー全員がファイルを開くURLを発行できます。公開ファイルは固定URLとexpiresAt: null、非公開ファイルは1時間有効なURLとISO 8601のexpiresAtを返します。本文は不要です。curlではContent-Length: 0を付けてください。未指定だと実行環境によって411で拒否されます。URL自体を持つ人は期限まで取得できるため、必要な相手だけに渡してください。
/api/v1/workspaces/:workspaceId/storage/usage
メンバー全員が、ワークスペース全体の保存容量・ファイル数・今月の配信量(日本時間、概算)とプラン上限を取得できます。値は10進文字列で返します。予約中の容量は含まないため、表示が上限未満でも予約を含むファイルAPIの判定で422になり得ます。支払い制限・停止中はlimitsの4値がすべて文字列の0になり、新規バケット・アップロードを止めます。既存の取得・配信は継続します。使用率は0で割らず、この状態を区別してください。配信量はアップロードを止める上限ではありません。
エンドポイント詳細
各 endpoint の method、path、入力、レスポンス、使用例です。
API トークン
API トークン一覧を取得
有効な API トークンの一覧を取得します。
/api/v1/user/tokens
パラメータ
項目
指定
タイプ
説明
limit
query
number
取得件数。省略時は 20、最大 100
until
query
number
この createdAt より前のトークンを取得
since
query
number
この createdAt より後のトークンを取得
レスポンス
200
トークン一覧とページ情報。bearerToken / tokenHash は含みません
401
Authorization header がない、またはトークンが無効
リクエスト例
GET /api/v1/user/tokens
const token = process.env.HANAMII_TOKEN; if (!token) throw new Error('HANAMII_TOKEN is required'); const response = await fetch('https://hanamii.jp/api/v1/user/tokens?limit=20', { method: 'GET', headers: { Authorization: `Bearer ${token}`, }, }); if (!response.ok) { throw new Error('Request failed'); } const data = await response.json(); // dataはサーバー内の必要な処理に渡す。応答全体をログへ出さない
レスポンス例
Response
{ "tokens": [ { "id": "tok_123", "name": "GitHub Actions Deploy", "scopeType": "workspace", "scopeWorkspaceId": "ws_123", "createdAt": 1777622400000, "expiresAt": 1809158400000, "lastUsedAt": null } ], "pagination": { "count": 1, "next": null, "prev": 1777622400000 } }
API トークン
API トークンを作成
新しい API トークンを作成します。(トークンの表示は作成時のみ)
/api/v1/user/tokens
パラメータ
項目
指定
タイプ
説明
name
body
string
表示用のトークン名、重複可能
scopeType
body
full_account | workspace
所属ワークスペース全体を対象にする場合は full_account
scopeWorkspaceId
body
string | null
workspace scope の対象ワークスペース ID、full_account は null
expiresAt
body
number | null
UNIX epoch milliseconds、null は期限なし、指定時は作成時点から1年以内
expiresAt の指定例
有効期限
TypeScript / Next.js
1時間
Date.now() + 60 * 60 * 1000
1日
Date.now() + 24 * 60 * 60 * 1000
30日
Date.now() + 30 * 24 * 60 * 60 * 1000
90日
Date.now() + 90 * 24 * 60 * 60 * 1000
期限なし
null
※ cURL では expiresAt に UNIX epoch milliseconds の数値を指定します。期限なしにする場合は null を指定してください。
レスポンス
200
トークンメタデータと bearerToken
400
入力値が不正、ISO 文字列の expiresAt、1年を超える expiresAt は不可
413
リクエスト body が 16KB を超過
リクエスト例
POST /api/v1/user/tokens
const token = process.env.HANAMII_TOKEN; if (!token) throw new Error('HANAMII_TOKEN is required'); const response = await fetch('https://hanamii.jp/api/v1/user/tokens', { method: 'POST', headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'GitHub Actions Deploy', scopeType: 'workspace', scopeWorkspaceId: 'workspace_id', expiresAt: Date.now() + 30 * 24 * 60 * 60 * 1000, }), }); if (!response.ok) { throw new Error('Request failed'); } const data = await response.json(); // dataはサーバー内の必要な処理に渡す。応答全体をログへ出さない
レスポンス例
Response
{ "token": { "id": "tok_123", "name": "GitHub Actions Deploy", "scopeType": "workspace", "scopeWorkspaceId": "ws_123", "createdAt": 1777622400000, "lastUsedAt": null, "expiresAt": 1809158400000 }, "bearerToken": "hnm_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" }
API トークン
API トークンを取得
指定した API トークンの情報を取得します。 :id に current を指定すると、このリクエストの認証に使用している API トークン自身の情報を取得します。
/api/v1/user/tokens/:id
パラメータ
項目
指定
タイプ
説明
id
path
string
トークン ID または current
レスポンス
200
トークン情報。bearerToken / tokenHash は含みません
404
トークンが存在しない、または参照できない
リクエスト例
GET /api/v1/user/tokens/:id
const token = process.env.HANAMII_TOKEN; if (!token) throw new Error('HANAMII_TOKEN is required'); const response = await fetch('https://hanamii.jp/api/v1/user/tokens/current', { method: 'GET', headers: { Authorization: `Bearer ${token}`, }, }); if (!response.ok) { throw new Error('Request failed'); } const data = await response.json(); // dataはサーバー内の必要な処理に渡す。応答全体をログへ出さない
レスポンス例
Response
{ "token": { "id": "tok_123", "name": "GitHub Actions Deploy", "scopeType": "workspace", "scopeWorkspaceId": "ws_123", "createdAt": 1777622400000, "lastUsedAt": 1777622400000, "expiresAt": 1809158400000 } }
API トークン
API トークンを失効
指定した API トークンを失効します。 :id に current を指定すると、このリクエストの認証に使用している API トークン自身を失効します。
/api/v1/user/tokens/:id
パラメータ
項目
指定
タイプ
説明
id
path
string
トークン ID または current
レスポンス
200
失効したトークン ID と deleted=true
404
トークンが存在しない、またはすでに失効済み
リクエスト例
DELETE /api/v1/user/tokens/:id
const token = process.env.HANAMII_TOKEN; if (!token) throw new Error('HANAMII_TOKEN is required'); const response = await fetch('https://hanamii.jp/api/v1/user/tokens/current', { method: 'DELETE', headers: { Authorization: `Bearer ${token}`, }, }); if (!response.ok) { throw new Error('Request failed'); } const data = await response.json(); // dataはサーバー内の必要な処理に渡す。応答全体をログへ出さない
レスポンス例
Response
{ "token": { "id": "tok_123", "deleted": true } }
ワークスペース
ワークスペース一覧を取得
トークンの scope 内で参照できるワークスペース一覧を取得します。 full_account token はトークン所有ユーザーが所属しているワークスペース、workspace scope token は対象ワークスペースのみを返します。
/api/v1/workspaces
パラメータ
項目
指定
タイプ
説明
なし
-
-
query / body はありません
レスポンス
200
ワークスペース一覧
401
Authorization header がない、またはトークンが無効
429
レート制限超過
リクエスト例
GET /api/v1/workspaces
const token = process.env.HANAMII_TOKEN; if (!token) throw new Error('HANAMII_TOKEN is required'); const response = await fetch('https://hanamii.jp/api/v1/workspaces', { method: 'GET', headers: { Authorization: `Bearer ${token}`, }, }); if (!response.ok) { throw new Error('Request failed'); } const data = await response.json(); // dataはサーバー内の必要な処理に渡す。応答全体をログへ出さない
レスポンス例
Response
{ "workspaces": [ { "id": "ws_123", "name": "Production", "role": "owner" } ] }
プロジェクト
プロジェクト一覧を取得
トークンの scope とユーザーの workspace role で参照できるプロジェクト一覧を取得します。 範囲: workspaceId を省略すると、トークンが参照できるすべてのワークスペース内のプロジェクトを返します。 絞り込み: workspaceId を指定すると、そのワークスペース内のプロジェクトだけを返します。
/api/v1/projects
パラメータ
項目
指定
タイプ
説明
workspaceId
query
string
任意。対象ワークスペース、scope 外は 403
limit
query
number
取得件数。省略時は 20、最大 100
until / since
query
number
createdAt cursor
レスポンス
200
プロジェクト一覧とページ情報
400
limit または cursor が不正
403
トークン scope 外のワークスペースを指定
リクエスト例
GET /api/v1/projects
const token = process.env.HANAMII_TOKEN; if (!token) throw new Error('HANAMII_TOKEN is required'); const response = await fetch('https://hanamii.jp/api/v1/projects?workspaceId=workspace_id', { method: 'GET', headers: { Authorization: `Bearer ${token}`, }, }); if (!response.ok) { throw new Error('Request failed'); } const data = await response.json(); // dataはサーバー内の必要な処理に渡す。応答全体をログへ出さない
レスポンス例
Response
{ "projects": [ { "id": "prj_123", "name": "my-api-test-app", "workspaceId": "ws_123", "status": "healthy", "url": "https://app-xxxx.ingress.apprun.sakura.ne.jp", "urls": [ { "type": "default", "host": "app-xxxx.ingress.apprun.sakura.ne.jp", "url": "https://app-xxxx.ingress.apprun.sakura.ne.jp" } ], "latestDeployment": { "id": "dpl_123", "readyState": "READY", "errorCode": null }, "runtimeStatus": { "status": "healthy", "detail": null, "syncedAt": 1777622400000 }, "healthCheck": { "enabled": true, "path": "/health", "port": null }, "createdAt": 1777622400000, "updatedAt": 1777622400000 } ], "pagination": { "count": 1, "next": null, "prev": 1777622400000 } }
プロジェクト
プロジェクトを作成
Git または ZIP から project を作成し、初回 deployment を開始します。 Git: repository と branch を指定します。 ZIP: デプロイ用ZIPの一時アップロード(POST /api/v1/uploads)でアップロード用URLを取得し、送信・チェックして checkId を取得し、その checkId を指定します。ZIP 作成前に node_modules、vendor、.git、.env*、.next、dist、build、cache などの不要ファイルや secret を除外してください。 checkId は1回の作成または再デプロイで使い切りです。 envs と healthCheck は任意です。指定した場合は初回 deployment に保存・反映され、指定しない場合は未設定のまま作成します。 レスポンス: 開始系APIのため、project.url / project.urls / latestDeployment は返しません。完了後のURLと状態は GET /api/v1/projects/:id で確認します。 権限: 作成可否はトークン所有ユーザーの workspace role で判定されます。
/api/v1/projects
パラメータ
項目
指定
タイプ
説明
name
body
string
プロジェクト名、英小文字、数字、ハイフンのみ
workspaceId
body
string
作成先ワークスペース ID。full_account token では必須、workspace scope token では省略可
source
body
object
Git または ZIP の作成元
source.type
body
git / zip
Git 作成は git、ZIP 作成は zip
source.repoFullName
body
string
Git 作成時に指定。owner/repo 形式
source.ref
body
string
Git 作成時に指定。branch 名
source.checkId
body
string
ZIP 作成時に指定。アップロード検証後に返る checkId
source.rootDirectory
body
string
任意。Git repository 内のデプロイ対象ディレクトリ
envs
body
array
任意。初回デプロイ時に登録する環境変数。未指定可
healthCheck
body
object
任意。enabled/path/port を指定。未指定可。port null は AppRun application port
レスポンス
200
プロジェクトと building 状態の deployment
400
source や name が不正
409
同じワークスペース内でプロジェクト名が重複
413
JSON body が 1MB を超過
リクエスト例
Git から作成する場合
application/json で repository と branch を指定します。envs と healthCheck は任意です。
POST /api/v1/projects
const response = await fetch('https://hanamii.jp/api/v1/projects', { method: 'POST', headers: { 'Authorization': 'Bearer YOUR_ACCESS_TOKEN', 'Content-Type': 'application/json', }, body: JSON.stringify({ workspaceId: 'workspace_id', name: 'my-api-test-app', source: { type: 'git', repoFullName: 'owner/repo', ref: 'main', }, // 任意。不要な場合は省略できます envs: [ { key: 'API_URL', value: 'https://example.com', type: 'plain' }, ], // 任意。不要な場合は省略できます healthCheck: { enabled: true, path: '/health', port: null }, }), }); if (!response.ok) throw new Error(await response.text()); const result = await response.json(); // サーバー内で使用し、応答全体をログへ出さない
ZIP から作成する場合
ZIP 本体は hanamii API へ直接送らず、発行された uploadUrl へ PUT します。最後に返った checkId を source.checkId に指定します。checkId は使い切りです。envs と healthCheck は任意です。CI/CD では通常 Git deploy を推奨します。
ZIP upload flow
import { readFile } from 'node:fs/promises'; const baseUrl = 'https://hanamii.jp'; const token = process.env.HANAMII_TOKEN!; async function uploadZipAndCreateCheckId(filePath: string) { const fileName = filePath.split('/').pop() ?? 'frontend.zip'; // 1. デプロイ用ZIPの一時アップロード用URLとuploadIdを発行 const uploadResponse = await fetch(`${baseUrl}/api/v1/uploads`, { method: 'POST', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ workspaceId: 'workspace_id', fileName, contentType: 'application/zip', }), }); if (!uploadResponse.ok) throw new Error(await uploadResponse.text()); const { upload } = await uploadResponse.json(); // 2. ZIP本体は hanamii API ではなく、発行された uploadUrl へ直接PUT const zipBuffer = await readFile(filePath); const putResponse = await fetch(upload.uploadUrl, { method: 'PUT', headers: { 'Content-Type': 'application/zip' }, body: zipBuffer, }); if (!putResponse.ok) throw new Error(await putResponse.text()); // 3. アップロード済みZIPを検証して checkId を取得 const checkResponse = await fetch(`${baseUrl}/api/v1/uploads/${upload.id}/check`, { method: 'POST', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json', }, body: JSON.stringify({}), }); if (!checkResponse.ok) throw new Error(await checkResponse.text()); const check = await checkResponse.json(); return check.result.checkId as string; } const checkId = await uploadZipAndCreateCheckId('./frontend.zip'); // 4. checkId を指定してプロジェクトを作成 const response = await fetch(`${baseUrl}/api/v1/projects`, { method: 'POST', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ workspaceId: 'workspace_id', name: 'my-api-test-app', source: { type: 'zip', checkId }, // 任意。不要な場合は省略できます envs: [ { key: 'API_URL', value: 'https://example.com', type: 'plain' }, ], // 任意。不要な場合は省略できます healthCheck: { enabled: true, path: "/health", port: null }, }), }); if (!response.ok) throw new Error(await response.text()); const result = await response.json(); // サーバー内で使用し、応答全体をログへ出さない
レスポンス例
ZIP 作成の cURL では、レスポンスの upload.putCurl のファイルパスだけ変更して実行します。その後、upload.id / result.checkId を次のリクエストに貼り付けます。healthCheck は作成時に保存されますが、作成開始レスポンスには含まれません。確認する場合は GET /api/v1/projects/:id または GET /api/v1/projects/:id/health-check を使います。
1. uploadUrl 発行
Response
{ "upload": { "id": "upload_123", "uploadUrl": "https://object-storage.example.com/uploads/upload_123/source.zip?...", "putCurl": "curl -X PUT 'https://object-storage.example.com/...' -H 'Content-Type: application/zip' --data-binary '@/path/to/frontend.zip'", "expiresAt": 1777622700000 } }
3. checkId 作成
Response
{ "result": { "checkId": "check_123", "canDeploy": true, "errorCount": 0, "errors": [] } }
4. プロジェクト作成
Response
{ "project": { "id": "prj_123", "name": "my-api-test-app", "workspaceId": "ws_123", "status": "initial", "createdAt": 1777622400000, "updatedAt": 1777622400000 }, "deployment": { "id": "dpl_123", "readyState": "BUILDING", "errorCode": null } }
checkId 再利用時
Response
{ "error": { "code": "validation_error", "message": "ZIPファイルが見つかりません。再度チェックを実行してください" } }
プロジェクト
プロジェクトを取得
指定したプロジェクトの情報を取得します。 URL: project.url は現在アクセスするための代表URLです。project.urls には利用可能なURL一覧が入ります。 CI/CD: latestDeployment.readyState を polling し、READY / ERROR を判定します。 注意: latestDeployment は現在稼働中の deployment ではなく、直近の deployment 試行を表します。前回成功版が稼働中のまま再デプロイに失敗した場合、project.status / project.url は現在公開中のアプリを表し、latestDeployment.readyState は ERROR になることがあります。 権限: 参照可否は token scope とトークン所有ユーザーの project 権限で判定されます。
/api/v1/projects/:id
パラメータ
項目
指定
タイプ
説明
id
path
string
URL の :id に入れるプロジェクト ID。body は不要
レスポンス
200
プロジェクト情報
403
トークン scope または project 権限不足
404
project が存在しない、または参照できない
リクエスト例
GET /api/v1/projects/:id
const token = process.env.HANAMII_TOKEN; if (!token) throw new Error('HANAMII_TOKEN is required'); const response = await fetch('https://hanamii.jp/api/v1/projects/project_id', { method: 'GET', headers: { Authorization: `Bearer ${token}`, }, }); if (!response.ok) { throw new Error('Request failed'); } const data = await response.json(); // dataはサーバー内の必要な処理に渡す。応答全体をログへ出さない
レスポンス例
Response
{ "project": { "id": "prj_123", "name": "my-api-test-app", "workspaceId": "ws_123", "status": "healthy", "url": "https://app-xxxx.ingress.apprun.sakura.ne.jp", "urls": [ { "type": "default", "host": "app-xxxx.ingress.apprun.sakura.ne.jp", "url": "https://app-xxxx.ingress.apprun.sakura.ne.jp" } ], "latestDeployment": { "id": "dpl_123", "readyState": "READY", "errorCode": null }, "runtimeStatus": { "status": "healthy", "detail": null, "syncedAt": 1777622400000 }, "healthCheck": { "enabled": true, "path": "/health", "port": null }, "createdAt": 1777622400000, "updatedAt": 1777622400000 } }
プロジェクト
プロジェクトを再デプロイ
既存プロジェクトを Git または ZIP から再デプロイします。 URL取得: この API はデプロイ開始 API のため URL は返しません。完了後の URL は GET /api/v1/projects/:id を polling し、latestDeployment.readyState が READY になった response から取得します。 ZIP: checkId は1回の再デプロイで使い切りです。ZIP 作成前に node_modules、vendor、.git、.env*、.next、dist、build、cache などの不要ファイルや secret を除外してください。 補足: API 側でも check 時に不要ディレクトリを除外しますが、元 ZIP が大きいほど時間がかかります。 権限: 実行可否は token scope とトークン所有ユーザーの project 権限で判定されます。
/api/v1/projects/:id/deploy
パラメータ
項目
指定
タイプ
説明
id
path
string
プロジェクト ID
source.type
body
git | zip
JSON リクエストの source。git は保存済みの GitHub 連携設定で再デプロイ
source.checkId
body
string
ZIP 再デプロイ時に指定。アップロード検証後に返る checkId
レスポンス
200
project と deployment
400
source が不正、またはデプロイ開始に失敗
403
トークン scope またはプロジェクト権限不足
413
JSON body が 1MB を超過
リクエスト例
Git から再デプロイする場合
application/json で Git 再デプロイを開始
POST /api/v1/projects/:id/deploy
const token = process.env.HANAMII_TOKEN; if (!token) throw new Error('HANAMII_TOKEN is required'); const response = await fetch('https://hanamii.jp/api/v1/projects/project_id/deploy', { method: 'POST', headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ source: { type: 'git', }, }), }); if (!response.ok) { throw new Error('Request failed'); } const data = await response.json(); // dataはサーバー内の必要な処理に渡す。応答全体をログへ出さない
ZIP から再デプロイする場合
ZIP upload flow で取得した checkId を指定して再デプロイ。checkId は使い切りです。CI/CD では通常 Git deploy を推奨します。
POST /api/v1/projects/:id/deploy
const token = process.env.HANAMII_TOKEN; if (!token) throw new Error('HANAMII_TOKEN is required'); const response = await fetch('https://hanamii.jp/api/v1/uploads', { method: 'POST', headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ source: { type: 'git', }, }), }); if (!response.ok) { throw new Error('Request failed'); } const data = await response.json(); // dataはサーバー内の必要な処理に渡す。応答全体をログへ出さない
レスポンス例
Response
{ "project": { "id": "prj_123", "name": "my-api-test-app", "workspaceId": "ws_123", "status": "healthy", "createdAt": 1777622400000, "updatedAt": 1777622400000 }, "deployment": { "id": "dpl_123", "readyState": "BUILDING", "errorCode": null } }
プロジェクト
プロジェクトを削除
指定したプロジェクトを削除します。 トークン所有ユーザーが、そのプロジェクトのワークスペースで owner または admin の場合のみ実行できます。外部リソース削除が継続する場合は、削除完了とせず 202 accepted を返します。
/api/v1/projects/:id
パラメータ
項目
指定
タイプ
説明
id
path
string
プロジェクト ID
レスポンス
200
物理削除済みのプロジェクト ID、deleted=true、deletion=completed
202
削除受付済み。deleted=false、deletion=accepted
403
トークン scope または project 権限不足
404
project が存在しない、または参照できない
429
レート制限超過
リクエスト例
DELETE /api/v1/projects/:id
const token = process.env.HANAMII_TOKEN; if (!token) throw new Error('HANAMII_TOKEN is required'); const response = await fetch('https://hanamii.jp/api/v1/projects/project_id', { method: 'DELETE', headers: { Authorization: `Bearer ${token}`, }, }); if (!response.ok) { throw new Error('Request failed'); } const data = await response.json(); // dataはサーバー内の必要な処理に渡す。応答全体をログへ出さない
レスポンス例
Response
{ "project": { "id": "prj_123", "deleted": true, "deletion": "completed" } }
プロジェクト
プロジェクトログを取得
プロジェクトのランタイムログを取得します。 保存期間: 新たに保存するログは、保存時点のワークスペースのプランに応じて無料24時間・有料90日です。有料から無料へ変更しても、変更前に保存した有料期間中のログは保存時の90日の期限を維持し、変更後のログは24時間になります。期限切れのログは取得できず、既に削除されたログはプランを変更しても復元されません。 範囲: limit や since / before で取得範囲を指定できます。since と before を省略すると直近15分を対象にします。保存期間と1回の取得範囲は異なります。 text形式: format=text を指定すると text/plain で返します。ログが0件の場合は 200 / 空文字 / text/plain; charset=utf-8 を返します。
/api/v1/projects/:id/logs
パラメータ
項目
指定
タイプ
説明
id
path
string
URL の :id に入れるプロジェクト ID。body は不要
limit
query
number
取得するログ行数。省略時は 100、最大 500
since
query
string
任意。-15m / -2h / -1d または ISO 8601 日時。省略時は -15m
before
query
string
任意。指定日時より前のログを取得。before 指定時は since より優先
format
query
string
任意。text を指定すると text/plain で返す
レスポンス
200
ログ一覧。標準は JSON、format=text の場合は text/plain
400
limit / since / before が不正
403
トークン scope または log 権限不足
404
project が存在しない、または参照できない
429
レート制限超過
リクエスト例
GET /api/v1/projects/:id/logs
const token = process.env.HANAMII_TOKEN; if (!token) throw new Error('HANAMII_TOKEN is required'); const response = await fetch('https://hanamii.jp/api/v1/projects/project_id/logs?limit=100&since=-15m', { method: 'GET', headers: { Authorization: `Bearer ${token}`, }, }); if (!response.ok) { throw new Error('Request failed'); } const data = await response.json(); // dataはサーバー内の必要な処理に渡す。応答全体をログへ出さない
レスポンス例
Response
{ "logs": [ { "timestamp": "2026-05-05T12:00:00.000Z", "message": "Server started" } ] }
環境変数
環境変数を取得・更新
プロジェクトに紐づく環境変数を取得または更新します。 PATCH は保存のみを行います。実行中のアプリへ反映するには AppRunに設定を反映 を実行するか、再デプロイしてください。 更新: PATCH は key 単位の upsert です。送信した key は作成または上書きされ、送信していない既存の環境変数は削除されません。 type: 公開APIの type は secret / plain のみで、encrypted は返しません。 権限: 取得・更新とも owner / admin / developer のみ実行可能です。
/api/v1/projects/:id/env
パラメータ
項目
指定
タイプ
説明
id
path
string
プロジェクト ID
decrypt
query
boolean
true のときだけ value を含める
envs
body
array
PATCH で upsert する key / value / type の配列。既存 env 全体の置換ではありません
envs[].type
body
secret | plain
任意。plain のとき非secret、secret または未指定は secret として保存。null やその他の値は 400
レスポンス
200
env 一覧または更新結果。encryptedValue / iv は含みません
400
envs が空配列、または item が不正
403
トークン scope または env 権限不足
413
リクエスト body が 2MB を超過
リクエスト例
環境変数を取得する場合
value も取得する場合は ?decrypt=true を指定
GET /api/v1/projects/:id/env
const token = process.env.HANAMII_TOKEN; if (!token) throw new Error('HANAMII_TOKEN is required'); const response = await fetch('https://hanamii.jp/api/v1/projects/project_id/env', { method: 'GET', headers: { Authorization: `Bearer ${token}`, }, }); if (!response.ok) { throw new Error('Request failed'); } const data = await response.json(); // dataはサーバー内の必要な処理に渡す。応答全体をログへ出さない
環境変数を更新する場合
key 単位で upsert。type は secret または plain。未指定時は secret として保存
PATCH /api/v1/projects/:id/env
const token = process.env.HANAMII_TOKEN; if (!token) throw new Error('HANAMII_TOKEN is required'); const response = await fetch('https://hanamii.jp/api/v1/projects/project_id/env', { method: 'PATCH', headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ envs: [ { key: 'API_URL', value: 'https://example.com', type: 'plain' }, { key: 'API_KEY', value: 'secret-value', type: 'secret' }, ], }), }); if (!response.ok) { throw new Error('Request failed'); } const data = await response.json(); // dataはサーバー内の必要な処理に渡す。応答全体をログへ出さない
レスポンス例
GET / PATCH の通常レスポンス
Response
{ "envs": [ { "id": "env_123", "key": "API_URL", "target": ["production"], "type": "plain", "createdAt": 1777622400000, "updatedAt": 1777622400000 } ] }
GET ?decrypt=true のレスポンス
Response
{ "envs": [ { "id": "env_123", "key": "API_URL", "value": "https://example.com", "target": ["production"], "type": "plain", "createdAt": 1777622400000, "updatedAt": 1777622400000 } ] }
プロジェクト
ヘルスチェック設定を取得 / 更新
Project の AppRun health check 設定を取得・更新します。 PUT は保存のみを行います。実行中のアプリへ反映するには AppRunに設定を反映 を実行するか、再デプロイしてください。 enabled=false の PUT は保存済み設定を削除します。enabled=true の場合は path が必須で、path は / から始める必要があります。port が null または未指定の場合は AppRun application port を使います。 保存した health check は deploy / restart 時に指定 path / port へ確認リクエストを行います。path が存在しない、正常応答しない、または timeout する場合は deploy / restart が失敗することがあります。失敗しても保存済み health check 設定は自動 rollback しません。
/api/v1/projects/:id/health-check
パラメータ
項目
指定
タイプ
説明
id
path
string
プロジェクト ID
enabled
body
boolean
PUT で必須。true は保存、false は削除
path
body
string
enabled=true で必須。/ から始める
port
body
number | null
任意。null は AppRun application port
レスポンス
200
healthCheck 設定
400
path / port が不正
403
トークン scope または project 権限不足
404
project が存在しない、または参照できない
リクエスト例
取得
GET /api/v1/projects/:id/health-check
const token = process.env.HANAMII_TOKEN; if (!token) throw new Error('HANAMII_TOKEN is required'); const response = await fetch('https://hanamii.jp/api/v1/projects/project_id/health-check', { method: 'GET', headers: { Authorization: `Bearer ${token}`, }, }); if (!response.ok) { throw new Error('Request failed'); } const data = await response.json(); // dataはサーバー内の必要な処理に渡す。応答全体をログへ出さない
更新
PUT /api/v1/projects/:id/health-check
const token = process.env.HANAMII_TOKEN; if (!token) throw new Error('HANAMII_TOKEN is required'); const response = await fetch('https://hanamii.jp/api/v1/projects/project_id/health-check', { method: 'PUT', headers: { Authorization: `Bearer ${token}`, }, }); if (!response.ok) { throw new Error('Request failed'); } const data = await response.json(); // dataはサーバー内の必要な処理に渡す。応答全体をログへ出さない
レスポンス例
Response
{ "healthCheck": { "enabled": true, "path": "/health", "port": null } }
プロジェクト
AppRunに設定を反映
この endpoint は互換性維持のため /restart という path を使用していますが、実際の動作は保存済み runtime 設定の AppRun 反映です。 現在のデプロイ済み image を使用し、ソースコードの再ビルドは行いません。保存済みの環境変数とヘルスチェック設定を AppRun に反映します。変更がある場合は新しい AppRun version を作成し、起動確認後に traffic を切り替えます。反映する変更がない場合は no-op となり、新しい deployment は作成されません。 PATCH /api/v1/projects/:id/env と PUT /api/v1/projects/:id/health-check は設定の保存のみを行います。実行中のアプリへ反映するには、この restart endpoint を呼び出すか、再デプロイしてください。 処理が長引く場合は keepalive streaming response になります。未デプロイ、currentVersion なし、デプロイ済み image なし、多重実行中、権限不足、rate limit は stream 開始前に error response を返します。 stream 開始後の起動確認失敗、ヘルスチェック失敗、timeout、traffic 切替失敗は、HTTP status が 200 のまま final JSON body の error として返る場合があります。client は HTTP status だけでなく、final JSON body の error を必ず確認してください。 ヘルスチェックに応答できない場合は、health_check_failed として返します。この場合、既存の公開中 version は維持されます。
/api/v1/projects/:id/restart
パラメータ
項目
指定
タイプ
説明
id
path
string
プロジェクト ID
レスポンス
200
project と deployment。no-op 時は deployment null / noop true
400
未デプロイ、または restart できない状態
403
トークン scope または project 権限不足
409
同一 project の反映処理が進行中
リクエスト例
保存済み設定を反映する場合
POST /api/v1/projects/:id/restart
const token = process.env.HANAMII_TOKEN; if (!token) throw new Error('HANAMII_TOKEN is required'); const response = await fetch('https://hanamii.jp/api/v1/projects/project_id/restart', { method: 'POST', headers: { Authorization: `Bearer ${token}`, }, }); if (!response.ok) { throw new Error('Request failed'); } const data = await response.json(); // dataはサーバー内の必要な処理に渡す。応答全体をログへ出さない
レスポンス例
Response
{ "project": { "id": "prj_123", "name": "my-api-test-app", "workspaceId": "ws_123", "status": "healthy", "createdAt": 1777622400000, "updatedAt": 1777622400000 }, "deployment": { "id": "dpl_123", "readyState": "READY", "errorCode": null } } // no-op { "project": { "id": "prj_123", "name": "my-api-test-app", "workspaceId": "ws_123", "status": "healthy", "createdAt": 1777622400000, "updatedAt": 1777622400000 }, "deployment": null, "noop": true, "message": "反映する変更はありません" }
データベース
データベースを取得・作成・削除
project に 1 つ持てる SQLite 互換データベース(libSQL / HTTPS 接続)を扱います。管理画面のデータベースタブと同じ操作です。 取得: 未作成のときは database: null を返します。 作成・削除: 非同期に進みます。レスポンスの status は creating / activating / deleting などの遷移中の値になるため、GET を繰り返して ready(削除時は null)になるまで待ってください。作成中・取込中のデータベースは削除できません。 権限: 取得はすべてのロール、作成・削除は owner / admin のみ実行可能です。 データベース基盤に接続できないときは 503 service_unavailable を返します。時間をおいて再試行してください。
/api/v1/projects/:id/database
パラメータ
項目
指定
タイプ
説明
id
path
string
プロジェクト ID
name
body
string
POST のみ・任意。表示名(100 文字以内)。省略時は接続 URL 用の slug が表示名の代わりになる。body 自体を省略してもよい
レスポンス
200
database。未作成の GET では null
400
name が string でない、または遷移中で削除できない
403
トークン scope または権限不足(作成・削除は owner / admin)
404
DELETE で対象データベースが無い
409
既にデータベースがある、または作成 / 取込が進行中
503
データベース基盤に接続できない
リクエスト例
データベースを取得する場合
GET /api/v1/projects/:id/database
const token = process.env.HANAMII_TOKEN; if (!token) throw new Error('HANAMII_TOKEN is required'); const response = await fetch('https://hanamii.jp/api/v1/projects/project_id/database', { method: 'GET', headers: { Authorization: `Bearer ${token}`, }, }); if (!response.ok) { throw new Error('Request failed'); } const data = await response.json(); // dataはサーバー内の必要な処理に渡す。応答全体をログへ出さない
空のデータベースを作成する場合
name は任意。body を省略して curl -X POST だけでも作成できます
POST /api/v1/projects/:id/database
const token = process.env.HANAMII_TOKEN; if (!token) throw new Error('HANAMII_TOKEN is required'); const response = await fetch('https://hanamii.jp/api/v1/projects/project_id/database', { method: 'POST', headers: { Authorization: `Bearer ${token}`, }, }); if (!response.ok) { throw new Error('Request failed'); } const data = await response.json(); // dataはサーバー内の必要な処理に渡す。応答全体をログへ出さない
データベースを削除する場合
DELETE /api/v1/projects/:id/database
const token = process.env.HANAMII_TOKEN; if (!token) throw new Error('HANAMII_TOKEN is required'); const response = await fetch('https://hanamii.jp/api/v1/projects/project_id/database', { method: 'DELETE', headers: { Authorization: `Bearer ${token}`, }, }); if (!response.ok) { throw new Error('Request failed'); } const data = await response.json(); // dataはサーバー内の必要な処理に渡す。応答全体をログへ出さない
レスポンス例
GET のレスポンス(ready)
Response
{ "database": { "id": "pdb_123", "name": "app db", "slug": "app-db-a1b2", "status": "ready", "hostname": "app-db-a1b2.db.hanamii.jp", "failureReason": null, "createdAt": 1777622400000 } }
POST のレスポンス(作成中)
Response
{ "database": { "id": "pdb_123", "name": "app db", "slug": "app-db-a1b2", "status": "creating", "hostname": null, "failureReason": null, "createdAt": 1777622400000 } }
データベース
接続トークンを一覧・発行
アプリやローカルの libSQL クライアント(@libsql/client、Turso 互換 SDK など)からデータベースへ接続するためのトークンを扱います。 発行: 平文の token と databaseUrl はこのレスポンスでのみ返します。hanamii 側には保存しないため、必ず控えてください。 一覧: metadata のみで、平文 token は含みません。 権限: owner / admin のみ。データベースが ready でないときは 400 を返します。
/api/v1/projects/:id/database/auth-tokens
パラメータ
項目
指定
タイプ
説明
id
path
string
プロジェクト ID
permission
body
read_write | read_only
POST のみ・任意。省略時は read_write
ttlSeconds
body
number
POST のみ・任意。有効期間(秒)。省略時は 2592000(30 日)。基盤側の許容範囲外は 400
name
body
string
POST のみ・任意。一覧に表示する用途ラベル(100 文字以内)
レスポンス
200
一覧: authTokens。発行: authToken / token / databaseUrl
400
permission / ttlSeconds / name が不正、またはデータベースが ready でない
403
トークン scope または権限不足(owner / admin)
404
データベースが無い
リクエスト例
接続トークンを一覧する場合
GET /api/v1/projects/:id/database/auth-tokens
const token = process.env.HANAMII_TOKEN; if (!token) throw new Error('HANAMII_TOKEN is required'); const response = await fetch('https://hanamii.jp/api/v1/projects/project_id/database/auth-tokens', { method: 'GET', headers: { Authorization: `Bearer ${token}`, }, }); if (!response.ok) { throw new Error('Request failed'); } const data = await response.json(); // dataはサーバー内の必要な処理に渡す。応答全体をログへ出さない
接続トークンを発行する場合
permission / ttlSeconds / name はすべて任意
POST /api/v1/projects/:id/database/auth-tokens
const token = process.env.HANAMII_TOKEN; if (!token) throw new Error('HANAMII_TOKEN is required'); const response = await fetch('https://hanamii.jp/api/v1/projects/project_id/database/auth-tokens', { method: 'POST', headers: { Authorization: `Bearer ${token}`, }, }); if (!response.ok) { throw new Error('Request failed'); } const data = await response.json(); // dataはサーバー内の必要な処理に渡す。応答全体をログへ出さない
レスポンス例
POST のレスポンス
Response
{ "authToken": { "id": "dbtok_123", "name": "CI", "permission": "read_write", "status": "active", "createdAt": 1777622400000, "expiresAt": 1780214400000, "revokedAt": null }, "token": "eyJhbGciOi...", "databaseUrl": "libsql://app-db-a1b2.db.hanamii.jp" }
GET のレスポンス
Response
{ "authTokens": [ { "id": "dbtok_123", "name": "CI", "permission": "read_write", "status": "active", "createdAt": 1777622400000, "expiresAt": 1780214400000, "revokedAt": null } ] }
データベース
接続トークンを失効
指定した接続トークンを失効します。失効は即座に効き、そのトークンを使った接続はできなくなります。 権限: owner / admin のみ。
/api/v1/projects/:id/database/auth-tokens/:tokenId
パラメータ
項目
指定
タイプ
説明
id
path
string
プロジェクト ID
tokenId
path
string
接続トークン ID(authToken.id)
レスポンス
200
失効したトークンの id と status: revoked
403
トークン scope または権限不足(owner / admin)
404
データベースまたは接続トークンが無い
リクエスト例
DELETE /api/v1/projects/:id/database/auth-tokens/:tokenId
const token = process.env.HANAMII_TOKEN; if (!token) throw new Error('HANAMII_TOKEN is required'); const response = await fetch('https://hanamii.jp/api/v1/projects/project_id/database/auth-tokens/$DB_TOKEN_ID', { method: 'DELETE', headers: { Authorization: `Bearer ${token}`, }, }); if (!response.ok) { throw new Error('Request failed'); } const data = await response.json(); // dataはサーバー内の必要な処理に渡す。応答全体をログへ出さない
レスポンス例
Response
{ "authToken": { "id": "dbtok_123", "status": "revoked" } }
データベース
テーブル一覧を取得
ユーザーテーブルと列定義(名前・型・主キー・NOT NULL)を返します。sqlite_ で始まるシステムテーブルは含みません。 読み取り専用です。SQL 文字列を受け取る endpoint はありません。書き込みは接続トークンを使ってアプリ側から行ってください。 権限: owner / admin のみ。
/api/v1/projects/:id/database/tables
パラメータ
項目
指定
タイプ
説明
id
path
string
プロジェクト ID
レスポンス
200
tables
400
データベースが ready でない
403
トークン scope または権限不足(owner / admin)
404
データベースが無い
503
読み取りタイムアウト(10 秒)または基盤に接続できない
リクエスト例
GET /api/v1/projects/:id/database/tables
const token = process.env.HANAMII_TOKEN; if (!token) throw new Error('HANAMII_TOKEN is required'); const response = await fetch('https://hanamii.jp/api/v1/projects/project_id/database/tables', { method: 'GET', headers: { Authorization: `Bearer ${token}`, }, }); if (!response.ok) { throw new Error('Request failed'); } const data = await response.json(); // dataはサーバー内の必要な処理に渡す。応答全体をログへ出さない
レスポンス例
Response
{ "tables": [ { "name": "users", "columns": [ { "name": "id", "type": "INTEGER", "isPrimaryKey": true, "isNotNull": true }, { "name": "email", "type": "TEXT", "isPrimaryKey": false, "isNotNull": true } ] } ] }
データベース
行データを取得
指定テーブルの行を返します。テーブル名はテーブル一覧に含まれるものと完全一致する必要があり、一致しなければ 404 です。 件数: totalCount は 100,000 件で数えるのをやめます。それ以上あるときは totalCount が 100000、totalCountTruncated が true になります。 セル値: NULL は null。BLOB は中身を返さず { "kind": "blob", "bytes": 長さ }。1,000 文字を超える文字列は先頭 1,000 文字と truncated: true を持つ object。JavaScript の安全な範囲を超える整数は文字列で返します。 権限: owner / admin のみ。
/api/v1/projects/:id/database/tables/:table/rows
パラメータ
項目
指定
タイプ
説明
id
path
string
プロジェクト ID
table
path
string
テーブル名(テーブル一覧の name と完全一致)
limit
query
number
1 ページの行数。省略時 50、1〜100 に丸める
offset
query
number
読み飛ばす行数。省略時 0、0〜1,000,000 に丸める
レスポンス
200
table / rows / pagination
400
limit / offset が整数でない、またはデータベースが ready でない
403
トークン scope または権限不足(owner / admin)
404
データベースまたはテーブルが無い
503
読み取りタイムアウト(10 秒)または基盤に接続できない
リクエスト例
GET /api/v1/projects/:id/database/tables/:table/rows
const token = process.env.HANAMII_TOKEN; if (!token) throw new Error('HANAMII_TOKEN is required'); const response = await fetch('https://hanamii.jp/api/v1/projects/project_id/database/tables/users/rows?limit=50&offset=0', { method: 'GET', headers: { Authorization: `Bearer ${token}`, }, }); if (!response.ok) { throw new Error('Request failed'); } const data = await response.json(); // dataはサーバー内の必要な処理に渡す。応答全体をログへ出さない
レスポンス例
Response
{ "table": "users", "rows": [ { "id": 1, "email": "alice@example.com", "avatar": { "kind": "blob", "bytes": 5120 } } ], "pagination": { "limit": 50, "offset": 0, "totalCount": 1, "totalCountTruncated": false } }
データベース
エクスポートを開始
エクスポートを受け付けます。中身は受付直後の読み取り時点で固定され、標準的な単一ファイルの SQLite .db として作り直されます。 流れ: 開始 → 状態照会(status が ready になるまで polling)→ ダウンロード URL 発行 → URL から取得。 Idempotency-Key: 同じ key を再送すると新しいエクスポートを始めず同じ job を返します。省略時は毎回新しいエクスポートになります。 上限: 基盤側で組織 20 回/時・利用者 10 回/時。超えると 429 です。完成したファイルは 24 時間保持されます。 権限: owner / admin のみ。
/api/v1/projects/:id/database/exports
パラメータ
項目
指定
タイプ
説明
id
path
string
プロジェクト ID
Idempotency-Key
header
string
任意。255 文字以内。同じ key の再送は同じ job を返す。body の idempotencyKey でも指定可(header 優先)
レスポンス
200
exportJob
400
データベースが ready でない
403
トークン scope または権限不足(owner / admin)
404
データベースが無い
429
エクスポート実行回数の上限(組織 20 回/時・利用者 10 回/時)
リクエスト例
POST /api/v1/projects/:id/database/exports
const token = process.env.HANAMII_TOKEN; if (!token) throw new Error('HANAMII_TOKEN is required'); const response = await fetch('https://hanamii.jp/api/v1/projects/project_id/database/exports', { method: 'POST', headers: { Authorization: `Bearer ${token}`, }, }); if (!response.ok) { throw new Error('Request failed'); } const data = await response.json(); // dataはサーバー内の必要な処理に渡す。応答全体をログへ出さない
レスポンス例
Response
{ "exportJob": { "id": "exp_123", "status": "queued", "failureCode": null, "artifactSizeBytes": null, "artifactSha256": null, "artifactAvailableUntil": null, "createdAt": 1777622400000 } }
データベース
エクスポートの状態を取得
エクスポート job の状態を返します。status は queued / running / validating / uploading / ready / cancelled / failed / expired のいずれかで、ready / cancelled / failed / expired が終端です。 ready になると artifactSizeBytes / artifactSha256 / artifactAvailableUntil(保持期限)が入ります。 権限: owner / admin のみ。
/api/v1/projects/:id/database/exports/:exportJobId
パラメータ
項目
指定
タイプ
説明
id
path
string
プロジェクト ID
exportJobId
path
string
エクスポート job ID(exportJob.id)
レスポンス
200
exportJob
403
トークン scope または権限不足(owner / admin)
404
データベースまたは job が無い
リクエスト例
GET /api/v1/projects/:id/database/exports/:exportJobId
const token = process.env.HANAMII_TOKEN; if (!token) throw new Error('HANAMII_TOKEN is required'); const response = await fetch('https://hanamii.jp/api/v1/projects/project_id/database/exports/$EXPORT_JOB_ID', { method: 'GET', headers: { Authorization: `Bearer ${token}`, }, }); if (!response.ok) { throw new Error('Request failed'); } const data = await response.json(); // dataはサーバー内の必要な処理に渡す。応答全体をログへ出さない
レスポンス例
Response
{ "exportJob": { "id": "exp_123", "status": "ready", "failureCode": null, "artifactSizeBytes": 1048576, "artifactSha256": "3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "artifactAvailableUntil": 1777708800000, "createdAt": 1777622400000 } }
データベース
ダウンロード URL を発行
ready になった job の .db ファイルを取得するための署名付き URL を発行します。URL の期限(urlExpiresAt、最長 10 分)と保持期限(availableUntil、24 時間)は別物で、URL が切れても保持期限内なら何度でも発行し直せます。 URL からの取得には Authorization header は不要です。 権限: owner / admin のみ。
/api/v1/projects/:id/database/exports/:exportJobId/download
パラメータ
項目
指定
タイプ
説明
id
path
string
プロジェクト ID
exportJobId
path
string
エクスポート job ID
レスポンス
200
download(url / urlExpiresAt / availableUntil / sizeBytes / sha256 / fileName)
400
job がまだ ready でない
403
トークン scope または権限不足(owner / admin)
404
データベースまたは job が無い
410
保持期限が過ぎた。新しくエクスポートし直す
リクエスト例
POST /api/v1/projects/:id/database/exports/:exportJobId/download
const token = process.env.HANAMII_TOKEN; if (!token) throw new Error('HANAMII_TOKEN is required'); const response = await fetch('https://hanamii.jp/api/v1/projects/project_id/database/exports/$EXPORT_JOB_ID/download', { method: 'POST', headers: { Authorization: `Bearer ${token}`, }, }); if (!response.ok) { throw new Error('Request failed'); } const data = await response.json(); // dataはサーバー内の必要な処理に渡す。応答全体をログへ出さない
レスポンス例
Response
{ "download": { "url": "https://object-storage.example.com/exports/app-db-a1b2.db?X-Amz-Signature=...", "urlExpiresAt": 1777623000000, "availableUntil": 1777708800000, "sizeBytes": 1048576, "sha256": "3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "fileName": "app-db-a1b2.db" } }
データベース
インポート: アップロード先を発行
手元の SQLite .db ファイルからデータベースを作成(インポート)する手順の 1 つ目です。ファイルサイズを申告すると、必要なパート数だけ署名付き PUT URL が返ります。 アップロードは常に分割です。各パートは contentLength ちょうどの body で PUT し、レスポンスの ETag header を控えてください(手順 2 で使います)。 上限: 100 MiB。URL は expiresAt で失効します。既にデータベースがある project(failed を除く)では 409 です。 権限: owner / admin のみ。
/api/v1/projects/:id/database/import-session
パラメータ
項目
指定
タイプ
説明
id
path
string
プロジェクト ID
fileSizeBytes
body
number
必須。.db ファイルの正確なサイズ(バイト)。最大 104857600
レスポンス
200
session(sessionId / partSizeBytes / parts / expiresAt)
400
fileSizeBytes が不正、または 100 MiB 超
403
トークン scope または権限不足(owner / admin)
409
既にデータベースがある、または作成 / 取込が進行中
リクエスト例
アップロード先を発行する場合
POST /api/v1/projects/:id/database/import-session
const token = process.env.HANAMII_TOKEN; if (!token) throw new Error('HANAMII_TOKEN is required'); const response = await fetch('https://hanamii.jp/api/v1/projects/project_id/database/import-session', { method: 'POST', headers: { Authorization: `Bearer ${token}`, }, }); if (!response.ok) { throw new Error('Request failed'); } const data = await response.json(); // dataはサーバー内の必要な処理に渡す。応答全体をログへ出さない
各パートを PUT して ETag を控える場合
partSizeBytes ごとに分割し、parts[].url へ順番に PUT します
POST /api/v1/projects/:id/database/import-session
const token = process.env.HANAMII_TOKEN; if (!token) throw new Error('HANAMII_TOKEN is required'); const response = await fetch('https://hanamii.jp/api/v1/projects/:id/database/import-session', { method: 'POST', headers: { Authorization: `Bearer ${token}`, }, }); if (!response.ok) { throw new Error('Request failed'); } const data = await response.json(); // dataはサーバー内の必要な処理に渡す。応答全体をログへ出さない
レスポンス例
Response
{ "session": { "sessionId": "imp_123", "partSizeBytes": 8388608, "parts": [ { "partNumber": 1, "url": "https://object-storage.example.com/...part1?X-Amz-Signature=...", "contentLength": 8388608 }, { "partNumber": 2, "url": "https://object-storage.example.com/...part2?X-Amz-Signature=...", "contentLength": 1048576 } ], "expiresAt": 1777626000000 } }
データベース
インポート: 取込を開始
インポート手順の 2 つ目です。全パートの ETag を送ると取込が始まり、status: importing のデータベースが返ります。GET /api/v1/projects/:id/database を繰り返して ready または failed になるまで待ってください。 ファイルが SQLite として不正な場合は failed になり failureReason が入ります。failed の記録は DELETE で消すか、そのまま作成 / インポートし直せます。 権限: owner / admin のみ。
/api/v1/projects/:id/database/import-start
パラメータ
項目
指定
タイプ
説明
id
path
string
プロジェクト ID
sessionId
body
string
必須。手順 1 の session.sessionId
parts
body
array
必須・1件以上。アップロードしたパートごとの { partNumber, etag }
parts[].partNumber
body
number
必須。手順1で受け取ったパート番号(1以上の整数)
parts[].etag
body
string
必須・空でない文字列。PUT レスポンスの ETag header の値(引用符付きならそのまま)
name
body
string
任意。表示名(100 文字以内)
レスポンス
200
database(status: importing)
400
sessionId / parts が不正
403
トークン scope または権限不足(owner / admin)
409
既にデータベースがある、または作成 / 取込が進行中
リクエスト例
POST /api/v1/projects/:id/database/import-start
const token = process.env.HANAMII_TOKEN; if (!token) throw new Error('HANAMII_TOKEN is required'); const response = await fetch('https://hanamii.jp/api/v1/projects/project_id/database/import-start', { method: 'POST', headers: { Authorization: `Bearer ${token}`, }, }); if (!response.ok) { throw new Error('Request failed'); } const data = await response.json(); // dataはサーバー内の必要な処理に渡す。応答全体をログへ出さない
レスポンス例
Response
{ "database": { "id": "pdb_123", "name": "app db", "slug": "app-db-a1b2", "status": "importing", "hostname": null, "failureReason": null, "createdAt": 1777622400000 } }
オブジェクトストレージ
ストレージのバケット一覧
ワークスペースのバケット一覧と、ファイルAPIの接続先apiOriginを返します。メンバー全員が利用できます。ストレージの一覧はcursorによるページ送りで、最大100件です。件数は固定で、limit・until・sinceは使用しません。createdAtなどの日時はISO 8601文字列です。
/api/v1/workspaces/:workspaceId/storage/buckets
パラメータ
項目
指定
タイプ
説明
workspaceId
path
string
対象ワークスペースのUUID。トークンのscopeと所属・役割を毎回確認します
cursor
query
string
前の応答のnextCursorをURLエンコードして指定。nullならパラメータを付けず終了。未指定・空は先頭
レスポンス
200
items、nextCursor、apiOrigin
400
validation_error。ID・cursor・入力の形式が不正
401
unauthorized。APIトークンが未指定・失効・期限切れ
403
forbidden。トークンのscope・所属または役割が不足
429
rate_limited。操作のレート制限超過
500
internal_error。内部エラー。詳細は公開しません
502 / 503
external_api_error / service_unavailable。連携失敗、または未設定
リクエスト例
GET /api/v1/workspaces/:workspaceId/storage/buckets
// サーバー内から呼ぶ関数。公開ルートから使う場合は、先に利用者と対象の権限を確認する export async function callEndpoint() { const token = process.env.HANAMII_TOKEN; if (!token) throw new Error('HANAMII_TOKEN is required'); const response = await fetch('https://hanamii.jp/api/v1/workspaces/workspace_id/storage/buckets', { method: 'GET', headers: { Authorization: `Bearer ${token}`, }, cache: 'no-store', }); if (!response.ok) throw new Error(`Request failed: ${response.status}`); const data = await response.json(); // 閲覧URLを含む応答はログへ出さず、認可済みの表示・処理にだけ使う return data; }
レスポンス例
Response
{"items":[{"id":"bucket_id","name":"assets","visibility":"private","createdAt":"2026-10-29T00:00:00.000Z"}],"nextCursor":null,"apiOrigin":"https://storage.hanamii.jp"}
オブジェクトストレージ
ストレージのバケットを作成
owner/adminがバケットを作成します。同名のバケットがある場合は409です。公開設定は作成後に変更できません。無料プランは非公開だけ作成できます。作成直前にその時点のプラン上限をストレージへ同期します。プランを判定できない場合は503で作成を止めます。応答を受け取れなかった場合は、自動で再作成せず一覧を確認してください。
/api/v1/workspaces/:workspaceId/storage/buckets
パラメータ
項目
指定
タイプ
説明
workspaceId
path
string
対象ワークスペースのUUID。トークンのscopeと所属・役割を毎回確認します
name
body
string
必須。3〜63文字の英小文字・数字・ハイフン。先頭と末尾は英小文字か数字。JSON本文は16KiB以内
visibility
body
public | private
必須。公開はURLを知る人、非公開は期限付きURLを持つ人が取得できます
レスポンス
201
作成したバケット
400
validation_error。ID・cursor・入力の形式が不正
401
unauthorized。APIトークンが未指定・失効・期限切れ
403
forbidden。scope・所属・役割不足、無料の公開作成、上限到達、支払い停止
409
conflict。処理の競合
413
payload_too_large。JSON本文が16KiBを超過
415
unsupported_media_type。JSON以外の本文
429
rate_limited。操作のレート制限超過
500
internal_error。内部エラー。詳細は公開しません
502 / 503
external_api_error / service_unavailable。連携失敗・未設定、またはプランを判定できない
リクエスト例
POST /api/v1/workspaces/:workspaceId/storage/buckets
// サーバー内から呼ぶ関数。公開ルートから使う場合は、先に利用者と対象の権限を確認する export async function callEndpoint() { const token = process.env.HANAMII_TOKEN; if (!token) throw new Error('HANAMII_TOKEN is required'); const response = await fetch('https://hanamii.jp/api/v1/workspaces/workspace_id/storage/buckets', { method: 'POST', headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'assets', visibility: 'private', }), cache: 'no-store', }); if (!response.ok) throw new Error(`Request failed: ${response.status}`); const data = await response.json(); // 閲覧URLを含む応答はログへ出さず、認可済みの表示・処理にだけ使う return data; }
レスポンス例
Response
{"id":"bucket_id","name":"assets","visibility":"private","createdAt":"2026-10-29T00:00:00.000Z"}
オブジェクトストレージ
ストレージのバケットを削除
owner/adminがバケットを削除します。ファイルとキーは使えなくなり、画面から元には戻せません。ファイルが残る場合は202で処理を継続し、空なら204を返します。削除済みへの再送も202または204で、存在しないIDの404とは異なります。公開URLの配信停止には、後処理とキャッシュの時間がかかります。
/api/v1/workspaces/:workspaceId/storage/buckets/:bucketId
パラメータ
項目
指定
タイプ
説明
workspaceId
path
string
対象ワークスペースのUUID。トークンのscopeと所属・役割を毎回確認します
bucketId
path
string
返されたIDを使用。英数字・ハイフン・アンダースコア1〜128文字。別ワークスペースは不可
レスポンス
202
削除受付。status: processing
204
削除完了。本文なし
400
validation_error。ID・cursor・入力の形式が不正
401
unauthorized。APIトークンが未指定・失効・期限切れ
403
forbidden。トークンのscope・所属または役割が不足
404
not_found。指定した対象が見つからない
409
conflict。処理の競合
429
rate_limited。操作のレート制限超過
500
internal_error。内部エラー。詳細は公開しません
502 / 503
external_api_error / service_unavailable。連携失敗、または未設定
リクエスト例
DELETE /api/v1/workspaces/:workspaceId/storage/buckets/:bucketId
// サーバー内から呼ぶ関数。公開ルートから使う場合は、先に利用者と対象の権限を確認する export async function callEndpoint() { const token = process.env.HANAMII_TOKEN; if (!token) throw new Error('HANAMII_TOKEN is required'); const response = await fetch('https://hanamii.jp/api/v1/workspaces/workspace_id/storage/buckets/bucket_id', { method: 'DELETE', headers: { Authorization: `Bearer ${token}`, }, cache: 'no-store', }); if (!response.ok) throw new Error(`Request failed: ${response.status}`); if (response.status === 204) return; const data = await response.json(); // 閲覧URLを含む応答はログへ出さず、認可済みの表示・処理にだけ使う return data; }
レスポンス例
ファイルの片付けが続く場合(202)
Response
{"status":"processing"}
空のバケット(204)
Response
HTTP/2 204 # レスポンス本文はありません
オブジェクトストレージ
ストレージのアクセスキー一覧
owner/adminがバケットの有効なアクセスキーを取得します。キーの平文は含まれません。1ページ50件です。
/api/v1/workspaces/:workspaceId/storage/buckets/:bucketId/access-keys
パラメータ
項目
指定
タイプ
説明
workspaceId
path
string
対象ワークスペースのUUID。トークンのscopeと所属・役割を毎回確認します
bucketId
path
string
返されたIDを使用。英数字・ハイフン・アンダースコア1〜128文字。別ワークスペースは不可
cursor
query
string
nextCursorをURLエンコードして指定。未指定・空は先頭、nullなら終了。件数は固定
レスポンス
200
items、nextCursor
400
validation_error。ID・cursor・入力の形式が不正
401
unauthorized。APIトークンが未指定・失効・期限切れ
403
forbidden。トークンのscope・所属または役割が不足
404
not_found。指定した対象が見つからない
409
conflict。処理の競合
429
rate_limited。操作のレート制限超過
500
internal_error。内部エラー。詳細は公開しません
502 / 503
external_api_error / service_unavailable。連携失敗、または未設定
リクエスト例
GET /api/v1/workspaces/:workspaceId/storage/buckets/:bucketId/access-keys
// サーバー内から呼ぶ関数。公開ルートから使う場合は、先に利用者と対象の権限を確認する export async function callEndpoint() { const token = process.env.HANAMII_TOKEN; if (!token) throw new Error('HANAMII_TOKEN is required'); const response = await fetch('https://hanamii.jp/api/v1/workspaces/workspace_id/storage/buckets/bucket_id/access-keys', { method: 'GET', headers: { Authorization: `Bearer ${token}`, }, cache: 'no-store', }); if (!response.ok) throw new Error(`Request failed: ${response.status}`); const data = await response.json(); // 閲覧URLを含む応答はログへ出さず、認可済みの表示・処理にだけ使う return data; }
レスポンス例
Response
{"items":[{"keyId":"storage_key_id","permission":"read_only","createdBy":"user_id","creatorEmail":null,"createdAt":"2026-10-29T00:00:00.000Z","lastUsedAt":null}],"nextCursor":null}
オブジェクトストレージ
ストレージのアクセスキーを発行
owner/adminがバケット専用のキーを発行します。keyの平文はこの応答で一度だけ返します。作成者はAPIトークンの所有者になります。応答を受け取れなかった場合は、一覧から発行結果を確認し、不要なキーを無効化してください。Hanamii APIトークンとストレージキーは用途が異なります。
/api/v1/workspaces/:workspaceId/storage/buckets/:bucketId/access-keys
パラメータ
項目
指定
タイプ
説明
workspaceId
path
string
対象ワークスペースのUUID。トークンのscopeと所属・役割を毎回確認します
bucketId
path
string
返されたIDを使用。英数字・ハイフン・アンダースコア1〜128文字。別ワークスペースは不可
permission
body
read_only | read_write
必須。read_onlyは一覧・取得・共有URL。read_writeは加えてアップロード・完了・削除が可能。JSON本文16KiB以内
レスポンス
201
keyId、permission、createdAt、key(平文は一度だけ)
400
validation_error。ID・cursor・入力の形式が不正
401
unauthorized。APIトークンが未指定・失効・期限切れ
403
forbidden。トークンのscope・所属または役割が不足
404
not_found。指定した対象が見つからない
409
conflict。処理の競合
413
payload_too_large。JSON本文が16KiBを超過
415
unsupported_media_type。JSON以外の本文
429
rate_limited。操作のレート制限超過
500
internal_error。内部エラー。詳細は公開しません
502 / 503
external_api_error / service_unavailable。連携失敗、または未設定
リクエスト例
POST /api/v1/workspaces/:workspaceId/storage/buckets/:bucketId/access-keys
// サーバー内から呼ぶ関数。公開ルートから使う場合は、先に利用者と対象の権限を確認する export async function callEndpoint( storeKey: (value: { keyId: string; key: string; permission: string }) => Promise<void>, ) { const token = process.env.HANAMII_TOKEN; if (!token) throw new Error('HANAMII_TOKEN is required'); const response = await fetch('https://hanamii.jp/api/v1/workspaces/workspace_id/storage/buckets/bucket_id/access-keys', { method: 'POST', headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ permission: 'read_write', }), cache: 'no-store', }); if (!response.ok) throw new Error(`Request failed: ${response.status}`); const data = await response.json(); // storeKeyはサーバー内の秘密情報保管処理。consoleやブラウザへの返却には使わない await storeKey({ keyId: data.keyId, key: data.key, permission: data.permission }); return { keyId: data.keyId, permission: data.permission, createdAt: data.createdAt }; }
レスポンス例
Response
{"keyId":"storage_key_id","permission":"read_write","createdAt":"2026-10-29T00:00:00.000Z","key":"<一度だけ返すストレージアクセスキー>"}
オブジェクトストレージ
ストレージのアクセスキーを無効化
owner/adminがアクセスキーを無効化します。既に無効なキーへの再送も204です。既発行の署名PUT URL・非公開配信URLは期限まで残り、キャッシュも即時には失効しません。
/api/v1/workspaces/:workspaceId/storage/buckets/:bucketId/access-keys/:keyId
パラメータ
項目
指定
タイプ
説明
workspaceId
path
string
対象ワークスペースのUUID。トークンのscopeと所属・役割を毎回確認します
bucketId
path
string
返されたIDを使用。英数字・ハイフン・アンダースコア1〜128文字。別ワークスペースは不可
keyId
path
string
key_に続く24文字の英数字・ハイフン・アンダースコア。平文のkeyではありません
レスポンス
204
無効化済み。本文なし
400
validation_error。ID・cursor・入力の形式が不正
401
unauthorized。APIトークンが未指定・失効・期限切れ
403
forbidden。トークンのscope・所属または役割が不足
404
not_found。指定した対象が見つからない
409
conflict。処理の競合
429
rate_limited。操作のレート制限超過
500
internal_error。内部エラー。詳細は公開しません
502 / 503
external_api_error / service_unavailable。連携失敗、または未設定
リクエスト例
DELETE /api/v1/workspaces/:workspaceId/storage/buckets/:bucketId/access-keys/:keyId
// サーバー内から呼ぶ関数。公開ルートから使う場合は、先に利用者と対象の権限を確認する export async function callEndpoint() { const token = process.env.HANAMII_TOKEN; if (!token) throw new Error('HANAMII_TOKEN is required'); const response = await fetch('https://hanamii.jp/api/v1/workspaces/workspace_id/storage/buckets/bucket_id/access-keys/storage_key_id', { method: 'DELETE', headers: { Authorization: `Bearer ${token}`, }, cache: 'no-store', }); if (!response.ok) throw new Error(`Request failed: ${response.status}`); if (response.status === 204) return; const data = await response.json(); // 閲覧URLを含む応答はログへ出さず、認可済みの表示・処理にだけ使う return data; }
レスポンス例
Response
HTTP/2 204 # レスポンス本文はありません
オブジェクトストレージ
ストレージのファイル一覧
メンバー全員がファイル一覧を取得できます。1ページ50件で、日時はISO 8601、sizeBytesは10進文字列です。URLは一覧には含めず、開くときに閲覧用URLを発行してください。
/api/v1/workspaces/:workspaceId/storage/buckets/:bucketId/files
パラメータ
項目
指定
タイプ
説明
workspaceId
path
string
対象ワークスペースのUUID。トークンのscopeと所属・役割を毎回確認します
bucketId
path
string
返されたIDを使用。英数字・ハイフン・アンダースコア1〜128文字。別ワークスペースは不可
cursor
query
string
nextCursorをURLエンコードして指定。未指定・空は先頭、nullなら終了。件数は固定
レスポンス
200
items、nextCursor
400
validation_error。ID・cursor・入力の形式が不正
401
unauthorized。APIトークンが未指定・失効・期限切れ
403
forbidden。トークンのscope・所属または役割が不足
404
not_found。指定した対象が見つからない
409
conflict。処理の競合
429
rate_limited。操作のレート制限超過
500
internal_error。内部エラー。詳細は公開しません
502 / 503
external_api_error / service_unavailable。連携失敗、または未設定
リクエスト例
GET /api/v1/workspaces/:workspaceId/storage/buckets/:bucketId/files
// サーバー内から呼ぶ関数。公開ルートから使う場合は、先に利用者と対象の権限を確認する export async function callEndpoint() { const token = process.env.HANAMII_TOKEN; if (!token) throw new Error('HANAMII_TOKEN is required'); const response = await fetch('https://hanamii.jp/api/v1/workspaces/workspace_id/storage/buckets/bucket_id/files', { method: 'GET', headers: { Authorization: `Bearer ${token}`, }, cache: 'no-store', }); if (!response.ok) throw new Error(`Request failed: ${response.status}`); const data = await response.json(); // 閲覧URLを含む応答はログへ出さず、認可済みの表示・処理にだけ使う return data; }
レスポンス例
Response
{"items":[{"id":"file_id","name":"photo.jpg","sizeBytes":"7900","contentType":"image/jpeg","createdAt":"2026-10-29T00:00:00.000Z","updatedAt":"2026-10-29T00:00:00.000Z"}],"nextCursor":null}
オブジェクトストレージ
ストレージの閲覧用URLを発行
メンバー全員がファイルを開くURLを発行できます。公開ファイルは固定URLとexpiresAt: null、非公開ファイルは1時間有効なURLとISO 8601のexpiresAtを返します。本文は不要です。curlではContent-Length: 0を付けてください。未指定だと実行環境によって411で拒否されます。URL自体を持つ人は期限まで取得できるため、必要な相手だけに渡してください。
/api/v1/workspaces/:workspaceId/storage/buckets/:bucketId/files/:fileId/view-url
パラメータ
項目
指定
タイプ
説明
workspaceId
path
string
対象ワークスペースのUUID。トークンのscopeと所属・役割を毎回確認します
bucketId
path
string
返されたIDを使用。英数字・ハイフン・アンダースコア1〜128文字。別ワークスペースは不可
fileId
path
string
返されたファイルID。英数字・ハイフン・アンダースコア1〜128文字
レスポンス
200
url、expiresAt
400
validation_error。ID・cursor・入力の形式が不正
401
unauthorized。APIトークンが未指定・失効・期限切れ
403
forbidden。トークンのscope・所属または役割が不足
404
not_found。指定した対象が見つからない
409
conflict。処理の競合
429
rate_limited。操作のレート制限超過
500
internal_error。内部エラー。詳細は公開しません
502 / 503
external_api_error / service_unavailable。連携失敗、または未設定
リクエスト例
POST /api/v1/workspaces/:workspaceId/storage/buckets/:bucketId/files/:fileId/view-url
// サーバー内から呼ぶ関数。公開ルートから使う場合は、先に利用者と対象の権限を確認する export async function callEndpoint() { const token = process.env.HANAMII_TOKEN; if (!token) throw new Error('HANAMII_TOKEN is required'); const response = await fetch('https://hanamii.jp/api/v1/workspaces/workspace_id/storage/buckets/bucket_id/files/file_id/view-url', { method: 'POST', headers: { Authorization: `Bearer ${token}`, }, cache: 'no-store', }); if (!response.ok) throw new Error(`Request failed: ${response.status}`); const data = await response.json(); // 閲覧URLを含む応答はログへ出さず、認可済みの表示・処理にだけ使う return data; }
レスポンス例
Response
{"url":"https://private.hanamii-storage.jp/...?...","expiresAt":"2026-10-29T01:00:00.000Z"}
オブジェクトストレージ
ストレージの利用量を取得
メンバー全員が、ワークスペース全体の保存容量・ファイル数・今月の配信量(日本時間、概算)とプラン上限を取得できます。値は10進文字列で返します。予約中の容量は含まないため、表示が上限未満でも予約を含むファイルAPIの判定で422になり得ます。支払い制限・停止中はlimitsの4値がすべて文字列の0になり、新規バケット・アップロードを止めます。既存の取得・配信は継続します。使用率は0で割らず、この状態を区別してください。配信量はアップロードを止める上限ではありません。
/api/v1/workspaces/:workspaceId/storage/usage
パラメータ
項目
指定
タイプ
説明
workspaceId
path
string
対象ワークスペースのUUID。トークンのscopeと所属・役割を毎回確認します
レスポンス
200
usedBytes、fileCount、deliveredBytes、limits(プラン不明ならnull、支払い制限・停止中は4値が文字列の0)
400
validation_error。ID・cursor・入力の形式が不正
401
unauthorized。APIトークンが未指定・失効・期限切れ
403
forbidden。トークンのscope・所属または役割が不足
429
rate_limited。操作のレート制限超過
500
internal_error。内部エラー。詳細は公開しません
502 / 503
external_api_error / service_unavailable。連携失敗、または未設定
リクエスト例
GET /api/v1/workspaces/:workspaceId/storage/usage
// サーバー内から呼ぶ関数。公開ルートから使う場合は、先に利用者と対象の権限を確認する export async function callEndpoint() { const token = process.env.HANAMII_TOKEN; if (!token) throw new Error('HANAMII_TOKEN is required'); const response = await fetch('https://hanamii.jp/api/v1/workspaces/workspace_id/storage/usage', { method: 'GET', headers: { Authorization: `Bearer ${token}`, }, cache: 'no-store', }); if (!response.ok) throw new Error(`Request failed: ${response.status}`); const data = await response.json(); // 閲覧URLを含む応答はログへ出さず、認可済みの表示・処理にだけ使う return data; }
レスポンス例
Response
{"usedBytes":"7900","fileCount":"1","deliveredBytes":"0","limits":{"maxBuckets":"30","maxTotalBytes":"100000000000","maxFiles":"100000","maxFileBytes":"2000000000"}}
日本の空に咲くクラウド
Calm. Fast. Trusted.
© 2026 hanamii. All rights reserved. 🌸