KotobaMedia Tile Kiln は、アップローダーと同じ処理を自動化するための小さな HTTP API を提供します。ジョブを作成し、 返された署名付き URL に GeoTIFF をアップロードし、変換完了までポーリングしてから、生成された TileJSON URL を利用します。ジョブ作成には連絡先メールアドレスまたは有効な API キーが必須ですが、公開ジョブレスポンスにはメールアドレスや API キーメタデータは含まれません。変更キー付きのジョブは期限前にアップロードと生成された出力を呼び出し元から削除できます。
ベース URL
| 環境 | ベース URL |
|---|---|
| 本番 | https://tile-kiln-api.kmproj.com |
| 開発 | https://tile-kiln-api-dev.kmproj.com |
API_URL="https://tile-kiln-api.kmproj.com"
制限とタイミング
- 入力ファイルは GeoTIFF 互換の TIFF または BigTIFF である必要があります。
- 入力アップロードの上限は
100000000バイトです。 POST /jobsでは内部トレース用の連絡先メールアドレスまたは有効な API キーが必須です。ジョブのレスポンスにはメールアドレスや API キーメタデータは返されません。- ジョブ作成時に
sizeBytes、fileSizeBytes、またはcontentLengthを含めてください。 - 署名付きアップロード URL の有効期限は現在 900 秒です。
- 元 GeoTIFF オブジェクトは、処理が
COMPLETEDまたはFAILEDになったあと削除されます。 - ジョブステータスは、処理完了から 7 日後に利用できなくなる場合があります。
changeKeyなしのアップロードは、アップロード受信から 1 カレンダーか月後に期限切れになります。ファイルがアップロードされなかったジョブは、ジョブ作成から 1 カレンダーか月後に期限切れになります。changeKey付きのアップロードは、アップロード受信から 6 カレンダーか月後に期限切れになり、期限前に呼び出し元から削除できます。ファイルがアップロードされなかったジョブは、ジョブ作成から 6 カレンダーか月後に期限切れになります。- 有効な API キーで作成したアップロードは自動的には期限切れになりません。
- 期限切れのアップロードと生成された出力は自動的にクリーンアップされます。
- アップロードリクエストでは、
upload.headersで返されたContent-Typeと完全に同じ値を使ってください。
1. ジョブを作成する
POST /jobs
curl -sS -X POST "$API_URL/jobs" \
-H "Content-Type: application/json" \
-d '{
"email": "maps@example.com",
"changeKey": "keep-this-to-delete-later",
"fileName": "source.tif",
"sizeBytes": 73400320,
"contentType": "image/tiff",
"options": {
"tileFormat": "png",
"tileSize": 512,
"resampling": "bilinear",
"minZoom": 4,
"maxZoom": 14
}
}'
API キーによるアップロードでは、x-api-key ヘッダーでキーを送信します。JSON 本文の apiKey または api_key も使用できます。有効な API キーが指定された場合、email は任意です。省略すると API キーに紐づく連絡先メールアドレスを使います。
curl -sS -X POST "$API_URL/jobs" \
-H "Content-Type: application/json" \
-H "x-api-key: $TILE_KILN_API_KEY" \
-d '{
"fileName": "source.tif",
"sizeBytes": 73400320,
"contentType": "image/tiff"
}'
リクエスト本文のフィールド
| フィールド | 必須 | 説明 |
|---|---|---|
email |
API キーを使わない場合は必須 | 内部トレース用の連絡先メールアドレスです。contactEmail も使用できます。API キーアップロードでは、省略すると API キーに紐づく連絡先メールアドレスを使い、指定するとそのジョブ用に上書きします。メールアドレスは POST /jobs と GET /jobs/{jobId} のジョブレスポンスには返されません。 |
fileName |
必須 | 元ファイル名です。filename も使用できます。安全でない文字はサニタイズされます。 |
changeKey |
任意 | 呼び出し元が保持する任意のキーです。API キーを使わないアップロードでは、指定すると保持期間が 6 カレンダーか月になり、DELETE /jobs/{jobId} で期限前に削除できます。API キーアップロードでは保持期間は無期限のままで、変更キーは呼び出し元削除だけを有効にします。省略すると呼び出し元からの削除はできません。change_key も使用できます。 |
apiKey |
任意 | 無期限保持アップロード用の API キーです。通常は x-api-key ヘッダーを使用してください。本文では api_key も使用できます。有効な API キーを使うとアップロードは期限切れにならず、ガベージコレクション対象外になります。 |
sizeBytes |
推奨 | 元ファイルのバイト数です。fileSizeBytes と contentLength も使用できます。 |
contentType |
任意 | アップロード時の content type です。省略時は image/tiff です。 |
options |
任意 | タイル変換オプションです。options を省略した場合は、各オプションをトップレベルで送ることもできます。 |
変換オプション
| オプション | デフォルト | 説明 |
|---|---|---|
tileFormat |
png |
ラスタータイル形式です。png、jpeg、webp のいずれかです。 |
tileSize |
256 |
タイルサイズのピクセル数です。128 から 4096 までの整数です。 |
resampling |
bilinear |
nearest、bilinear、cubic、cubicspline、lanczos、mode、average のいずれかです。 |
minZoom |
未設定 | 任意の最小ズームです。0 から 24 までの整数です。 |
maxZoom |
未設定 | 任意の最大ズームです。0 から 24 までの整数です。minZoom 以上である必要があります。 |
quality |
未設定 | 任意の出力 quality です。1 から 100 までの整数です。 |
overviewLevels |
[2,4,8,16,32,64,128,256] |
2 以上の 2 の累乗を含む空でない配列です。 |
成功レスポンス
公開ジョブオブジェクトには、連絡先メールアドレス、変更キー、API キーメタデータは含まれません。
ジョブレスポンスの expiresAt は、公開ジョブステータスの有効期限の目安です。API キージョブは無期限のため、expiresAt は省略されます。
{
"job": {
"jobId": "43f5a43d-3081-4378-9a19-7f4a47d0dc0b",
"status": "AWAITING_UPLOAD",
"fileName": "source.tif",
"canDelete": true,
"contentType": "image/tiff",
"createdAt": "2026-06-25T04:30:00.000Z",
"updatedAt": "2026-06-25T04:30:00.000Z",
"expiresAt": 1798173000,
"input": {
"bucket": "tile-kiln-input",
"key": "uploads/43f5a43d-3081-4378-9a19-7f4a47d0dc0b/source.tif",
"sizeBytes": 73400320
},
"output": {
"bucket": "km-tileserver",
"key": "uploads/raster/43f5a43d-3081-4378-9a19-7f4a47d0dc0b/source.pmtiles"
},
"options": {
"overviewLevels": [2, 4, 8, 16, 32, 64, 128, 256],
"resampling": "bilinear",
"tileFormat": "png",
"tileSize": 512,
"minZoom": 4,
"maxZoom": 14
}
},
"upload": {
"method": "PUT",
"url": "https://...",
"headers": {
"Content-Type": "image/tiff"
},
"maxSizeBytes": 100000000,
"expiresInSeconds": 900
}
}
2. GeoTIFF をアップロードする
返された署名付き URL に元ファイルを直接アップロードします。Authorization ヘッダーは追加しないでください。
UPLOAD_URL="https://..."
curl -sS -X PUT "$UPLOAD_URL" \
-H "Content-Type: image/tiff" \
--data-binary @source.tif
3. ジョブをポーリングする
GET /jobs/{jobId}
JOB_ID="43f5a43d-3081-4378-9a19-7f4a47d0dc0b"
curl -sS "$API_URL/jobs/$JOB_ID"
ステータス値
| ステータス | 意味 |
|---|---|
AWAITING_UPLOAD |
ジョブは存在しますが、元ファイルはまだアップロードされていません。 |
PROCESSING |
アップロードイベントを受け取り、変換を実行中です。 |
COMPLETED |
PMTiles アーカイブが正常に書き込まれました。 |
FAILED |
変換に失敗しました。ジョブに error と errorDetails が含まれる場合があります。 |
数秒ごとにポーリングしてください。ステータスが COMPLETED または FAILED になったら停止します。
4. TileJSON URL を組み立てる
完了した出力キーは .pmtiles で終わります。公開 TileJSON URL は、同じキーから
.pmtiles を除き、.json を付けて https://tiles.kmproj.com/ 配下に置いた URL です。
OUTPUT_KEY="uploads/raster/43f5a43d-3081-4378-9a19-7f4a47d0dc0b/source.pmtiles"
TILEJSON_URL="https://tiles.kmproj.com/${OUTPUT_KEY%.pmtiles}.json"
echo "$TILEJSON_URL"
map.addSource("uploaded-raster", {
type: "raster",
url: "https://tiles.kmproj.com/uploads/raster/43f5a43d-3081-4378-9a19-7f4a47d0dc0b/source.json",
tileSize: 512,
});
5. 任意の呼び出し元削除
DELETE /jobs/{jobId}
呼び出し元からの削除は、ジョブ作成時に空でない changeKey を指定した場合のみ利用できます。API キー認証だけでは削除は認可されません。変更キーは API から返されません。
完了済みの変換では、保持された変換状態と生成された PMTiles 出力を削除します。一時的な元ファイルやエラー状態がまだ存在する場合は、それらも削除します。変換が完了していない場合は、一時的なアップロード状態を削除します。
ジョブが PROCESSING の間は delete は 409 を返します。COMPLETED または FAILED になってから再試行してください。
JOB_ID="43f5a43d-3081-4378-9a19-7f4a47d0dc0b"
curl -sS -X DELETE "$API_URL/jobs/$JOB_ID" \
-H "Content-Type: application/json" \
-d '{"changeKey":"keep-this-to-delete-later"}'
変更キーは x-change-key ヘッダーでも送信できます。
エンドツーエンドのシェルスクリプト
このスクリプトは jq を使い、ジョブ完了までポーリングします。
#!/usr/bin/env sh
set -eu
API_URL="${API_URL:-https://tile-kiln-api.kmproj.com}"
FILE_PATH="${1:?Usage: $0 source.tif maps@example.com}"
EMAIL="${2:?Usage: $0 source.tif maps@example.com}"
CHANGE_KEY="${CHANGE_KEY:-}"
FILE_NAME="$(basename "$FILE_PATH")"
SIZE_BYTES="$(wc -c < "$FILE_PATH" | tr -d ' ')"
CREATE_RESPONSE="$(
jq -n \
--arg email "$EMAIL" \
--arg changeKey "$CHANGE_KEY" \
--arg fileName "$FILE_NAME" \
--arg contentType "image/tiff" \
--argjson sizeBytes "$SIZE_BYTES" \
'({
email: $email,
fileName: $fileName,
sizeBytes: $sizeBytes,
contentType: $contentType,
options: {
tileFormat: "png",
tileSize: 512,
resampling: "bilinear"
}
} + (if $changeKey == "" then {} else { changeKey: $changeKey } end))' |
curl -sS -X POST "$API_URL/jobs" \
-H "Content-Type: application/json" \
--data-binary @-
)"
JOB_ID="$(printf '%s' "$CREATE_RESPONSE" | jq -r '.job.jobId')"
UPLOAD_URL="$(printf '%s' "$CREATE_RESPONSE" | jq -r '.upload.url')"
CONTENT_TYPE="$(printf '%s' "$CREATE_RESPONSE" | jq -r '.upload.headers["Content-Type"]')"
curl -sS -X PUT "$UPLOAD_URL" \
-H "Content-Type: $CONTENT_TYPE" \
--data-binary "@$FILE_PATH"
while :; do
JOB_RESPONSE="$(curl -sS "$API_URL/jobs/$JOB_ID")"
STATUS="$(printf '%s' "$JOB_RESPONSE" | jq -r '.job.status')"
printf '%s\n' "job $JOB_ID: $STATUS"
case "$STATUS" in
COMPLETED)
OUTPUT_KEY="$(printf '%s' "$JOB_RESPONSE" | jq -r '.job.output.key')"
printf '%s\n' "https://tiles.kmproj.com/${OUTPUT_KEY%.pmtiles}.json"
exit 0
;;
FAILED)
printf '%s\n' "$JOB_RESPONSE" >&2
exit 1
;;
esac
sleep 3
done
エラー
エラーレスポンスは JSON です。
{
"message": "fileName is required."
}
| HTTP ステータス | 意味 |
|---|---|
400 |
JSON 本文が不正、必須フィールドが不足、メールアドレスが不正、変更キーが不正、または変換オプションが不正です。 |
403 |
指定された API キーが不正、または保存済みの変更キーがないアップロードや誤った変更キーで削除をリクエストしました。 |
404 |
ルート、ジョブ ID、または保持された変換が見つかりません。 |
409 |
アップロード処理中に削除をリクエストしました。 |
413 |
宣言された入力サイズが 100000000 バイトを超えています。本文に maxSizeBytes も含まれます。 |
500 |
予期しないサービスエラーです。 |