Twitter APIのWrite権限を凍結された2019夏

本当はこういう話、恥ずかしくて記事にしたくないのですが…
BANされた時、下記の記事に助けられたので私も記録として残しておこうと思います。
[Twitterアカウント,appsの凍結で生きた心地のしない正月7日間を過ごした話](https://qiita.com/ma7ma7pipipi/items/0c9c1ca364fa4498176c)

# 何がダメだったのか
結論から言うと、下記の[自動化ルール](https://help.twitter.com/ja/rules-and-policies/twitter-automation)に違反していました。
> 2.自動化された@ツイートや返信の投稿

> 返信と@ツイートは、Twitter利用者が簡単にコミュニケーションをとれるように用意されている機能です。この機能を自動的に利用して、不特定多数の利用者に一方的にメッセージを送ることは不適切な行為であり、禁止されています。たとえば、単純にキーワード検索にヒットしただけのツイートに対して自動的に返信を送ることは許可されません。@ツイートや返信をスパムとして利用したり、同一内容の@ツイートや返信を繰り返し投稿したりした場合、検索結果からの該当ツイートの除外や、アプリやアカウントの凍結などの強制執行措置の対象となる場合があります。 

ザッとググった感じ、このルールに違反したという記事は見当たらなかったので稀な事例だと思います（悪意が無い場合）
経緯やTwitter社とのやりとり、何を思って違反してしまったのか等を書いていきます。

# それは夏休み最終日の出来事でした
2019年8月14日、夏休みも折り返し地点に入った頃合いで下記の個人開発をローンチしました。

[Twitter連動型 大喜利サイト「ついぎり」](https://twigiri.app/)

このサービスでは下記のような流れでTwitterAPIを使用しています。

1. ボケを投稿
2. **TwitterAPI経由でツイート**
3. Responseに含まれるTweetIDを保存
4. 下記の処理をスケジュールして定期実行
 1. 保存されてるTweetIDをキーに **TwitterAPIでツイート情報を取得** 
 2. Responseに含まれる「いいね数」「RT数」を取得してボケの座布団数を更新

ツイートに付いた「いいね」「RT」の総数でランキングされるというシステムがウリなのですが、StreamAPIが廃止されてツイートのリアルタイム取得が出来なくなっている為、この様な処理を組んで定期的にツイートを取得しています。

ローンチ後は[結構使って頂けて](https://qiita.com/kinmi/items/ce39b52ff712098431c4)、その分バグ報告や要望もたくさん頂き、その対応に追われて夏休みを過ごしました。対応も一段落し「この勢いで流行るといいなぁ」と思いながら床についた夏休み最終日の深夜。
事件は起こります。

**スッコココ**

深夜1時をまわった頃、Slackに1通のメッセージが入りました。
> 何度試してもボケを投稿できません。

最初はTwitterのアカウント情報がうまく紐づいてないのかなと思いました。
その場合は再ログインやキャッシュ削除で何とかなっていたので、そう促します。
返ってきた言葉は「やっぱりダメ」
そんな馬鹿な、と**焦る気持ちを抑えて渾身のボケを投稿**したのですがエラー。
なんてこった、再現しちまった。

ツイート処理のログを確認するとTwitter認証でエラーレスポンス。
・・・BANか？
*TwitterAPIを使うサービスは流行り始めた頃に一度はBANされる* と聞いた事がある。
やったぜ。流行ったって認められた。
いや違う、定期実行で動いてるツイートの取得は正常終了している。
なんだこれ。

# Twitter社へ問い合わせ
Twitter Developer Consoleで確認するとWrite権限が凍結された旨が記載されており、Read権限は生きている状態。
「[こちら](https://help.twitter.com/forms/general)から問い合わせてください」
みたいな、問い合わせフォームへのリンクが貼られています。

APIを使わせてもらう以上、規約やルールは全て目を通して、その上でサービス作っている。
心当たりなんてあるはずもなく。
確か、そういう旨で問い合わせフォームから異議を申し立てました（うろ覚え）

涙目になりつつ、ついぎりに「只今ご利用頂けません」的なメッセージ表示する機能を実装します。
仕事中にBANが解除される可能性を考え、スマホからでも表示を消せるように・・・とか、少し凝った実装。

問い合わせ直後、即レスがメールで来ていました。
> ***8月19日(月) 2:00***
>Hello @_kinmi,
Thank you for reaching out. We have reviewed your request and have reactivated your API key. Going forward, carefully ensure that your application adheres to Twitter’s policies:
>
[Developer Agreement and Policy](https://dev.twitter.com/overview/terms/agreement-and-policy)
[Automation Rules](http://support.twitter.com/articles/76915)
[Twitter Rules](http://support.twitter.com/articles/18311)
>
Please note, applications found to be violating policy again may be subject to permanent suspension.
>
Regards,
>
Twitter Platform Operations

ようは
「解除したよ」
と。

こんな感じのツイートをする。
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">書き込み制限（ツイートとか）のエラーレスポンス<br>→Twitterへ問い合わせ<br>→５分後Twitter社より返信<br>「ミスってたわ。解除しといたで」<br><br>あーもう…<br>あーもう！！！<br>お知らせ表示機能実装してて、メールに1時間気付かなかった。<br>明日から10日ぶりの仕事なのに… <a href="https://t.co/GRTgkhF9ls">https://t.co/GRTgkhF9ls</a></p>&mdash; きんみ | ツイッター大喜利サイト🎍ついぎり🎍作りました🙄 (@_kinmi) <a href="https://twitter.com/_kinmi/status/1163148703852617729?ref_src=twsrc%5Etfw">August 18, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

この時点で深夜3時である。
夏休みが終わり、仕事が始まる。

問題無いことを確認し、4時ごろ安堵のため息を吐きながら再び床につく。

# 悪夢は起床後にやってくる
寝不足のまま仕事始めか・・・と思いながら起床。
上記のツイートにリプがついてる。
> もしかして、またロックされてない？

あぁぁぁぁ！？！？
**寝ぼけ眼をこすりながら渾身のボケを投稿**する。
・・・エラーだ。

開発者コンソールを確認すると、またWrite権限のみ凍結されてる旨が記載されてる。
メールボックスを確認するとTwitter社からメールが届いてる。
> ***8月19日(月) 7:17***
>Hello,
>
Thanks for reaching out. Your app has been restricted or suspended due to one or more violations of our [Developer Agreement and Policy](https://dev.twitter.com/overview/terms/agreement-and-policy), [Automation Rules](https://support.twitter.com/articles/76915-automation-rules-and-best-practices), [Display Requirements](https://dev.twitter.com/overview/terms/display-requirements) and/or [Twitter Rules](https://support.twitter.com/articles/18311-the-twitter-rules). Common reasons for this happening include:
>
Users reporting content posted through your app as spam (Tweets, RTs, favs, Ms, etc.)
Abusive use of automations, like auto-following/unfollowing  
Suspicious API usage, such as repeatedly hitting rate limits
Display violations regarding how you must show Tweets
This list is not exhaustive, so review our policy documentation to ensure that your app and your app’s users are following all of our rules.
>
Please respond to this email if you need further clarification, but note that we will only consider a request to lift this restriction after you provide us with the following information:
>
App ID and consumer key
Link to and instructions on how to log into your app to review it for compliance
A list of specific changes that you have made to resolve policy non-compliance
We will not respond to requests to lift restrictions that do not include this information.
>
Regards,
>
Twitter Platform Operations

ようは
「君のアプリやっぱダメだわ。ちゃんとルール確認して対応したら対応内容をメールしてな。」

泣く。

英語でメールか・・・
日本語でもいけるかもしれないが、出来る限りタイムロスは無くしたいところ。
幸いなことに、私は**英検4級**を持っているので日本語をGoogle翻訳で英語にエンコード、更にデコードして可逆な英語になっている事を確認できます。
通勤電車の中で完璧な英文メールを作成して送りつけました。
> ***8月19日(月) 8:57***
>Hello.
My name is 本名(@_kinmi) and I am writing you from Japan.
>
>> App ID and consumer key

>App ID:開発者コンソールに表示されてるApp ID
consumer key:開発者コンソールに表示されてるconsumer key

>> Link to and instructions on how to log into your app to review it for compliance

>My App link is
https://twigiri.app
>
and login is
top right of the screen green button
[ログイン / 登録]

>> A list of specific changes that you have made to resolve policy non-compliance

>My app has the ability to send tweets.
and can analyze that tweet.
This feature is the same as other apps, so I think there is no problem.
And comply with terms of service and rate limits.
I made an app for a development environment a few days ago. Was this bad?
I deleted the app for the development environment.
>
Please let me know if there are other reasons.
thanks.

ようは
「ワシのアプリはツイートする機能と、そのツイートを分析(いいね/RTの集計)する機能を持っとる。これは他のアプリにもよくある機能や。何がダメか分からん。教えてくれ」

と、強気なメールを送ってみたものの心当たりとしては下記がありました。

## 心当たり
### テスト用アプリの登録

本番用とは別に、テスト用のアプリを登録していました。
「用途はテストのみ」という旨を説明欄に記載していれば問題無いのですが、[開発者ポリシー](https://developer.twitter.com/ja/developer-terms/policy.html)の下記に該当してBANされたという記事がネット上には[沢山](https://www.itmedia.co.jp/news/articles/1712/15/news118.html)あります。
>同じ機能を備えた複数のアプリケーションを別の名前で提供することによって不正に占拠 (スクワッティング)すること

つまりリクエストを分散させてレート制限回避するなよって事です。念のためテスト用アプリを削除して「削除してるよ」と上記のメールに記載しました。

### 表示要件違反

ツイートを取得してWebサイトに表示する場合、厳密な[表示要件](https://developer.twitter.com/en/developer-terms/display-requirements.html)があります。
APIによるツイート取得は行っているものの、表示しているデータのソースはこちらのサービスで発生したもの。
現に[質問箱](https://peing.net/ja/)に代表される、ツイート送信機能をもつサービスも表示要件は満たしていません。

ただ、Twitterから「ダメ」と言われればそれまで。
その場合は**デスマ**だな、と腹を括っていました。

### なんでWrite権限だけ・・・？
上記２点に違反していた場合、なぜWrite権限だけ制限されるのか謎でした。
そもそもTwitterAPIのルールに違反している訳だから、Read権限も制限されるはずでは・・・？

#次の日の朝
Twitter社からメールが届いていました。
> ***8月20日(火) 6:55***
>Thanks for reaching out. Your app was restricted for sending a large volume of unsolicited and/or repeat @mentions. This is prohibited by the [Twitter Rules](https://support.twitter.com/articles/18311): 
>
**Spam**: You may not use the Twitter service for the purpose of spamming anyone. What constitutes “spamming” will evolve as we respond to new tricks and tactics by spammers. Some of the factors that we take into account when determining what conduct is considered to be spamming are:
>
- if you send large numbers of unsolicited replies or mentions;
- if you send large numbers of duplicate replies or mentions;
>
Note that this behavior is not allowed regardless of whether or not it is automated. Per the Automation Rules if you are sending automated @mentions the recipient or mentioned user(s) must have requested or have clearly indicated an intent on Twitter  to be contacted by you. 
>
As a next step please respond to this email listing the measures that you have taken to limit this behavior on your platform. 
>
Please let us know if you have any questions. 
>
Regards, 
>
Twitter Platform Operations

ようは
「君のアプリ、スパムやろ。沢山メンション飛ばしとるやないか。」

ついぎりはローンチ当初、ボケツイートにお題作成者宛てのメンションが含まれる仕様でした。
ローンチ前に行ったクローズドテストで「自分が投稿したお題で誰かボケたら通知が欲しい」という要望があり、[note](https://note.mu/)をシェアした時に含まれる「via @〜〜」の様なメンション通知をイメージして実装していました。
これが結構好評で「たくさん通知来て楽しい」という声を多く頂けました。

自動化ルールにある「自動化された@ツイートや返信の投稿」は確認していたのですが、不特定多数にメンションを飛ばす悪質なbot対策のルールだと誤認おり、明確な指摘を貰えたことで無事
「なるほど:innocent:」
という顔になりました。

早朝、出勤前にメンションを含める機能を削除し、完璧な英文謝罪メールを送信。
> ***8月20日(火) 8:36***
>Thank you for your reply.
I understand.
My app is similar to a QA service.
Users can post questions and others will answer.
And can tweet the answer (can choose whether to send a tweet)
>
Tweet: Question
Mention: Question creator
URL: Answer page
>
My understanding is that this mention is a problem.
A version with a mention removed from the tweet has been released.
Please remove the restriction.
>
Regards, 

「私のアプリはQAサービスのようなものです。回答ツイートには質問者宛てのメンションを追加していました。この機能は削除しました。お願いですから凍結を解除してください。」
改めて読むと凄く言い訳がましい。

# 即レスが来る
> ***8月20日(火) 9:17***
>Hello @_kinmi,
> 
Thank you for reaching out. We have reviewed your request and have reactivated your API key. Going forward, carefully ensure that your application adheres to Twitter’s policies:
> 
- [Developer Agreement and Policy](https://dev.twitter.com/overview/terms/agreement-and-policy)
- [Automation Rules](http://support.twitter.com/articles/76915)
- [Twitter Rules](http://support.twitter.com/articles/18311)
>
Please note, applications found to be violating policy again may be subject to permanent suspension.
>
Regards,
>
Twitter Platform Operations

ようは
「まぁ許したるわ。解除しといたで。ちゃんとルール確認しとき。次は無いからな（意訳）」

仕事中ですが、思いっきりガッツポーズしました。
内心ウッキウキで公式アカウントから謝罪と再開の報告ツイートを送信。
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">【お知らせ・お詫び ①】<br>Twitter社より連絡があり、再度ツイート機能が開放されました！<br><br>現在は正常にボケをツイートする事ができます。<br><br>長らくお待たせしてしまい、申し訳ございません。<a href="https://twitter.com/hashtag/%E3%81%A4%E3%81%84%E3%81%8E%E3%82%8A?src=hash&amp;ref_src=twsrc%5Etfw">#ついぎり</a></p>&mdash; ついぎり@公式アカウント (@twigiri_app) <a href="https://twitter.com/twigiri_app/status/1163615777347391494?ref_src=twsrc%5Etfw">August 20, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

無事、復活を果たしました。

# 教訓
**・ APIでツイート送信する場合、メンションは付けない方が良い**
[ツイートボタン](https://developer.twitter.com/en/docs/twitter-for-websites/tweet-button/overview)なら良いと思います。あれは送信前にユーザーが編集出来るので。
noteのシェアも同じです。
アプリ側で「メンションを付けて送信する」というユーザーの許可があれば大丈夫かもしれませんが、Twitter側からそれを確認することは出来ないので、別途Twitterへ申請する必要があると思います。
（一時的な凍結=>即解除=>再度凍結 の流れを考えると、恐らく自動検知されてそうです）

**・ Write権限のみのチェックが存在する**
TwitterAPIでは三段階の権限設定が出来ます。

`Read-only`: ツイートやユーザー情報の取得、SNS認証等の読み込み専用の権限
`Read and write`: 上記に加えてツイートの送信等、Twitter上のデータを操作出来る権限
`Read, write, and Direct Messages`: 上記に加えてDM送信を行える権限

ついぎりでは`Read and write`を使っていますが、今回ルール違反により一時的に権限レベルが`Read-only`に落ちました。
強い権限レベルの方が使用状況に対する検査が厳しいということです。
不用意に権限レベルを上げるとユーザーの不信感も買ってしまうので、用途に合わせた設定をした方が良いです。

**・ Twitter社の対応まじ早い**
8/19 2:00 凍結
8/20 9:17 解放
という、このスピード感。
無料で使わせてもらってるんですけど？
100%私が悪いこの状況で、この迅速さには感動しました。正直「1週間ぐらいはかかるよな、、、せっかく使ってもらえてたのに忘れ去られるな・・・」とか考えてました。
もうTwitter社には足向けて寝られません。

# おわり
軽率な判断により、ローンチ直後から躓いてしまったサービスですが、
現在は安定稼働しており、要望に合わせたアップデートを随時行っております。
[Twitter連動型 大喜利サイト「ついぎり」](https://twigiri.app/)
![ogpTop_small.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/127547/f683ce0d-4201-8ce0-a870-ac8a3eec0f7d.png)
面白いボケ、お待ちしております:yum: