#MastodonAPI

Thomas Steiner :chrome:tomayac@toot.cafe
2026-02-04

I've created a little #Mastodon 🐘 toot edit history viewer that lets you explore the history of a toot, edit by edit, through the #MastodonAPI. Here's an example: tomayac.github.io/mastodon-edi. Source code: github.com/tomayac/mastodon-ed.

Richard Orilla :mastodon:richardorilla
2025-12-18

I finally did it!

I've been linking my blog posts here recently to get more readers, but mostly because I wanted to integrate Mastodon directly into my site as my comment engine.

The system is now live. Replies to this post will appear on my blog!

2025-11-11

Okay, my analysis is complete! Here are the core changes to Ktistec required for Mastodon API compatibility:

  • PKCE (Proof Key for Code Exchange) must be optional: Because Mastodon makes PKCE optional, clients don't support it, which means other servers can't require it. PKCE (and the code_challenge parameter) ensures that an authorization code can only be exchanged by the client that initiated the OAuth request.
  • Support for the client_credentials grant type: The client_credentials grant type is used to grant a client app-level access without requiring user authentication. Mastodon requires this for some of its "public" API endpoints. This necessitates a change to the database schema to allow a null account id in the client secrets table.
  • Addition of a created_at timestamp property: Mastodon requires a non-standard created_at property in the body of the /oauth/token endpoint response instead of (in addition to) the standard expires_in property.
  • Support for both form-encoded and JSON request bodies: This isn't a Mastodon requirement per se but popular clients clearly demand some latitude in what they send.
  • WebFinger must accept requests with no resource parameter: This is honestly a bug on my part.
  • Mastodon-compatible endpoints: A boatload of them. Clients expect many endpoints and don't gracefully degrade if they're not present. Really I should just implement features like pinned posts and bookmarks...

The only thing here that gives me heartburn is that PKCE is not required.

#ktistec #mastodonapi #oauth

⚯ Michel de Cryptadamus ⚯cryptadamist@universeodon.com
2025-11-05
2025-10-31

¡Hola, mundo! 🐘 Estoy publicando esto usando un script de Python y la API de Mastodon.

Abraham Williamsabraham@indieweb.social
2025-10-06

I started refactoring @meow to use ID objects for resources encoding the string ID, the resource type (account/status), and server the resource is from together.

The idea being that a status URL could be parsed from text into an ID and the status details page knows if it's a local status or remote status.

It's enough work that I'm somewhat regretting it.

#mastodon #mastodonapi

Terence Eden’s Blogblog@shkspr.mobi
2025-10-03

Getting started with Mastodon's Quote Posts - technical implementation details for servers

shkspr.mobi/blog/2025/10/getti

Quoting posts on Mastodon is slightly complex. Because of the privacy conscious nature of the platform and its users, reposting isn't merely a case of sharing a URl.

A user writes a status. The user can choose to make their statuses quotable or not. What happens when a quoter quotes that post?

I've read through the specification and tried to simplify it. Quoting is a multi-step process:

  1. The status must opt-in to being shared.
  2. The quoter quotes the status.
  3. The quoter's server sends a request to the status's server.
  4. The status's server sends an accept message back to the quoter's server.
  5. When other servers see the quote, they check with the status's server to see if it is allowed.

I'm going to walk you through each stage as best as I understand them.

Opting In

An ActivityPub status message is JSON. In order to opt-in, it needs this additional field.

"interactionPolicy": {  "canQuote": {    "automaticApproval": "https://www.w3.org/ns/activitystreams#Public"  }}

That tells ActivityPub clients that anyone is allowed to quote this post. It is also possible to say that only specific users, or only followers, or no-one is allowed.

The QuoteRequest

Someone has hit the quote post button, typed their own message, and shared their wisdom. Their server sends the following message to the server which hosts the quoted status. This has been edited for brevity.

{  "@context": [    "https://www.w3.org/ns/activitystreams",    {      "QuoteRequest":   "https://w3id.org/fep/044f#QuoteRequest"    }  ],  "type": "QuoteRequest",  "id":     "https://mastodon.test/users/Edent/quote_requests/1234-5678-9101",  "actor":  "https://mastodon.test/users/Edent",  "object": "https://example.com/posts/987654321.json",  "instrument": {    "id":           "https://mastodon.test/users/Edent/statuses/123456789",    "url":          "https://mastodon.test/@Edent/123456789",    "attributedTo": "https://mastodon.test/users/Edent",    "quote":          "https://example.com/posts/987654321.json",    "_misskey_quote": "https://example.com/posts/987654321.json",    "quoteUri":       "https://example.com/posts/987654321.json"  }}

All this says is "I would like permission to quote you."

The Stamp

The quoted server needs to approve this quote. First, it generates a "stamp".

This is a file which lives on the quoted server. It is proof that the quote is allowed. If it is deleted, the quote permission is revoked. When the stamp's ID is requested the stamp must be returned.

{  "@context": [    "https://www.w3.org/ns/activitystreams",    {      "gts": "https://gotosocial.org/ns#",      "QuoteAuthorization": {        "@id": "https://w3id.org/fep/044f#QuoteAuthorization",        "@type": "@id"      },      "interactingObject": {        "@id": "gts:interactingObject"      },      "interactionTarget": {        "@id": "gts:interactionTarget"      }    }  ],  "type": "QuoteAuthorization",  "id":                "https://example.com/quote-987654321.json",  "attributedTo":      "https://example.com/users/username",  "interactionTarget": "https://example.com/posts/987654321.json",  "interactingObject": "https://mastodon.test/users/Edent/statuses/123456789"}

If the quoted status is viewed from a different server, that server will query the stamp to make sure the share is allowed.

The Accept

This is the message that the quoted server sends to the quoting server. It references the request and the stamp.

{  "@context": [    "https://www.w3.org/ns/activitystreams",    {      "QuoteRequest": "https://w3id.org/fep/044f#QuoteRequest"    }  ],  "type": "Accept",  "to":    "https://mastodon.test/users/Edent",  "id":    "https://example.com/posts/987654321.json",  "actor": "https://example.com/account",  "object": {    "type": "QuoteRequest",    "id":         "https://mastodon.test/users/Edent/quote_requests/1234-5678-9101",    "actor":      "https://mastodon.test/users/Edent",    "instrument": "https://mastodon.test/users/Edent/statuses/123456789",    "object":     "https://example.com/posts/987654321.json"  },  "result": "https://example.com/quote-987654321.json"}

The "result" must be the same as the stamp's URl.

And then?

You can follow and quote @colours@colours.bots.edent.tel on your favourite Fediverse platform.

I've written an ActivityPub server in a single file which is designed to teach you have the protocol works. Have a play with ActivityBot.

#ActivityPub #fediverse #mastodon #MastodonAPI

Terence EdenEdent
2025-10-03

🆕 blog! “Getting started with Mastodon's Quote Posts - technical implementation details for servers”

Quoting posts on Mastodon is slightly complex. Because of the privacy conscious nature of the platform and its users, reposting isn't merely a case of sharing a URl.

A user writes a status. The user…

👀 Read more: shkspr.mobi/blog/2025/10/getti

Terence EdenEdent
2025-10-02

Another curious / issue.

A Mastodon server is sending me a DELETE message.

The delete is because a user has been deleted.

My server tries to validate the HTTP Signature.

My server looks up the deleted user's main-key.

The user has been deleted so the public key 404s.

My server never acknowledges the delete, so the other server keeps sending me the same request.

So… How do I validate the signature of a deleted user?

JSON code.
Terence EdenEdent
2025-09-28

Here's the Quote Request Mastodon sends me.
colours.bots.edent.tel/data/in

This is the Stamp my bot generates.
colours.bots.edent.tel/quotes/

This is the Accept my bot sends Mastodon.
colours.bots.edent.tel/quotes/

The Mastodon.Social server shows the quote toot. External servers don't.

Please, someone explain what bone-headed mistake I've made.

(Edit: Updated the links)

Terence EdenEdent
2025-09-28

RE: colours.bots.edent.tel/posts/6

Ok, I need some help, please.

The reply to this will have links to the QuoteRequest the bot received, the QuoteAuthorization which it saves, and the Accept message it returns.

Can anyone figure out why the Quote permissions aren't showing on external servers?

🤖 Test post from Mastodon API client at 2025-09-27 17:15:20 #MastodonAPI #Python

📚 Example post from Mastodon API client at 2025-09-27 17:13:23 #MastodonAPI #Python #Example

🤖 Test post from Mastodon API client at 2025-09-27 17:12:45 #MastodonAPI #Python

Terence EdenEdent
2025-09-27

OK gang, I'm stumped (and a little drunk).

I'm trying to get Quote posts working ActivityBot.

✅ Quote posts are an available option.

❓ This Accept message is sent - colours.bots.edent.tel/quotes/

❓ Which references this stamp - colours.bots.edent.tel/quotes/

But the quote never gets approved. Can you spot any obvious mistakes with my JSON?

EDIT! Solved. Turns out, you actually have to post the message to the right server. Who knew?!?!

Terence EdenEdent
2025-09-27

I want to allow my bots' posts to be quoted.

Do I need all these interaction policies - or can I just have the simplified interactionPolicy?

Long list of policies.Simple interaction policy.
⚯ Michel de Cryptadamus ⚯cryptadamist@universeodon.com
2025-09-23

Ω🪬Ω
#FediAlgo (the customizable timeline algorithm / filtering system for your Mastodon feed) v1.2.2 is deployed now. Has a switch that makes sure any #hashtags / users / etc. that you follow are displayed as filter options even if they don't meet the minimum number of recent toots threshold.

Also a bunch of bug fixes and small improvements.

* Try it here: michelcrypt4d4mus.github.io/fe
* Code: github.com/michelcrypt4d4mus/f
* Video of FediAlgo in action (slightly outdated): universeodon.com/@cryptadamist

#activitypub #algorithm #algorithmicFeed #algorithmicTimeline #Fedi #FediTips #FediTools #Fediverse #Feed #FOSS #GoToSocial #hashtag #hashtags #javascript #MastoAdmin #Mastodon #MastodonApi #mastohelp #mastojs #node #nodejs #opensource #socialmedia #SocialWeb #timeline #TL #typescript #webdev

screenshot of fedialgo demo
Karsten Schmidttoxi@mastodon.thi.ng
2025-09-16

Finally made that tool I've been planning for a while: A configurable batch deleter of #Mastodon #bookmarks, supporting a threshold date (i.e. only older bookmarks considered) and lists of accounts and hashtags to always keep.

gist.github.com/postspectacula

After editing the script to fill in your own details and preferences at the top, you can run it via command line `node delete-bookmarks.js` or paste it in the browser console to execute.

The script outputs details of each bookmark being removed, supports retrying with exponential back-off (5x) and is configured to use quite generous pauses between requests to not trigger rate limiting.

The script also prints out `max_id` values, used for pagination purposes by the Mastodon API. Should you interrupt the script to make some changes and then re-run, you can also find the latest `max_id` and set `MAX_ID` to that value in the script to save time (bookmarks are processed in batches of 40)

(FWIW I've been ferociously bookmarking posts for almost 3 years (had ~13500) and my media storage became over 100GB. So it's urgent time for some serious pruning...)

#OpenSource #JavaScript #MastodonAPI #Utilities

Client Info

Server: https://mastodon.social
Version: 2025.07
Repository: https://github.com/cyevgeniy/lmst