#mastodonapi — Public Fediverse posts
Live and recent posts from across the Fediverse tagged #mastodonapi, aggregated by home.social.
-
Mastodon APIでAccount.last_status_atが何で時刻情報入っていないんだあと思ったら敢えて入れてないのね。この情報はアカウントがアクティブ状態であるかを知る目的で提供しているので、恐らくプライバシー保護的な理由で日付レベルの粒度にしているのか。
https://github.com/mastodon/mastodon/pull/12966 -
We will soon be publishing a blog post for Mastodon client developers, showcasing the new API and features that are available in this version.
-
We will soon be publishing a blog post for Mastodon client developers, showcasing the new API and features that are available in this version.
-
🆕 blog! “Using FourSquare's API to post location checkins to social media”
What is this, 2016?
I like sharing my location with my pocket friends sometimes. If I'm in a cool bar that they know, perhaps they can recommend a drink. If they live nearby, maybe they want to come for dinner. Not everyone has FourSquare's…
👀 Read more: https://shkspr.mobi/blog/2026/06/using-foursquares-api-to-post-location-checkins-to-social-media/
⸻
#api #BlueSky #FourSquare #geolocation #MastodonAPI -
🆕 blog! “Using FourSquare's API to post location checkins to social media”
What is this, 2016?
I like sharing my location with my pocket friends sometimes. If I'm in a cool bar that they know, perhaps they can recommend a drink. If they live nearby, maybe they want to come for dinner. Not everyone has FourSquare's…
👀 Read more: https://shkspr.mobi/blog/2026/06/using-foursquares-api-to-post-location-checkins-to-social-media/
⸻
#api #BlueSky #FourSquare #geolocation #MastodonAPI -
Using FourSquare's API to post location checkins to social media
https://shkspr.mobi/blog/2026/06/using-foursquares-api-to-post-location-checkins-to-social-media/What is this, 2016?
I like sharing my location with my pocket friends sometimes. If I'm in a cool bar that they know, perhaps they can recommend a drink. If they live nearby, maybe they want to come for dinner. Not everyone has FourSquare's SwarmApp, so it is handy to automatically share its updates with other people.
Of course, Swarm doesn't cross-post to social media because walled-gardens are the most profitable. This is my attempt to open it back up again.
Here's what they look like on BlueSky and Mastodon:
Checked in to Hamburger Fischmarkt, Große Elbstr. 9 (Fischmarkt), Germany Probably a *bit* early for a breakfast beer. See on Swarm
— Terence Eden (@edent.tel) 24 May 2026 at 07:45
[image or embed]Post by @[email protected] View on Mastodon
tl;dr
You can get the SwarmToSocial code from my GitLab.
At the moment, developers get 10,000 API calls for free each month. That's probably more than enough for most personal uses.
Documentation
I was pleasantly surprised that FourSquare's CheckIn documentation was fairly easy to use and understand.
Once you've signed up for a developer account you can create an OAuth app. That will generate a Client ID (
ABC123), Client Secret (XYZ789), and you supply a Project URL.Once done you can follow the Authentication documentation. Or just visit:
https://foursquare.com/oauth2/authenticate? client_id=ABC123 &response_type=code &redirect_uri=https://example.com/Sign in with your FourSquare account. It will redirect you to:
https://example.com/?code=456QWEUse that code to construct the final URl:
https://foursquare.com/oauth2/access_token? client_id=ABC123 &client_secret=XYZ789 &grant_type=authorization_code &redirect_uri=http://example.com/ &code=456QWEThat will respond with the Access Token:
{ "access_token":"asdfghjkl123456" }Hurrah! Posting a new checkin is relatively simple. POST to this URl with a header of
accept: application/jsonhttps://api.foursquare.com/v2/checkins/add? v=20260223 &venueId=13600425 &shout=This%20is%20a%20test &oauth_token=asdfghjkl123456vis, rather confusingly, a date. The versioning documentation has more details but, basically, set it to the date you deployed your app.venuIdyou'll need to find yourself (more on that later).shoutis up to 140 characters (!) of URl encoded text.
That will send back rather a lot of JSON. Here are the important bits:
{ "meta": { "code": 200, "requestId": "123456789" }, "response": { "checkin": { "id": "987654321", "createdAt": 1771843820, "type": "checkin", "visibility": "closeFriends", "shout": "This is a test of the API", "timeZoneOffset": -300, "editableUntil": 1771930220000, "user": { "id": "56367", "firstName": "Terence", "lastName": "Eden", "relationship": "self", "displayName": "Terence Eden" }, "venue": { "id": "QWERTYUIOP", "name": "My Birthday Party!", "contact": {}, "location": { "isFuzzed": true, "lat": 39.123456789, "lng": -84.987654321, "cc": "US", "city": "Cincinnati", "state": "KY", "country": "United States", "formattedAddress": [ "Cincinnati, KY", "United States" ] } }, "checkinShortUrl": "https://swarmapp.com/user/56367/checkin/987654321?s=wRZ7ByNfCW1DNrOIpsRcytPZelE" } } }For my purposes, the
shoutandcheckinShortUrlare the most important. You can view a sample check in:https://swarmapp.com/user/56367/checkin/699c34b55bad6b7fb1695544?s=LA7jCaAtH-s9CwSpgQrQdHrP5-8
Venue ID
If you're already using a service like Untappd you might be able to get the venue ID from that.
If not, FourSquare provides 100 million points of interest for free - although with questionable data quality.
Alternatively, you can search by location:
curl --request GET \ --url 'https://places-api.foursquare.com/places/search?ll=51.123%2C0.123&radius=1000&sort=POPULARITY' \ --header 'X-Places-Api-Version: 2025-06-17' \ --header 'accept: application/json' \ --header 'authorization: Bearer ABC123'As far as I can see, the
Bearer Tokenonly exists on the documentation page. I couldn't find it in my developer console. Weird!That gets you back:
{ "results": [ { "fsq_place_id": "4be584ed2457a593ad8cab15", "latitude": 51.11783041264215, "longitude": 0.11219274871133413, "categories": [ { "fsq_category_id": "4bf58dd8d48988d1fa941735", "name": "Farmers Market", "short_name": "Farmers Market", "plural_name": "Farmers Markets", "icon": { "prefix": "https://ss3.4sqi.net/img/categories_v2/shops/food_farmersmarket_", "suffix": ".png" } } ], "date_created": "2010-05-08", "date_refreshed": "2025-11-01", "distance": 970, "extended_location": {}, "link": "/places/4be584ed2457a593ad8cab15", "location": { "address": "", "locality": "Hartfield", "region": "East Sussex", "postcode": "", "admin_region": "England", "country": "GB", "formatted_address": "Hartfield, East Sussex" }, "name": "Perryhill Farm Shop", "placemaker_url": "https://foursquare.com/placemakers/review-place/4be584ed2457a593ad8cab15", "related_places": {}, "social_media": { "twitter": "" }, "tel": "", "website": "http://www.perryhillorchards.co.uk/index.php?sec=4" }, { "fsq_place_id": "8896f77565e54a658585301d", "latitude": 51.11649, "longitude": 0.13131, "categories": [], "date_created": "2021-12-06", "date_refreshed": "2021-12-06", "distance": 909, "extended_location": {}, "link": "/places/8896f77565e54a658585301d", "location": { "address": "Priory Park, Beech Green Lane", "locality": "Withyham", "region": "East Sussex", "postcode": "TN7 4DB", "admin_region": "England", "post_town": "Hartfield", "country": "GB", "formatted_address": "Priory Park, Beech Green Lane, Withyham, East Sussex, TN7 4DB" }, "name": "Spectra Studios", "placemaker_url": "https://foursquare.com/placemakers/review-place/8896f77565e54a658585301d", "related_places": {}, "social_media": {}, "tel": "01892 487149" }, ], "context": { "geo_bounds": { "circle": { "center": { "latitude": 51.123, "longitude": 0.1234 }, "radius": 1000 } } } }You can manually check a place using the Placemaker site: https://foursquare.com/placemakers/review-place/64eca80f0398c97ab52298ec
Getting Existing Checkins
What if you've checked in to a place using the official Swarm app? How do you get your own recent checkin data?
Again, there is documentation on getting user checkins.
curl --request GET \ --url 'https://api.foursquare.com/v2/users/self/checkins?v=20260223&limit=2&offset=0&oauth_token=asdfghjkl123456' \ --header 'accept: application/json'Where it says
oauth_tokenit actually means theaccess_token.The JSON that is returned is a bit verbose, so I've simplified it here:
{ "meta": { "code": 200, "requestId": "699c6505b488565a31e315e3" }, "response": { "checkins": { "count": 2344, "items": [ { "id": "699c34b55bad6b7fb1695544", "createdAt": 1771844789, "type": "checkin", "visibility": "closeFriends", "entities": [], "shout": "Testing the API using an Untappd FourSquare ID.", "timeZoneOffset": 0, "editableUntil": 1771931189000, "venue": { "id": "64eca80f0398c97ab52298ec", "name": "Abbey Wood Fossil Pit", "contact": {}, "location": { "lat": 51.487514, "lng": 0.13048041, "postalCode": "SE2 0AX", "cc": "GB", "country": "United Kingdom", "formattedAddress": [ "SE2 0AX" ] }, "createdAt": 1693231119 }, },Annoyingly, there's no
checkinShortUrlwhich means it can't easily be shared.For that, you'll need to use the
get-checkin-detailsAPI:curl --request GET \ --url 'https://api.foursquare.com/v2/checkins/699c34b55bad6b7fb1695544?v=20250202&oauth_token=asdfghjkl123456' \ --header 'accept: application/json'Which will return this (truncated for brevity):
{ "meta": { "code": 200, "requestId": "699c67de5f5c0a0e8ab234db" }, "response": { "checkin": { "id": "699c34b55bad6b7fb1695544", "createdAt": 1771844789, "type": "checkin", "shout": "Testing the API using an Untappd FourSquare ID.", "timeZoneOffset": 0, "checkinShortUrl": "https://swarmapp.com/user/56367/checkin/699c34b55bad6b7fb1695544?s=LA7jCaAtH-s9CwSpgQrQdHrP5-8",Photos
If there's a photo with the checkin, it will be return in the JSON like this:
{ "response": { "checkin": { "photos": { "count": 1, "items": [ { "id": "699f3a9f96799c05c0f16c9c", "createdAt": 1772042911, "prefix": "https://fastly.4sqi.net/img/general/", "suffix": "/56367_5VYox4Y-hs66wURVsYc1NLgOokfwBfcWhtKQrOlMdD8.jpg", "width": 1008, "height": 1344,The URl for the image is
prefix width x height suffix- in this case https://fastly.4sqi.net/img/general/1008x1344/56367_5VYox4Y-hs66wURVsYc1NLgOokfwBfcWhtKQrOlMdD8.jpgYou can adjust the width and height if you want a thumbnail or some other resolution.
If there's no photo, the count will be 0.
Putting it all together
Every 15 minutes, the SwarmToSocial code does the following:
- Get the most recent checkin.
- Read a local file to get the previously seen checkin ID.
- If the checkin ID hasn't been seen before:
- Get the checkin details.
- Get the photo if it exists
- Post the checkin (plus photo) to Mastodon & BlueSky.
- Save the checkin ID to a file.
Enjoy!
#api #BlueSky #FourSquare #geolocation #MastodonAPI -
Using FourSquare's API to post location checkins to social media
https://shkspr.mobi/blog/2026/06/using-foursquares-api-to-post-location-checkins-to-social-media/What is this, 2016?
I like sharing my location with my pocket friends sometimes. If I'm in a cool bar that they know, perhaps they can recommend a drink. If they live nearby, maybe they want to come for dinner. Not everyone has FourSquare's SwarmApp, so it is handy to automatically share its updates with other people.
Of course, Swarm doesn't cross-post to social media because walled-gardens are the most profitable. This is my attempt to open it back up again.
Here's what they look like on BlueSky and Mastodon:
Checked in to Hamburger Fischmarkt, Große Elbstr. 9 (Fischmarkt), Germany Probably a *bit* early for a breakfast beer. See on Swarm
— Terence Eden (@edent.tel) 24 May 2026 at 07:45
[image or embed]Post by @[email protected] View on Mastodon
tl;dr
You can get the SwarmToSocial code from my GitLab.
At the moment, developers get 10,000 API calls for free each month. That's probably more than enough for most personal uses.
Documentation
I was pleasantly surprised that FourSquare's CheckIn documentation was fairly easy to use and understand.
Once you've signed up for a developer account you can create an OAuth app. That will generate a Client ID (
ABC123), Client Secret (XYZ789), and you supply a Project URL.Once done you can follow the Authentication documentation. Or just visit:
https://foursquare.com/oauth2/authenticate? client_id=ABC123 &response_type=code &redirect_uri=https://example.com/Sign in with your FourSquare account. It will redirect you to:
https://example.com/?code=456QWEUse that code to construct the final URl:
https://foursquare.com/oauth2/access_token? client_id=ABC123 &client_secret=XYZ789 &grant_type=authorization_code &redirect_uri=http://example.com/ &code=456QWEThat will respond with the Access Token:
{ "access_token":"asdfghjkl123456" }Hurrah! Posting a new checkin is relatively simple. POST to this URl with a header of
accept: application/jsonhttps://api.foursquare.com/v2/checkins/add? v=20260223 &venueId=13600425 &shout=This%20is%20a%20test &oauth_token=asdfghjkl123456vis, rather confusingly, a date. The versioning documentation has more details but, basically, set it to the date you deployed your app.venuIdyou'll need to find yourself (more on that later).shoutis up to 140 characters (!) of URl encoded text.
That will send back rather a lot of JSON. Here are the important bits:
{ "meta": { "code": 200, "requestId": "123456789" }, "response": { "checkin": { "id": "987654321", "createdAt": 1771843820, "type": "checkin", "visibility": "closeFriends", "shout": "This is a test of the API", "timeZoneOffset": -300, "editableUntil": 1771930220000, "user": { "id": "56367", "firstName": "Terence", "lastName": "Eden", "relationship": "self", "displayName": "Terence Eden" }, "venue": { "id": "QWERTYUIOP", "name": "My Birthday Party!", "contact": {}, "location": { "isFuzzed": true, "lat": 39.123456789, "lng": -84.987654321, "cc": "US", "city": "Cincinnati", "state": "KY", "country": "United States", "formattedAddress": [ "Cincinnati, KY", "United States" ] } }, "checkinShortUrl": "https://swarmapp.com/user/56367/checkin/987654321?s=wRZ7ByNfCW1DNrOIpsRcytPZelE" } } }For my purposes, the
shoutandcheckinShortUrlare the most important. You can view a sample check in:https://swarmapp.com/user/56367/checkin/699c34b55bad6b7fb1695544?s=LA7jCaAtH-s9CwSpgQrQdHrP5-8
Venue ID
If you're already using a service like Untappd you might be able to get the venue ID from that.
If not, FourSquare provides 100 million points of interest for free - although with questionable data quality.
Alternatively, you can search by location:
curl --request GET \ --url 'https://places-api.foursquare.com/places/search?ll=51.123%2C0.123&radius=1000&sort=POPULARITY' \ --header 'X-Places-Api-Version: 2025-06-17' \ --header 'accept: application/json' \ --header 'authorization: Bearer ABC123'As far as I can see, the
Bearer Tokenonly exists on the documentation page. I couldn't find it in my developer console. Weird!That gets you back:
{ "results": [ { "fsq_place_id": "4be584ed2457a593ad8cab15", "latitude": 51.11783041264215, "longitude": 0.11219274871133413, "categories": [ { "fsq_category_id": "4bf58dd8d48988d1fa941735", "name": "Farmers Market", "short_name": "Farmers Market", "plural_name": "Farmers Markets", "icon": { "prefix": "https://ss3.4sqi.net/img/categories_v2/shops/food_farmersmarket_", "suffix": ".png" } } ], "date_created": "2010-05-08", "date_refreshed": "2025-11-01", "distance": 970, "extended_location": {}, "link": "/places/4be584ed2457a593ad8cab15", "location": { "address": "", "locality": "Hartfield", "region": "East Sussex", "postcode": "", "admin_region": "England", "country": "GB", "formatted_address": "Hartfield, East Sussex" }, "name": "Perryhill Farm Shop", "placemaker_url": "https://foursquare.com/placemakers/review-place/4be584ed2457a593ad8cab15", "related_places": {}, "social_media": { "twitter": "" }, "tel": "", "website": "http://www.perryhillorchards.co.uk/index.php?sec=4" }, { "fsq_place_id": "8896f77565e54a658585301d", "latitude": 51.11649, "longitude": 0.13131, "categories": [], "date_created": "2021-12-06", "date_refreshed": "2021-12-06", "distance": 909, "extended_location": {}, "link": "/places/8896f77565e54a658585301d", "location": { "address": "Priory Park, Beech Green Lane", "locality": "Withyham", "region": "East Sussex", "postcode": "TN7 4DB", "admin_region": "England", "post_town": "Hartfield", "country": "GB", "formatted_address": "Priory Park, Beech Green Lane, Withyham, East Sussex, TN7 4DB" }, "name": "Spectra Studios", "placemaker_url": "https://foursquare.com/placemakers/review-place/8896f77565e54a658585301d", "related_places": {}, "social_media": {}, "tel": "01892 487149" }, ], "context": { "geo_bounds": { "circle": { "center": { "latitude": 51.123, "longitude": 0.1234 }, "radius": 1000 } } } }You can manually check a place using the Placemaker site: https://foursquare.com/placemakers/review-place/64eca80f0398c97ab52298ec
Getting Existing Checkins
What if you've checked in to a place using the official Swarm app? How do you get your own recent checkin data?
Again, there is documentation on getting user checkins.
curl --request GET \ --url 'https://api.foursquare.com/v2/users/self/checkins?v=20260223&limit=2&offset=0&oauth_token=asdfghjkl123456' \ --header 'accept: application/json'Where it says
oauth_tokenit actually means theaccess_token.The JSON that is returned is a bit verbose, so I've simplified it here:
{ "meta": { "code": 200, "requestId": "699c6505b488565a31e315e3" }, "response": { "checkins": { "count": 2344, "items": [ { "id": "699c34b55bad6b7fb1695544", "createdAt": 1771844789, "type": "checkin", "visibility": "closeFriends", "entities": [], "shout": "Testing the API using an Untappd FourSquare ID.", "timeZoneOffset": 0, "editableUntil": 1771931189000, "venue": { "id": "64eca80f0398c97ab52298ec", "name": "Abbey Wood Fossil Pit", "contact": {}, "location": { "lat": 51.487514, "lng": 0.13048041, "postalCode": "SE2 0AX", "cc": "GB", "country": "United Kingdom", "formattedAddress": [ "SE2 0AX" ] }, "createdAt": 1693231119 }, },Annoyingly, there's no
checkinShortUrlwhich means it can't easily be shared.For that, you'll need to use the
get-checkin-detailsAPI:curl --request GET \ --url 'https://api.foursquare.com/v2/checkins/699c34b55bad6b7fb1695544?v=20250202&oauth_token=asdfghjkl123456' \ --header 'accept: application/json'Which will return this (truncated for brevity):
{ "meta": { "code": 200, "requestId": "699c67de5f5c0a0e8ab234db" }, "response": { "checkin": { "id": "699c34b55bad6b7fb1695544", "createdAt": 1771844789, "type": "checkin", "shout": "Testing the API using an Untappd FourSquare ID.", "timeZoneOffset": 0, "checkinShortUrl": "https://swarmapp.com/user/56367/checkin/699c34b55bad6b7fb1695544?s=LA7jCaAtH-s9CwSpgQrQdHrP5-8",Photos
If there's a photo with the checkin, it will be return in the JSON like this:
{ "response": { "checkin": { "photos": { "count": 1, "items": [ { "id": "699f3a9f96799c05c0f16c9c", "createdAt": 1772042911, "prefix": "https://fastly.4sqi.net/img/general/", "suffix": "/56367_5VYox4Y-hs66wURVsYc1NLgOokfwBfcWhtKQrOlMdD8.jpg", "width": 1008, "height": 1344,The URl for the image is
prefix width x height suffix- in this case https://fastly.4sqi.net/img/general/1008x1344/56367_5VYox4Y-hs66wURVsYc1NLgOokfwBfcWhtKQrOlMdD8.jpgYou can adjust the width and height if you want a thumbnail or some other resolution.
If there's no photo, the count will be 0.
Putting it all together
Every 15 minutes, the SwarmToSocial code does the following:
- Get the most recent checkin.
- Read a local file to get the previously seen checkin ID.
- If the checkin ID hasn't been seen before:
- Get the checkin details.
- Get the photo if it exists
- Post the checkin (plus photo) to Mastodon & BlueSky.
- Save the checkin ID to a file.
Enjoy!
#api #BlueSky #FourSquare #geolocation #MastodonAPI -
Is getting this really the best way to fetch a post on a remote instance via the mastodon API?
https://${localInstance}/api/v2/search?q=${postUrl}&resolve=true&limit=1
#Mastodonapi #API -
Is getting this really the best way to fetch a post on a remote instance via the mastodon API?
https://${localInstance}/api/v2/search?q=${postUrl}&resolve=true&limit=1
#Mastodonapi #API -
Today I unfollowed about 120 accounts that hadn't posted in more than ~8 months.
It's a bummer to see so many gone and I hope they return, but my feed has been more active than ever. Plus, I'll likely be more liberal in following new folks for a while.
What do ya'll do for user management? I cobbled together some JS for the MastoAPI to sort out the >8mo old accounts. I really didn't find any existing apps / repos for that type of thing.
-
Today I unfollowed about 120 accounts that hadn't posted in more than ~8 months.
It's a bummer to see so many gone and I hope they return, but my feed has been more active than ever. Plus, I'll likely be more liberal in following new folks for a while.
What do ya'll do for user management? I cobbled together some JS for the MastoAPI to sort out the >8mo old accounts. I really didn't find any existing apps / repos for that type of thing.
-
Federated swarm 16:26:07 @fedmini001 #mastodonapi
-
Federated swarm 16:25:14 @fedmini005 #mastodonapi [fed-edit 16:25:15]
-
Federated swarm 16:23:20 @fedmini004 #mastodonapi
-
Federated swarm 16:20:07 @fedmini001 #mastodonapi
-
Federated swarm 16:19:18 @fedmini005 #mastodonapi
-
Federated swarm 16:18:59 @fedmini001 #mastodonapi
-
Federated swarm 16:18:55 @fedmini004 #mastodonapi
-
Federated swarm 16:18:48 @fedmini004 #mastodonapi [fed-edit 16:18:51]
-
🆕 blog! “Adding "Log In With Mastodon" to Auth0”
I use Auth0 to provide social logins for the OpenBenches website. I don't want to deal with creating user accounts, managing passwords, or anything like that, so Auth0 is perfect for my needs.
There are a wide range of social media logins provided by Auth0 - including the usual suspects like…
👀 Read more: https://shkspr.mobi/blog/2026/03/adding-log-in-with-mastodon-to-auth0/
⸻
#Auth0 #HowTo #mastodon #MastodonAPI #SocialMedia -
🆕 blog! “Adding "Log In With Mastodon" to Auth0”
I use Auth0 to provide social logins for the OpenBenches website. I don't want to deal with creating user accounts, managing passwords, or anything like that, so Auth0 is perfect for my needs.
There are a wide range of social media logins provided by Auth0 - including the usual suspects like…
👀 Read more: https://shkspr.mobi/blog/2026/03/adding-log-in-with-mastodon-to-auth0/
⸻
#Auth0 #HowTo #mastodon #MastodonAPI #SocialMedia -
Adding "Log In With Mastodon" to Auth0
https://shkspr.mobi/blog/2026/03/adding-log-in-with-mastodon-to-auth0/I use Auth0 to provide social logins for the OpenBenches website. I don't want to deal with creating user accounts, managing passwords, or anything like that, so Auth0 is perfect for my needs.
There are a wide range of social media logins provided by Auth0 - including the usual suspects like Facebook, Twitter, WordPress, Discord, etc. Sadly, there's no support for Mastodon0.
All is not lost though. The Auth0 documentation says:
However, you can use Auth0’s Connections API to add any OAuth2 Authorization Server as an identity provider.
You can manually add a single Mastodon instance, but that doesn't work with the decentralised nature of the Fediverse. Instead, I've come up with a manual solution which works with any Mastodon server!
Background
Every Mastodon1 server is independent. I have an account on
mastodon.socialyou have an account onwhatever.chaos. They are separate servers, albeit running similar software. A generic authenticator needs to work with all these servers. There's no point only allowing log ins from a single server.Fortuitously, Mastodon allows app developers to automatically create new apps. A few simple lines of code and you will have an API key suitable for read-only access to that server. You can read how to instantly create Mastodon API keys or you can steal my PHP code.
User Experience
The user clicks the sign-in button on OpenBenches. They're taken to the Auth0 social login screen:
The user clicks on Mastodon. This is where Auth0's involvement ends!
The user is asked to provide the URl of their instance:
In the background, my server contacts the Mastodon instance and creates a read-only API key.
The user is asked to sign in to Mastodon.
The user is asked to authorise read-only access.
The user is now signed in and OpenBenches can retrieve their name, avatar image, and other useful information. Hurrah!
Auth0
Once you have created a service to generate API keys, it will need to run on a publicly accessible web server. For example
https://example.com/mastodon_login.Here's what you need to do within your Auth0 tennant:
- Authentication → Social → Create Connection
- At the bottom, choose "Create Custom".
- Choose "Authentication" only.
- Give your connection a name. This will be visible to users.
- "Authorization URL" and "Token URL" have the same value - the URl of your service.
- "Client ID" is only visible to you.
- "Client Secret" any random password; it won't be used for anything.
- Leave everything else in the default state.
It should look something like this:
Click the "Create" button and you're (almost) done.
Auth0 Icon
You will need to add a custom icon to the social integration. Annoyingly, there's no way to do it through the web interface, so follow that guide to use the command line.
Done!
I'll admit, this isn't the most straightforward thing to implement. Auth0 could make this easier - but it would still rely on users knowing the URl of their home instance.
That said, the Mastodon API is a delight to work with and the read-only permissions reduce risk for all parties.
Auth0 did blog about Mastodon a few years ago but never bothered implementing it! ↩︎
I do mean Mastodon; not the wider Fediverse. This only works with sites which have implemented Mastodon's APIs. ↩︎
-
Adding "Log In With Mastodon" to Auth0
https://shkspr.mobi/blog/2026/03/adding-log-in-with-mastodon-to-auth0/I use Auth0 to provide social logins for the OpenBenches website. I don't want to deal with creating user accounts, managing passwords, or anything like that, so Auth0 is perfect for my needs.
There are a wide range of social media logins provided by Auth0 - including the usual suspects like Facebook, Twitter, WordPress, Discord, etc. Sadly, there's no support for Mastodon0.
All is not lost though. The Auth0 documentation says:
However, you can use Auth0’s Connections API to add any OAuth2 Authorization Server as an identity provider.
You can manually add a single Mastodon instance, but that doesn't work with the decentralised nature of the Fediverse. Instead, I've come up with a manual solution which works with any Mastodon server!
Background
Every Mastodon1 server is independent. I have an account on
mastodon.socialyou have an account onwhatever.chaos. They are separate servers, albeit running similar software. A generic authenticator needs to work with all these servers. There's no point only allowing log ins from a single server.Fortuitously, Mastodon allows app developers to automatically create new apps. A few simple lines of code and you will have an API key suitable for read-only access to that server. You can read how to instantly create Mastodon API keys or you can steal my PHP code.
User Experience
The user clicks the sign-in button on OpenBenches. They're taken to the Auth0 social login screen:
The user clicks on Mastodon. This is where Auth0's involvement ends!
The user is asked to provide the URl of their instance:
In the background, my server contacts the Mastodon instance and creates a read-only API key.
The user is asked to sign in to Mastodon.
The user is asked to authorise read-only access.
The user is now signed in and OpenBenches can retrieve their name, avatar image, and other useful information. Hurrah!
Auth0
Once you have created a service to generate API keys, it will need to run on a publicly accessible web server. For example
https://example.com/mastodon_login.Here's what you need to do within your Auth0 tennant:
- Authentication → Social → Create Connection
- At the bottom, choose "Create Custom".
- Choose "Authentication" only.
- Give your connection a name. This will be visible to users.
- "Authorization URL" and "Token URL" have the same value - the URl of your service.
- "Client ID" is only visible to you.
- "Client Secret" any random password; it won't be used for anything.
- Leave everything else in the default state.
It should look something like this:
Click the "Create" button and you're (almost) done.
Auth0 Icon
You will need to add a custom icon to the social integration. Annoyingly, there's no way to do it through the web interface, so follow that guide to use the command line.
Done!
I'll admit, this isn't the most straightforward thing to implement. Auth0 could make this easier - but it would still rely on users knowing the URl of their home instance.
That said, the Mastodon API is a delight to work with and the read-only permissions reduce risk for all parties.
Auth0 did blog about Mastodon a few years ago but never bothered implementing it! ↩︎
I do mean Mastodon; not the wider Fediverse. This only works with sites which have implemented Mastodon's APIs. ↩︎
-
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: https://tomayac.github.io/mastodon-edit-history/#https://mastodon.social/@firefoxwebdevs/116002119945073671. Source code: https://github.com/tomayac/mastodon-edit-history.
-
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: https://tomayac.github.io/mastodon-edit-history/#https://mastodon.social/@firefoxwebdevs/116002119945073671. Source code: https://github.com/tomayac/mastodon-edit-history.
-
Wondering how easy Mastodon's API is? 😁
-
Wondering how easy Mastodon's API is? 😁
-
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!
-
thanks to @paige for the very flattering and in depth video about the #FediAlgo project and the larger case for having demonic "algorithms" in the #Fediverse.
https://video.fedihost.co/w/a1522517-704e-44a3-aa0e-5c4e7d49e7d1
#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
-
thanks to @paige for the very flattering and in depth video about the #FediAlgo project and the larger case for having demonic "algorithms" in the #Fediverse.
https://video.fedihost.co/w/a1522517-704e-44a3-aa0e-5c4e7d49e7d1
#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
-
Ω🪬Ω
Just released version 1.2.32 of #FediAlgo, the customizable timeline algorithm / filtering system for your Mastodon feed. Very minor changes that improve a couple of things in a small way.https://universeodon.com/@cryptadamist/115255251993344917
#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
-
Ω🪬Ω
Just released version 1.2.32 of #FediAlgo, the customizable timeline algorithm / filtering system for your Mastodon feed. Very minor changes that improve a couple of things in a small way.https://universeodon.com/@cryptadamist/115255251993344917
#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
-
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.
-
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.
-
🆕 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: https://shkspr.mobi/blog/2025/10/getting-started-with-mastodons-quote-posts-technical-implementation-details-for-servers/
⸻
#ActivityPub #fediverse #mastodon #MastodonAPI -
🆕 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: https://shkspr.mobi/blog/2025/10/getting-started-with-mastodons-quote-posts-technical-implementation-details-for-servers/
⸻
#ActivityPub #fediverse #mastodon #MastodonAPI -
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 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:
- The status must opt-in to being shared.
- The quoter quotes the status.
- The quoter's server sends a request to the status's server.
- The status's server sends an accept message back to the quoter's server.
- 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 @[email protected] 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.
-
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 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:
- The status must opt-in to being shared.
- The quoter quotes the status.
- The quoter's server sends a request to the status's server.
- The status's server sends an accept message back to the quoter's server.
- 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 @[email protected] 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.
-
Another curious #ActivityPub / #MastodonAPI 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?
-
Another curious #ActivityPub / #MastodonAPI 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?
-
Here's the Quote Request Mastodon sends me.
https://colours.bots.edent.tel/data/inbox/68d979af-145daa4fe72cf333caba16effb8419ee85f7ed100b15c7ec16b0394629a309bb.jsonThis is the Stamp my bot generates.
https://colours.bots.edent.tel/quotes/68d979af-3a15-f520-ac6e-13b2d6d96d1b.jsonThis is the Accept my bot sends Mastodon.
https://colours.bots.edent.tel/quotes/68d979af-aeb1-83c3-a66c-fcb359e1ff90.jsonThe 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)
#ActivityPub #MastodonAPI -
Here's the Quote Request Mastodon sends me.
https://colours.bots.edent.tel/data/inbox/68d979af-145daa4fe72cf333caba16effb8419ee85f7ed100b15c7ec16b0394629a309bb.jsonThis is the Stamp my bot generates.
https://colours.bots.edent.tel/quotes/68d979af-3a15-f520-ac6e-13b2d6d96d1b.jsonThis is the Accept my bot sends Mastodon.
https://colours.bots.edent.tel/quotes/68d979af-aeb1-83c3-a66c-fcb359e1ff90.jsonThe 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)
#ActivityPub #MastodonAPI -
RE: https://colours.bots.edent.tel/posts/68d87379-8e35-18be-b901-2730376a090d.json
Ok, I need some #ActivityPub 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?
-
RE: https://colours.bots.edent.tel/posts/68d87379-8e35-18be-b901-2730376a090d.json
Ok, I need some #ActivityPub 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
-
🤖 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
-
📚 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
-
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 - https://colours.bots.edent.tel/quotes/68d85b0d-1b15-f5b5-8a57-4115155d48c0.json
❓ Which references this stamp - https://colours.bots.edent.tel/quotes/68d85b0d-a589-851c-961d-438079e30caf.json
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?!?!
-
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?
-
Ω🪬Ω
#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: https://michelcrypt4d4mus.github.io/fedialgo_demo_app_foryoufeed/
* Code: https://github.com/michelcrypt4d4mus/fedialgo_demo_app_foryoufeed
* Video of FediAlgo in action (slightly outdated): https://universeodon.com/@cryptadamist/114395249311910522#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
-
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.
https://gist.github.com/postspectacular/599fbf6ebe84ebaf7e2349a1ac8039e4
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...)
-
Ω🪬Ω
#FediAlgo v1.1.19 is deployed. Minor bugfixes and improvements to the customizable timeline algorithm / filtering system for your Mastodon feed.* Link: https://michelcrypt4d4mus.github.io/fedialgo_demo_app_foryoufeed/
* Code: https://github.com/michelcrypt4d4mus/fedialgo_demo_app_foryoufeed
* Video of FediAlgo in action (slightly out of date): https://universeodon.com/@cryptadamist/114395249311910522#activitypub #algorithm #algorithmicFeed #algorithmicTimeline #Fedi #FediTips #FediTools #Fediverse #Feed #FOSS #GoToSocial #hashtag #hashtags #MastoAdmin #Mastodon #MastodonApi #mastohelp #mastojs #nodejs #nod #opensource #socialmedia #SocialWeb #timeline #TL #typescript #webdev