Instagram の API (2020年4月以降)

Instagramの画像を自作のwebページに表示したかったのですが
なにやら2020年4月から仕様が変わったらしく
ぐぐったものがあまり役に立たなかったので
忘備録としてAPIが使えるまでの手順を残します。

## まとめ

`access_token`と`instagram_business_accountのid`が必要。

|output|API|input|input|input|
|----|----|----|----|----|----|
|**access_token**|/accounts|自分のfacebookID|OAuth access_token||
|**instagram_business_account.id**|/me?fields=instagram_business_account | access_token|||
|自分のfacebookID|/me?|OAuth access_token|||
|OAuth access_token|/oauth/access_token?grant_type=fb_exchange_token|client_id|client_secret|fb_exchange_token|
|client_id|（https://developers.facebook.com/apps/ から対象アプリの「アプリID」を確認||||
|client_secret|（https://developers.facebook.com/apps/ から対象アプリの「app secret」を確認||||
|fb_exchange_token|（https://developers.facebook.com/tools/explorer/ で生成||||

## 0. 前提

- Instagramはビジネスアカウントにしておく
    - スマホアプリで以下手順を操作
    - https://help.instagram.com/502981923235522
- FacebookページにInstagramアカウントをリンクしておく
    - PCで以下手順を操作（スマホでも良いけど）
    - https://www.facebook.com/business/help/898752960195806
- facebook for developersで何かしらアプリを作成しておく
    - https://developers.facebook.com/
    - その際プロダクト(製品)として `Instagram` を追加しておく

## 1. fb_exchange_token を作成

グラフAPIエクスプローラにアクセスする。
https://developers.facebook.com/tools/explorer/

以下のパーミッション設定を行う。

|設定項目|設定値|
|------|------|
|Facebookアプリ|(自作アプリ)|
|ユーザーまたはページ|ユーザートークン|
|アクセス許可|business_management<br>pages_show_list<br>instagram_basic<br>public_profile(規定値)|

`Generate Access Token` を押下する。
すると上部のテキストボックスに生成したトークンが表示される。250文字くらい。
（Copy Tokenボタンを押すと便利）

## 2. OAuthでclientのアクセストークンを作成

clientとは上記で選んだ自作のFacebookアプリのこと。
OAuthに必要なのは以下の３点。

- client_id
- client_secret
- fb_exchange_token *（上記で作成したもの）*

### 2.1. アプリIDとapp secretの確認

client_idとclient_secretは下記ページから確認。
https://developers.facebook.com/apps/

Facebookアプリの一覧が表示されるので、fb_exchange_token作成時と同じものを選択。
その後の画面で `設定` ＞ `ベーシック` のページを開いて以下を確認する。

- `アプリID`　→ client_idになる
- `app secret`　→ client_secretになる

app secretは `表示` ボタンを押すと確認できる。
（この時パスワードの入力を求められるが、Facebookのものを入力する）

### 2.2. RESTでアクセストークン発行

ここまで準備できたら、以下のURLをブラウザでアクセスする。
バージョン番号はグラフAPIエクスプローラ(前述)のものに合わせる。
執筆時点では `v7.0`

`https://graph.facebook.com/v7.0/oauth/access_token?grant_type=fb_exchange_token&client_id={client_id}&client_secret={client_secret}&fb_exchange_token={手順1のfb_exchange_token}`

するとブラウザに以下のような結果が表示される。
この時のアクセストークンは190文字くらい。

```json:結果
{"access_token":"X0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xo","token_type":"bearer"}
```

## 3. APIで利用するアクセストークンの作成

### 3.1. 自分のfacebookIDを調べる

ブラウザで以下URLにアクセスする。`id` が自分のfacebookIDになる。

`https://graph.facebook.com/v7.0/me?access_token={手順2のaccess_token}`

```json:結果
{
   "name": "\u81EA\u5206\u306E\u540D\u524D",
   "id": "123456789012345"
}
```

### 3.2. アクセストークン発行

ブラウザで以下URLにアクセスする。

`https://graph.facebook.com/v7.0/{自分のfacebookID}/accounts?access_token={手順2のaccess_token}`

```json:結果
{
   "data": [
      {
         "access_token": "X0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xo",
         "category": "\u30DA\u30FC\u30B8\u306E\u30AB\u30C6\u30B4\u30EA",
         "category_list": [
            {
               "id": "1234567890123456",
               "name": "\u30DA\u30FC\u30B8\u306E\u30AB\u30C6\u30B4\u30EA"
            }
         ],
         "name": "facebook_page_name",
         "id": "123456789012345",
         "tasks": [
            "ANALYZE",
            "ADVERTISE",
            "MODERATE",
            "CREATE_CONTENT",
            "MANAGE"
         ]
      }
   ],
   "paging": {
      "cursors": {
         "before": "X0xoX0xoX0xoX0xoX0xo",
         "after": "X0xoX0xoX0xoX0xoX0xo"
      }
   }
}
```

`data` とはfacebookページの属性情報。
ここで取り出した `access_token` がAPIで使える。

### 3.3. 作成したトークンの確認

アクセストークンデバッガーを使うと有効期限やスコープ(権限)を確認できる。
https://developers.facebook.com/tools/debug/accesstoken/

トークンを入力して `デバッグ` ボタンを押す。

<table>
  <tbody>
    <tr>
      <th colspan="2">アクセストークン情報</th>
    </tr>
    <tr>
      <td colspan="2">(途中省略)</td>
    </tr>
    <tr>
      <td>有効期限</td>
      <td>受け取らない</td>
    </tr>
    <tr>
      <td colspan="2">(途中省略)</td>
    </tr>
    <tr>
      <td>スコープ</td>
      <td>page_show_list, business_management, instagram_basic, public_profile</td>
    </tr>
  </tbody>
</table>

有効期限が `受け取らない` になっていること、
スコープが手順1で指定したものになっていることを確認する。

### 3.4. instagram_business_accountを確認

`https://graph.facebook.com/v7.0/me?fields=instagram_business_account&access_token={手順3のaccess_token}`

```json:結果
{
   "instagram_business_account": {
      "id": "12345678901234567"
   },
   "id": "123456789012345"
}
```

## 4. 動作確認

試しに自分の投稿を取得してみる。

`https://graph.facebook.com/v7.0/{instagram_business_accountのid}/?fields=name,media{caption,media_url,permalink}&access_token={手順3のaccess_token}`

```json:結果
{
   "name": "\u30A4\u30F3\u30B9\u30BF\u8868\u793A\u540D",
   "media": {
      "data": [
         {
            "caption": "%u6295%u7A3F%u3057%u305F%u30B3%u30E1%u30F3%u30C8",
            "media_url": "https://scontent-nrt1-1.xx.fbcdn.net/v/t51.2885-15/12345678_123456789012345_1234567890123456789_n.jpg?_nc_cat=123&_nc_sid=X0xoX0&_nc_oc=X0xoX0xoX0xoX0xoX_X0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0x_X0xoX0xoX0xo_X0xoX0xoX0_Eb&_nc_ht=scontent-nrt1-1.xx&oh=X0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xo&oe=X0X0X0X0",
            "permalink": "https://www.instagram.com/p/B_X0xoX0xoX/",
            "id": "12345678901234567"
         },
         {
            "caption": "%u6295%u7A3F%u3057%u305F%u30B3%u30E1%u30F3%u30C8",
            "media_url": "https://scontent-nrt1-1.xx.fbcdn.net/v/t51.2885-15/12345678_123456789012345_1234567890123456789_n.jpg?_nc_cat=123&_nc_sid=X0xoX0&_nc_oc=X0xoX0xoX0xoX0xoX_X0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0x_X0xoX0xoX0xo_X0xoX0xoX0_Eb&_nc_ht=scontent-nrt1-1.xx&oh=X0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xo&oe=X0X0X0X0",
            "permalink": "https://www.instagram.com/p/B_X0xoX0xoX/",
            "id": "12345678901234567"
         }
      ],
      "paging": {
         "cursors": {
            "before": "X0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX",
            "after": "X0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0xoX0x"
         }
      }
   },
   "id": "12345678901234567"
}
```

`data` が投稿一件分のデータ。