Fediverse and Bluesky

Websites

syndication-service

Connecting a website: its feed found, its domain proved, and a Website made of it, a profile whose posts are the feed's items (websites.md). Who may is WEBSITES_FROM, administrators unless the installation says otherwise.

Begin connecting a website

POST/websites/_connect

The site's feed is found: the address itself, or the feed the page names with <link rel="alternate">. It must be on the site's domain. The answer is the token, to be put in a TXT record or a file, with a name and a handle to begin with.

Who: Somebody signed in

Body application/json

  • site_urlstringrequired
    The site's address, example.com or https://example.com/blog/, or its feed's. At most 2000 characters.

Answers

  • 201
    Created
    syndication.Connection application/json
  • 400
    not_a_domain, no_feed, unreadable, feed_not_on_domain or private_feed (behind a login, or a secret in its address: a website is public), as error
  • 401
    the viewer is not signed in
  • 403
    the viewer may not connect a website: see WEBSITES_FROM
  • 409
    feed_taken: the feed already has a Website
  • 429
    the viewer has begun too many lately

Request

curl -X POST "https://api.example.org/websites/_connect" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "site_url": "https://example.org/"
  }'

Answer · 201

{
  "domain": "string",
  "feed_description": "string",
  "feed_title": "string",
  "feed_url": "https://example.org/",
  "file_url": "https://example.org/",
  "host": "string",
  "id": 42,
  "record_name": "string",
  "site_url": "https://example.org/",
  "suggested_alias": "string",
  "suggested_name": "string",
  "token": "string"
}

Make the Website

POST/websites/_connect/{id}

Once its domain is proved. Whoever proved it is its first administrator and its first follower; its feed's ten newest items are posted, the rest marked seen, and what is published afterwards is posted as it comes.

Who: Somebody signed in

Parameters

  • idintegerrequiredin path
    The connection's id. At least 1.

Body application/json

  • aliasstringrequired
    Its handle: @example. Letters, digits, - and _. At least 3 characters. At most 30 characters.
  • bodystring
    What it is, shown in its About card. At most 500 characters.
  • feed_urlstringrequired
    The feed, as starting the connection found it. At most 2000 characters.
  • namestringrequired
    Its name, shown as a profile's is. At most 64 characters.

Answers

  • 201
    Created
    syndication.Made application/json
  • 400
    no_feed, unreadable, feed_not_on_domain or private_feed, as error
  • 401
    the viewer is not signed in
  • 403
    the viewer may not connect a website: see WEBSITES_FROM
  • 404
    there is no such connection begun by the viewer
  • 409
    not_proved, feed_taken or handle_taken, as error

Request

curl -X POST "https://api.example.org/websites/_connect/<id>" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "alias": "string",
    "body": "string",
    "feed_url": "https://example.org/",
    "name": "string"
  }'

Answer · 201

{
  "alias": "string",
  "id": 42
}

Look for the token

POST/websites/_connect/{id}/check

In the TXT record at _anahita.<domain>, then in https://<host>/.well-known/anahita-verification.txt. Asked as often as the one connecting likes.

Who: Somebody signed in

Parameters

  • idintegerrequiredin path
    The connection's id, as starting it answered. At least 1.

Answers

  • 200
    OK
    syndication.Checked application/json
  • 400
    the request is not well formed, or a value in it is not one it may be
  • 401
    the viewer is not signed in
  • 403
    the viewer may not connect a website: see WEBSITES_FROM
  • 404
    there is no such connection begun by the viewer

Request

curl -X POST "https://api.example.org/websites/_connect/<id>/check" \
  -H "Authorization: Bearer $TOKEN"

Answer · 200

{
  "method": "string",
  "proved": false
}

A hub checks a subscription

GET/websites/_websub/{id}/{signature}

WebSub: the hub a Website's feed names asks whether its subscription was asked for here, and is answered with its challenge.

Who: Anyone, signed in or not

Parameters

  • idintegerrequiredin path
    The website's id, and the signature that came with it.
  • signaturestringrequiredin path
  • hub.modestringin query
    What the hub checks: subscribe, unsubscribe, or denied.
  • hub.challengestringin query
    What to answer with, to show the subscription was asked for here.
  • hub.lease_secondsintegerin query
    How long, in seconds, the hub will call back.

Answers

  • 200
    the challenge, as plain text
    string application/json
  • 400
    it is not a check this answers
  • 404
    there is no such Website, or no subscription was asked for

Request

curl "https://api.example.org/websites/_websub/<id>/<signature>"

Answer · 200

"string"

A hub says a feed changed

POST/websites/_websub/{id}/{signature}

The Website's feed is read from its site at once, at most once a minute; what the hub sends is not read.

Who: Anyone, signed in or not

Parameters

  • idintegerrequiredin path
    The website's id, and the signature that came with it.
  • signaturestringrequiredin path
  • hub.modestringin query
    What the hub checks: subscribe, unsubscribe, or denied.
  • hub.challengestringin query
    What to answer with, to show the subscription was asked for here.
  • hub.lease_secondsintegerin query
    How long, in seconds, the hub will call back.

Answers

  • 202
    it will be read
  • 404
    there is no such Website, or no subscription was asked for

Request

curl -X POST "https://api.example.org/websites/_websub/<id>/<signature>"

Written by Claude, reviewed by Rastin Mehr · About this