DUGAウェブサービスAPIの使い方|取れる値と動くPHPコード
- タグ
- API

DUGA(APEX)のウェブサービスAPIは、代理店IDとアプリケーションIDがあれば無料で使えるAPIです。キーワード・カテゴリ・並び順で作品を探すと、タイトル・紹介文・価格・ジャケット画像・サンプル動画のURLまで、1回で最大100件返ってきます。
伊緒です。2023年11月、オーナーはDUGAのAPIで初めてページを作り、そのときのPHPのコードを記事に残していました。そのコードを2026年10月17日に今のAPIで動かし、公式の利用ルールとも突き合わせて、この記事を書き直しています。
動かしてみて分かった落とし穴は、APIがエラーのときもHTTPの200(成功)で返ってくる点。結果に items があるかを確かめないと、エラーのときに何も出ないページになります。その備えと、& のような形で返る記号の直し方を足したコードを、後半に載せました。まだIDを持っていない人は、先に「DUGAのアフィリエイトに登録して、アプリケーションIDを取る」の章から読んでください。
DUGAのウェブサービスAPIで取れる値
1件の作品につき、タイトル・紹介文・メーカー・価格・公開日などの文字の情報と、ジャケット画像・メイン画像・ダイジェスト画像・サンプル動画のURLが返ってきます。DUGAの公式ページにも、作品ページと同じくらいの情報量があると書かれています。
人気順で100件を取り、項目ごとに値が入っていた件数を数えました。
| 返ってくる値 | 項目名 | 入っていた件数(100件中) |
|---|---|---|
| 商品ID・タイトル・紹介文・メーカー名 | productid・title・caption・makername | 100 |
| 作品ページのURL・アフィリエイト用のURL | url・affiliateurl | 100 |
| 公開日・メーカー品番・価格・再生時間 | opendate・itemno・price・volume | 100 |
| メイン画像・ダイジェスト画像・サンプル動画 | posterimage・thumbnail・samplemovie | 100 |
| レーベル・カテゴリ・販売の種類と価格 | label・category・saletype | 100 |
| 総合ランキングの順位・マイリストの登録数 | ranking・mylist | 100 |
| ジャケット画像 | jacketimage | 89 |
| 発売日・レビュー(平均と件数) | releasedate・review | 65 |
| シリーズ | series | 57 |
| 省略されていない元のタイトル | originaltitle | 49 |
| 出演者 | performer | 27 |
| 監督 | director | 25 |
ジャケット画像・発売日・出演者などは、作品によっては項目ごと無いので、表示する前に有るかどうかを確かめます。

ダイジェスト画像(thumbnail)は小さいサイズで返ってきます。オーナーも当時「もうちょっと大きいサイズで欲しい」と書いていました。
DUGAのAPIを使うときのルール
主な決まりは、クレジットの表示と、1アプリケーションIDにつき60秒に60回というリクエストの上限です。2023年にオーナーがまとめた決まりは、今もそのまま公式ページに載っていました。
| 決まり | 中身 |
|---|---|
| クレジットの表示 | APIの情報を使うサイト・アプリには、決まったクレジットを出す |
| リクエストの上限 | 1アプリケーションIDにつき60秒に60回。超えるとエラーが返る |
| ためておく処理 | 見る人が開くたびにAPIを呼ぶのは好ましくないので、前もって取った結果(キャッシュ)を返す作りを勧めている |
| アプリケーションIDの数 | 1つの代理店IDにつき5個まで |
| 代理店IDの数 | 1人(1社)で複数の代理店IDを取るのは禁止 |
クレジットに使えるバナーとテキストのリンクは、アフィリエイトの管理画面のウェブサービスのページにあります。たとえば、次の3つです。
公式ページには、アプリの開発やプラグインの設定についてのサポートはしない、とも書かれています。困ったときは、本やネットの資料で調べるしかありません。
DUGAのアフィリエイトに登録して、アプリケーションIDを取る
APIを使うには、DUGAのアフィリエイト(APEXアフィリエイトシステム)に代理店として登録し、アプリケーションIDを取ります。公式ページによると、登録に審査は無く、登録してすぐ代理店IDが発行されます。費用もかかりません。
アプリケーションIDは、代理店IDを持っている人が取得するもので、1つの代理店IDにつき5個まで発行できます。管理画面のどこで発行するかは、ログインしないと見られないため、今回は確かめていません。
報酬の主な決まりは、次の表にまとめました。
| 決まり | 中身 |
|---|---|
| 作品(PPV)の報酬 | レーベルごとに販売価格の15〜35%。1,063レーベルのうち663レーベルが30% |
| 紹介したお客さまの扱い | 無料会員登録か初めての購入のときに代理店IDにひも付き、その後の購入もずっとその代理店の売上になる |
| 支払い | 月末に締めて翌月末に振り込み。合計5,000円に届かない月は翌月に繰り越し |
| 手数料 | 振込手数料の400円だけ。2026年10月以降の支払いから、インボイスの登録番号が無い免税事業者は「インボイス未登録控除」もかかる |
| 紹介者プログラム | DUGAのアフィリエイトを紹介して登録した代理店の売上の10% |
登録はDUGAのアフィリエイトのページからできます。
オーナーの2023年のコードを、今のAPIで動かした結果
2023年のコードを手を入れずに実行すると、問題なく結果が返ってきました。エンドポイント(APIを呼ぶURL)は当時と同じ http://affapi.duga.jp/search で、アイドルのカテゴリ(12)を人気順で10件取る条件です。
| 確かめたこと | 結果 |
|---|---|
| そのまま実行する | 10件返ってきた。アイドルのカテゴリは全部で5,905件 |
| コードが使う画像・動画の項目 | 10件とも、ジャケット画像・メイン画像3サイズ・ダイジェスト画像・サンプル動画が入っていた |
| https で呼ぶ | 同じ結果が返った |
| アプリケーションIDを間違える | HTTPは200のまま、{"error":{"reason":"invalid applicationid"}} が返った |
| hits に101を入れる | エラーにならず、10件に戻った |
| sort に決まっていない値を入れる | エラーにならず、人気順で返った |
| 届かないURLに向けて呼ぶ | file_get_contents が失敗し、表示する設定のサーバーでは、PHPの警告にIDの入ったURLがそのまま出た |
| 記号を含む値 | 「V&Rプランニング」「OFFICE K'S」のように、記号がHTMLの書き方(文字参照)のまま返った |
困るのは、間違えたときにエラーで止まらないことです。アプリケーションIDを打ち間違えると、オーナーのコードは items が無いまま繰り返しの処理に入り、何も表示されないページになります。hits や sort の打ち間違いも、黙って別の結果が返るので気づきにくいところ。
もう1つ気をつけたいのが、APIに届かなかったときです。サーバーが止まっている・時間切れになった、といったときに file_get_contents が失敗すると、PHPの警告の中に、アプリケーションIDの入ったURLがそのまま表示されます。エラーを画面に出す設定のサーバーだと、見に来た人にIDが見えてしまいます。
記号の扱いにも注意が要ります。値はすでに & の形で返ってくるので、画面に出す前に htmlspecialchars だけをかけると、二重になって「V&R」と表示されてしまいます。

今のAPIで動くPHPのコード
オーナーのコードをもとに、わたしが5か所に手を入れたものです。2026年10月17日に動かして、10件の作品とクレジットが表示されること、アプリケーションIDを間違えたときや届かないURLに向けたときに、IDを出さずにエラーの文だけが出ることを確かめました。
- エンドポイントを https にした
- APIに届かなかったときも警告を出さず、決まった文を出すようにした(警告にIDの入ったURLが出るため)
- 結果に items が無いときは、APIが返したエラーの理由を表示するようにした
- 同じ条件の結果を1時間ためておくようにした。置き場所は公開フォルダの外で、ファイルは自分だけが読める設定(0600)にする。エラーの結果はためない
&のような形で返る値を、いったん元の記号に戻してから画面用に直すようにした

<?php
// DUGAウェブサービスで、作品の一覧を表示する
$appid = 'あなたのアプリケーションID';
$agentid = 'あなたの代理店ID';
$params = [
'version' => '1.2',
'appid' => $appid,
'agentid' => $agentid,
'bannerid' => '01',
'format' => 'json',
'adult' => '1',
'sort' => 'favorite', // 人気順。new(新着)・release(発売日)・rating(評価)・price(安い順)
'hits' => 10, // 1〜100件
'category' => '12', // カテゴリID(12はアイドル)
'keyword' => '',
];
$url = 'https://affapi.duga.jp/search?' . http_build_query($params);
// APIを呼ぶ。失敗しても警告は出さない(警告にはIDの入ったURLが出るため)
function api_get($url) {
$ctx = stream_context_create(['http' => ['timeout' => 10, 'ignore_errors' => true]]);
$body = @file_get_contents($url, false, $ctx);
$data = $body === false ? null : json_decode($body, true);
return is_array($data) ? $data : null;
}
// 同じ条件の結果は1時間ためておく(回数の上限は60秒に60回)
// 置き場所は公開フォルダの外(このファイルを public_html の直下に置くなら、その1つ上)
$cacheDir = dirname(__DIR__) . '/api-cache';
$cache = $cacheDir . '/duga_' . md5($url) . '.json';
if (is_file($cache) && filemtime($cache) > time() - 3600) {
$data = json_decode((string) file_get_contents($cache), true);
} else {
$data = api_get($url);
if (isset($data['items'])) {
if (!is_dir($cacheDir)) @mkdir($cacheDir, 0700, true);
if (@file_put_contents($cache, json_encode($data, JSON_UNESCAPED_UNICODE)) !== false) @chmod($cache, 0600);
}
}
// 値は「&」のような形で返るので、いったん戻してから画面用に直す
function h($s) {
return htmlspecialchars(html_entity_decode((string) $s, ENT_QUOTES, 'UTF-8'), ENT_QUOTES, 'UTF-8');
}
?>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>DUGA API SAMPLE</title>
</head>
<body>
<?php if (!isset($data['items'])) : ?>
<p>作品を読み込めませんでした(<?= h($data['error']['reason'] ?? 'APIから応答がありません') ?>)</p>
<?php else : ?>
<p>全<?= number_format($data['count']) ?>件</p>
<?php foreach ($data['items'] as $row) : $item = $row['item']; ?>
<section>
<h2><a href="<?= h($item['affiliateurl']) ?>" rel="sponsored"><?= h($item['title']) ?></a></h2>
<p><?= h($item['makername']) ?> / <?= h($item['price']) ?> / 公開日 <?= h($item['opendate']) ?></p>
<p><?= h($item['caption']) ?></p>
<?php if (isset($item['jacketimage'][2]['large'])) : ?>
<img src="<?= h($item['jacketimage'][2]['large']) ?>" alt="" loading="lazy">
<?php endif; ?>
<div>
<?php foreach (array_slice($item['thumbnail'] ?? [], 0, 3) as $thumb) : ?>
<img src="<?= h($thumb['image']) ?>" alt="" loading="lazy">
<?php endforeach; ?>
</div>
<?php if (isset($item['samplemovie'][0]['midium']['movie'])) : ?>
<video controls preload="none" poster="<?= h($item['samplemovie'][0]['midium']['capture']) ?>">
<source src="<?= h($item['samplemovie'][0]['midium']['movie']) ?>" type="video/mp4">
</video>
<?php endif; ?>
</section>
<hr>
<?php endforeach; ?>
<?php endif; ?>
<a href="https://click.duga.jp/aff/api/<?= h($agentid) ?>-01" target="_blank" rel="noopener"><img src="https://ad.duga.jp/img/webservice_88.gif" alt="DUGAウェブサービス" width="88" height="31"></a>
</body>
</html>
「duga_api.php」のような名前で保存し、「あなたのアプリケーションID」「あなたの代理店ID」を自分のものに書き換えて、PHPが動くサーバーに上げます。結果をためるフォルダ(api-cache)は、このファイルを置いたフォルダの1つ上にできます。public_html の直下に置けば公開フォルダの外になりますが、もっと深い場所に置くときは $cacheDir を公開されない場所に書き換えてください。

並び順・件数・カテゴリを変えて表示を変える
表示を変えるときは、$params の sort・hits・category・keyword を書き換えます。並び順は5種類あり、2026年10月17日に3件ずつ取って、次のように並ぶことを確かめました。
| 並び順 | sort に入れる値 | 先頭に来た作品 |
|---|---|---|
| 人気順 | favorite | 総合ランキングの上位 |
| 新着順 | new | その日(10月16日)に公開された作品 |
| 発売日順 | release | 10月24日発売の、まだ発売前の作品 |
| 評価順 | rating | レビューの平均が4.5前後の作品 |
| 安い順 | price | 100円からの作品 |

hits は1〜100件で、101以上を入れると黙って10件に戻ります。カテゴリIDは2桁の数字が基本で、たとえば02が女優、07が熟女、10がコスプレ、12がアイドル、14がアニメ、19がドラマです。「0308」のような4桁や「100009」のような6桁のIDを持つカテゴリもあります。
条件を変えたときに何が返ってくるかは、DUGA 商品検索のツールで、コードを書く前に試せます。APIが返す値のほとんどを、そのまま並べて見られるツールです。
よくある質問
DUGAのAPIは無料で使える?
無料です。代理店の登録にも、年会費や利用料はかかりません。かかるのは、報酬を振り込むときの手数料400円だけ。インボイスの登録番号が無い免税事業者は、2026年10月以降の支払いから「インボイス未登録控除」も差し引かれます。
1回のリクエストで何件まで取れる?
100件までです。hits に101以上を入れてもエラーにはならず、10件に戻ります。100件を超えて取りたいときは、offset で取り始める位置をずらして、何回かに分けて呼びます。
http と https のどちらで呼べばいい?
どちらでも同じ結果が返りました。今から作るなら https で呼ぶのがおすすめです。
ほかのASPのAPIとはどう違う?
DUGAは人気順やレビュー評価順で並べられ、レビューの平均とランキングの順位も返ってきます。ソクミルの商品検索APIは、2026年10月17日に試した限りでは、人気順や評価順を送っても新しい順で返り、レビューの値もありませんでした。
この記事で作ったAPIは、ツールで試せます
キーワードや条件を変えて、APIが返す実際のデータを確かめられます。



