toui ブログ

短縮リンクの運用を自動化する — toui.io API 開発者ガイド

公開日 2026年8月28日

短縮リンクの運用を自動化する — toui.io API 開発者ガイド

マーケティング担当が、共有スプレッドシートに商品URLを50本流し込んできました。件名は「今週末セール。金曜までに、これ全部の計測できるリンクをお願いします」。

スプレッドシートを開きます。50行。1行ごとに、わかりやすいタイトルとソーシャルプレビューのメタデータを付けた短縮リンクが要ります。FacebookやXで共有したときに、リンクの見た目が整っているようにするためです。toui.io のダッシュボードを開いて、URLを1本ずつ貼って、OGの項目を埋めて、短縮リンクをコピーして戻して……それを、あと49回。

あるいは、30秒で終わるスクリプトを書くこともできます。

この記事で書くのは、まさにそれです。私が toui.io をつくった理由のひとつが、この場面に何度も出くわしたことでした。だからAPIは、この作業を中心に設計してあります。読み終わるころには、短縮リンクをつくり、それを確認し、キャンペーンの成果を取り出すところまでが動いています。ブラウザは不要です。

始める前に

用意するものは3つです。

  1. toui.io のアカウント。 Freeプランでも REST API を使えます(60 リクエスト/分、5,000 リクエスト/月、500 リクエスト/日)。連携をひととおりつくるには十分です。バーストや月間の上限がもっと必要になったら、Pro か Business にアップグレードしてください。料金プランはこちら

  2. APIキー。 toui.io のダッシュボードにログインし、「API」のページでキーを作成します。表示されるのは一度きりなので、コピーしてプロジェクト直下の .env ファイルに保存してください。

# .env
TOUI_API_KEY=toui_your_key_here

.env.gitignore に入っていることを確認してください。APIキーは、絶対にバージョン管理にコミットしないでください。

  1. Node.js 18以上fetch が組み込みで使えます)と、環境変数を読み込む dotenv
npm install dotenv

Node.js 20.6以上なら、dotenv を省いて組み込みの --env-file フラグを使えます。node --env-file=.env create-links.js

この記事のコードは、どれも環境変数からキーを読みます。どのスクリプトも、冒頭はこうなります。

import "dotenv/config";

const API_KEY = process.env.TOUI_API_KEY;
if (!API_KEY) {
  throw new Error("Missing TOUI_API_KEY in .env file");
}

このチェックが最初に走ります。誰かがリポジトリをクローンして .env をつくり忘れたとき、意味のわからない401ではなく、はっきりしたエラーを受け取れます。

ステップ1 — 短縮リンクをつくる

エンドポイントは POST https://toui.io/api/v1/shorten です。リンク先のURLと、任意のメタデータをJSONで送ると、短縮リンクが返ってきます。

いちばん短い呼び出しは、これです。

const response = await fetch("https://toui.io/api/v1/shorten", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.TOUI_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    url: "https://shop.example.com/products/wireless-earbuds-pro",
    title: "Wireless Earbuds Pro - Flash Sale",
  }),
});

if (!response.ok) {
  const err = await response.json();
  throw new Error(`API error ${response.status}: ${err.error}`);
}

const data = await response.json();
console.log(data);
// {
//   short_url: "https://toui.io/xK3mQp",
//   short_code: "xK3mQp",
//   target_url: "https://shop.example.com/products/wireless-earbuds-pro",
//   created_at: "2026-04-10T08:30:00.000Z"
// }

これが基本の形です。URLをPOSTし、response.ok を確認し、結果をパースする。以下の例も、すべて同じ形をしています。

ソーシャルプレビューのメタデータを付ける

短縮リンクがFacebookやX、Slackで共有されると、各プラットフォームはプレビューカードを描くためにOpen Graphのタグを取りに行きます。toui.io では、この内容を作成時に指定できます。

const result = await createLink({
  url: "https://shop.example.com/products/wireless-earbuds-pro",
  title: "Wireless Earbuds Pro - Flash Sale",
  og_title: "60% Off Wireless Earbuds Pro -- This Weekend Only",
  og_description: "Our top-rated earbuds at the lowest price ever. 48 hours only.",
});

og_titleog_description は任意です。省いた場合、各プラットフォームはリンク先ページのメタデータをそのまま使います。とはいえ、1クリックでも多く取りたいセールでは、2行追加してでもプレビューカードを自分で指定する価値があります。

画像を用意してあるなら og_image_url も渡せます。公開されている https:// の画像URLなら、何でも受け付けます。

短縮コードを自分で決める

toui.io は、既定ではランダムな6文字のコードを生成します。ただ、読める形にしたいとき——ポッドキャストで読み上げるリンクや、パッケージに印刷するリンクなど——には、コードを指定できます。

{
  url: "https://shop.example.com/flash-sale",
  title: "Weekend Flash Sale",
  custom_code: "sale426"
}
// 結果:https://toui.io/sale426

カスタム短縮コードは英数字4〜16文字です。すでに使われているコードを指定すると、APIは400を返します。これは有料プランの機能で、Freeプランのアカウントでは自動生成のコードのみが使えます。

50件の商品をループで処理する

ここまでをまとめます。商品リストを読み込んで、それぞれに計測できる短縮リンクをつくる、完成版のスクリプトです。

import "dotenv/config";

const API_KEY = process.env.TOUI_API_KEY;
if (!API_KEY) {
  throw new Error("Missing TOUI_API_KEY in .env file");
}

const API_BASE = "https://toui.io/api/v1";

// マーケティング担当から届いた商品リスト
const products = [
  {
    name: "Wireless Earbuds Pro",
    url: "https://shop.example.com/products/wireless-earbuds-pro",
    discount: "60%",
  },
  {
    name: "USB-C Hub 7-in-1",
    url: "https://shop.example.com/products/usb-c-hub-7in1",
    discount: "45%",
  },
  // ……残り48件
];

async function createLink(body) {
  const response = await fetch(`${API_BASE}/shorten`, {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify(body),
  });

  if (!response.ok) {
    const err = await response.json();
    throw new Error(`Failed to shorten ${body.url}: ${err.error}`);
  }

  return response.json();
}

async function main() {
  const results = [];

  for (const product of products) {
    const result = await createLink({
      url: product.url,
      title: `${product.name} - Flash Sale`,
      og_title: `${product.discount} Off ${product.name} -- This Weekend Only`,
      og_description: `Flash sale pricing on ${product.name}. Limited time offer.`,
    });

    results.push({
      product: product.name,
      short_url: result.short_url,
      code: result.short_code,
    });

    console.log(`Created: ${result.short_url} -> ${product.name}`);
  }

  console.log(`\nDone. Created ${results.length} short links.`);
  return results;
}

main().catch(console.error);

実行すると、ターミナルに50本の短縮リンクが並びます。どれも計測でき、ソーシャルプレビューのメタデータが付いていて、メールの配信、広告のクリエイティブ、SNSの投稿にそのまま入れられます。

ステップ2 — つくったリンクを確認する

マーケティング担当にリンクを渡す前に、ざっと点検しておくと安心です。GET /api/v1/urls/{code} は、その短縮リンクについて toui.io が持っている情報をすべて返します。

async function getLink(code) {
  const response = await fetch(`${API_BASE}/urls/${code}`, {
    headers: {
      "Authorization": `Bearer ${API_KEY}`,
    },
  });

  if (!response.ok) {
    const err = await response.json();
    throw new Error(`Lookup failed for ${code}: ${err.error}`);
  }

  return response.json();
}

const link = await getLink("xK3mQp");
console.log(link);
// {
//   short_code: "xK3mQp",
//   target_url: "https://shop.example.com/products/wireless-earbuds-pro",
//   title: "Wireless Earbuds Pro - Flash Sale",
//   click_count: 0,
//   is_active: 1,
//   og_title: "60% Off Wireless Earbuds Pro -- This Weekend Only",
//   og_description: "Our top-rated earbuds at the lowest price ever. 48 hours only.",
//   og_image_url: null,
//   created_at: "2026-04-10T08:30:00.000Z"
// }

抜き取り検査に便利です。target_url が正しいか、OGの項目が入っているか、is_active が 1 かを確認できます。50本すべてに対して走らせて、スプレッドシートを返す前の検証工程にしてもいいでしょう。

ステップ3 — キャンペーンの成果を見る

セールが終わりました。何が効いたのかを見る番です。GET /api/v1/urls/{code}/stats は、日別の推移と訪問者の内訳を含むクリックデータを返します。

async function getStats(code, days = 7) {
  const response = await fetch(`${API_BASE}/urls/${code}/stats?days=${days}`, {
    headers: {
      "Authorization": `Bearer ${API_KEY}`,
    },
  });

  if (!response.ok) {
    const err = await response.json();
    throw new Error(`Stats failed for ${code}: ${err.error}`);
  }

  return response.json();
}

const stats = await getStats("xK3mQp", 7);
console.log(stats);
// {
//   short_code: "xK3mQp",
//   target_url: "https://shop.example.com/products/wireless-earbuds-pro",
//   total_clicks: 1284,
//   daily: [
//     { date: "2026-04-10", clicks: 412, unique_visitors: 389 },
//     { date: "2026-04-09", clicks: 507, unique_visitors: 461 },
//     { date: "2026-04-08", clicks: 365, unique_visitors: 330 },
//     ...
//   ],
//   countries: [
//     { country: "TW", clicks: 623 },
//     { country: "JP", clicks: 287 },
//     { country: "US", clicks: 194 },
//     ...
//   ],
//   referers: [
//     { referer: "facebook.com", clicks: 512 },
//     { referer: "line.me", clicks: 401 },
//     ...
//   ],
//   devices: [
//     { device_type: "mobile", browser: "Chrome Mobile", clicks: 743 },
//     { device_type: "desktop", browser: "Chrome", clicks: 412 },
//     ...
//   ],
//   limited: false
// }

limited について補足します。国・参照元・デバイスの詳しい内訳は、Pro か Business のプランで全件が見られます。Freeプランでは limited: true が付いた短い形で返り、各項目の上位3件までが含まれます。連携が正しく動いているかを確かめるには十分です。全件を見るには、アップグレードしてください。

コンソールにレポートを出す

キャンペーンのリンクをまとめて集計し、要約を表示する短いスクリプトです。

async function campaignReport(codes) {
  console.log("Product Link Report");
  console.log("=".repeat(60));

  let totalClicks = 0;

  for (const code of codes) {
    const stats = await getStats(code, 7);
    totalClicks += stats.total_clicks;

    const topCountry = stats.countries[0];
    const topReferer = stats.referers[0];

    console.log(`\n${stats.short_code} -> ${stats.target_url}`);
    console.log(`  Total clicks: ${stats.total_clicks}`);
    if (topCountry) {
      console.log(`  Top country:  ${topCountry.country} (${topCountry.clicks})`);
    }
    if (topReferer) {
      console.log(`  Top referrer: ${topReferer.referer} (${topReferer.clicks})`);
    }
  }

  console.log(`\n${"=".repeat(60)}`);
  console.log(`Campaign total: ${totalClicks} clicks across ${codes.length} links`);
}

// ステップ1で受け取った短縮コードを渡す
const codes = ["xK3mQp", "bR7nWz", /* ... */];
campaignReport(codes).catch(console.error);

キャンペーン後の分析はこれで全部です。ダッシュボードをクリックして回る必要も、CSVを書き出して整える必要もありません。チームがすでに使っているレポートツールに、そのまま流し込めるデータが手に入ります。

運用のこつ

レート制限

toui.io は、プランごとに1分あたりのバースト上限を設けています。

プランバースト上限月間のリクエスト数
Free60 リクエスト/分5,000 リクエスト/月
Pro200 リクエスト/分500,000 リクエスト/月
Business600 リクエスト/分2,000,000 リクエスト/月

商品50件なら、どちらの上限にも届きません。ただ、何千本ものリンクを発行する仕組み——たとえば取扱量の多いショップで、注文ごとに追跡用URLを出すようなもの——をつくるなら、リクエストの間隔を調整したくなるはずです。

429(レート制限)に対処する

上限に達すると、APIは429を返します。単純なバックオフで、きれいに処理できます。

async function fetchWithRetry(url, options, maxRetries = 3) {
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    const response = await fetch(url, options);

    if (response.status === 429 && attempt < maxRetries) {
      const body = await response.json();
      const delay = (body.retry_after || Math.pow(2, attempt)) * 1000;
      console.log(`Rate limited. Retrying in ${delay / 1000}s...`);
      await new Promise((resolve) => setTimeout(resolve, delay));
      continue;
    }

    return response;
  }
}

429のレスポンスボディには retry_after(秒)が入っていて、どれだけ待てばよいかがそのままわかります。成功したレスポンスにも X-RateLimit-Remaining ヘッダーが付くので、必要なら先回りして間隔を調整できます。

エラーコード早見表

ステータス意味よくある原因
400リクエストが不正url がない、カスタムコードが不正、JSONの形式が誤っている
401認証されていないAPIキーがない、または無効
403許可されていないFreeプランでカスタムコードを指定した、またはURLが Safe Browsing で危険と判定された
404見つからない短縮コードが存在しない、または別のチームのもの
429レート制限1分あたりのリクエストが多すぎる、または月間の上限を超えた

パースの前に、必ず response.ok を確認してください。エラーのレスポンスボディには、人が読めるメッセージが error に必ず入っています。それをログに出しておけば、原因追跡はぐっと楽になります。

いま、つくり終えたもの

100行に満たないJavaScriptで、次のことをするキャンペーン用のしくみができました。

  • ソーシャルプレビューカード付きの、計測できる短縮リンクを50本つくる
  • 1本ずつ、設定が正しいかを確認する
  • キャンペーン後に、国・参照元・デバイスの内訳を含む分析データを取り出す

Node.js のほかに依存はありません。ダッシュボードのクリックもありません。node create-links.js を実行すれば、リンクが配れる状態になっています。

同じ形は、計測できるリンクをまとめて必要とするもの全般に使えます。注文確認、イベントの招待、メールマガジンの配信、アフィリエイトの管理。

APIはこれで全部です。エンドポイントは3つ、インストールするSDKもなく、fetch だけ。toui.io を個人のプロジェクトとしてつくったのは、Bitly のようなツールが備えるもののうち、私に必要だったのは5%ほどで、そのために月35米ドルを払うのは割に合わないと思ったからです。

まずは試してみたい方のためにFreeプランがあります。APIはどのプランでも使えます。週に数本つくるだけなら、Freeプランで始めるのに十分です。バースト上限や月間のリクエスト数がもっと必要になったら、Pro か Business にアップグレードしてください。

← すべての記事