← 返回所有文章
用 API 自動化你的短網址:toui.io 開發者指南

用 API 自動化你的短網址:toui.io 開發者指南

發佈於 2026年4月10日

行銷部丟了 50 條商品連結過來,說這週末要做限時特賣。

每條連結都要變成短網址,每條都要加上社群預覽標題跟描述——因為會丟到 LINE 群組和 Facebook 粉專。哦對了,活動結束後還要看成效報表。

你打開後台,手動建了三條,心裡開始算:50 條,每條要填網址、標題、OG 描述⋯⋯大概要花一整個下午。

然後你想起來:「等一下,這個東西有 API 吧?」

沒錯。這篇文章就是要帶你用 toui.io 的 API,從零到完成一個促銷活動連結產生器。三個步驟,不到 100 行程式碼。

開始之前

你需要:

  • toui.io Pro 或 Business 方案 — API 存取需要付費方案(方案比較
  • 一組 API Key — 登入後台,到「API Keys」頁面建立
  • Node.js 18+ — 我們用 Node 內建的 fetch(),不需要裝額外套件

API Key 長得像 toui_ 開頭加一串亂碼。拿到之後,在專案根目錄建一個 .env 檔案:

# .env
TOUI_API_KEY=toui_your_key_here

記得把 .env 加進 .gitignore——API Key 絕對不要 commit 進版本控制。

然後裝 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");
}

少了這個 guard,漏設環境變數的人只會拿到一個莫名其妙的 401,debug 半天。

Step 1:批次建立短網址

情境:行銷部給了你一份商品清單,你要把每一條都變成有追蹤功能的短網址,順便加上 LINE 跟 Facebook 分享時的預覽資訊。

API 端點:POST https://toui.io/api/v1/shorten

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";

// Weekend flash sale products
const products = [
  {
    url: "https://shop.example.com/airpods-pro-2",
    title: "AirPods Pro 2",
    code: "airpods",
    og_title: "AirPods Pro 2 限時特價 $5,990",
    og_description: "原價 $7,490,週末兩天限定。主動降噪、USB-C 充電盒。",
  },
  {
    url: "https://shop.example.com/air-fryer-japan",
    title: "日本氣炸鍋",
    code: "airfryer",
    og_title: "日本氣炸鍋 現折 $1,200",
    og_description: "4.5L 大容量,八種預設模式,少油更健康。",
  },
  {
    url: "https://shop.example.com/robot-vacuum-x1",
    title: "掃地機器人 X1",
    code: "vacuum",
    og_title: "掃地機器人 X1 直降 $3,000",
    og_description: "雷射導航、自動集塵、App 遠端遙控。",
  },
];

async function createShortUrl(product) {
  const res = await fetch(`${API_BASE}/shorten`, {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      url: product.url,
      title: product.title,
      custom_code: product.code,
      og_title: product.og_title,
      og_description: product.og_description,
    }),
  });

  if (!res.ok) {
    const err = await res.json();
    throw new Error(`Failed to create ${product.title}: ${err.error}`);
  }

  return res.json();
}

async function main() {
  console.log("Creating short URLs for flash sale...\n");

  for (const product of products) {
    const result = await createShortUrl(product);
    console.log(`${product.title}: ${result.short_url}`);
  }

  console.log("\nDone! All links ready.");
}

main().catch(console.error);

跑起來大概長這樣:

Creating short URLs for flash sale...

AirPods Pro 2: https://toui.io/airpods
日本氣炸鍋: https://toui.io/airfryer
掃地機器人 X1: https://toui.io/vacuum

Done! All links ready.

幾件事情說明一下:

  • custom_code 是選填的,4-8 個英數字元。不填的話會自動產生 6 碼隨機短碼。自訂短碼是付費功能。
  • og_titleog_description 也是選填的。但如果你的連結要丟到 LINE 群組或 Facebook,強烈建議填上——預覽卡片好不好看,直接影響點擊率。
  • title 是給你自己在後台辨識用的,不會顯示在外部。
  • 回傳的 short_url 就是可以直接用的完整短網址。

50 條商品?把 products 陣列換成從 Excel 或資料庫讀進來的資料,一樣的邏輯,兩分鐘跑完。

Step 2:確認連結狀態

建完之後,你可能想確認一下某條連結有沒有成功建立、目標網址對不對。

API 端點:GET https://toui.io/api/v1/urls/{code}

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

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

  return res.json();
}

// Spot-check one link
const info = await checkUrl("airpods");
console.log("Short code:", info.short_code);
console.log("Target:", info.target_url);
console.log("Title:", info.title);
console.log("Clicks:", info.click_count);
console.log("OG title:", info.og_title);
console.log("Active:", info.is_active);

回傳的欄位包含:

欄位說明
short_code短碼
target_url目標網址
title標題(後台用)
click_count累計點擊數
is_active是否啟用中
og_title社群預覽標題
og_description社群預覽描述
og_image_url社群預覽圖片
created_at建立時間

這一步在正式環境裡通常不會每條都手動查——但寫進你的建立流程尾端做一次 spot check,debug 的時候會感謝自己。

Step 3:活動結束,看成效

週末結束了,行銷部問你:「哪個商品連結點最多?流量從哪來的?」

API 端點:GET https://toui.io/api/v1/urls/{code}/stats?days=7

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

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

  return res.json();
}

// Build a quick report
async function report() {
  const codes = ["airpods", "airfryer", "vacuum"];

  for (const code of codes) {
    const stats = await getStats(code, 7);
    console.log(`\n--- ${stats.short_code} ---`);
    console.log(`Total clicks: ${stats.total_clicks}`);

    // Daily breakdown
    for (const day of stats.daily) {
      console.log(`  ${day.date}: ${day.clicks} clicks, ${day.unique_visitors} unique`);
    }

    // Top countries
    if (stats.countries?.length) {
      console.log("Top countries:");
      for (const c of stats.countries) {
        console.log(`  ${c.country}: ${c.clicks}`);
      }
    }

    // Top referers
    if (stats.referers?.length) {
      console.log("Top referers:");
      for (const r of stats.referers) {
        console.log(`  ${r.referer}: ${r.clicks}`);
      }
    }

    // Devices
    if (stats.devices?.length) {
      console.log("Devices:");
      for (const d of stats.devices) {
        console.log(`  ${d.device_type}: ${d.clicks}`);
      }
    }
  }
}

report().catch(console.error);

跑出來大概長這樣:

--- airpods ---
Total clicks: 1,847
  2026-04-05: 823 clicks, 614 unique
  2026-04-06: 1024 clicks, 789 unique
Top countries:
  TW: 1,650
  HK: 102
  US: 53
Top referers:
  line.me: 894
  facebook.com: 612
  direct: 341
Devices:
  mobile: 1,423
  desktop: 424

一眼就看出來——LINE 帶來的流量比 Facebook 多,而且絕大多數是手機點的。下次活動素材該怎麼調整,數據說了算。

有一個要注意的地方:進階分析(countries、referers、devices)需要 Pro 以上方案。如果你的方案不支援,這些欄位會回傳有限的資料,並帶有 limited: true 標記。

正式環境注意事項

把上面的 script 搬到正式環境之前,有幾件事要注意:

速率限制

方案每分鐘上限每月 API 總量
Pro200 req/min500,000 req/月
Business600 req/min500,000 req/月

超過限制會收到 429 Too Many Requests。每次回應的 header 裡都有 X-RateLimit-LimitX-RateLimit-RemainingX-RateLimit-Reset,讓你知道上限、剩餘配額、什麼時候重置。被 429 的時候,response body 裡會有 retry_after 秒數。

處理 429

50 條連結不會碰到限制,但如果你要一次建幾百條,加個簡單的 backoff:

async function createWithRetry(product, maxRetries = 3) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    const res = await fetch(`${API_BASE}/shorten`, {
      method: "POST",
      headers: {
        "Authorization": `Bearer ${API_KEY}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        url: product.url,
        title: product.title,
        custom_code: product.code,
        og_title: product.og_title,
        og_description: product.og_description,
      }),
    });

    if (res.status === 429) {
      const body = await res.json();
      const retryAfter = body.retry_after || 5;
      console.log(`Rate limited, waiting ${retryAfter}s... (attempt ${attempt})`);
      await new Promise((r) => setTimeout(r, retryAfter * 1000));
      continue;
    }

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

    return res.json();
  }

  throw new Error(`Max retries exceeded for ${product.title}`);
}

錯誤碼速查

HTTP 狀態碼意思怎麼處理
400參數錯誤(URL 格式不對、短碼不合規等)檢查 request body
401API Key 無效或沒帶確認 Authorization header
403權限不足(Free 方案打 API、自訂短碼等)確認方案等級
404短碼不存在或不屬於你的團隊確認短碼正確
429超過速率限制讀 body 的 retry_after 秒數後重試

安全提醒

  • API Key 永遠放環境變數,不要 hardcode
  • 不要在 log 裡印出完整的 API Key
  • URL 會經過 Google Safe Browsing 檢查,惡意網址會被擋(403
  • 自訂短碼如果不可用,API 會回傳錯誤——換一個就好

你剛建了一個促銷活動引擎

回頭看一下——你用不到 100 行程式碼,做了這些事:

  1. 批次建立帶有社群預覽的短網址
  2. 自動驗證每條連結的狀態
  3. 活動結束後拉出完整的成效報表

這整套邏輯可以包成一個 script,下次行銷部再丟 50 條連結過來,你花 30 秒改一下商品清單,跑一次就搞定了。比手動建快 100 倍,而且不會漏、不會錯。

更進階的用法——串進你的電商後台、每次上新品自動建短網址、定期拉報表寄給行銷部——都是在這個基礎上加工而已。

立即取得你的 API Key

準備好試試這些超能力了嗎?

免費開始使用 toui.io,不需要信用卡。