hanamii
hanamii

特徴

料金

お知らせ

お問い合わせ

API ドキュメント / hanamii REST API

REST API を使う

hanamii のワークスペース、プロジェクト、デプロイ、ログ、環境変数、オブジェクトストレージ、API トークンを HTTP リクエストから操作できます。

API トークンを発行

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・利用量

可

可

可

可

ストレージのバケット作成・削除・キー管理

可

可

不可

不可

プロジェクト一覧・詳細

可

可

可

可

ログ取得

可

可

可

可

環境変数の取得

可

可

可

不可

プロジェクト作成・デプロイ・再デプロイ

可

可

可

不可

環境変数の追加・更新

可

可

可

不可

プロジェクト削除

可

可

不可

不可

データベースの取得

可

可

可

可

データベースの作成・削除・接続トークン・データ閲覧・エクスポート・インポート

可

可

不可

不可

レート制限

レート制限を超過した場合、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 トークン

GET

/api/v1/user/tokens

有効な API トークンの一覧を取得します。

POST

/api/v1/user/tokens

新しい API トークンを作成します。(トークンの表示は作成時のみ)

GET

/api/v1/user/tokens/:id

指定した API トークンの情報を取得します。 :id に current を指定すると、このリクエストの認証に使用している API トークン自身の情報を取得します。

DELETE

/api/v1/user/tokens/:id

指定した API トークンを失効します。 :id に current を指定すると、このリクエストの認証に使用している API トークン自身を失効します。

ワークスペース

GET

/api/v1/workspaces

トークンの scope 内で参照できるワークスペース一覧を取得します。 full_account token はトークン所有ユーザーが所属しているワークスペース、workspace scope token は対象ワークスペースのみを返します。

プロジェクト

GET

/api/v1/projects

参照可能なプロジェクト一覧を取得します。

POST

/api/v1/projects

Git または ZIP から project を作成し、初回 deployment を開始します。

GET

/api/v1/projects/:id

project 情報、公開URL、直近 deployment 試行の状態を取得します。

POST

/api/v1/projects/:id/deploy

既存 project の再デプロイを開始します。

DELETE

/api/v1/projects/:id

指定したプロジェクトを削除します。 トークン所有ユーザーが、そのプロジェクトのワークスペースで owner または admin の場合のみ実行できます。外部リソース削除が継続する場合は、削除完了とせず 202 accepted を返します。

GET

/api/v1/projects/:id/logs

project の runtime logs を JSON または text で取得します。

GET / PUT

/api/v1/projects/:id/health-check

AppRun health check 設定を取得または保存します。

POST

/api/v1/projects/:id/restart

保存済みの環境変数とヘルスチェック設定を AppRun に反映します。

環境変数

GET / PATCH

/api/v1/projects/:id/env

project の環境変数を取得または key 単位で更新します。

データベース

GET / POST / DELETE

/api/v1/projects/:id/database

project の SQLite 互換データベースを取得、作成、削除します。

GET / POST

/api/v1/projects/:id/database/auth-tokens

データベースへ接続するためのトークンを一覧・発行します。

DELETE

/api/v1/projects/:id/database/auth-tokens/:tokenId

接続トークンを失効します。即座に接続できなくなります。

GET

/api/v1/projects/:id/database/tables

テーブルと列定義の一覧を取得します(読み取り専用)。

GET

/api/v1/projects/:id/database/tables/:table/rows

指定テーブルの行を offset ページングで取得します(読み取り専用)。

POST

/api/v1/projects/:id/database/exports

データベースを単一の SQLite .db ファイルとしてエクスポートします。

GET

/api/v1/projects/:id/database/exports/:exportJobId

エクスポート job の進行状態を取得します。

POST

/api/v1/projects/:id/database/exports/:exportJobId/download

完成したエクスポートの署名付きダウンロード URL を発行します。

POST

/api/v1/projects/:id/database/import-session

SQLite ファイルからデータベースを作る手順 1/2。分割アップロード用の署名付き URL を発行します。

POST

/api/v1/projects/:id/database/import-start

SQLite ファイルからデータベースを作る手順 2/2。アップロード済みパートの ETag を送って取込を開始します。

オブジェクトストレージ

GET

/api/v1/workspaces/:workspaceId/storage/buckets

ワークスペースのバケット一覧と、ファイルAPIの接続先apiOriginを返します。メンバー全員が利用できます。ストレージの一覧はcursorによるページ送りで、最大100件です。件数は固定で、limit・until・sinceは使用しません。createdAtなどの日時はISO 8601文字列です。

POST

/api/v1/workspaces/:workspaceId/storage/buckets

owner/adminがバケットを作成します。同名のバケットがある場合は409です。公開設定は作成後に変更できません。無料プランは非公開だけ作成できます。作成直前にその時点のプラン上限をストレージへ同期します。プランを判定できない場合は503で作成を止めます。応答を受け取れなかった場合は、自動で再作成せず一覧を確認してください。

DELETE

/api/v1/workspaces/:workspaceId/storage/buckets/:bucketId

owner/adminがバケットを削除します。ファイルとキーは使えなくなり、画面から元には戻せません。ファイルが残る場合は202で処理を継続し、空なら204を返します。削除済みへの再送も202または204で、存在しないIDの404とは異なります。公開URLの配信停止には、後処理とキャッシュの時間がかかります。

GET

/api/v1/workspaces/:workspaceId/storage/buckets/:bucketId/access-keys

owner/adminがバケットの有効なアクセスキーを取得します。キーの平文は含まれません。1ページ50件です。

POST

/api/v1/workspaces/:workspaceId/storage/buckets/:bucketId/access-keys

owner/adminがバケット専用のキーを発行します。keyの平文はこの応答で一度だけ返します。作成者はAPIトークンの所有者になります。応答を受け取れなかった場合は、一覧から発行結果を確認し、不要なキーを無効化してください。Hanamii APIトークンとストレージキーは用途が異なります。

DELETE

/api/v1/workspaces/:workspaceId/storage/buckets/:bucketId/access-keys/:keyId

owner/adminがアクセスキーを無効化します。既に無効なキーへの再送も204です。既発行の署名PUT URL・非公開配信URLは期限まで残り、キャッシュも即時には失効しません。

GET

/api/v1/workspaces/:workspaceId/storage/buckets/:bucketId/files

メンバー全員がファイル一覧を取得できます。1ページ50件で、日時はISO 8601、sizeBytesは10進文字列です。URLは一覧には含めず、開くときに閲覧用URLを発行してください。

POST

/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自体を持つ人は期限まで取得できるため、必要な相手だけに渡してください。

GET

/api/v1/workspaces/:workspaceId/storage/usage

メンバー全員が、ワークスペース全体の保存容量・ファイル数・今月の配信量(日本時間、概算)とプラン上限を取得できます。値は10進文字列で返します。予約中の容量は含まないため、表示が上限未満でも予約を含むファイルAPIの判定で422になり得ます。支払い制限・停止中はlimitsの4値がすべて文字列の0になり、新規バケット・アップロードを止めます。既存の取得・配信は継続します。使用率は0で割らず、この状態を区別してください。配信量はアップロードを止める上限ではありません。

エンドポイント詳細

各 endpoint の method、path、入力、レスポンス、使用例です。

API トークン

API トークン一覧を取得

有効な API トークンの一覧を取得します。

GET

/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 トークンを作成します。(トークンの表示は作成時のみ)

POST

/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 トークン自身の情報を取得します。

GET

/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 トークン自身を失効します。

DELETE

/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 は対象ワークスペースのみを返します。

GET

/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 を指定すると、そのワークスペース内のプロジェクトだけを返します。

GET

/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 で判定されます。

POST

/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 権限で判定されます。

GET

/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 権限で判定されます。

POST

/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 を返します。

DELETE

/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 を返します。

GET

/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 のみ実行可能です。

GET / PATCH

/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 しません。

GET / PUT

/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 は維持されます。

POST

/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 を返します。時間をおいて再試行してください。

GET / POST / DELETE

/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 を返します。

GET / POST

/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 のみ。

DELETE

/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 のみ。

GET

/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 のみ。

GET

/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 のみ。

POST

/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 のみ。

GET

/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 のみ。

POST

/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 のみ。

POST

/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 のみ。

POST

/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文字列です。

GET

/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で作成を止めます。応答を受け取れなかった場合は、自動で再作成せず一覧を確認してください。

POST

/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の配信停止には、後処理とキャッシュの時間がかかります。

DELETE

/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件です。

GET

/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トークンとストレージキーは用途が異なります。

POST

/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は期限まで残り、キャッシュも即時には失効しません。

DELETE

/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を発行してください。

GET

/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自体を持つ人は期限まで取得できるため、必要な相手だけに渡してください。

POST

/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で割らず、この状態を区別してください。配信量はアップロードを止める上限ではありません。

GET

/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"}}
hanamii

日本の空に咲くクラウド

Calm. Fast. Trusted.

プロダクト

SECURITY ACTION セキュリティ対策自己宣言 一つ星

© 2026 hanamii. All rights reserved. 🌸