raresats.net API
Chat & profiles API View as Markdown

Display names

An address may take a display name, which the site shows wherever it shows that address (the address stays on hover, and links still go to the address page). The rules and the message to sign: Chat & profiles guide.

Set a display name #

POST/api/profile

Sets (or, with an empty name, clears) an address's display name. Every change needs its own BIP-322 signature by the address of raresats.net profile <address> display_name=<name> <unix seconds>, at most 10 minutes old and usable once; a chat session is not enough. 3-24 characters of letters, digits, spaces and _ . -; unique; no address-like or reserved names; at most one change in 24 hours. A banned address may not set one; the hourly cap is 10 changes per IPv4 address or IPv6 /64. Where the AI moderation is on, a new name is checked last, before it is taken (names show site-wide): refused, 422 moderated; not checked, 503 moderation_unavailable (the signed message is not used up: send it again).

Request body #

content-type: application/json

FieldTypeRequiredDescription
addressstringyesThe address whose name it is.
display_namestring | nullyesThe new name, trimmed with spaces collapsed; empty or null clears it.
messagestringyesraresats.net profile <address> display_name=<name> <unix seconds>, the name exactly as set, at most 10 minutes old.
signaturestringyesBIP-322 signature of message by address.

Example request #

cURL
curl -X POST 'https://raresats.net/api/profile' \
  -H 'content-type: application/json' \
  -d '{
  "address": "bc1p4qhjn9zdvkux4e44uhx8tc55attvtyu358kutcqkudyccelu0was9fqzwh",
  "display_name": "Rare Hunter",
  "message": "raresats.net profile bc1p4qhjn9zdvkux4e44uhx8tc55attvtyu358kutcqkudyccelu0was9fqzwh display_name=Rare Hunter 1790949400",
  "signature": "AUBGQvdc2H+7HTo1njZ1vlDxoX6ncoehAGbaHcAY1FtfSNg7lmo8Ih3WGInhAH/snOUIb8DkwRSQxc2dOu911Z9E"
}'
JavaScript
const response = await fetch('https://raresats.net/api/profile', {
  method: 'POST',
  headers: { 'content-type': 'application/json' },
  body: JSON.stringify({
    "address": "bc1p4qhjn9zdvkux4e44uhx8tc55attvtyu358kutcqkudyccelu0was9fqzwh",
    "display_name": "Rare Hunter",
    "message": "raresats.net profile bc1p4qhjn9zdvkux4e44uhx8tc55attvtyu358kutcqkudyccelu0was9fqzwh display_name=Rare Hunter 1790949400",
    "signature": "AUBGQvdc2H+7HTo1njZ1vlDxoX6ncoehAGbaHcAY1FtfSNg7lmo8Ih3WGInhAH/snOUIb8DkwRSQxc2dOu911Z9E"
  })
});
const data = await response.json();
Python
import requests

data = requests.post("https://raresats.net/api/profile", json={
    "address": "bc1p4qhjn9zdvkux4e44uhx8tc55attvtyu358kutcqkudyccelu0was9fqzwh",
    "display_name": "Rare Hunter",
    "message": "raresats.net profile bc1p4qhjn9zdvkux4e44uhx8tc55attvtyu358kutcqkudyccelu0was9fqzwh display_name=Rare Hunter 1790949400",
    "signature": "AUBGQvdc2H+7HTo1njZ1vlDxoX6ncoehAGbaHcAY1FtfSNg7lmo8Ih3WGInhAH/snOUIb8DkwRSQxc2dOu911Z9E"
}).json()

Response 200 #

FieldTypeDescription
profileobject
profile.addressstring
profile.display_namestring | nullThe display name, null when it has none.
profile.adminbooleanThe address is a chat admin.
profile.changed_atinteger | nullWhen the name last changed, unix seconds.
profile.next_change_atinteger | nullWhen it may change again, unix seconds.
profile.server_timeintegerThe server's clock, unix seconds: date the profile message by it.

Errors #

{error, code}; see Errors for every code.

StatusCodeMeaning
400bad_addressAn address is not a mainnet address (or not one at all).
400bad_jsonThe body is not valid JSON.
400bad_messageThe cancel message is not raresats.net cancel <ids> <unix seconds> or names other listings than ids; or the registration message is not raresats.net affiliate <address> <unix seconds> for address.
400bad_requestThe body is not a JSON object, or the engine refused a malformed request (e.g. a purchase submitted without its signed setup PSBT).
400, 422bad_signature400: signature is missing or too long. 422: a signature does not verify (cancel or registration message, listing or purchase input).
403bannedThe address is banned from chat: it may not post or set a display name.
403cross_originA POST from a browser on another site (a foreign Origin, or sec-fetch-site: cross-site). Server-side clients send no Origin and are not affected.
403mutedThe address is muted (by the AI moderation after repeated refusals: 3 in 10 minutes), or its network (an IPv4 address or IPv6 /48) is paused after 6 refusals within an hour, until until, unix seconds: it may not post or set a display name until then.
404chat_disabledChat and display names are off on this server.
405method_not_allowedWrong method for the route; the allow header lists the right ones.
409name_takenAnother address has that display name (compared without case, separators or look-alike digits), gave it up less than 7 days ago, or it was removed by a moderator and is never given out again.
409replayedThat cancel or registration message was used already.
409unchangedThat is already the display name.
413too_largeThe body is over 256 KiB.
415not_jsonA POST without content-type: application/json.
422future_messageThe cancel or registration message is dated more than 2 minutes ahead: check the clock.
422moderatedThe AI moderation refused the chat message or display name; category says why (the message is not posted, the name not taken). Three refusals in 10 minutes mute the address for an hour (until).
422name_addressA display name must not look like an address (bc1…, base58) or a hash.
422name_charsA display name uses only letters, digits, spaces and _ . -, and starts and ends with a letter or digit.
422name_lengthA display name is 3 to 24 characters.
422name_reservedThe display name is reserved (raresats, admin, moderator, support, official, satoshi and the like).
422stale_messageThe cancel or registration message is more than 10 minutes old: sign a new one.
429chat_busyToo many chat messages and names are being checked across the site right now (over the global cap of model calls a minute); wait retry-after seconds.
429name_change_too_soonA display name changes at most once in 24 hours; next_change_at says when.
429rate_limitedOver 30 POSTs a minute from your IPv4 address or IPv6 /64 (in chat, counted per IPv4 address or IPv6 /64: 30 writes and 20 login nonces a minute, 20 sign-ins and 10 display-name changes an hour; one message every 3 s and 20 a minute per address); wait retry-after seconds. With the AI moderation on, at most 6 messages and names a minute are checked per address and per IPv4 address or IPv6 /48.
503moderation_unavailableThe AI moderation could not check the text right now (timeout or model error): nothing was posted. Try again in a moment.
Error (503)
{
  "error": "Couldn't check your display name right now: try again in a moment",
  "code": "moderation_unavailable"
}

Get a profile #

GET/api/profile/{address}

An address's display name (null when it has none), whether it is a chat admin, and when its name may change next.

Path parameters #

ParameterTypeRequiredDescription
addressstringyesA mainnet address.

Example request #

cURL
curl 'https://raresats.net/api/profile/bc1p4qhjn9zdvkux4e44uhx8tc55attvtyu358kutcqkudyccelu0was9fqzwh'
JavaScript
const response = await fetch('https://raresats.net/api/profile/bc1p4qhjn9zdvkux4e44uhx8tc55attvtyu358kutcqkudyccelu0was9fqzwh');
const data = await response.json();
Python
import requests

data = requests.get("https://raresats.net/api/profile/bc1p4qhjn9zdvkux4e44uhx8tc55attvtyu358kutcqkudyccelu0was9fqzwh").json()

Response 200 #

FieldTypeDescription
addressstring
display_namestring | nullThe display name, null when it has none.
adminbooleanThe address is a chat admin.
changed_atinteger | nullWhen the name last changed, unix seconds.
next_change_atinteger | nullWhen it may change again, unix seconds.
server_timeintegerThe server's clock, unix seconds: date the profile message by it.

Errors #

{error, code}; see Errors for every code.

StatusCodeMeaning
400bad_addressAn address is not a mainnet address (or not one at all).
400bad_pathThe path is not valid percent-encoding.
404chat_disabledChat and display names are off on this server.
405method_not_allowedWrong method for the route; the allow header lists the right ones.

Get display names #

GET/api/profiles

The display names of up to 200 addresses at once; addresses without one (or that are no address) are left out. Cached 15 s.

Query parameters #

ParameterTypeRequiredDescription
addressesstringyesComma-separated addresses, at most 200.

Example request #

cURL
curl 'https://raresats.net/api/profiles?addresses=bc1p4qhjn9zdvkux4e44uhx8tc55attvtyu358kutcqkudyccelu0was9fqzwh,bc1qm34lsc65zpw79lxes69zkqmk6ee3ewf0j77s3h'
JavaScript
const response = await fetch('https://raresats.net/api/profiles?addresses=bc1p4qhjn9zdvkux4e44uhx8tc55attvtyu358kutcqkudyccelu0was9fqzwh,bc1qm34lsc65zpw79lxes69zkqmk6ee3ewf0j77s3h');
const data = await response.json();
Python
import requests

data = requests.get("https://raresats.net/api/profiles", params={"addresses": "bc1p4qhjn9zdvkux4e44uhx8tc55attvtyu358kutcqkudyccelu0was9fqzwh,bc1qm34lsc65zpw79lxes69zkqmk6ee3ewf0j77s3h"}).json()

Response 200 #

FieldTypeDescription
profilesmap of stringaddress → display name, for the addresses that have one.
Response
{
  "profiles": {
    "bc1p4qhjn9zdvkux4e44uhx8tc55attvtyu358kutcqkudyccelu0was9fqzwh": "Rare Hunter"
  }
}

Errors #

{error, code}; see Errors for every code.

StatusCodeMeaning
400bad_addressesaddresses must list 1 to 200 addresses.
404chat_disabledChat and display names are off on this server.
405method_not_allowedWrong method for the route; the allow header lists the right ones.

Remove a display name (admin) #

DELETE/api/profile/{address}

An admin session removes an address's display name. The name is never given out again, to anyone. Pages are told with a profile event. Logged.

Path parameters #

ParameterTypeRequiredDescription
addressstringyesA mainnet address.

Example request #

cURL
curl -X DELETE 'https://raresats.net/api/profile/bc1p4qhjn9zdvkux4e44uhx8tc55attvtyu358kutcqkudyccelu0was9fqzwh' -H 'cookie: __Host-rs_chat=<token>'
JavaScript
const response = await fetch('https://raresats.net/api/profile/bc1p4qhjn9zdvkux4e44uhx8tc55attvtyu358kutcqkudyccelu0was9fqzwh', { method: 'DELETE', credentials: 'include' });
const data = await response.json();

Response 200 #

FieldTypeDescription
profileobject
profile.addressstring
profile.display_namestring | nullThe display name, null when it has none.
profile.adminbooleanThe address is a chat admin.
profile.changed_atinteger | nullWhen the name last changed, unix seconds.
profile.next_change_atinteger | nullWhen it may change again, unix seconds.
profile.server_timeintegerThe server's clock, unix seconds: date the profile message by it.
removedstringThe name removed.

Errors #

{error, code}; see Errors for every code.

StatusCodeMeaning
400bad_addressAn address is not a mainnet address (or not one at all).
400bad_pathThe path is not valid percent-encoding.
401no_sessionNo chat session: sign in (POST /api/session) and send its cookie.
403cross_originA POST from a browser on another site (a foreign Origin, or sec-fetch-site: cross-site). Server-side clients send no Origin and are not affected.
403not_adminOnly a chat admin (SUPPLY_CHAT_ADMINS) may do that.
404chat_disabledChat and display names are off on this server.
404not_foundNo such listing or offer. In chat: no such message. A display name to remove that does not exist.
405method_not_allowedWrong method for the route; the allow header lists the right ones.
429rate_limitedOver 30 POSTs a minute from your IPv4 address or IPv6 /64 (in chat, counted per IPv4 address or IPv6 /64: 30 writes and 20 login nonces a minute, 20 sign-ins and 10 display-name changes an hour; one message every 3 s and 20 a minute per address); wait retry-after seconds. With the AI moderation on, at most 6 messages and names a minute are checked per address and per IPv4 address or IPv6 /48.