Mastodon API を使ってみる


Mastodon API の使い方などの説明です (2018/8/15 新規作成)。

Mastodon / API / REST / Streaming / WebSocket / Web Push / 認証 / ID / ID範囲 / 文字数 / 制限 / ActivityPub / NodeInfo / / 外部 / 戻る / トップページ


Mastodon

Mastodon は脱中央集権型のSNSで、 だれでも自由に運用できるTwitterに似たサービスです。
 
Mastodon APIは、タイムラインを参照したり トゥート(Twitterのツイート)したりする機能が用意されています。 公式クライアント(サーバーのWeb UI)でも使われているため、 クライアントやBOTを作るのに必要な機能は揃っています。

Mastodon APIの基本

Mastodon APIは基本的にOAuth2.0で認証をするREST APIで、 レスポンスはJSON形式です。 ドキュメントは こちら で提供されています。
 
認証周りから手を付けていくと、 実際に使うまでに長い説明が必要になってしまうので、 まずは認証を必要としない 指定IDのトゥートの情報を得るAPI から呼んでみましょう。
    https://サーバー名/api/v1/statuses/トゥートID
具体例として https://mastodon.social/api/v1/statuses/99730307203414093 をブラウザで開くと、レスポンスがJSONで表示されると思います。
 
次に認証ありを試しましょう。 OAuthではサーバー(以前はインスタンスと呼んでいました)にアプリ情報を登録して クライアントキー・クライアントシークレットを準備し、 この値とAPIを駆使して利用者に アプリからのアクセスを認可してもらいます。 その証として「アクセストークン」が得られるので、 アクセストークン情報を付与してAPIを呼び出す流れとなります。 これも実際に使うまでに長い説明が必要になってしまうので、 アプリ情報を登録するアカウント自身だけであればWeb上の操作だけで アクセストークンを直接得られますので、その方法からやってみましょう。
 
まず、適当なMastodonサーバーで実験に使うアカウントを用意し、 「ユーザー設定」画面に入ります。 サイドバーから「開発」を選び「新規アプリ」ボタンを押します。 「アプリの名前」に "API Test" など名前を入力したら他の情報はそのままで、 送信ボタンを押してアプリ登録をします。 生成されたアプリ名を選ぶと、アクセストークン等の情報が表示されます。
 
あとは、APIにアクセスする際に、ヘッダー名 "Authorization" に "Bearer アクセストークン" を渡すだけです。 ここでは、ホームタイムラインを取得する JavaScriptの例を載せておきます。
	var xmlHttpRequest=new XMLHttpRequest();
	xmlHttpRequest.addEventListener("load",function(event) {
		// xmlHttpRequest.responseにレスポンスが入っています
	},false);
	xmlHttpRequest.responseType="json";
	xmlHttpRequest.open("GET","https://サーバー名/api/v1/timelines/home");
	xmlHttpRequest.setRequestHeader("Authorization","Bearer アクセストークン");
	xmlHttpRequest.send();
なお、デフォルトで Access-Control-Allow-Origin ヘッダーが送出されるので、 クロスドメインでアクセスできます (サーバーの管理者が設定を変更していない限り)。

REST API

後はこの応用で色々なAPIを呼び出せます。 ドキュメント から欲しいAPIを探せば、 必要なURLとパラメータが分かります。 レスポンスの詳細はドキュメントの Entitiesに書いてあり、 Entities単体か配列が返ってきます。 検索できる拙作ツール を用意してますので、良ければご利用下さい。
 
APIは基本的にドキュメントから探せますが、 新しいAPIはまだ反映されていないことがまれにあるため、念のため リリースノート も参照した方が良いです。
 
トゥートも普通にPOSTでできます。 自動でトゥートする時はマナーとしてローカルタイムラインに載らないように 非収載 (visibility=unlisted) 指定をしましょう。
	var xmlHttpRequest=new XMLHttpRequest();
	xmlHttpRequest.addEventListener("load",function(event) {
		// xmlHttpRequest.responseにレスポンスが入っています
	},false);
	xmlHttpRequest.responseType="json";
	xmlHttpRequest.open("POST","https://mstdn.jp/api/v1/statuses?access_token=アクセストークン");
	xmlHttpRequest.setRequestHeader("Content-Type","application/x-www-form-urlencoded; charset=UTF-8");
	xmlHttpRequest.send("status="+encodeURIComponent("テスト")+"&visibility=unlisted");
	// file:///以下から試すと422エラーになるので注意
ドキュメントに明記されていないため いつか使えなくなってしまうかも知れませんが、 この例のようにどのAPIでも、 アクセストークンはヘッダーではなく クエリーに "access_token=アクセストークン" を渡すことでも使えるようです。
 
タイムラインのようにレスポンスに続きがある時は HTTPのレスポンスヘッダーの "Link" にページング先のアドレスが渡されます。 引数でページ数等を指定するのではなく、 Linkヘッダーのnext, prevで示されたURLを開くことで次・前ページの情報を得ます (それらしい引数が含まれていても、 内部IDで将来的に変更されうるので直接扱ってはいけません)。
	xmlHttpRequest.addEventListener("load",function(event) {
		// xmlHttpRequest.responseにレスポンスが入っています
		
		// xmlHttpRequest.getResponseHeader("Link")にページング情報
		var links=xmlHttpRequest.getResponseHeader("Link").split(/, /);
		var pagination={};
		for (var i=0;i<=links.length-1;i++)
		{
			var parsed=links[i].match(/<([^>]+)>; rel="([^"]+)"/);
			pagination[parsed[2]]=parsed[1];
		}
		// 次ページを開くなら pagination.next
		// 前ページを開くなら pagination.prev
	},false);
任意個の引数を渡せるAPIでは、 https://mstdn.jp/api/v1/accounts/relationships?id[]=1231&id[]=42645&id[]=429164&id[]=72843&id[]=63076 のように 引数名に[]をつけて複数指定することで実現します。

Streaming API

REST APIはこちらからAPIを呼び出すため、 トゥートを受信した瞬間に処理をすることが実現できません。 そこで、Streaming APIが用意されています。
 
Streaming API は呼び出し方法はREST APIと同じですが、 接続を持続して返すべき情報が出来た時にその分だけレスポンスを返すことで、 リアルタイムな情報をやりとりする仕組みです。 Mastodonでは流れるタイムラインを実現するために Streaming APIが利用されています。
	var xmlHttpRequest=new XMLHttpRequest();
	var lastResponse="";
	var data="";
	xmlHttpRequest.addEventListener("progress",function(event) {
		// chunk=今回受信した断片
		var chunk=xmlHttpRequest.response.substring(lastResponse.length);
		lastResponse=xmlHttpRequest.response;
		
		// data=まだ処理してない断片 (改行まで受信してるとは限らない)
		data=data+chunk;
		
		// 空行をスキップ
		data=data.replace(/^\n/gm,"");
		
		// タイムアウトで切断されないようにするためのダミーデータをスキップ
		data=data.replace(/^:(.*)\n/gm,"");
		
		var content;
		do {
			content=data.match(/^event: (.*)\ndata: (.*)\n([\s\S]*)$/);
			if (content!=null)
			{
				var event=content[1];
				var payload=(content[2]!="undefined" ? JSON.parse(content[2]) : null);
				
				// event(イベント名), payload(データ内容)で処理をする
				
				data=content[3];
			}
		} while (content!=null);
	},false);
	xmlHttpRequest.open("GET","https://mstdn.jp/api/v1/streaming/public/local");
	xmlHttpRequest.send(null);
データは "event: イベント名↵data: データ内容↵" の形でリアルタイムに流れてきます。データ内容はJSON型です。
 
ドキュメントに書かれていないイベント があるので、 ここにまとめておきます。
 
Streaming APIのイベント
イベント名 イベント内容 データ内容
update 新しいトゥート Status
status.update トゥートの更新 (Mastodon3.5.0〜) Status
delete トゥートの削除 削除されたトゥートのID
notification 新しい通知 Notification
filters_changed 設定のフィルターの更新 (Mastodon2.4.3〜) なし (undefinedの文字)
announcement 新しいお知らせ? (Mastodon3.1〜?) Announcement ?
announcement.reaction お知らせへの新しいリアクション? (Mastodon3.1〜?) AnnouncementReaction ?
announcement.delete お知らせの削除? (Mastodon3.1〜?) 削除されたお知らせのID ?
 
しばらくデータを流さないとブラウザやサーバーが タイムアウトで切断してしまいます。 タイムアウトを防ぐために空行や:で始まるダミーデータが流れてくるため、 それらは読み捨てます。
 
なお、この例では認証不要のローカルタイムラインを受信していますが、 ホームタイムラインなどの認証が必要な時はREST API同様に "Authorization: Bearer アクセストークン" ヘッダーを設定するか、 クエリーに "access_token=アクセストークン" を追加します。

Streaming API (WebSocket版)

ドキュメント化されていませんが、Streaming APIにはWebSocket版があります。 さきほど説明したHTTP接続を持続させる方法はLong pollingと呼ばれ、 既存の技術の応用なので導入しやすい一方、 効率面などで最適とは言えません。 WebSocketは双方向の逐次通信を実現するために作られた 比較的新しい技術なため、利用可能な環境なら WebSocket版をお勧めします。 Internet Explorer以外のモダンブラウザならWebSocketはサポートされていますし、 公式Web UIもこちらを使っているようです。
 
WebSocketはhttpsではないプロトコルなので、 サーバーに対して /api/v1/instance を呼び出し、 返ってきた値の urls.streaming_api をWebSocketのアドレスのベースに します (通常は wss://サーバー名 になっています)。 このベースに /api/v1/streaming を足したアドレスが WebSocket版Streaming APIになります。 引数streamに種類を指定します (Long polling版とは指定方法が違う点に注意が必要です)。
 
Long polling版にも ドキュメントに書かれていないAPI があるので、 ここにまとめておきます。
 
Streaming API
WebSocket版 Long polling版 内容
/api/v1/streaming/?stream=user GET /api/v1/streaming/user 自分のホームタイムライン+通知
/api/v1/streaming/?stream=user:notification GET /api/v1/streaming/user/notification 自分へ通知
/api/v1/streaming/?stream=public GET /api/v1/streaming/public 連合タイムライン (認証不要)
/api/v1/streaming/?stream=public:local GET /api/v1/streaming/public/local ローカルタイムライン (認証不要)
/api/v1/streaming/?stream=public:remote GET /api/v1/streaming/public/remote 連合タイムラインの別サーバーのみ (認証不要) (Mastodon3.1.4〜)
/api/v1/streaming/?stream=public:media GET /api/v1/streaming/public?only_media=true 連合タイムラインのメディアのみ (認証不要)
/api/v1/streaming/?stream=public:local:media GET /api/v1/streaming/public/local?only_media=true ローカルタイムラインのメディアのみ (認証不要)
/api/v1/streaming/?stream=public:remote:media GET /api/v1/streaming/public/remote?only_media=true 連合タイムラインの別サーバーのメディアのみ (認証不要) (Mastodon3.1.4〜?)
/api/v1/streaming/?stream=direct GET /api/v1/streaming/direct 自分のダイレクトメッセージ
/api/v1/streaming/?stream=hashtag GET /api/v1/streaming/hashtag 連合タイムラインのクエリーtag(#は含めない)で指定したハッシュタグのトゥート (認証不要)
/api/v1/streaming/?stream=hashtag:local GET /api/v1/streaming/hashtag/local ローカルタイムラインのクエリーtag(#は含めない)で指定したハッシュタグのトゥート (認証不要)
/api/v1/streaming/?stream=list GET /api/v1/streaming/list クエリーlistで指定した自分のリストのトゥート
 
認証が必要なAPIでは クエリーに "access_token=アクセストークン" を追加します。
	// instanceInfoには /api/v1/instance のレスポンスを入れておく
	
	var socket=new WebSocket(instanceInfo.urls.streaming_api+"/api/v1/streaming/?stream=public:local");
	socket.addEventListener("message",function(event) {
		var data=JSON.parse(event.data);
		
		var event=data.event;
		var payload=data.payload;
		if (event=="update" || event=="notification")
		{
			payload=JSON.parse(data.payload);
		}
		
		// event, payloadで処理をする
	},false);
WebSocketに接続してしまえば後はデータが順次流れてきます。 Long polling版同様にevent, data情報が渡されますが形式が異なり、 { "event": イベント名, "payload": データ内容 } の形のJSON型で、 データ内容はもう一度JSON文字列化された形式で格納されていますので、 注意が必要です。
 
Mastodon3.3からは1本の接続で複数のStreamingを受け取れるようになりました。 リソースの節約にもなるため、サーバーのバージョン制限が許せるなら こちらを使いましょう。
	var socket=new WebSocket(instanceInfo.urls.streaming_api+"/api/v1/streaming");
	socket.addEventListener("message",function(event) {
		var data=JSON.parse(event.data);
		
		var stream=data.stream;
		// event, payloadの扱いは変更なし
		
		if (stream[0]=="public")
		{
			// 連合タイムラインの場合
		}
	},false);
	
	// 受け取るStreamingに連合タイムラインを追加
	socket.send(JSON.stringify({ "type": "subscribe", "stream": "public" }));
引数なしでStreaming APIに繋ぐと何も受信しない状態で接続が確立されます。 { "type": "subscribe", "stream": Streamingの種類 } の形のJSON型のデータを送るとそのStreamingの受信が始まります。 複数回呼べば複数種類のStreamingが届くようになるため、 受信データのstreamで区別して扱えます。{ "type": "unsubscribe" } で 特定のStreamingだけ止めることももちろんできます。

Web Push API

MastodonはWeb Push機能も実装されています。 公式Web UIでも使われていますが、Web Pushを使うと ユーザーがWebページを開いていなくても通知を受け取ることができます。 これを操作するAPIも公開されています。
 
Mastodonサーバーがアプリケーションサーバーの役割を担うため、 Webアプリ開発者は自前の通知元サーバーを用意する必要はありません (httpsなWebページからしか動作しないため、Webサーバーは必要ですが)。
 
Web Pushを使うにはService Worker, Notification APIを利用します。 まずブラウザのPushManagerに購読登録をして、 アプリケーションサーバーとブラウザがやりとりするのに必要な情報(エンドポイントや鍵)を受け取り、 MastodonサーバーのREST API POST /api/v1/push/subscription に引き渡して登録をします。
	// Service Workerを登録しておく
	navigator.serviceWorker.register("serviceWorker.js");
	// Notification APIの利用許可を得ておく
	Notification.requestPermission(function(permission) { ... });
	
	function encodeBase64(buffer)
	{
		return window.btoa(
		    String.fromCharCode.apply(null,new Uint8Array(buffer)))
		    .replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"");
	}
	function decodeBase64(string)
	{
		return new Uint8Array([].map.call(
		    window.atob((string+"=".repeat((4-string.length%4)%4))
		    .replace(/\-/g,"+").replace(/_/g,"/")),
		    function(c) { return c.charCodeAt(0) }));
	}
	
	navigator.serviceWorker.ready.then(function(registration) {
		registration.pushManager.subscribe({
			userVisibleOnly: true,
			applicationServerKey: decodeBase64("VAPID公開鍵"),
		}).then(function(subscription) {
			var endpoint=subscription.endpoint;
			var publicKey=encodeBase64(subscription.getKey("p256dh"));
			var authSecret=encodeBase64(subscription.getKey("auth"));
			
			var xmlHttpRequest=new XMLHttpRequest();
			xmlHttpRequest.open("POST","https://サーバー名/api/v1/push/subscription?access_token=アクセストークン");
			xmlHttpRequest.setRequestHeader("Content-Type","application/x-www-form-urlencoded; charset=UTF-8");
			xmlHttpRequest.send(
			    "subscription[endpoint]="+endpoint+
			    "&subscription[keys][p256dh]="+publicKey+
			    "&subscription[keys][auth]="+authSecret+
			    "&data[alerts][follow]=true&data[alerts][favourite]=true"+
			    "&data[alerts][reblog]=true&data[alerts][mention]=true");
		});
	});
ブラウザに購読登録をする際にVAPID公開鍵を渡す必要がありますが、 VAPID公開鍵はアプリ情報に結びついており、 後述する /api/v1/apps で返ってくるクライアントキーと並んで vapid_key の名前で得られます。 作成済みのアプリでは /api/v1/apps/verify_credentials を呼んでも得ることが出来ます。
 
登録に成功すると、後は通知が起こったときにService Workerのイベントが発生するので、ユーザーにその情報をNotification APIで知らせます。
	// serviceWorker.jsの中身
	self.addEventListener("push",function(event) {
		var data=event.data.json();
		
		// data.notification_typeには"favourite"など通知の種類
		return event.waitUntil(
			self.registration.showNotification(
				data.title,			// 通知内容の文章
				{
					icon: data.icon,
					body: data.body,		// 対象のトゥートなど
				}
			)
		);
	});

認証

Mastodon APIは基本的にOAuth2.0で認証をします。 特定のアカウントだけでAPIを呼ぶのであれば、 さきほどのようにWeb上の操作だけでアクセストークンを得られますが、 任意のアカウントに対してAPIアクセスを認可してもらうためには 手順が必要になります。 ここではその手順について説明します。
 
認証は最終的にアクセストークンが得られればAPIを呼ぶ権利が得られるため、 そこを目指します。 まずおさらいです。
  1. サーバーにアプリ情報を登録してクライアントキー・クライアントシークレットを得る
  2. 「あなたのアカウントへのアクセスを要求しています。」画面を出して、ユーザーに承認してもらう
  3. 承認情報を元にアクセストークンを得る
このような流れとなります。
 
アプリ情報の登録
 
Mastodonは多数のサーバーの連合で動いているので、 ユーザーが新しいサーバーを使っていたら 都度アプリ情報の登録が必要になります。
	var clientId,clientSecret;
	
	var xmlHttpRequest=new XMLHttpRequest();
	xmlHttpRequest.addEventListener("load",function(event) {
		clientId    =xmlHttpRequest.response.client_id;		// クライアントキー
		clientSecret=xmlHttpRequest.response.client_secret;	// クライアントシークレット
		
		// 次のステップへ
	},false);
	xmlHttpRequest.responseType="json";
	xmlHttpRequest.open("POST","https://サーバー名/api/v1/apps");
	xmlHttpRequest.setRequestHeader("Content-Type","application/x-www-form-urlencoded; charset=UTF-8");
	xmlHttpRequest.send("client_name="+encodeURIComponent("アプリ名")+
	    "&redirect_uris=リダイレクト先"+
	    "&scopes="+encodeURIComponent(["read","write"].join(" ")));
	// file:///以下から試すと422エラーになるので注意
このようにアプリ名と、ユーザー承認後に飛ばすリダイレクト先、 認可してもらう権利を渡して/api/v1/appsを呼ぶと、 クライアントキー・クライアントシークレットが得られます。 当然ですがこのAPI自体は認証不要で呼べます。
 
引数redirect_urisにはユーザー承認後に飛ばすリダイレクト先のアドレスを指定します。 アプリがWeb形式ではない場合はリダイレクト先に 特殊な値 "urn:ietf:wg:oauth:2.0:oob" を指定することができます。 その場合はユーザーが承認した後にコードが表示されるので、ユーザーに 自分のアプリにそのコードをコピー&ペーストして貰う方法で承認情報を貰います。
 
引数scopesには ユーザーに許可してもらう操作 を空白区切りで書きます。
 
scopes
scope 許可される操作
read 読み取り系
write 書き込み系 (トゥート)
follow フォロー、ブロック (Mastodon3.5.0〜はread/writeを使うように変更)
push Web Push (Mastodon2.4.0〜)
 
Mastodon2.4.3以降では、 "read:statuses" 指定でタイムラインやトゥートの読み取りのみにするなど、 より 限定的な指定 ができるようになりました。
 
サーバーがMastodonの最新バージョンを使っているとは限らないため、 新しいAPIを使う際はサーバーそのものの情報が得られる 認証不要の/api/v1/instanceを呼んでバージョンチェックをすると良いでしょう。 具体例として https://mstdn.jp/api/v1/instance をブラウザで見ると分かるように、versionにバージョン情報が入っています。
 
ユーザーの認可
 
OAuth認可には何通りか方法がありますが、ここでは最も一般的な Authorization Code Grantを使います。 認可用のWebページのURLは次の形になります。
    https://サーバー名/oauth/authorize?client_id=クライアントキー&scope=許可される操作&response_type=code&redirect_uri=リダイレクト先
リダイレクト先と許可される操作は、 先ほど登録したアプリ情報の範囲内である必要があります。 このURLを開くと「あなたのアカウントへのアクセスを要求しています。」 画面になるのでユーザーに承認してもらうと、 リダイレクト先のアドレスに飛びます。 リダイレクト先ではアドレスにクエリーの形で承認情報がついているので、 その中のcodeを次に使います。
    リダイレクト先?code=code&scope=許可される操作
リダイレクト先を特殊指定 "urn:ietf:wg:oauth:2.0:oob" にした時は、 ユーザーにコピー&ペーストしてもらった値がcodeになります。
 
承認情報からアクセストークン
 
受け取ったcodeと、 関連情報をアプリから認可用APIの/oauth/tokenへ投げて、 アクセストークンを受け取ります。
	var accessToken;
	
	var xmlHttpRequest=new XMLHttpRequest();
	xmlHttpRequest.addEventListener("load",function(event) {
		accessToken=xmlHttpRequest.response.access_token;	// アクセストークン
	},false);
	xmlHttpRequest.responseType="json";
	xmlHttpRequest.open("POST","https://サーバー名/oauth/token");
	xmlHttpRequest.setRequestHeader("Content-Type","application/x-www-form-urlencoded; charset=UTF-8");
	xmlHttpRequest.send("client_id="+clientId+"&client_secret="+clientSecret+
	    "&redirect_uri=リダイレクト先"+
	    "&grant_type=authorization_code"+
	    "&code="+code);
JSON形式で情報が返ってきますが、 その中にaccess_tokenの値としてアクセストークンが入っています。
 
本来OAuthのアクセストークンは一定時間で失効するため、 この返り値の中に含まれるrefresh_tokenを使って 時々新しいアクセストークンに更新するのですが、 Mastodonのデフォルト設定ではユーザーが失効させない限りは使い続けられます。

ID

トゥートIDやアカウントID等のIDは数値で表現されていますが、 API上では文字列型で扱われています。 IDは64bit整数なので、プログラミング言語によって桁あふれを起こすためです。 2010年頃にTwitterのIDが53bitを越えたために、 JavaScriptの数値型(64bit浮動小数で、仮数部の52bitを越える)で 扱えなくなるため、IDを文字列型に変えた経緯があります。 それを参考にあらかじめ対応したのだと思います。
 
トゥートIDは一意になるよう、 Snowflake的な考えで設計されています。 ちなみに、上位48bitがUNIX時間になっているので、 特定時間のトゥートIDの範囲を算出することができます (unixtime×216〜unixtime×216+65535)。 なお、Mastodon1.*時代はIDは数値型で、算出ルールも違っていました。 バージョンの古いサーバーでも動作させるアプリを作る際は注意が必要です。 Mastodon2.0になった際のAPIの唯一の破壊的変更になります。
 
トゥートID・アカウントIDはサーバーごとにローカル管理されているため、注意が必要です。 例えばMastodon@mastodon.socialのIDを/api/v1/accounts/searchで検索すると、mastodon.socialサーバー上では13179ですが、mstdn.jpサーバー上では42645となります。 トゥート・アカウントを扱うAPIはほとんどがID指定を必要としますが、そのアカウントが属するサーバーでIDを調べるようにしましょう。
 
他のサーバー上のIDが判明しているけど、 手元のサーバーでのIDが分からない時は検索APIを使って調べられます。
    https://mstdn.jp/api/v2/search?q=https%3A%2F%2Fサーバー名%2F%40ユーザー名%2FトゥートID&resolve=true (トゥートIDを探す)
    https://mstdn.jp/api/v1/accounts/search?q=ユーザー名%40サーバー名&resolve=true (アカウントIDを探す)
    https://mstdn.jp/api/v1/accounts/lookup?acct=ユーザー名%40サーバー名 (サーバー上に既にIDがあるアカウントIDを探す) (Mastodon3.4〜)
手元のサーバーにトゥートが届いていない時も、 自動で取り寄せてIDを割り当てた上で返してくれるそうです。

IDの範囲指定

タイムラインや通知では 引数 max_id, since_id で取得範囲を絞ることができますが、 取得されるデータは since_id<id<max_id の範囲になります (Twitterのsince_id<id≦max_id とは微妙に違いますのでご注意を)。
 
Mastodon2.6以降では、似た指定として min_id がありますが、 こちらも取得されるデータは min_id<id の範囲です。 引数 limit で取得件数を指定しますが(指定しなくてもデフォルト値で) 指定範囲内の件数が溢れているときに、 since_id指定なら新しい方から、min_id指定なら古い方から、 その件数が得られます。
 
古いトゥートIDを基準にした時、その直後のトゥートが欲しいならmin_id指定を、 それ以降の最新のトゥートが欲しいならsince_id指定と使い分けます。 なお、min_idはmax_idと同時に指定することはできませんでしたが (min_id指定が優先されます)、 Mastodon3.3以降は同時指定できます

文字数

Mastodonでの文字数のカウントは、原則見た目の数になっているようです。
 
英語・日本語とも1文字カウント、 サロゲートペア(例:🐲(U+1F432 または U+D83D U+DC32))でも1文字カウント、 ゼロ幅接合子で作られた文字(例:👨‍👩‍👦‍👦(U+1F468 U+200D U+1F469 U+200D U+1F466 U+200D U+1F466))も1文字カウント、 絵文字シークエンス各種(例:1️⃣(U+0031 U+FE0F U+20E3), 👏🏽(U+1F44F U+1F3FD), 🇯🇵(U+1F1EF U+1F1F5))も1文字カウントです。 ただし、漢字の異体字(例:葛󠄁(U+845B U+E0101))は現状2文字カウント(普通の漢字+異体字セレクタ)になっているようです。
 
Mastodon1.5.0以降は URLは23文字カウント、 別サーバーのユーザー名はドメイン部分を除外してカウント(例:@Mastodon@mastodon.socialは@Mastodonの9文字カウント)です。 23の数字は実装時のTwitterの短縮URLのt.coの文字数にあわせたようですが (Twitterのように短縮URLに置き換えはしてません)、 ハードコードされているので 今後数字が増えることはなさそうです。

制限

APIの呼び出し回数には制限があります。 レスポンスヘッダー x-ratelimit-* に制限情報が入っています。
    x-ratelimit-limit: 300
    x-ratelimit-remaining: 299
    x-ratelimit-reset: 2018-08-30T02:40:00.363679Z
x-ratelimit-limit が制限数、x-ratelimit-remaining が残り回数、 x-ratelimit-reset が残り回数が復活する時間です。 基本はAPIの種類に関わらず共通でカウントされます。 デフォルトでは (サーバーの管理者が設定を変更していない限り) アクセストークンごとに5分間に300コールのようで、 普通はまず気にしなくてもよい緩さになっています。
 
ドキュメントに書かれていない制限 もあるので、 ここにまとめておきます。
 
Rate Limitの種類と制限内容
Endpoint Bucket 制限数 期間 制限単位
* /api/* アカウントでのアクセス 300 5分 アカウント
* /api/* 認証不要のアクセス 300 5分 IPアドレス
POST /api/v1/statuses 新規トゥート (Mastodon3.1.3〜) 300 3時間 アカウント
POST /api/v1/media メディアのアップロード 30 30分 アカウント
DELETE /api/v1/statuses/:id
POST /api/v1/statuses/:id/unreblog
トゥートの削除 30 30分 アカウント
POST /api/v1/accounts/:id/follow フォロー (Mastodon3.1.3〜) 400 24時間 アカウント
POST /api/v1/reports 通報 (Mastodon3.1.3〜) 400 24時間 アカウント
POST /api/v1/accounts アカウント作成 5 30分 IPアドレス

ActivityPub/WebFingerのAPI

Mastodonは複数のサーバー間を連合させて動作しますが、 その実現のために ActivityPubプロトコル (Mastodon1.6以降の話、それ以前や下位互換用としてOStatus) や WebFinger仕様 を使っています ActivityPubはW3Cで勧告されている標準仕様で、 ActivityPubに対応している他のSNSのアカウントもフォローできるのは そのおかげです。
 
ActivityPub/WebFingerを実現するためにAPIが整備されているため、 これを利用することができます。 ただし、クライアント開発者向けに提供されているのではない、 内部的に使っている機能を勝手に使うことになるので、 アドレスや仕様変更される可能性がないとは言えない点には気をつけましょう。 実装目的が違うため、形式等もREST APIと統一されてませんし、 余計な情報も含まれていますが、 認証不要で情報が拾えるため上手く使えば便利です。
    https://サーバー名/users/ユーザー名.json (アカウント情報)
    https://サーバー名/users/ユーザー名/following.json?page=1 (フォロー情報)
    https://サーバー名/users/ユーザー名/followers.json?page=1 (フォロワー情報)
    https://サーバー名/users/ユーザー名/outbox?page=true (タイムライン情報)
    https://サーバー名/users/ユーザー名/collections/featured (固定されたトゥート)
    https://サーバー名/users/ユーザー名/collections/tags (注目のハッシュタグ)
    https://サーバー名/users/ユーザー名/statuses/トゥートID.json (トゥート情報)
    https://サーバー名/tags/ハッシュタグ(#は含まない).json (ハッシュタグ検索結果情報)
"/users/ユーザー名" は "/@ユーザー名"、 "/users/ユーザー名/statuses/トゥートID" は "/@ユーザー名/トゥートID" としても同じ情報が取れます (例外あり)。 アドレスさえ知っていればログインせずに見られるページのURLに .jsonを付ければ大抵情報が取れます。
 
WebFingerはサーバーの /.well-known/host-meta にアクセスして得られる XMLデータのrel="lrdd"なLinkタグのtemplateのアドレスに目的のアドレスを展開したURLから情報を得ます。
    https://サーバー名/.well-known/host-meta
    https://サーバー名/.well-known/webfinger?resource=https://サーバー名/@ユーザー名 (現行のMastodonの指定先)
    https://サーバー名/.well-known/webfinger?resource=acct:ユーザー名@サーバー名 (現行のMastodonの指定先)

NodeInfoのAPI

MastodonはFediverseで他のサーバーと連合を組んでいるため、 Mastodonではないサービスの情報をトゥートとして受け取っていることがあります。 先方のサーバーをAPIでアクセスしようとした時に、 そこがMastodon APIを持っているサービスかどうか判断が必要な時があります。 なお、PleromaPixelfedなど Mastodonの互換APIを実装しているサービスも少なからずありますが、 戻り値が違ったりと完全に互換があるとは限らないため注意が必要です。
 
このようなFediverseに参加しているサーバーのサービス情報を提供する NodeInfo の仕様が提案されており、Mastodon3.0以降を含む多くのサービスで実装されています。 NodeInfoはサーバーの /.well-known/nodeinfo にアクセスして得られる JSONデータ() のlinks[].hrefのアドレスにアクセスすることで情報が得られます ()。
    https://サーバー名/.well-known/nodeinfo
    https://サーバー名/nodeinfo/2.0.json (現行のMastodonの指定先)

その他の機能

フィード
 
APIではありませんが、外部ツールと連携するのに便利なフィード情報があります。 Atomフィードは始めから実装されていましたが、Mastodon3.0で廃止されました。 RSSフィードはMastodon2.4で実装されて今も使うことができますので、 RSSフィードを使いましょう。
    https://サーバー名/users/ユーザー名.rss (投稿)
    https://サーバー名/users/ユーザー名/with_replies.rss (投稿と返信)
    https://サーバー名/users/ユーザー名/media.rss (メディア付きトゥートのみ)
    https://サーバー名/users/ユーザー名/tagged/ハッシュタグ(#は含まない).rss (注目のハッシュタグ)
    https://サーバー名/tags/ハッシュタグ(#は含まない).rss (ハッシュタグタイムライン)
例として https://mastodon.social/users/Mastodon.rss をブラウザで開くと、 指定したアカウントのトゥート情報が取れるのがわかると思います。 "/users/ユーザー名" の部分は "/@ユーザー名" と書くことも出来ます。 Mastodon3.2以降で引数limitで件数指定できるようになっています(最大200件まで)。
 
REST APIの項で書いたように、アクセストークンをWebページから取得したら、 https://サーバー名/api/v1/statuses?access_token=アクセストークン に "status=トゥート内容&visibility=unlisted" をPOSTするだけで トゥートもできますので、 この二つを使って、外部サービスとのトゥートの入出力は簡単に実現できます (アクセストークンは漏洩しないように注意)。
 
Webページへの埋め込み
 
Web UIでトゥートの「…」メニューから「埋め込み」を選ぶことで、 個別のトゥートをWebページに貼り付けることもできます。 https://サーバー名/@ユーザー名/トゥートID/embed でも直接表示できますが、適切なサイズにしてくれるので 埋め込みメニューから取得したコードを使った方が良いです。
 
公式のタイムライン等の埋め込みはまだないようです。
 
oEmbed
 
埋め込みコードをWebサービスに限らず生成する仕様であるoEmbedに、 Mastodonも対応してます。
    https://サーバー名/api/oembed.json?url=埋め込みたいページのURL
埋め込みたいページのURLはトゥートなら https://サーバー名/@ユーザー名/トゥートID になります。
 
Card
 
URLが書かれているトゥートの詳細表示をすると、 画像や動画等が埋め込まれたり ()、 リンク先の詳細情報を表示することがあります ()。 これはリンク先のページの情報を元に展開するCardと呼ばれる機能です。
 
Mastodonではリンク先のページがoEmbedか、 Open Graph Protocol(OGP)情報を持っていると解析してくれるようです。
 
Intents
 
Mastodonはサーバーが複数あるために シェアボタンやフォローボタンを実現するのに一工夫必要です。 そのために、特殊なプロトコルweb+mastodon:が用意されています。 Mastodon1.6.0以降でモダンブラウザであればWeb UIにログインしているときに (開いてから5分ぐらいすると) web+mastodon:の登録を促されると思います。 この登録をした後であれば、 以下のURLにアクセスした時にシェアやフォロー画面に遷移できます。 公式Widgetはないので、自分でリンクしましょう。
    web+mastodon://share?text=トゥート本文 (シェア)
    web+mastodon://follow?uri=ユーザー名@サーバー名 (フォロー)
でしたが、UXがよろしくないとの理由でMastodon2.5.0で廃止されました。
 
固定のサーバーで良ければ (ユーザーにサーバー名を入力して貰うなどして)、 以下のアドレスに飛ばすことでシェアボタンやフォローボタンを実現できます
    https://サーバー名/share?text=トゥート本文 (シェア)
    https://サーバー名/authorize_interaction?uri=ユーザー名@サーバー名 (フォロー)
    https://サーバー名/interact/トゥートID?type=reply (返信)
    https://サーバー名/interact/トゥートID?type=reblog (ブースト)
    https://サーバー名/interact/トゥートID?type=favourite (いいね)
/shareにはtextクエリー以外にtitle, urlでもトゥート本文の指定ができます。 Mastodon3.2以降であれば、 クエリーvisibilityで公開範囲の指定もできます。
 
iOS公式アプリ
 
2021年7月末にiOSの公式アプリがリリースされましたが、 URLスキームとして "mastodon://" が使えるようです。 指定できる引数はないようです (アプリを立ち上げるのみ)。
 
iOSの共有機能で、URLを送って公式アプリのトゥート入力画面を開けるため、 Web Share APIで共有画面を開いてそちらへ持っていくことができます。 今はURLのみが持って行けるようです。
    navigator.share({ url: 共有したいURL });
Siriショートカットで任意の文章をトゥートできますが、 確認なしにいきなり送るタイプです。

外部サービスのAPI

MastodonはAPIを提供したり、Fediverseで他のサーバーと連合を組んでいるため、 それらを利用して新しいサービスを提供してくれている方々がいます。 それらのサービスがさらにAPIを提供してくれている場合、 MastodonのAPIでは実現できなかったことができます。
 
検索サービス
 
Mastodonには全トゥートからの検索機能は存在しませんが、 検索サービスを提供している方々がいます。 そのサービスがAPIを提供している場合、検索機能を実現することができます。 なお、サーバー管理人がElasticsearchをインストールしていれば、 Mastodonの検索APIで自分のトゥートを探すことは元々できます。
 
tootsearch は 一部のクライアントが許可を得てAPIを使わせて貰っているようです。 データ保持期間は3日のみなので直近のトゥートのみが探せます。 対応している数個のサーバーの 連合タイムラインから情報収集しているそうです。
 
マストドン検索ポータル 2021年3月末に閉鎖予定でしたが、新しい管理人に引き継がれています。 一部のクライアントが許可を得て APIを使わせて貰っていたことがあるようです。 対応しているサーバーの ローカルタイムラインから情報収集しているそうです。
 
notestock は トゥートのログサービスですが、検索APIが公開されており、 誰でも利用することができます。 ただし、検索許可設定をしたnotestock登録ユーザーのみが検索対象です。 登録ユーザーをフォローして情報収集するため、 非収載トゥートも検索対象に入ります。
 
Misskey は Mastodonとは別のSNSサービスですが、 Fediverseに参加しているためトゥートが届いており、 検索APIが提供されているため、 間接的に利用させて貰う手があります。
 
サーバー一覧サービス
 
APIの/api/v1/instance/peersを使うことで、 そのサーバーが接続している連合サーバーを取得することができるため、 再帰的に呼ぶことでサーバー一覧情報を得ることはできます。 この方法だとどこで切り上げれば良いのかが難しかったり、 基点とするサーバーによって有名なサーバーを取りこぼしたり、 Mastodon以外のFediverseに参加しているサービスも拾ってしまうなど 気にしなければいけない点が多々あります。
 
Mastodonの主要サーバーの一覧が欲しいのであれば、joinmastodon.orgが 内部で使っているAPI https://api.joinmastodon.org/servers を借りる手があります。
 
Mastodon instancesAPI が公開されています。
 
Pixelfed作者によるActivityPub関連アプリケーション作成支援の FediDBAPI が公開されています。

戻る