Framed! User API · v1.3.0

ユーザーAPI

Framed! に自分として投稿し、反応し、プロフィールを整えるための API です。扱えるのは 4 つです。

  • 投稿: HTML・Markdown・リブログ(URL の共有)のどれかで書く。作る・本文を書き換える・消す(自分の投稿だけ)
  • コメント: 投稿へのプレーンテキスト。書く・書き換える・消す(自分のコメントだけ)
  • いいね: 投稿に付ける・外す。何度呼んでも同じ結果になります
  • プロフィール: 表示名・ハンドル・自己紹介・画像を書き換える(自分のものだけ)
  • 認証はアカウントごとに発行するユーザーAPIトークンで行います(Authorization: Bearer <トークン>)。

トークンは Framed! の https://framed.dog/account/api-tokens で自分で発行します。

  • トークンで出来ることは、あなたが画面から出来ることの部分集合です。 他人の投稿やコメントは書き換えられません。
  • 本文は JSON、エラーは RFC 9457(application/problem+json)で返します。
  • 呼び出しはトークンごとに 60 回/分までです。
  • トークンには触れる範囲が付きます。 まず GET /me を呼んで、そのトークンで何ができるかを確かめてください。
  • トークンは秘密情報で、あなたのアカウントそのものです。 サーバからだけ呼び出してください。ブラウザからの呼び出し(CORS)には対応していません。

スペースのサイト(フリーページ・データストア・ストレージ)は別の API です。そちらはスペースごとの API キーで認証します → Framed! API のドキュメント

はじめる

  1. Framed! にサインインし、アカウントのユーザーAPIトークンの画面(/account/api-tokens)でトークンを発行します。トークンは発行したときに一度だけ表示されます。
  2. トークンを環境変数などの秘密の置き場所に保存します(例: FRAMED_USER_TOKEN)。
  3. サーバから次のように呼び出すと、すぐタイムラインに出ます。その前に GET /v1/me を呼ぶと、そのトークンで何ができるか(範囲)と入力の規則が分かります。
curl
curl -X POST https://api.framed.dog/v1/posts \
-H "Authorization: Bearer $FRAMED_USER_TOKEN" \
-H "Content-Type: application/json" \
-d '{"format":"markdown","markdown":"## 今日の散歩\n\n川沿いを **3km** 歩いた。\n\n- 桜はまだ\n- 鴨がいた","tags":["散歩"]}'
JavaScript(Node.js などのサーバで)
const token = process.env.FRAMED_USER_TOKEN
// まず、このトークンで何ができるかを確かめる。
const me = await fetch('https://api.framed.dog/v1/me', {
headers: { Authorization: `Bearer ${token}` },
}).then((r) => r.json())
if (!me.scopes.includes('posts')) {

認証

アカウントごとに発行するユーザーAPIトークン。Framed! の /account/api-tokens で自分で発行します。

トークンは発行したときに一度だけ表示されます。あなたのアカウントそのものとして扱ってください。

トークンには触れる範囲が付きます(発行時に選び、あとから変えられません)。

  • posts: 自分の投稿を読み、投稿を作り、自分の投稿の本文を書き換え、削除します。ほかの人の投稿は読めますが書き換えられません。
  • comments: 投稿へのコメントを読み、コメントを書き、自分のコメントを書き換え、削除します。ほかの人のコメントは書き換えられません。
  • likes: 投稿にいいねを付け、外します。
  • profile: 自分の表示名・ハンドル・自己紹介・画像を書き換えます。ハンドルを変えると、古いハンドルのプロフィールの URL は開けなくなります。

範囲の足りない操作を呼ぶと 403 insufficient_scope を返します。

スペースごとの API キー(framed_sk_…)とは別物で、こちらでは使えません(401 になります)。

ヘッダ
Authorization: Bearer framed_ut_…

触れる範囲

トークンには資源ごとの範囲が付きます。読み取りと書き込みは分けていません (投稿もコメントもタイムラインで公開されるので、意味のある境目は「何を書き換えられるか」の方です)。

posts投稿
自分の投稿を読み、投稿を作り、自分の投稿の本文を書き換え、削除します。ほかの人の投稿は読めますが書き換えられません。
commentsコメント
投稿へのコメントを読み、コメントを書き、自分のコメントを書き換え、削除します。ほかの人のコメントは書き換えられません。
likesいいね
投稿にいいねを付け、外します。
profileプロフィール
自分の表示名・ハンドル・自己紹介・画像を書き換えます。ハンドルを変えると、古いハンドルのプロフィールの URL は開けなくなります。

GET /v1/me だけは範囲を問わず答えます。何ができるトークンなのかを知る手段が無いと、範囲を分けた意味が薄れるためです。

エンドポイント

ベース URL は https://api.framed.dog/v1 です。

トークンの持ち主と、このトークンで出来ることを確かめる

GEThttps://api.framed.dog/v1/me

ハンドル・表示名・画像・自己紹介に加えて、このトークンに付いている範囲(`scopes`)と、

投稿・コメント・プロフィールの入力の規則、呼び出し回数の上限を返します。

最初にこれを呼んでください。 範囲の足りない操作は 403 insufficient_scope になるので、

何ができるトークンなのかを先に知る必要があります。この操作だけは範囲を問わず答えます。

規則の値は実装と同じ定義から組み立てているので、上限を変えてもここがずれることはありません。

応答(200)トークンの持ち主と、このトークンで出来ること。

トークンの持ち主と、このトークンで出来ることを確かめるの応答
項目説明
handle必須string

あなたのハンドル(user.name)。投稿やコメントの表示に使われます。

display_name必須stringnull

表示名。設定していなければ null(画面にはハンドルが出ます)。

icon_url必須string,null (uri)

アカウントの画像の URL。設定していなければ null。

bio必須stringnull

自己紹介(プレーンテキスト。改行は \n)。設定していなければ null。

scopes必須string[]

このトークンに付いている範囲。 足りない操作は 403 になります。

rules必須object

入力の規則。画面と同じ定義から組み立てています。

rate_limit必須object

ここに無い項目を送ると 422 になります。

応答の例
{
"handle": "tanaka_yu_7k2mp",
"display_name": "田中結衣",
"icon_url": "https://framed.dog/account-icons/tanaka_yu_7k2mp?v=1789000000000",
"bio": "散歩と川の写真。\nHTML で遊んでいます。",
"scopes": [
"posts",
"comments",

返りうるステータス

  • 200トークンの持ち主と、このトークンで出来ること。
  • 401API キーが無いか、有効ではありません
  • 403トークンにその操作の範囲が付いていない(`insufficient_scope`)。範囲は発行するときに決まり、あとから増やせません。
  • 429呼び出しの回数が上限を超えました
  • 500サーバの内部で問題が起きました

表示名・ハンドル・自己紹介を書き換える

PATCHhttps://api.framed.dog/v1/me

送った項目だけを書き換えます。範囲 profile が要ります。応答は書き換えたあとの GET /me と同じです。

規則はアカウントの画面と同じで、上限は GET /me の rules.profile にあります。

  • display_name: 表示名。日本語・空白・絵文字も使え、ほかの人と同じでもかまいません。

`null` か空の文字列で外れ、画面にはハンドルが出ます。

  • bio: 自己紹介。プレーンテキストで、改行を使えます(HTML も Markdown も解釈しません)。null か空の文字列で外れます。
  • handle: ハンドル。英字・数字・.・_ だけ。先頭の @ は取り除きます。

大文字・小文字を区別せずに一意で、使われていれば 409 handle_taken です。

古いハンドルはすぐに空き、誰でも取れます。 古いハンドルのプロフィールの URL は開けなくなり、転送もしません。

規則を満たさない項目が 1 つでもあれば、どの項目も書き換えません(422 に全部の理由が並びます)。

ハンドルがぶつかったとき(409)も、表示名と自己紹介は書き換えません。

リクエスト本文(application/json)

表示名・ハンドル・自己紹介を書き換えるのリクエスト本文
項目説明
handle任意string

ハンドル。英字・数字・.・_ の 3〜15 文字。

前後の空白と先頭の @ は取り除きます。大文字・小文字を区別せずに一意です。外すことはできません。

display_name任意stringnull

表示名。前後の空白を落として 30 文字まで(コードポイントで数えます)。

改行・制御文字・文字の向きを変える制御は使えません。null か空の文字列で外れます。

bio任意stringnull

自己紹介(プレーンテキスト)。前後の空白を落として 1000 文字まで(コードポイントで数え、改行も 1 文字)。

改行は使えますが、タブなどほかの制御文字と、文字の向きを変える制御は使えません。null か空の文字列で外れます。

ここに無い項目を送ると 422 になります。

本文の例
{
"display_name": "田中結衣",
"bio": "散歩と川の写真。\nHTML で遊んでいます。"
}

応答(200)書き換えました。

表示名・ハンドル・自己紹介を書き換えるの応答
項目説明
handle必須string

あなたのハンドル(user.name)。投稿やコメントの表示に使われます。

display_name必須stringnull

表示名。設定していなければ null(画面にはハンドルが出ます)。

icon_url必須string,null (uri)

アカウントの画像の URL。設定していなければ null。

bio必須stringnull

自己紹介(プレーンテキスト。改行は \n)。設定していなければ null。

scopes必須string[]

このトークンに付いている範囲。 足りない操作は 403 になります。

rules必須object

入力の規則。画面と同じ定義から組み立てています。

rate_limit必須object

ここに無い項目を送ると 422 になります。

応答の例
{
"handle": "tanaka_yu_7k2mp",
"display_name": "田中結衣",
"icon_url": "https://framed.dog/account-icons/tanaka_yu_7k2mp?v=1789000000000",
"bio": "散歩と川の写真。\nHTML で遊んでいます。",
"scopes": [
"posts",
"comments",

返りうるステータス

  • 200書き換えました。
  • 400リクエスト本文を JSON として読めません
  • 401API キーが無いか、有効ではありません
  • 403トークンにその操作の範囲が付いていない(`insufficient_scope`)。範囲は発行するときに決まり、あとから増やせません。
  • 409そのハンドルはすでに使われています
  • 413リクエスト本文が大きすぎます
  • 415Content-Type は application/json にしてください
  • 422入力が規則を満たしていません
  • 429呼び出しの回数が上限を超えました
  • 500サーバの内部で問題が起きました

画像を設定する

PUThttps://api.framed.dog/v1/me/icon

アカウントの画像を設定します(あれば置き換えます)。範囲 profile が要ります。

  • 256×256 の PNG だけを、base64 にして png に入れて送ります(1048576 バイトまで)。

切り抜きや縮小はしません。正方形に切り抜いて縮めてから送ってください。

  • サーバは中身を信用せず、画素だけを使って PNG を作り直して保存します(メタデータは残りません)。
  • 画像の URL は設定するたびに変わります。応答の icon_url を使ってください。
  • 本文の上限は、このエンドポイントだけ 1399128 バイトです。

リクエスト本文(application/json)

画像を設定するのリクエスト本文
項目説明
png必須string

256×256 の PNG を base64 にしたもの(改行は無視します)。

  • 1 文字以上

ここに無い項目を送ると 422 になります。

本文の例
{
"png": "iVBORw0KGgoAAAANSUhEUgAAAQAAAAEACAYAAABccqhmAAAA…"
}

応答(200)設定しました。

画像を設定するの応答
項目説明
handle必須string

あなたのハンドル(user.name)。投稿やコメントの表示に使われます。

display_name必須stringnull

表示名。設定していなければ null(画面にはハンドルが出ます)。

icon_url必須string,null (uri)

アカウントの画像の URL。設定していなければ null。

bio必須stringnull

自己紹介(プレーンテキスト。改行は \n)。設定していなければ null。

scopes必須string[]

このトークンに付いている範囲。 足りない操作は 403 になります。

rules必須object

入力の規則。画面と同じ定義から組み立てています。

rate_limit必須object

ここに無い項目を送ると 422 になります。

応答の例
{
"handle": "tanaka_yu_7k2mp",
"display_name": "田中結衣",
"icon_url": "https://framed.dog/account-icons/tanaka_yu_7k2mp?v=1789000000000",
"bio": "散歩と川の写真。\nHTML で遊んでいます。",
"scopes": [
"posts",
"comments",

返りうるステータス

  • 200設定しました。
  • 400リクエスト本文を JSON として読めません
  • 401API キーが無いか、有効ではありません
  • 403トークンにその操作の範囲が付いていない(`insufficient_scope`)。範囲は発行するときに決まり、あとから増やせません。
  • 413リクエスト本文が大きすぎます
  • 415Content-Type は application/json にしてください
  • 422入力が規則を満たしていません
  • 429呼び出しの回数が上限を超えました
  • 500サーバの内部で問題が起きました

画像を外す

DELETEhttps://api.framed.dog/v1/me/icon

アカウントの画像を外します。範囲 profile が要ります。

画面には名前の先頭の 1 文字が出ます。設定していなくても成功します。

応答(204)外しました(本文なし)。

返りうるステータス

  • 204外しました(本文なし)。
  • 401API キーが無いか、有効ではありません
  • 403トークンにその操作の範囲が付いていない(`insufficient_scope`)。範囲は発行するときに決まり、あとから増やせません。
  • 429呼び出しの回数が上限を超えました
  • 500サーバの内部で問題が起きました

自分の投稿の一覧

GEThttps://api.framed.dog/v1/posts

自分の投稿を新しい順に返します。本文(HTML)は含みません。

画面で作りかけの下書きも含み、published で見分けられます。

ほかの人の投稿の一覧(タイムライン)は、この API では読めません。

応答(200)自分の投稿の一覧。

自分の投稿の一覧の応答
項目説明
data必須Post[]

自分の投稿。新しい順。

ここに無い項目を送ると 422 になります。

応答の例
{
"data": [
{
"id": "v7n3k9q2m5x8b4p6",
"url": "https://v7n3k9q2m5x8b4p6.usercontents.frmd.spot",
"author_handle": "tanaka_yu_7k2mp",
"format": "html",
"tags": [

返りうるステータス

  • 200自分の投稿の一覧。
  • 401API キーが無いか、有効ではありません
  • 403トークンにその操作の範囲が付いていない(`insufficient_scope`)。範囲は発行するときに決まり、あとから増やせません。
  • 429呼び出しの回数が上限を超えました
  • 500サーバの内部で問題が起きました

投稿する

POSThttps://api.framed.dog/v1/posts

本文を送ると投稿になり、すぐタイムラインに出ます。 書き方は format で選びます。

  • html(省略したときもこれ): HTML をそのまま。サーバは書き換えません(サニタイズしません)。

CSS と JavaScript も、配信オリジンのフレームの中で動きます。

  • markdown: Markdown。画面の「文章」と同じ形に移して保存します。スクリプトは動きません。
  • reblog: 共有する URL と、添える短い文。画面にはリンクカードが出ます。
  • tags でタグを付けられます(あとから付け外しはできません)。
  • 応答の url が配信オリジンです。
  • 画面の下書きには触りません。 画面で書きかけのものは、この呼び出しで消えません。
  • 宛先は本体のタイムラインだけです(スペース宛ての投稿はまだ API から作れません)。

リクエスト本文(application/json)

投稿するのリクエスト本文
項目説明
本文の例
{
"format": "markdown",
"markdown": "## 今日の散歩\n\n川沿いを **3km** 歩いた。\n\n- 桜はまだ\n- 鴨がいた",
"tags": [
"散歩"
]
}

応答(201)投稿しました。

投稿するの応答
項目説明
id必須string

投稿の ID。本文を書き換えても変わりません。

  • パターン: ^[2-9a-z]{16}$
url必須string (uri)

投稿の HTML が配信される URL。投稿ごとに 1 つのオリジンです。

タイムラインはこの URL をフレームで読み込みます。

author_handle必須string

投稿した人のハンドル。

format必須string

いまの本文の書き方。

  • html: HTML で書いた投稿。配信オリジンのフレームの中で、スクリプトも含めて動く
  • rich: 画面の「文章」か、Markdown で書いた投稿(どちらだったかは残りません)。画面にはフレームを使わずに出る
  • reblog: URL を共有した投稿(reblog に URL と文)。画面には文とリンクカードが出る
  • 次のいずれか: html, rich, reblog
tags必須string[]

付いているタグ(名前の順)。付いていなければ空の配列。

published必須boolean

公開されているか。false は画面で作りかけの下書きです(→ published_at)。

published_at必須string,null (date-time)

公開した日時(UTC、ISO 8601)。下書きなら null。

created_at必須string (date-time)

作った日時(UTC、ISO 8601)。

updated_at必須string (date-time)

最後に書き換えた日時(UTC、ISO 8601)。作っただけなら作った日時。

like_count必須integer

いいねの数。

comment_count必須integer

コメントの数。

ここに無い項目を送ると 422 になります。

応答の例
{
"id": "v7n3k9q2m5x8b4p6",
"url": "https://v7n3k9q2m5x8b4p6.usercontents.frmd.spot",
"author_handle": "tanaka_yu_7k2mp",
"format": "html",
"tags": [
"demo"
],

返りうるステータス

  • 201投稿しました。
  • 400リクエスト本文を JSON として読めません
  • 401API キーが無いか、有効ではありません
  • 403トークンにその操作の範囲が付いていない(`insufficient_scope`)。範囲は発行するときに決まり、あとから増やせません。
  • 413リクエスト本文が大きすぎます
  • 415Content-Type は application/json にしてください
  • 422入力が規則を満たしていません
  • 429呼び出しの回数が上限を超えました
  • 500サーバの内部で問題が起きました

投稿を本文ごと取得する

GEThttps://api.framed.dog/v1/posts/{post_id}

投稿を 1 件、本文(配信している HTML)といいね・コメントの数まで返します。

リブログなら reblog に URL と文が入ります。

ほかの人の公開済みの投稿も読めます(タイムラインに並ぶものなので)。

ただし下書きは本人だけです。ほかの人の下書きを指すと 404 になります。

パスパラメータ

投稿を本文ごと取得するのパスパラメータ
項目説明
post_id必須string

投稿の ID(作成・一覧の応答の id)。本文を書き換えても変わりません。

  • パターン: ^[2-9a-z]{16}$

応答(200)投稿の本文と数。

投稿を本文ごと取得するの応答
項目説明
id必須string

投稿の ID。本文を書き換えても変わりません。

  • パターン: ^[2-9a-z]{16}$
url必須string (uri)

投稿の HTML が配信される URL。投稿ごとに 1 つのオリジンです。

タイムラインはこの URL をフレームで読み込みます。

author_handle必須string

投稿した人のハンドル。

format必須string

いまの本文の書き方。

  • html: HTML で書いた投稿。配信オリジンのフレームの中で、スクリプトも含めて動く
  • rich: 画面の「文章」か、Markdown で書いた投稿(どちらだったかは残りません)。画面にはフレームを使わずに出る
  • reblog: URL を共有した投稿(reblog に URL と文)。画面には文とリンクカードが出る
  • 次のいずれか: html, rich, reblog
tags必須string[]

付いているタグ(名前の順)。付いていなければ空の配列。

published必須boolean

公開されているか。false は画面で作りかけの下書きです(→ published_at)。

published_at必須string,null (date-time)

公開した日時(UTC、ISO 8601)。下書きなら null。

created_at必須string (date-time)

作った日時(UTC、ISO 8601)。

updated_at必須string (date-time)

最後に書き換えた日時(UTC、ISO 8601)。作っただけなら作った日時。

like_count必須integer

いいねの数。

comment_count必須integer

コメントの数。

html必須string

配信している HTML 文書そのもの(url が返すもの)。

format が html なら送った HTML のまま。rich と reblog は、サーバが組み立てた文書です。

reblog必須objectnull

リブログの URL と文。format が reblog でなければ null。

ここに無い項目を送ると 422 になります。

応答の例
{
"id": "v7n3k9q2m5x8b4p6",
"url": "https://v7n3k9q2m5x8b4p6.usercontents.frmd.spot",
"author_handle": "tanaka_yu_7k2mp",
"format": "html",
"tags": [
"demo"
],

返りうるステータス

  • 200投稿の本文と数。
  • 401API キーが無いか、有効ではありません
  • 403トークンにその操作の範囲が付いていない(`insufficient_scope`)。範囲は発行するときに決まり、あとから増やせません。
  • 404その投稿がない、ほかの人の下書きである、または**書き換え・削除でほかの人の投稿を指した**(`post_not_found`)。ID の存在を他人に伝えないため、権限が無い場合も 404 です。
  • 429呼び出しの回数が上限を超えました
  • 500サーバの内部で問題が起きました

投稿の本文を書き換える

PATCHhttps://api.framed.dog/v1/posts/{post_id}

自分の投稿の本文だけを、丸ごと書き換えます。ほかの人の投稿を指すと 404 です。

本文の送り方は作成と同じ(format と、その書き方の項目)です。

  • ID と配信オリジン(`url`)は変わりません。 書き換えは次に開いた人にすぐ届きます。
  • 書き方は元と違ってもかまいません(Markdown で書いた投稿を HTML で書き換える、など)。
  • タグと公開の状態は変わりません(下書きは下書きのまま)。

パスパラメータ

投稿の本文を書き換えるのパスパラメータ
項目説明
post_id必須string

投稿の ID(作成・一覧の応答の id)。本文を書き換えても変わりません。

  • パターン: ^[2-9a-z]{16}$

リクエスト本文(application/json)

投稿の本文を書き換えるのリクエスト本文
項目説明
本文の例
{
"format": "reblog",
"url": "https://example.com/articles/42",
"text": "これよかった"
}

応答(200)書き換えました。

投稿の本文を書き換えるの応答
項目説明
id必須string

投稿の ID。本文を書き換えても変わりません。

  • パターン: ^[2-9a-z]{16}$
url必須string (uri)

投稿の HTML が配信される URL。投稿ごとに 1 つのオリジンです。

タイムラインはこの URL をフレームで読み込みます。

author_handle必須string

投稿した人のハンドル。

format必須string

いまの本文の書き方。

  • html: HTML で書いた投稿。配信オリジンのフレームの中で、スクリプトも含めて動く
  • rich: 画面の「文章」か、Markdown で書いた投稿(どちらだったかは残りません)。画面にはフレームを使わずに出る
  • reblog: URL を共有した投稿(reblog に URL と文)。画面には文とリンクカードが出る
  • 次のいずれか: html, rich, reblog
tags必須string[]

付いているタグ(名前の順)。付いていなければ空の配列。

published必須boolean

公開されているか。false は画面で作りかけの下書きです(→ published_at)。

published_at必須string,null (date-time)

公開した日時(UTC、ISO 8601)。下書きなら null。

created_at必須string (date-time)

作った日時(UTC、ISO 8601)。

updated_at必須string (date-time)

最後に書き換えた日時(UTC、ISO 8601)。作っただけなら作った日時。

like_count必須integer

いいねの数。

comment_count必須integer

コメントの数。

ここに無い項目を送ると 422 になります。

応答の例
{
"id": "v7n3k9q2m5x8b4p6",
"url": "https://v7n3k9q2m5x8b4p6.usercontents.frmd.spot",
"author_handle": "tanaka_yu_7k2mp",
"format": "html",
"tags": [
"demo"
],

返りうるステータス

  • 200書き換えました。
  • 400リクエスト本文を JSON として読めません
  • 401API キーが無いか、有効ではありません
  • 403トークンにその操作の範囲が付いていない(`insufficient_scope`)。範囲は発行するときに決まり、あとから増やせません。
  • 404その投稿がない、ほかの人の下書きである、または**書き換え・削除でほかの人の投稿を指した**(`post_not_found`)。ID の存在を他人に伝えないため、権限が無い場合も 404 です。
  • 413リクエスト本文が大きすぎます
  • 415Content-Type は application/json にしてください
  • 422入力が規則を満たしていません
  • 429呼び出しの回数が上限を超えました
  • 500サーバの内部で問題が起きました

投稿を消す

DELETEhttps://api.framed.dog/v1/posts/{post_id}

自分の投稿だけを消します。ほかの人の投稿を指すと 404 です。

元に戻せません。 配信オリジンはすぐ 404 になり、その投稿へのいいね・コメント・

通報も一緒に消えます。

パスパラメータ

投稿を消すのパスパラメータ
項目説明
post_id必須string

投稿の ID(作成・一覧の応答の id)。本文を書き換えても変わりません。

  • パターン: ^[2-9a-z]{16}$

応答(204)削除しました(本文なし)。

返りうるステータス

  • 204削除しました(本文なし)。
  • 401API キーが無いか、有効ではありません
  • 403トークンにその操作の範囲が付いていない(`insufficient_scope`)。範囲は発行するときに決まり、あとから増やせません。
  • 404その投稿がない、ほかの人の下書きである、または**書き換え・削除でほかの人の投稿を指した**(`post_not_found`)。ID の存在を他人に伝えないため、権限が無い場合も 404 です。
  • 429呼び出しの回数が上限を超えました
  • 500サーバの内部で問題が起きました

投稿へのコメントの一覧

GEThttps://api.framed.dog/v1/posts/{post_id}/comments

その投稿のコメントを古い順に返します(会話として読む順なので、新しい順にはしません)。

一度に 100 件までです。

パスパラメータ

投稿へのコメントの一覧のパスパラメータ
項目説明
post_id必須string

投稿の ID(作成・一覧の応答の id)。本文を書き換えても変わりません。

  • パターン: ^[2-9a-z]{16}$

応答(200)コメントの一覧。

投稿へのコメントの一覧の応答
項目説明
data必須Comment[]

コメント。古い順。

ここに無い項目を送ると 422 になります。

応答の例
{
"data": [
{
"id": "q2m5x8b4p6v7n3k9",
"post_id": "v7n3k9q2m5x8b4p6",
"author_handle": "tanaka_yu_7k2mp",
"body": "これ、クリックすると変わるんですね",
"created_at": "2026-09-20T09:30:00.000Z",

返りうるステータス

  • 200コメントの一覧。
  • 401API キーが無いか、有効ではありません
  • 403トークンにその操作の範囲が付いていない(`insufficient_scope`)。範囲は発行するときに決まり、あとから増やせません。
  • 404その投稿がない、ほかの人の下書きである、または**書き換え・削除でほかの人の投稿を指した**(`post_not_found`)。ID の存在を他人に伝えないため、権限が無い場合も 404 です。
  • 429呼び出しの回数が上限を超えました
  • 500サーバの内部で問題が起きました

コメントする

POSThttps://api.framed.dog/v1/posts/{post_id}/comments

その投稿にコメントします。本文はプレーンテキストで、HTML として解釈されません。

同じ投稿に何件でも書けます(1 人 1 件の制限はありません)。

パスパラメータ

コメントするのパスパラメータ
項目説明
post_id必須string

投稿の ID(作成・一覧の応答の id)。本文を書き換えても変わりません。

  • パターン: ^[2-9a-z]{16}$

リクエスト本文(application/json)

コメントするのリクエスト本文
項目説明
body必須string

コメントの本文。プレーンテキストです(HTML として解釈されません)。

前後の空白を取り除いたうえで、空でなく 500 文字以内であること。

改行は \n にそろえ、改行とタブ以外の制御文字と双方向制御文字は受け付けません。

  • 1〜500 文字

ここに無い項目を送ると 422 になります。

本文の例
{
"body": "これ、クリックすると変わるんですね"
}

応答(201)コメントしました。

コメントするの応答
項目説明
id必須string

コメントの ID。

  • パターン: ^[2-9a-z]{16}$
post_id必須string

コメントした先の投稿の ID。

  • パターン: ^[2-9a-z]{16}$
author_handle必須string

コメントした人のハンドル。

body必須string

コメントの本文(プレーンテキスト)。

created_at必須string (date-time)

書いた日時(UTC、ISO 8601)。

updated_at必須string (date-time)

最後に書き換えた日時(UTC、ISO 8601)。書いただけなら書いた日時。

ここに無い項目を送ると 422 になります。

応答の例
{
"id": "q2m5x8b4p6v7n3k9",
"post_id": "v7n3k9q2m5x8b4p6",
"author_handle": "tanaka_yu_7k2mp",
"body": "これ、クリックすると変わるんですね",
"created_at": "2026-09-20T09:30:00.000Z",
"updated_at": "2026-09-20T09:30:00.000Z"
}

返りうるステータス

  • 201コメントしました。
  • 400リクエスト本文を JSON として読めません
  • 401API キーが無いか、有効ではありません
  • 403トークンにその操作の範囲が付いていない(`insufficient_scope`)。範囲は発行するときに決まり、あとから増やせません。
  • 404その投稿がない、ほかの人の下書きである、または**書き換え・削除でほかの人の投稿を指した**(`post_not_found`)。ID の存在を他人に伝えないため、権限が無い場合も 404 です。
  • 413リクエスト本文が大きすぎます
  • 415Content-Type は application/json にしてください
  • 422入力が規則を満たしていません
  • 429呼び出しの回数が上限を超えました
  • 500サーバの内部で問題が起きました

いいねを付ける

PUThttps://api.framed.dog/v1/posts/{post_id}/like

その投稿にいいねを付けます。何度呼んでも同じ結果で、すでに付いていても数は増えません。

呼び出しが失敗して再試行しても、数が狂うことはありません。

本文は要りません(送っても無視します)。

パスパラメータ

いいねを付けるのパスパラメータ
項目説明
post_id必須string

投稿の ID(作成・一覧の応答の id)。本文を書き換えても変わりません。

  • パターン: ^[2-9a-z]{16}$

応答(200)いまのいいねの状態。

いいねを付けるの応答
項目説明
post_id必須string

いいねを付けた投稿の ID。

  • パターン: ^[2-9a-z]{16}$
liked必須boolean

いいねが付いているか。PUT の応答では常に真。

like_count必須integer

その投稿のいいねの数。

ここに無い項目を送ると 422 になります。

応答の例
{
"post_id": "v7n3k9q2m5x8b4p6",
"liked": true,
"like_count": 4
}

返りうるステータス

  • 200いまのいいねの状態。
  • 401API キーが無いか、有効ではありません
  • 403トークンにその操作の範囲が付いていない(`insufficient_scope`)。範囲は発行するときに決まり、あとから増やせません。
  • 404その投稿がない、ほかの人の下書きである、または**書き換え・削除でほかの人の投稿を指した**(`post_not_found`)。ID の存在を他人に伝えないため、権限が無い場合も 404 です。
  • 429呼び出しの回数が上限を超えました
  • 500サーバの内部で問題が起きました

いいねを外す

DELETEhttps://api.framed.dog/v1/posts/{post_id}/like

その投稿のいいねを外します。付いていなくても成功します(PUT と同じく冪等です)。

パスパラメータ

いいねを外すのパスパラメータ
項目説明
post_id必須string

投稿の ID(作成・一覧の応答の id)。本文を書き換えても変わりません。

  • パターン: ^[2-9a-z]{16}$

応答(204)外しました(本文なし)。

返りうるステータス

  • 204外しました(本文なし)。
  • 401API キーが無いか、有効ではありません
  • 403トークンにその操作の範囲が付いていない(`insufficient_scope`)。範囲は発行するときに決まり、あとから増やせません。
  • 404その投稿がない、ほかの人の下書きである、または**書き換え・削除でほかの人の投稿を指した**(`post_not_found`)。ID の存在を他人に伝えないため、権限が無い場合も 404 です。
  • 429呼び出しの回数が上限を超えました
  • 500サーバの内部で問題が起きました

コメントを書き換える

PATCHhttps://api.framed.dog/v1/comments/{comment_id}

自分のコメントだけを書き換えます。ほかの人のコメントを指すと 404 です。投稿は変えられません。

パスパラメータ

コメントを書き換えるのパスパラメータ
項目説明
comment_id必須string

コメントの ID(作成・一覧の応答の id)。

  • パターン: ^[2-9a-z]{16}$

リクエスト本文(application/json)

コメントを書き換えるのリクエスト本文
項目説明
body必須string

コメントの本文。プレーンテキストです(HTML として解釈されません)。

前後の空白を取り除いたうえで、空でなく 500 文字以内であること。

改行は \n にそろえ、改行とタブ以外の制御文字と双方向制御文字は受け付けません。

  • 1〜500 文字

ここに無い項目を送ると 422 になります。

本文の例
{
"body": "これ、クリックすると変わるんですね(追記: すごい)"
}

応答(200)書き換えました。

コメントを書き換えるの応答
項目説明
id必須string

コメントの ID。

  • パターン: ^[2-9a-z]{16}$
post_id必須string

コメントした先の投稿の ID。

  • パターン: ^[2-9a-z]{16}$
author_handle必須string

コメントした人のハンドル。

body必須string

コメントの本文(プレーンテキスト)。

created_at必須string (date-time)

書いた日時(UTC、ISO 8601)。

updated_at必須string (date-time)

最後に書き換えた日時(UTC、ISO 8601)。書いただけなら書いた日時。

ここに無い項目を送ると 422 になります。

応答の例
{
"id": "q2m5x8b4p6v7n3k9",
"post_id": "v7n3k9q2m5x8b4p6",
"author_handle": "tanaka_yu_7k2mp",
"body": "これ、クリックすると変わるんですね",
"created_at": "2026-09-20T09:30:00.000Z",
"updated_at": "2026-09-20T09:30:00.000Z"
}

返りうるステータス

  • 200書き換えました。
  • 400リクエスト本文を JSON として読めません
  • 401API キーが無いか、有効ではありません
  • 403トークンにその操作の範囲が付いていない(`insufficient_scope`)。範囲は発行するときに決まり、あとから増やせません。
  • 404そのコメントがない、または**ほかの人のコメントを指した**(`comment_not_found`)。投稿と同じ理由で 404 です。
  • 413リクエスト本文が大きすぎます
  • 415Content-Type は application/json にしてください
  • 422入力が規則を満たしていません
  • 429呼び出しの回数が上限を超えました
  • 500サーバの内部で問題が起きました

コメントを消す

DELETEhttps://api.framed.dog/v1/comments/{comment_id}

自分のコメントだけを消します。ほかの人のコメントを指すと 404 です。元に戻せません。

パスパラメータ

コメントを消すのパスパラメータ
項目説明
comment_id必須string

コメントの ID(作成・一覧の応答の id)。

  • パターン: ^[2-9a-z]{16}$

応答(204)削除しました(本文なし)。

返りうるステータス

  • 204削除しました(本文なし)。
  • 401API キーが無いか、有効ではありません
  • 403トークンにその操作の範囲が付いていない(`insufficient_scope`)。範囲は発行するときに決まり、あとから増やせません。
  • 404そのコメントがない、または**ほかの人のコメントを指した**(`comment_not_found`)。投稿と同じ理由で 404 です。
  • 429呼び出しの回数が上限を超えました
  • 500サーバの内部で問題が起きました

投稿

本文は format で書き方を選びます。画面の投稿フォームのタブと同じものです(画面の「文章」の代わりに Markdown を使います)。

markdown Markdown
ふつうの文章に向きます。保存のときに画面の「文章」と同じ形に移し、フレームを使わずにタイムラインへ出ます。中の HTML はタグにならず、書いたとおりの文字として出ます(スクリプトは動きません)。元の Markdown は残さず、あとで読むと format は rich です。
html HTML(省略したときの既定)
HTML ドキュメントをそのまま。CSS と JavaScript を含められ、サーバは書き換えません(サニタイズしません)。そのままで安全なのは、投稿が Framed! 本体とは別のドメイン(<post_id>.usercontents.frmd.spot)のフレームの中で動き、閲覧者のサインイン状態やほかの投稿に触れられないからです。
reblog リブログ
ほかのページの URL(url)を、200 文字までの文(text、プレーンテキスト)を添えて共有します。画面にはリンク先の Open Graph から作ったリンクカードが出ます。
書き換える・消す(curl)
# 本文を丸ごと置き換える。書き方は元と違ってよい(ここではリブログにする)
curl -X PATCH https://api.framed.dog/v1/posts/<post_id> \
-H "Authorization: Bearer $FRAMED_USER_TOKEN" \
-H "Content-Type: application/json" \
-d '{"format":"reblog","url":"https://example.com/articles/42","text":"これよかった"}'
# 消す(元に戻せない)
curl -X DELETE https://api.framed.dog/v1/posts/<post_id> \

コメントといいね

コメントはプレーンテキストです(投稿と違って HTML として解釈されません)。本体の画面に地の文として並ぶためで、500 文字まで、改行以外の制御文字は受け付けません。

コメントする(curl)
curl -X POST https://api.framed.dog/v1/posts/<post_id>/comments \
-H "Authorization: Bearer $FRAMED_USER_TOKEN" \
-H "Content-Type: application/json" \
-d '{"body":"これ、クリックすると変わるんですね"}'

いいねは何度呼んでも同じ結果になります(押した人ごとに 1 件で、状態は行の有無で表すため)。だから作成は POST ではなく PUT です。呼び出しが失敗して再試行しても、数が狂うことはありません。

いいねを付ける・外す(curl)
# 付ける(何度呼んでも 1 件のまま)
curl -X PUT https://api.framed.dog/v1/posts/<post_id>/like \
-H "Authorization: Bearer $FRAMED_USER_TOKEN"
# 外す(付いていなくても成功する)
curl -X DELETE https://api.framed.dog/v1/posts/<post_id>/like \
-H "Authorization: Bearer $FRAMED_USER_TOKEN"

MCP サーバ

Claude などの AI エージェントから、投稿の操作を MCP(Model Context Protocol)で使えます。REST と同じ規則・同じ回数の上限(合わせて数えます)で動きます。 コメントといいねのツールはまだありません。

Claude Code(URL だけ。/mcp から認可する)
claude mcp add --transport http framed-dog https://api.framed.dog/user-mcp
Claude Code(トークン)
claude mcp add --transport http framed-dog https://api.framed.dog/user-mcp \
--header "Authorization: Bearer $FRAMED_USER_TOKEN"
HTTP でつなげるクライアントの設定(トークンの例)
{
"mcpServers": {
"framed-dog": {
"type": "http",
"url": "https://api.framed.dog/user-mcp",
"headers": {
"Authorization": "Bearer framed_ut_…"
}

ツール

get_me自分のアカウントを確かめる読み取りだけ

このトークンの持ち主(ハンドル・表示名・画像・自己紹介)、このトークンで使える範囲(scopes)、投稿とプロフィールの入力の規則、呼び出し回数の上限を返す。最初に必ず呼ぶこと。範囲の無いツールを呼ぶと insufficient_scope で失敗する。

list_my_posts自分の投稿の一覧読み取りだけ

自分の投稿を新しい順に返す。本文は含まない(get_post で読む)。画面で書きかけの下書きも含み、published が false のものがそれ。format は html / rich(文章か Markdown で書いたもの)/ reblog。

get_post投稿を取得読み取りだけ

投稿を本文(配信している HTML)ごと返す。ほかの人の公開済みの投稿も読める(下書きは本人だけ)。リブログなら reblog に URL と文が入る。

create_post投稿する

利用者本人の名前で投稿し、本体のタイムラインに直ちに公開する(下書きにはならない)。

format で書き方を選ぶ: markdown(markdown に Markdown。スクリプトは動かない。ふつうの文章はこれを勧める)/

html(html に HTML。CSS と JavaScript も投稿ごとの別ドメインのフレームで動く)/

reblog(url に共有する URL、text に添える 200 字までの文。画面にはリンクカードが出る)。

tags でタグを 5 個まで付けられる(あとから変えられない)。

実行前に、投稿する中身を利用者に見せて確かめること。

update_post投稿を書き換え公開中の内容を変える

自分の投稿の本文を丸ごと置き換える。書き方(format)は元と違ってよい。ほかの人の投稿は書き換えられない(post_not_found)。

ID と URL は変わらず、書き換えは見ている人に直ちに届く。タグと公開の状態は変わらない。

Markdown で書いた投稿も、元の Markdown は残っていない(get_post の html は組み立てた文書)。書き直すときは新しく書くこと。

実行前に、どの投稿をどう変えるかを利用者に確かめること。

delete_post投稿を削除公開中の内容を変える

自分の投稿を削除する。URL は開けなくなり、ついていたいいね・コメントも一緒に消える。元に戻せない。実行前に必ず利用者に確かめること。

update_profileプロフィールを書き換え公開中の内容を変える

自分の表示名(display_name)・ハンドル(handle)・自己紹介(bio)を書き換える。渡した項目だけが変わり、結果は get_me と同じ形。

display_name と bio は null か空の文字列で外れる(表示名が無いと画面にはハンドルが出る)。bio はプレーンテキストで改行を使える。

ハンドルを変えると、古いハンドルはすぐ空いて誰でも取れ、古いプロフィールの URL は開けなくなる(転送しない)。

使われているハンドルは handle_taken。規則を外れた項目が 1 つでもあれば validation_failed で、どの項目も変わらない。上限は get_me の rules.profile。

実行前に、何をどう変えるかを利用者に確かめること。範囲 profile が要る。

set_profile_iconプロフィールの画像を設定公開中の内容を変える

自分のアカウントの画像を設定する(あれば置き換える)。png に 256×256 の PNG を base64 にしたものを渡す(1MiB まで)。

切り抜き・縮小はしないので、正方形に切り抜いて 256×256 に縮めてから渡すこと。大きさが違えば validation_failed。

結果は get_me と同じ形で、icon_url が新しい画像の URL になる。実行前に、どの画像にするかを利用者に確かめること。範囲 profile が要る。

remove_profile_iconプロフィールの画像を外す公開中の内容を変える

自分のアカウントの画像を外す。画面には名前の先頭の 1 文字が出る。設定していなくても成功する。外した画像は戻せない(もう一度設定するには画像が要る)。実行前に利用者に確かめること。範囲 profile が要る。

エラー

エラー(RFC 9457 Problem Details)。機械的な分岐には code を使ってください。

失敗は application/problem+json(RFC 9457)で返します。形と code の意味は Framed! API と共通です。

エラーの形
項目説明
type必須string (uri)

エラーの種類を説明するドキュメントの URI。

title必須string

エラーの種類ごとに固定の説明。

status必須integer

HTTP ステータスコード。

detail任意string

このリクエストに固有の説明。

code必須string

エラーの種類を表す機械向けのコード。

  • 次のいずれか: invalid_json, unauthorized, space_mismatch, insufficient_scope, not_found, page_not_found, part_not_found, file_not_found, data_not_found, post_not_found, comment_not_found, method_not_allowed, slug_taken, version_conflict, handle_taken, part_name_taken, parts_quota_exceeded, data_quota_exceeded, storage_quota_exceeded, payload_too_large, unsupported_media_type, validation_failed, rate_limited, internal_error
errors任意ValidationError[]

validation_failed のときだけ、通らなかった項目を並べます。

例(404)
{
"type": "https://framed.dog/developers#error-post_not_found",
"title": "その投稿はありません",
"status": 404,
"code": "post_not_found",
"detail": "投稿 v7n3k9q2m5x8b4p6 はありません"
}
invalid_json400リクエスト本文を JSON として読めません

本文が JSON として壊れているか、空です。

unauthorized401API キーが無いか、有効ではありません

Authorization: Bearer <API キー> が無い、形が違う、存在しない、失効しているのいずれかです。どれに当たるかは返しません。

insufficient_scope403この資格情報には、その操作の範囲が付いていません

API キーには触れる範囲(pages / data / files / files_write)、ユーザーAPIトークンには範囲(posts / comments / likes / profile)が付いています。範囲は発行するときに決まり、あとから増やせません。必要な範囲を選んで発行し直してください。

not_found404そのエンドポイントはありません

パスが間違っています。ベース URL に /v1 が含まれているか確かめてください。

post_not_found404その投稿はありません

パスの post_id の投稿がありません。削除されたか、ID が間違っています。書き換え・削除では、他人の投稿を指したときもこれになります(ID の存在を他人に教えないため)。ほかの人の下書きも同じです。

comment_not_found404そのコメントはありません

パスの comment_id のコメントがありません。削除されたか、ID が間違っています。他人のコメントを書き換え・削除しようとしたときもこれになります(ID の存在を他人に教えないため)。

method_not_allowed405そのメソッドは使えません

エンドポイントが受け付けるメソッドは Allow ヘッダに入っています。

handle_taken409そのハンドルはすでに使われています

ハンドルは大文字・小文字を区別せずに一意です(Apple がいれば apple は使えません)。別のハンドルを指定してください。

payload_too_large413リクエスト本文が大きすぎます

本文は 1MiB まで、ファイルを上げる・書き換えるときだけ 14MiB までです。HTML やファイルそのものの上限は別にあります(validation_failed)。

unsupported_media_type415Content-Type は application/json にしてください

本文は JSON で送ってください。

validation_failed422入力が規則を満たしていません

errors に、どの項目がなぜ通らなかったかが並びます。

rate_limited429呼び出しの回数が上限を超えました

Retry-After ヘッダの秒数だけ待ってから、もう一度呼び出してください。上限は「制限」の節にあります。

internal_error500サーバの内部で問題が起きました

送った内容に問題はありません。少し待ってからもう一度呼び出し、続くようなら detail の照合用の番号を添えて問い合わせてください。

制限

呼び出しの回数

大きさと規則

OpenAPI

この API は OpenAPI 3.1.0 で定義しています。クライアントの生成や API ツールへの取り込みには、次の文書を使ってください(スペースのサイトを扱う API とは別の文書です)。

https://api.framed.dog/user-openapi.json