Documentation
Broadcast with blaastr
blaastr is a write-only nostr relay. Send it a signed event from a subscribed pubkey and it is published to every relay currently online (about a thousand, from profilestr), plus the author's own write relays. A subscription costs 21,000 sats per year and belongs to a pubkey: there are no API keys, and paying needs no sign-in.
Quick start
- Subscribe your npub on the home page.
- Add
wss://blaastr.comto your client's relay list (write enabled). - Post as usual. That's it.
Websocket relay
wss://blaastr.com speaks NIP-01. It accepts EVENT and answers every event with an OK. It stores nothing, so REQ is answered with CLOSED.
import { Relay } from "nostr-tools/relay";
import { finalizeEvent } from "nostr-tools/pure";
const relay = await Relay.connect("wss://blaastr.com");
const event = finalizeEvent(
{ kind: 1, created_at: Math.floor(Date.now() / 1000), tags: [], content: "hello, every relay" },
secretKey,
);
await relay.publish(event); // resolves on OK true, throws with the reason on OK false
relay.close();Raw protocol:
→ ["EVENT", {"id":"…","pubkey":"…","created_at":1761270000,"kind":1,"tags":[],"content":"hello","sig":"…"}]
← ["OK", "<event id>", true, ""]
→ ["REQ", "sub1", {"kinds":[1]}]
← ["CLOSED", "sub1", "unsupported: this relay is write-only"]Relay info (NIP-11): curl -H "Accept: application/nostr+json" https://blaastr.com
HTTP publish
For servers and scripts, POST /api/event takes the same ["EVENT", {…}] message and returns the OK message as JSON. No key is needed: the signature identifies the author, and CORS is open.
curl -X POST https://blaastr.com/api/event \
-H "Content-Type: application/json" \
-d '["EVENT", {"id":"…","pubkey":"…","created_at":1761270000,"kind":1,"tags":[],"content":"hello","sig":"…"}]'
# → ["OK","<event id>",true,""]const res = await fetch("https://blaastr.com/api/event", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(["EVENT", signedEvent]),
});
const [, id, ok, reason] = await res.json();
if (!ok) throw new Error(reason);Responses
The same OK messages come back over the websocket and HTTP. true means the event was queued; publishing to relays happens in the background, usually within seconds.
| Case | OK message |
|---|---|
| Accepted and queued | ["OK","<id>",true,""] |
| Already published (last 30 days) | ["OK","<id>",true,"duplicate: already published"] |
| Author not subscribed or expired | ["OK","<id>",false,"restricted: no active subscription for this pubkey, …"] |
| Bad id or signature | ["OK","<id>",false,"invalid: bad id or signature"] |
| Over 1 MB | ["OK","<id>",false,"invalid: event too large"] |
| Ephemeral kind (20000–29999) | ["OK","<id>",false,"blocked: ephemeral events are not broadcast"] |
| Disallowed kind (1064) | ["OK","<id>",false,"blocked: disallowed event kind"] |
| Scheduled (?publish_at=) | ["OK","<id>",true,"scheduled: <publish_at>"] |
| Over 30 events/min | ["OK","<id>",false,"rate-limited: …"] |
| Over 1,000 events/day | ["OK","<id>",false,"rate-limited: daily limit reached"] |
| Upstream outage | ["OK","<id>",false,"error: broadcast service unavailable, try again later"] |
Over HTTP, a body that isn't ["EVENT", {…}] gets a 400.
Scheduling
Add ?publish_at=<unix time> to POST /api/event or POST /api/events to send it later, up to 30 days ahead. A time in the past means right away. Date the event's created_at at the same time so clients show it then.
curl -X POST "https://blaastr.com/api/event?publish_at=1761300000" -H "Content-Type: application/json" -d '["EVENT", {…}]'
# → ["OK","<id>",true,"scheduled: 1761300000"]It counts toward the daily limit of the day you schedule it. Until it goes out you can follow or cancel it from your account; cancelling gives the limit back. A publish_at more than 30 days ahead gets a 400.
Batches
POST /api/events takes a JSON array of 1 to 50 signed events (bare events, not EVENT messages, up to 5 MB in all) and answers with one OK message per event, in the same order. Events can be from different authors; each gets the same checks as a single publish.
curl -X POST https://blaastr.com/api/events -H "Content-Type: application/json" -d '[{"id":"…","kind":1,…}, {"id":"…","kind":7,…}]'
# → [["OK","<id 1>",true,""], ["OK","<id 2>",false,"invalid: bad id or signature"]]Your account
Log in with a nostr extension (NIP-07) or a remote signer app (NIP-46) to manage your own key. You sign a one-time login message; your key never leaves your signer. From your account you can:
- See every broadcast from the last 7 days and what each relay said (accepted, rejected and why, no reply, unreachable).
- Reblast an event to the relays that haven't taken it, including ones that joined since. Reblasts count toward the daily limit.
- Schedule a note, and cancel scheduled events before they go out.
- See your usage per day and what's left of today's 1,000.
- Set a webhook to get a signed
POSTwhen each broadcast settles (broadcast.doneorbroadcast.incomplete).
The relays we publish to, and which are being skipped, are listed on Relays.
Subscription status
GET /api/subscription/:pubkey accepts an npub or hex key. It's public, so apps can check before offering blaastr to a user.
curl https://blaastr.com/api/subscription/npub1…
{
"pubkey": "82341f88…", // hex
"active": true,
"expiresAt": 1792800000, // unix seconds, null if never subscribed
"eventsSent": 412,
"lastEventAt": 1761270000 // null if none yet
}Paying from your app
You can take users through payment without leaving your app:
// 1. Create a one-year invoice for any pubkey
POST https://blaastr.com/api/invoice
{"pubkey": "npub1…"}
→ {"paymentHash":"…","pubkey":"…","bolt11":"lnbc…","amountSats":21000,"expiresAt":1761270900,"paid":false}
// 2. Pay bolt11 with any lightning wallet (WebLN, NWC, QR code…)
// 3. Poll until paid (every few seconds)
GET https://blaastr.com/api/invoice/<paymentHash>
→ {…, "paid": true}Asking for an invoice while an unpaid one for the same pubkey has more than 5 minutes left returns that one. Payments are credited even if nobody polls. Each payment adds a year to the time left.
Limits and rules
- Only events signed by a subscribed pubkey are broadcast. Anyone may submit them.
- 30 events per minute and 1,000 events plus reblasts per UTC day per pubkey.
- Events up to 1 MB. Many relays have their own, smaller limits and may reject large events.
- Ephemeral events (kinds 20000–29999, including NWC and AUTH) are not broadcast.
- The same event id is only broadcast once per 30 days.
- Relays that refuse our events (paid, auth-required, rate-limiting, unreachable) are skipped automatically, so “every relay” means every relay that accepts events from us.