メインコンテンツへスキップ

ペイメントリンクAPI

Omiseペイメントリンク APIを使用してペイメントリンク作成及び管理を自動化。多くのリンク生成、既存システムとの統合、またはダイナミック支払い体験を作成する必要があるビジネスに最適。

概要

ペイメントリンク APIでは以下が可能:

  • プログラムによるペイメントリンク作成
  • リンク詳細及びステータス取得
  • リンク設定を更新
  • すべてのペイメントリンクをリスト
  • リンクパフォーマンスを追跡
  • 支払いイベント向けWebhookを処理

認証

すべてのAPIリクエストはシークレットキー使用の認証が必要:

curl https://api.omise.co/links \
-u skey_test_xxx:

重要:

  • テストモード用に skey_test_xxx を使用
  • ライブモード用に skey_live_xxx を使用
  • シークレットキーをクライアント側のコードで公開しない
  • シークレットキーをセキュアに保つ

APIエンドポイント

ベースURL

https://api.omise.co

利用可能なエンドポイント

メソッドエンドポイント説明
POST/linksペイメントリンク作成
GET/links/:idペイメントリンク取得
PATCH/links/:idペイメントリンク更新
GET/linksすべてのペイメントリンクをリスト

ペイメントリンク作成

基本作成

シンプルなペイメントリンク作成:

const omise = require('omise')({
secretKey: 'skey_test_xxx'
});

omise.links.create({
amount: 100000, // 最小通貨単位での金額(1,000.00 THB)
currency: 'thb',
title: '商品購入',
description: 'プレミアムウィジェット購入',
multiple: true // マルチユースリンク
}, function(error, link) {
if (error) {
console.error('エラー:', error);
} else {
console.log('リンク作成:', link.payment_uri);
}
});

レスポンス:

{
"object": "link",
"id": "payl_test_5xyx8z94w46ixr9l",
"livemode": false,
"location": "/links/payl_test_5xyx8z94w46ixr9l",
"amount": 100000,
"currency": "thb",
"title": "商品購入",
"description": "プレミアムウィジェット購入",
"multiple": true,
"payment_uri": "https://pay.omise.co/links/payl_test_5xyx8z94w46ixr9l",
"used": false,
"charges": {
"object": "list",
"data": [],
"total": 0
},
"created_at": "2026-02-06T10:30:00Z"
}

cURL使用

curl https://api.omise.co/links \
-u skey_test_xxx: \
-d "amount=100000" \
-d "currency=thb" \
-d "title=商品購入" \
-d "description=プレミアムウィジェット購入" \
-d "multiple=true"

Python使用

import omise

omise.api_secret = 'skey_test_xxx'

link = omise.Link.create(
amount=100000,
currency='thb',
title='商品購入',
description='プレミアムウィジェット購入',
multiple=True
)

print(f"リンクURL: {link.payment_uri}")

PHP使用

<?php
require_once 'vendor/autoload.php';

define('OMISE_SECRET_KEY', 'skey_test_xxx');

$link = OmiseLink::create([
'amount' => 100000,
'currency' => 'thb',
'title' => '商品購入',
'description' => 'プレミアムウィジェット購入',
'multiple' => true
]);

echo "リンクURL: " . $link['payment_uri'];
?>

Ruby使用

require 'omise'

Omise.api_key = 'skey_test_xxx'

link = Omise::Link.create({
amount: 100000,
currency: 'thb',
title: '商品購入',
description: 'プレミアムウィジェット購入',
multiple: true
})

puts "リンクURL: #{link.payment_uri}"

リクエストパラメータ

必須パラメータ

パラメータ説明
amountinteger最小通貨単位での金額(例: THB用サタン)
currencystring3文字のISO通貨コード(例: thb, usd)
titlestring顧客に表示されるリンクタイトル(最大200文字)

オプショナルパラメータ

パラメータデフォルト説明
descriptionstringnull詳細説明(最大1000文字)
multiplebooleanfalse複数使用を許可(true)またはシングルユース(false)
metadataobjectカスタムメタデータ(キー・バリュー ペア)

高度な作成例

シングルユースペイメントリンク

請求書に最適:

omise.links.create({
amount: 250000, // 2,500.00 THB
currency: 'thb',
title: '請求書 #INV-001',
description: 'コンサルティングサービスの支払い',
multiple: false, // シングルユースのみ
metadata: {
invoice_id: 'INV-001',
customer_id: 'CUST-123',
customer_email: 'customer@example.com'
}
}, function(error, link) {
if (!error) {
console.log('請求書リンク:', link.payment_uri);
console.log('リンク ID:', link.id);
}
});

メタデータ付きリンク

カスタム情報を保存:

omise.links.create({
amount: 150000,
currency: 'thb',
title: 'コンサルテーション予約',
description: '1時間のコンサルテーションセッション',
multiple: true,
metadata: {
service_type: 'consultation',
duration: '60_minutes',
category: 'business',
booking_date: '2026-03-15',
time_slot: '14:00',
consultant_id: 'CONS-456'
}
}, function(error, link) {
if (!error) {
console.log('予約リンク作成');
// link.idをデータベースに保存
}
});

複数通貨リンク

異なる通貨でリンク作成:

// 国際顧客向けUSDリンク
omise.links.create({
amount: 5000, // $50.00
currency: 'usd',
title: '国際商品',
description: '世界中の配送利用可能',
multiple: true
}, function(error, usdLink) {
console.log('USDリンク:', usdLink.payment_uri);
});

// 国内顧客向けTHBリンク
omise.links.create({
amount: 150000, // 1,500.00 THB
currency: 'thb',
title: 'タイ商品',
description: 'タイ国内の顧客向け',
multiple: true
}, function(error, thbLink) {
console.log('THBリンク:', thbLink.payment_uri);
});

ペイメントリンク取得

特定リンク取得

IDでリンク取得:

omise.links.retrieve('payl_test_5xyx8z94w46ixr9l', function(error, link) {
if (!error) {
console.log('リンクステータス:', link.used ? '使用済み' : 'アクティブ');
console.log('総チャージ数:', link.charges.total);
console.log('作成日:', link.created_at);
}
});

cURL使用:

curl https://api.omise.co/links/payl_test_5xyx8z94w46ixr9l \
-u skey_test_xxx:

レスポンス:

{
"object": "link",
"id": "payl_test_5xyx8z94w46ixr9l",
"livemode": false,
"amount": 100000,
"currency": "thb",
"title": "商品購入",
"description": "プレミアムウィジェット購入",
"multiple": true,
"payment_uri": "https://pay.omise.co/links/payl_test_5xyx8z94w46ixr9l",
"used": false,
"charges": {
"object": "list",
"data": [
{
"object": "charge",
"id": "chrg_test_xxx",
"amount": 100000,
"status": "successful",
"created_at": "2026-02-06T11:00:00Z"
}
],
"total": 1
},
"created_at": "2026-02-06T10:30:00Z"
}

すべてのリンクをリスト

すべてのリンクのページ分割済みリストを取得:

omise.links.list({
limit: 20,
offset: 0,
order: 'reverse_chronological'
}, function(error, list) {
if (!error) {
console.log('総リンク:', list.total);
list.data.forEach(function(link) {
console.log(`${link.title}: ${link.payment_uri}`);
});
}
});

cURL使用:

curl https://api.omise.co/links?limit=20&offset=0 \
-u skey_test_xxx:

リストパラメータ:

パラメータデフォルト説明
limitinteger20ページあたりのリンク数(最大100)
offsetinteger0スキップするリンク数
orderstringchronologicalソート順: chronological または reverse_chronological
fromstringnullフィルタ リンク作成開始日(ISO 8601)
tostringnullフィルタ リンク作成終了日(ISO 8601)

ペイメントリンク更新

リンク詳細を更新(限定フィール):

omise.links.update('payl_test_5xyx8z94w46ixr9l', {
description: '詳細情報を含むアップデート商品説明',
metadata: {
updated_at: '2026-02-06',
reason: 'price_change',
updated_by: 'admin'
}
}, function(error, link) {
if (!error) {
console.log('リンク更新成功');
}
});

cURL使用:

curl https://api.omise.co/links/payl_test_5xyx8z94w46ixr9l \
-X PATCH \
-u skey_test_xxx: \
-d "description=アップデート商品説明"

更新可能なフィール:

  • description - リンク説明
  • metadata - カスタムメタデータ

更新不可なフィール:

  • amount - 金額変更不可
  • currency - 通貨変更不可
  • title - タイトル変更不可
  • multiple - 型変更不可

: 大きな変更の場合は、新しいリンク作成して古いものを無効化。

実用的な統合例

例1: eコマース商品リンク

各商品のリンク生成:

const products = [
{ id: 'PROD-001', name: 'Tシャツ赤', price: 45000 },
{ id: 'PROD-002', name: 'Tシャツ青', price: 45000 },
{ id: 'PROD-003', name: 'Tシャツ緑', price: 45000 }
];

products.forEach(product => {
omise.links.create({
amount: product.price,
currency: 'thb',
title: product.name,
description: `${product.name}を購入`,
multiple: true,
metadata: {
product_id: product.id,
product_name: product.name,
category: 'apparel'
}
}, function(error, link) {
if (!error) {
// link.payment_uriをデータベースに保存
console.log(`${product.name}: ${link.payment_uri}`);

// データベースに保存
saveToDatabase({
product_id: product.id,
payment_link: link.payment_uri,
link_id: link.id
});
}
});
});

例2: ダイナミック請求書生成

オンデマンドで請求書リンク作成:

function createInvoiceLink(invoice) {
return new Promise((resolve, reject) => {
omise.links.create({
amount: invoice.total,
currency: invoice.currency,
title: `請求書 ${invoice.number}`,
description: `${invoice.description}の支払い`,
multiple: false, // シングルユース
metadata: {
invoice_number: invoice.number,
customer_id: invoice.customer_id,
customer_email: invoice.customer_email,
due_date: invoice.due_date,
items: JSON.stringify(invoice.items)
}
}, function(error, link) {
if (error) {
reject(error);
} else {
resolve(link);
}
});
});
}

// 使用方法
const invoice = {
number: 'INV-2026-001',
total: 350000, // 3,500.00 THB
currency: 'thb',
description: 'ウェブ開発サービス',
customer_id: 'CUST-123',
customer_email: 'customer@example.com',
due_date: '2026-03-06',
items: [
{ description: 'ホームページデザイン', amount: 150000 },
{ description: 'お問い合わせページ', amount: 100000 },
{ description: 'モバイルレスポンシブ', amount: 100000 }
]
};

createInvoiceLink(invoice)
.then(link => {
console.log('請求書リンク:', link.payment_uri);

// 顧客にメール送信
sendInvoiceEmail(invoice.customer_email, {
invoice_number: invoice.number,
payment_link: link.payment_uri,
amount: invoice.total,
due_date: invoice.due_date
});
})
.catch(error => {
console.error('請求書リンク作成エラー:', error);
});

例3: イベント登録システム

チケット付きリンク生成:

const events = {
'workshop-2026': {
name: 'ウェブ開発ワークショップ 2026',
tickets: [
{ type: 'early_bird', price: 150000, available: 50 },
{ type: 'regular', price: 200000, available: 100 },
{ type: 'vip', price: 350000, available: 20 }
]
}
};

async function generateEventLinks(eventId, event) {
const links = [];

for (const ticket of event.tickets) {
const link = await new Promise((resolve, reject) => {
omise.links.create({
amount: ticket.price,
currency: 'thb',
title: `${event.name} - ${ticket.type.replace('_', ' ').toUpperCase()} チケット`,
description: `${event.name}に登録`,
multiple: true,
metadata: {
event_id: eventId,
ticket_type: ticket.type,
tickets_available: ticket.available
}
}, (error, link) => {
if (error) reject(error);
else resolve(link);
});
});

links.push({
ticket_type: ticket.type,
link: link.payment_uri,
link_id: link.id
});
}

return links;
}

// イベント向けリンク生成
generateEventLinks('workshop-2026', events['workshop-2026'])
.then(links => {
console.log('イベントリンク生成:');
links.forEach(l => {
console.log(`${l.ticket_type}: ${l.link}`);
});
});

例4: 定期購読支払いリンク

月間支払いリンク作成:

function generateMonthlyLink(subscription) {
const currentDate = new Date();
const month = currentDate.toLocaleString('ja-JP', { month: 'long' });
const year = currentDate.getFullYear();

return omise.links.create({
amount: subscription.monthly_amount,
currency: 'thb',
title: `${subscription.plan_name} - ${month} ${year}`,
description: `${subscription.plan_name}サブスクリプションの月間支払い`,
multiple: false, // 毎月ユニークなリンク
metadata: {
subscription_id: subscription.id,
customer_id: subscription.customer_id,
plan: subscription.plan_name,
billing_month: `${year}-${currentDate.getMonth() + 1}`,
auto_generated: 'true'
}
});
}

// 例: すべてのアクティブ定期購読向けに生成
const activeSubscriptions = [
{
id: 'SUB-001',
customer_id: 'CUST-123',
plan_name: 'プレミアム',
monthly_amount: 99000
},
{
id: 'SUB-002',
customer_id: 'CUST-456',
plan_name: 'ビジネス',
monthly_amount: 299000
}
];

activeSubscriptions.forEach(subscription => {
generateMonthlyLink(subscription)
.then(link => {
console.log(`${subscription.customer_id}向けリンク:`, link.payment_uri);

// 顧客にメール送信
emailCustomer(subscription.customer_id, {
subject: '月間定期購読支払い',
payment_link: link.payment_uri
});
})
.catch(error => {
console.error(`${subscription.id}エラー:`, error);
});
});

例5: 一括リンク生成

多くのリンクを効率的に生成:

async function bulkCreateLinks(items) {
const results = {
successful: [],
failed: []
};

// レート制限を避けるため、バッチ処理
const batchSize = 10;
for (let i = 0; i < items.length; i += batchSize) {
const batch = items.slice(i, i + batchSize);

const promises = batch.map(item =>
new Promise((resolve) => {
omise.links.create({
amount: item.amount,
currency: 'thb',
title: item.title,
description: item.description,
multiple: true,
metadata: item.metadata || {}
}, (error, link) => {
if (error) {
resolve({ success: false, item, error });
} else {
resolve({ success: true, item, link });
}
});
})
);

const batchResults = await Promise.all(promises);

batchResults.forEach(result => {
if (result.success) {
results.successful.push(result);
} else {
results.failed.push(result);
}
});

// レート制限遅延
if (i + batchSize < items.length) {
await new Promise(resolve => setTimeout(resolve, 1000));
}
}

return results;
}

// 使用方法
const products = [
{ title: '商品 A', amount: 50000, description: '説明 A' },
{ title: '商品 B', amount: 75000, description: '説明 B' },
{ title: '商品 C', amount: 100000, description: '説明 C' },
// ... 他の商品
];

bulkCreateLinks(products)
.then(results => {
console.log(`作成成功: ${results.successful.length}`);
console.log(`失敗: ${results.failed.length}`);

// 成功したリンクをエクスポート
const csv = results.successful.map(r =>
`${r.item.title},${r.link.payment_uri}`
).join('\n');

console.log('\nCSVエクスポート:\n', csv);
});

Webhooks統合

支払いリンクイベントについてリアルタイム通知を受け取り:

Webhooks設定

  1. ダッシュボードでWebhookエンドポイント設定
  2. 支払いリンクイベントをリッスン
  3. Webhook署名を確認
  4. イベント処理

Webhookイベント

const express = require('express');
const app = express();

app.post('/webhooks/omise', express.json(), (req, res) => {
const event = req.body;

switch(event.key) {
case 'charge.create':
handleChargeCreated(event.data);
break;
case 'charge.complete':
handleChargeCompleted(event.data);
break;
case 'charge.failed':
handleChargeFailed(event.data);
break;
}

res.sendStatus(200);
});

function handleChargeCompleted(charge) {
// チャージがペイメントリンク由来か確認
if (charge.source && charge.source.type === 'link') {
const linkId = charge.source.id;

console.log('リンク向け支払い受信:', linkId);

// リンク詳細を取得
omise.links.retrieve(linkId, (error, link) => {
if (!error) {
const metadata = link.metadata;

// メタデータに基づいて処理
if (metadata.invoice_id) {
markInvoicePaid(metadata.invoice_id);
} else if (metadata.product_id) {
fulfillOrder(metadata.product_id, charge);
}

// 確認メール送信
sendConfirmationEmail(charge.customer_email, {
amount: charge.amount,
description: link.title
});
}
});
}
}

app.listen(3000);

Webhook署名検証

Webhook真正性を確認:

const crypto = require('crypto');

function verifyWebhook(payload, signature, secret) {
const computed = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');

return computed === signature;
}

app.post('/webhooks/omise', express.raw({type: 'application/json'}), (req, res) => {
const signature = req.headers['omise-signature'];
const secret = process.env.WEBHOOK_SECRET;

if (!verifyWebhook(req.body, signature, secret)) {
return res.status(401).send('無効な署名');
}

const event = JSON.parse(req.body);
// イベント処理...

res.sendStatus(200);
});

エラーハンドリング

一般的なエラー

omise.links.create({
amount: 100000,
currency: 'thb',
title: '商品'
}, function(error, link) {
if (error) {
switch(error.code) {
case 'invalid_amount':
console.error('無効な金額:', error.message);
break;
case 'invalid_currency':
console.error('通貨非サポート:', error.message);
break;
case 'authentication_failure':
console.error('無効なAPIキー:', error.message);
break;
default:
console.error('エラー:', error.message);
}
}
});

エラーレスポンス形式

{
"object": "error",
"location": "https://www.omise.co/api-errors#authentication-failure",
"code": "authentication_failure",
"message": "認証失敗"
}

一般的なエラーコード

コード説明ソリューション
authentication_failure無効なAPIキーシークレットキーを確認
invalid_amount無効な金額最小単位での正の整数を使用
invalid_currency非サポート通貨サポート通貨コードを使用
invalid_cardカード検証失敗カード詳細を確認
insufficient_fund残高不足顧客が資金を追加する必要
failed_processing支払い処理失敗リトライまたはサポートに連絡

リトライロジック

指数バックオフを実装:

async function createLinkWithRetry(data, maxRetries = 3) {
let lastError;

for (let i = 0; i < maxRetries; i++) {
try {
const link = await new Promise((resolve, reject) => {
omise.links.create(data, (error, link) => {
if (error) reject(error);
else resolve(link);
});
});

return link;
} catch (error) {
lastError = error;

// 特定のエラーはリトライしない
if (error.code === 'authentication_failure' ||
error.code === 'invalid_amount') {
throw error;
}

// 指数バックオフ: 1s、2s、4s
const delay = Math.pow(2, i) * 1000;
await new Promise(resolve => setTimeout(resolve, delay));
}
}

throw lastError;
}

レート制限

制限

  • 60リクエスト/分 あたりのAPIキー
  • 1000リクエスト/時間 あたりのAPIキー

レート制限処理

const rateLimit = {
requests: 0,
resetAt: Date.now() + 60000
};

function checkRateLimit() {
if (Date.now() > rateLimit.resetAt) {
rateLimit.requests = 0;
rateLimit.resetAt = Date.now() + 60000;
}

if (rateLimit.requests >= 60) {
const waitTime = rateLimit.resetAt - Date.now();
throw new Error(`レート制限超過。${waitTime}ms後にリトライ`);
}

rateLimit.requests++;
}

async function createLinkSafe(data) {
checkRateLimit();

return new Promise((resolve, reject) => {
omise.links.create(data, (error, link) => {
if (error) reject(error);
else resolve(link);
});
});
}

ベストプラクティス

1. メタデータを効果的に使用

関連するすべての情報を保存:

omise.links.create({
amount: 100000,
currency: 'thb',
title: '商品購入',
metadata: {
// ビジネスコンテキスト
order_id: 'ORD-123',
customer_id: 'CUST-456',

// 商品詳細
product_id: 'PROD-789',
product_sku: 'WIDGET-001',

// 履行情報
shipping_required: 'true',
warehouse: 'BKK-01',

// 追跡
campaign: 'summer-sale',
referrer: 'social-media',

// 連絡
customer_email: 'customer@example.com',
customer_phone: '+66812345678'
}
});

2. べき等性を実装

重複リンク防止:

const linkCache = new Map();

async function createLinkIdempotent(key, data) {
// リンクが既に存在するか確認
if (linkCache.has(key)) {
return linkCache.get(key);
}

// 新しいリンク作成
const link = await new Promise((resolve, reject) => {
omise.links.create(data, (error, link) => {
if (error) reject(error);
else resolve(link);
});
});

// リンクをキャッシュ
linkCache.set(key, link);

return link;
}

// 使用方法
const invoiceId = 'INV-001';
const link = await createLinkIdempotent(invoiceId, {
amount: 100000,
currency: 'thb',
title: `請求書 ${invoiceId}`,
metadata: { invoice_id: invoiceId }
});

3. リンク IDを保存

常にデータベースにリンク IDを保存:

async function createAndStoreLinkInfo(orderData) {
// リンク作成
const link = await createLink(orderData);

// データベースに保存
await database.orders.update(orderData.id, {
payment_link_id: link.id,
payment_link_url: link.payment_uri,
link_created_at: link.created_at
});

return link;
}

4. Webhooksを適切に処理

app.post('/webhooks', async (req, res) => {
// すぐに応答
res.sendStatus(200);

// 非同期で処理
processWebhook(req.body).catch(error => {
console.error('Webhook処理エラー:', error);
// 手動レビュー用にログ
});
});

async function processWebhook(event) {
// 署名を確認
// 重複処理を防止
// データベースを更新
// 通知を送信
}

5. リンクパフォーマンスを監視

リンク使用を追跡:

async function getLinkStats(linkId) {
const link = await omise.links.retrieve(linkId);

return {
total_charges: link.charges.total,
successful_payments: link.charges.data.filter(c =>
c.status === 'successful'
).length,
failed_payments: link.charges.data.filter(c =>
c.status === 'failed'
).length,
total_revenue: link.charges.data
.filter(c => c.status === 'successful')
.reduce((sum, c) => sum + c.amount, 0),
conversion_rate: calculateConversionRate(link)
};
}

テスト

テストモード

テスト APIキーを使用:

const omise = require('omise')({
secretKey: 'skey_test_xxx' // テストキー
});

テストカード

// テスト成功支払い
const testCardSuccess = {
number: '4242424242424242',
name: 'テストユーザー',
expiration_month: 1,
expiration_year: 2026,
security_code: '123'
};

// テスト失敗支払い
const testCardFailed = {
number: '4000000000000002',
name: 'テストユーザー',
expiration_month: 1,
expiration_year: 2026,
security_code: '123'
};

Webhooksテスト

ngrokなどのツールを使用:

# ngrok開始
ngrok http 3000

# ダッシュボード Webhook設定で ngrok URLを使用
https://abc123.ngrok.io/webhooks/omise

よくある質問

Q: 金額なしでリンク作成できますか(顧客が決定)? A: いいえ。API は現在固定金額を必須としています。柔軟な金額の場合は、ダッシュボードインターフェースを使用。

Q: ペイメントリンク削除方法は? A: APIでリンク削除不可。使用制限に達したり失効によってのみマークされます。

Q: API経由で支払いページデザインをカスタマイズできますか? A: いいえ。デザインカスタマイズはダッシュボードのみ利用可能。API はリンク作成及び管理に焦点。

Q: 作成可能なリンク数に制限がありますか? A: 標準アカウントは最大100アクティブなリンク可能。より高い制限の場合はサポートに連絡。

Q: 支払いがどのチャネルから来たかを追跡できますか? A: メタデータを使用してリンクをチャネル情報でタグ付け、またはチャネルごとに異なるリンク作成。

Q: 定期支払いリンク作成できますか? A: ペイメントリンク はワンタイム支払い用。定期請求の場合は、定期購読APIを使用。

Q: 作成後、リンクはどのくらい迅速に利用可能? A: リンクは作成直後に即座に利用可能。伝播遅延なし。

Q: 既存リンクの金額を更新できますか? A: いいえ。金額は変更できません。アップデート金額で新しいリンク作成。

Q: 異なる支払い方法向けに別々にリンク作成する必要がありますか? A: いいえ。1つのリンクはあなたのアカウントで有効化されたすべての支払い方法をサポート。顧客は希望する方法を選択。

Q: リンク経由で支払いがいつ行われたかを知る方法は? A: Webhooks用リアルタイム通知、またはAPIを使用してチャージリストをポーリング。

Q: モバイルアプリでリンクを使用できますか? A: はい。payment_uri を webview または外部ブラウザで開く。ページはモバイル最適化。

Q: レート制限超過時はどうなりますか? A: 429 リクエスト多すぎるエラーを受信。指数バックオフを実装してリトライ。

次のステップ

追加リソース


ヘルプが必要ですか? support@omise.co までサポートチームに連絡するか、ヘルプセンターをご覧ください。