APIリファレンス

REST API
リンクを基盤に、開発しよう。

APIトークンで認証し、リンクの一覧表示と作成、訪問データの読み取り、Webhookの登録を行います。

ベースURL https://letl.ink/api/v1 HTTPSのみ

プラン Growth Ultimate
このページの内容

はじめに

REST APIはGrowthとUltimateで利用できます。リクエストはHTTPSでhttps://letl.ink/api/v1に送ります。FreeまたはSoloのワークスペースは/api/v1から403 plan_requiredを受け取ります。MCPエンドポイントは別途Ultimateに限定されています。

  1. 連携 → REST APIを開きます(ワークスペースのオーナーと管理者のみ)。
  2. トークンを生成します。有効期限はありません。
  3. パスワードと同様に保管してください。1つのトークンで、REST API、MCPサーバー、このワークスペースに接続したすべての自動化プラットフォームを利用するため、再生成するとそれらすべてが一度に無効になります。

メンバーは生成済みの既存トークンをコピーできます。ローテーションできるのはオーナーと管理者のみです。

認証

トークンはX-API-KEYまたはAuthorization: Bearerとして送信します。/api/v1と/mcpではどちらも受け付けます。トークンがまったくないリクエストは401 unauthenticatedを返します。

GET 自分の情報
curl -H "X-API-KEY: YOUR_TOKEN" \
  https://letl.ink/api/v1/auth/me

同等のヘッダー: Authorization: Bearer YOUR_TOKEN

規約

以下のすべてのエンドポイントに共通です。

レスポンスの構造

成功したレスポンスはすべてdataキーを持つJSONオブジェクトで、結果について補足がある場合(ページネーション、確定した期間、地域データを含むかどうか)はmetaキーも含まれます。失敗した場合はすべてerrorキーを持つオブジェクトで、安定したcode、人が読むためのmessage、場合によってはdetailsが含まれます。分岐にはメッセージのテキストではなく、必ずcodeを使ってください。

形
// success
{ "data": { … }, "meta": { … } }

// failure
{ "error": { "code": "invalid_parameter",
             "message": "sort must be one of: created_at, clicks.",
             "details": { "parameter": "sort" } } }

ページネーション

一覧系のエンドポイントはlimit(1〜200、デフォルト50)とoffsetを受け付けます。metaブロックにはtotal、has_more、next_offsetが含まれるため、計算せずにページ送りできます:has_moreがfalseになるまでoffset = meta.next_offsetで呼び出し続けてください。

すべてのリンクをページ送りで取得
offset=0
while [ "$offset" != "null" ]; do
  page=$(curl -s -H "X-API-KEY: $TOKEN" \
    "https://letl.ink/api/v1/links?limit=200&offset=$offset")
  echo "$page" | jq -c '.data[]'
  offset=$(echo "$page" | jq -r '.meta.next_offset')
done

並べ替え、絞り込み、検索

GET /linksはsort(created_at、clicks、short_code、title、updated_at)、direction(asc/desc)、search(短縮コード、タイトル、リンク先に一致)、type、archived、favorite、domainを受け付けます。不明な値は黙って無視されるのではなく、invalid_parameterと許可される値の一覧とともに拒否されます。

期間指定

start_dateとend_dateはYYYY-MM-DD形式で、両日を含みます。期間はプランのデータ保持期間に合わせて切り詰められます — 保持期間30日のプランで1年分の履歴を要求すると保持されている30日分が返され、実際に使われた期間はmeta.date_rangeで確認できます。

レート制限

アカウントごとに1分あたり600リクエスト(スライディングウィンドウ方式)。すべてのレスポンスにX-RateLimit-Limit、X-RateLimit-Remaining、X-RateLimit-Reset(Unixタイムスタンプ)が含まれます。上限を超えると、秒数を示すRetry-Afterヘッダー付きで429 rate_limitedが返されます。すぐに再試行せず、Retry-Afterに従って待機してください。

すべてのレスポンスに含まれるヘッダー
X-RateLimit-Limit: 600
X-RateLimit-Remaining: 586
X-RateLimit-Reset: 1789000816

バージョニング

パスにはバージョンが含まれます。レスポンスへのフィールド追加や新しい任意パラメータは破壊的変更ではなく、いつでも行われる可能性があるため、防御的に解析し、認識できないキーは無視してください。既存のフィールドを変更・削除するものは、新しいバージョンのプレフィックスでリリースされます。

エンドポイント

アカウント

GET /me 接続テスト

ID、ワークスペース、プラン、そのプランのすべての利用権限。トークンを確認し、操作を試す前にアカウントで何ができるかを把握する最も手軽な方法です。

GET cURL
curl -H "X-API-KEY: YOUR_TOKEN" \
  https://letl.ink/api/v1/me
レスポンス 200
{
  "data": {
    "user": { "id": 1, "email": "[email protected]", "name": "You" },
    "workspace": { "id": 12, "name": "My Workspace", "block_bots": true },
    "plan": {
      "id": "growth",
      "name": "Growth",
      "limits": {
        "links": 200,
        "monthly_clicks": 100000,
        "custom_domains": 3,
        "qr_codes": 30,
        "retention_days": 365
      },
      "features": {
        "api": true,
        "webhooks": true,
        "integrations": true,
        "ai_access": false,
        "geo_analytics": false,
        "smart_link_types": true
      }
    },
    "base_domain": "letl.ink"
  }
}
GET /usage

今月の請求期間に各上限をどれだけ消費したか。計測クリックの上限に達する前にお客様に警告するのに使えます — 上限を超えてもリダイレクトは機能しますが、クリックは記録されなくなります。

レスポンス 200
{
  "data": {
    "links": { "used": 42, "limit": 200, "remaining": 158, "percent_used": 21.0 },
    "clicks_this_month": { "used": 8140, "limit": 100000, "remaining": 91860, "percent_used": 8.1 },
    "custom_domains": { "used": 1, "limit": 3, "remaining": 2, "percent_used": 33.3 },
    "qr_codes": { "used": 4, "limit": 30, "remaining": 26, "percent_used": 13.3 }
  },
  "meta": { "plan": "growth", "period": "2026-09" }
}
GET /domains

ワークスペースのカスタムドメインと、それぞれのDNS認証が完了しているかどうか。リンク作成時のdomainフィールドには認証済みのドメインのみ使用できます。

GET /integrations

製品が提供するすべての連携について、プランに含まれるか、このワークスペースで接続済みか、配信状況(最新のステータス、最新のエラー、連続失敗回数)を返します。複数のワークスペースを監視するのに便利です。

リンク

分析

GET /analytics/summary

ワークスペース全体の主要な数値:累計と期間内のクリック、ユニーク訪問者、QRスキャン、ピーク日、時間帯と曜日の分布。days(デフォルト30、保持期間内に制限)を受け付けます。

レスポンス 200(抜粋)
{
  "data": {
    "window_days": 30,
    "clicks": {
      "total": 24592, "window": 8140, "last_7_days": 2103,
      "daily_average": 271,
      "peak_day": { "date": "Sep 02", "clicks": 612 }
    },
    "visitors": { "unique_total": 18204, "unique_window": 6021 },
    "qr": { "scans_total": 940, "scans_window": 310 },
    "timing": {
      "by_hour": [12, 4, 2, …],
      "by_weekday": [1420, 1610, 1585, 1490, 1310, 480, 245],
      "peak_hour": { "peakHour": 14, "peakValue": 812, "label": "14:00–14:59" },
      "peak_weekday": { "peakDay": 1, "peakValue": 1610, "label": "Tuesday" }
    },
    "links": { "active": 42, "limit": 200 }
  },
  "meta": { "plan": "growth", "geo_included": true, "retention_days": 365 }
}
GET /analytics/timeseries

グラフ用の日別クリック数。link_idで1つのリンクに絞り込み、daysで期間を設定します。トラフィックのない日は省略されずゼロとして返されるため、系列は常に連続しています。

レスポンス 200
{
  "data": [
    { "date": "Sep 04", "clicks": 22 },
    { "date": "Sep 05", "clicks": 11 }
  ],
  "meta": { "window_days": 7, "total": 33, "link_id": null }
}
GET /analytics/breakdown

1つの軸でグループ化したクリックと、各行の合計に対する割合。

クエリパラメータ

  • dimension string

    channel、referrer、device、browser、os、brand、variationまたはcountry。browser、os、brand、variationにはlink_idが必要です。

    必須
  • link_id integer

    1つのリンクに限定します。省略するとワークスペース全体が対象です。

    任意
  • limit integer

    1〜100。デフォルトは10。

    任意
レスポンス 200
{
  "data": [
    { "label": "Search", "value": 215, "share": 33.1 },
    { "label": "Social", "value": 201, "share": 30.9 },
    { "label": "Direct / none", "value": 142, "share": 21.8 }
  ],
  "meta": { "dimension": "channel", "link_id": 49, "total": 650 }
}
GET /events ページ分割

ワークスペース内のすべてのリンクの生の訪問フィード(新しい順)。GET /visitsの現行版で、同じデータに標準のエンベロープとlimit・offsetのサポートが加わっています。

レスポンス 200
{
  "data": [
    {
      "id": 2691,
      "link_id": 49,
      "short_code": "spring",
      "occurred_at": "2026-09-10T22:45:33+00:00",
      "ip_address": "203.0.113.7",
      "referrer": "https://twitter.com/",
      "browser": "Chrome",
      "os": "iOS",
      "device_type": "mobile",
      "device_brand": "Apple",
      "country": "US",
      "variation": "control"
    }
  ],
  "meta": { "limit": 50, "returned": 50, "geo_included": true }
}

Webhook

GET /hooks

このアカウントに登録されているWebhookエンドポイント。

POST /hooks

HTTPSエンドポイントを登録すると、記録されたクリックごとにJSONペイロードを受け取れます。1アカウントにつき最大25件。失敗した配信は自動的に再試行されます。

JSONボディ

  • target_url

    https://である必要があります。

    必須
  • event

    デフォルトはlink_visitedで、現在唯一のイベントです。

    任意
POST cURL
curl -X POST https://letl.ink/api/v1/hooks \
  -H "X-API-KEY: YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"target_url": "https://example.com/hooks/clicks"}'
DELETE /hooks/{id}

Webhookのエンドポイントを削除します。ZapierのREST Hookフロー用にPOST /hooks/subscribeとDELETE /hooks/unsubscribe/{id}も引き続き利用できます。

レガシー

GET /auth/me レガシー

元の接続テスト:ユーザーID、メールアドレス、ワークスペースのID/名前をフラットなオブジェクトで返します。GET /meは同じ情報に加えてプランの上限と機能フラグを返すため、新しいコードにはそちらが適しています。

GET cURL
curl -H "X-API-KEY: YOUR_TOKEN" \
  https://letl.ink/api/v1/auth/me
レスポンス 200
{
  "id": 1,
  "email": "[email protected]",
  "workspace_id": 12,
  "workspace_name": "My Workspace"
}
GET /visits レガシー

ワークスペース全体の最新50件の訪問を、エンベロープなしのJSON配列として、visit_id、visit_time、link_shortcode、visitor_*のフィールド名で返します。ZapierのREST Hookの「perform list」ステップが読み取るもののため、形式は固定されています。新規開発にはGET /eventsを使ってください。

POST /hooks/subscribe Zapier

REST Hookの購読。target_urlと任意のevent(デフォルトlink_visited)を受け取り、作成された購読をエンベロープなしでフラットに返します。POST /hooksは標準形式での同じ操作です。

DELETE /hooks/unsubscribe/{id} Zapier

REST Hookの購読解除。{"success": true}を返します。DELETE /hooks/{id}は標準形式での同等の操作です。

エラー

  • 400 invalid_request

    ボディがJSONオブジェクトではないか、必須フィールドがありません。

  • 400 invalid_parameter

    クエリパラメータの形式が不正か、許可された値の範囲外です。details.parameterに該当するパラメータが示されます。

  • 401 unauthenticated

    トークンが送信されていません。X-API-KEYまたはAuthorization: Bearerを追加してください。

  • 401 invalid_token

    トークンがどのアカウントとも一致しません。再生成された可能性があります。

  • 403 plan_required

    アカウントのプランにこのエンドポイントまたは機能が含まれていません。details.upgrade_urlは請求ページを指しています。

  • 403 forbidden

    認証済みですが権限がありません — 例:メンバーがオーナー専用の操作を試みた場合。

  • 404 not_found

    このワークスペースにそのリソースはありません。他のワークスペースのIDは、アクセス禁止ではなく見つからないとして報告されます。

  • 409 conflict

    リクエストが現在の状態と競合しています — Webhookの上限に達しているか、アカウントにまだワークスペースがありません。

  • 422

    POST /links/bulkでバッチ内のすべての行が失敗した場合に返されます。meta.errorsを確認してください。

  • 429 rate_limited

    直近1分間のリクエストが600件を超えました。Retry-Afterの秒数だけ待ってください。

従来のGET /visitsとGET /links/{id}/visitsエンドポイントは独自のフィールド名を持つJSON配列を返し、それらを使って構築済みのZapier連携のために固定されています。新しいコードでは、標準のエンベロープとページネーションに対応したGET /eventsとGET /links/{id}/eventsを使ってください。

まだご質問がありますか?

お手伝いします。ご連絡いただければ、できるだけ早くご返信します。