GET /v1/me
Who am I
The workspace and key this request authenticated as. Use it to test a key.
Any key
curl -X GET https://app.noosletter.com/v1/me \ -H "Authorization: Bearer $NOOS_API_KEY"
Invite subscribers from your own systems, write and send emails, and hear about changes as they happen. Everything is scoped to one workspace and follows the same rules as the app. The API does not return who opened, clicked or visited.
Create a key in Settings → Developers. A read key can only read; a read and write key can also change things and send. Older Subscribers & tags keys still work: they can create, update and tag subscribers, and look up one by id or email, but nothing else. Keep keys on your server. Send the key as a bearer token:
curl https://app.noosletter.com/v1/newsletters \ -H "Authorization: Bearer $NOOS_API_KEY"
{ "data": … }, or { "error": { "type", "message" } }.limit (up to 100) and the next_cursor you were given.429 with a Retry-After header.Idempotency-Key header. Repeat it within 24 hours and you get the first response back instead of a second subscriber or a second send.| 400 invalid_request | Something in the request isn't right. The message says what. |
| 401 unauthorized | The key is missing, wrong or revoked. |
| 403 forbidden | A read key tried to change something. |
| 404 not_found | It doesn't exist in this workspace. |
| 409 | It conflicts with how things are, e.g. already_sent, already_exists, unsubscribed_by_reader. |
| 422 | It can't be done as asked, e.g. invalid_email, blocked, not_ready, no_recipients. |
| 429 rate_limited | Slow down; see Retry-After. |
GET /v1/me
Who am I
The workspace and key this request authenticated as. Use it to test a key.
Any key
curl -X GET https://app.noosletter.com/v1/me \ -H "Authorization: Bearer $NOOS_API_KEY"
GET /v1/subscribers
List subscribers
Newest first.
Any key -- a Subscribers & tags key can only use ?email, not list or export
limit 1 to 100, default 25cursor The next_cursor from the previous pageemail Find one address -- the only way a free-tier Subscribers & tags key may call this endpoint (without it, 403)newsletter_id Only subscribers of this newsletterstatus With newsletter_id: subscribed (default) or unsubscribedcurl -X GET https://app.noosletter.com/v1/subscribers \ -H "Authorization: Bearer $NOOS_API_KEY"
POST /v1/subscribers
Invite someone to subscribe
Nobody is added directly. This runs your Blocklist and address verification (an address that can't receive email is refused), then emails an invite for each newsletter in newsletter_ids. The person becomes a subscriber only when they accept it, and invites expire after 30 days. Someone who left a newsletter can't be invited back to it. Names, tags and fields aren't accepted: the subscriber fills in their own profile.
Read and write key, or a Subscribers & tags key · accepts Idempotency-Key
email string, requiredfirst_name stringlast_name stringnewsletter_ids array of string. Invite them to these newsletters. They are subscribed only when they accept the invite email.consent object. Contains consent.basis.tag_ids array of stringcurl -X POST https://app.noosletter.com/v1/subscribers \
-H "Authorization: Bearer $NOOS_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"email":"ada@example.com","first_name":"Ada","newsletter_ids":["NEWSLETTER_ID"],"consent":{"basis":"Ticked the box at checkout"}}'GET /v1/subscribers/{id}
Get a subscriber
Any key
curl -X GET https://app.noosletter.com/v1/subscribers/ID \ -H "Authorization: Bearer $NOOS_API_KEY"
PATCH /v1/subscribers/{id}
Update a subscriber's name
Read and write key, or a Subscribers & tags key
first_name objectlast_name objectcurl -X PATCH https://app.noosletter.com/v1/subscribers/ID \
-H "Authorization: Bearer $NOOS_API_KEY" \
-H "Content-Type: application/json" \
-d '{"first_name":"Ada"}'POST /v1/subscribers/{id}/subscriptions
Invite a subscriber to another newsletter
Sends them an invite to this newsletter; they are subscribed only when they accept. Someone who left it can't be invited back (blocked).
Read and write key · accepts Idempotency-Key
newsletter_id string, requiredconsent object. Contains consent.basis.curl -X POST https://app.noosletter.com/v1/subscribers/ID/subscriptions \
-H "Authorization: Bearer $NOOS_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"newsletter_id":"NEWSLETTER_ID","consent":{"basis":"Asked at our event"}}'DELETE /v1/subscribers/{id}/subscriptions/{newsletter_id}
Unsubscribe from a newsletter
Read and write key
curl -X DELETE https://app.noosletter.com/v1/subscribers/ID/subscriptions/NEWSLETTER_ID \ -H "Authorization: Bearer $NOOS_API_KEY"
POST /v1/subscribers/{id}/tags
Tag a subscriber
Read and write key, or a Subscribers & tags key
tag_id string, requiredcurl -X POST https://app.noosletter.com/v1/subscribers/ID/tags \
-H "Authorization: Bearer $NOOS_API_KEY" \
-H "Content-Type: application/json" \
-d '{"tag_id":"TAG_ID"}'DELETE /v1/subscribers/{id}/tags/{tag_id}
Remove a tag
Read and write key, or a Subscribers & tags key
curl -X DELETE https://app.noosletter.com/v1/subscribers/ID/tags/TAG_ID \ -H "Authorization: Bearer $NOOS_API_KEY"
GET /v1/stats/growth
Subscriber growth
New subscribers and unsubscribes this week (from Monday) and this month (from the 1st), on UK calendar days, and the current total. Totals only.
Read, or read and write key
newsletter_id Only this newslettercurl -X GET https://app.noosletter.com/v1/stats/growth \ -H "Authorization: Bearer $NOOS_API_KEY"
GET /v1/forms
List forms
Read, or read and write key
curl -X GET https://app.noosletter.com/v1/forms \ -H "Authorization: Bearer $NOOS_API_KEY"
GET /v1/forms/{id}
Get a form
Read, or read and write key
curl -X GET https://app.noosletter.com/v1/forms/ID \ -H "Authorization: Bearer $NOOS_API_KEY"
GET /v1/segments
List segments
Read, or read and write key
curl -X GET https://app.noosletter.com/v1/segments \ -H "Authorization: Bearer $NOOS_API_KEY"
GET /v1/segments/{id}
Get a segment and how many people are in it
Read, or read and write key
curl -X GET https://app.noosletter.com/v1/segments/ID \ -H "Authorization: Bearer $NOOS_API_KEY"
GET /v1/emails
List emails
Read, or read and write key
limit 1 to 100, default 25cursor The next_cursor from the previous pagestatus draft, scheduled, sending, sent, failed, cancelled or held_for_reviewcurl -X GET https://app.noosletter.com/v1/emails \ -H "Authorization: Bearer $NOOS_API_KEY"
POST /v1/emails
Create a draft
Written in Markdown, the same as the editor. It's sent from your default verified sender.
Read and write key · accepts Idempotency-Key
newsletter_id string. Needed when the account has more than one newslettername string. Defaults to the subjectsubject stringpreview_text objectbody_markdown string. The email, in Markdowncurl -X POST https://app.noosletter.com/v1/emails \
-H "Authorization: Bearer $NOOS_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"subject":"This week","body_markdown":"# Hello\n\nIt's been a busy week."}'GET /v1/emails/{id}
Get an email
Read, or read and write key
curl -X GET https://app.noosletter.com/v1/emails/ID \ -H "Authorization: Bearer $NOOS_API_KEY"
PATCH /v1/emails/{id}
Edit a draft
Read and write key
name stringnewsletter_id stringsubject stringpreview_text objectbody_markdown stringcurl -X PATCH https://app.noosletter.com/v1/emails/ID \
-H "Authorization: Bearer $NOOS_API_KEY" \
-H "Content-Type: application/json" \
-d '{"subject":"This week, properly"}'POST /v1/emails/{id}/schedule
Schedule
Checks there's a subject, a body, a verified sender and your postal address first.
Read and write key · accepts Idempotency-Key
send_at string, required. When to send, ISO 8601 with a time zone offsettimezone string. IANA time zone to show it in, e.g. Europe/London. Defaults to the account's.curl -X POST https://app.noosletter.com/v1/emails/ID/schedule \
-H "Authorization: Bearer $NOOS_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"send_at":"2026-10-02T08:00:00+01:00"}'POST /v1/emails/{id}/cancel
Cancel a schedule
It goes back to being a draft.
Read and write key
curl -X POST https://app.noosletter.com/v1/emails/ID/cancel \ -H "Authorization: Bearer $NOOS_API_KEY"
POST /v1/emails/{id}/send
Send now
Sends to everyone subscribed to the email's newsletter who can receive it. Pass an Idempotency-Key so a retry can never send twice; without one, a second send is refused.
Read and write key · accepts Idempotency-Key
curl -X POST https://app.noosletter.com/v1/emails/ID/send \ -H "Authorization: Bearer $NOOS_API_KEY" \ -H "Idempotency-Key: $(uuidgen)"
GET /v1/emails/{id}/stats
Stats
Per-email totals. The API does not return who opened or clicked.
Read, or read and write key
curl -X GET https://app.noosletter.com/v1/emails/ID/stats \ -H "Authorization: Bearer $NOOS_API_KEY"
POST /v1/emails/{id}/test
Send a test to yourself
Sends a test of the email to the person the key belongs to, and nobody else. A test never counts towards a sending limit. A key that isn't tied to a person gets 422 no_person.
Read and write key
curl -X POST https://app.noosletter.com/v1/emails/ID/test \ -H "Authorization: Bearer $NOOS_API_KEY"
GET /v1/emails/{id}/recipients
Recipient count
How many subscribers would get this email if it went out now, after every sendability check. A count only.
Read, or read and write key
curl -X GET https://app.noosletter.com/v1/emails/ID/recipients \ -H "Authorization: Bearer $NOOS_API_KEY"
GET /v1/stats/top-emails
Top emails
Your best-performing recent sent emails (the latest 200), by unique opens or clickers. Totals only.
Read, or read and write key
by opens (default) or clickslimit 1 to 20, default 5newsletter_id Only this newsletter's emailscurl -X GET https://app.noosletter.com/v1/stats/top-emails \ -H "Authorization: Bearer $NOOS_API_KEY"
GET /v1/automations
List automation rules
Read-only. Comes with Pro (upgrade a newsletter to Pro to use it). There's no way to create or edit a rule through the API yet.
Read, or read and write key
curl -X GET https://app.noosletter.com/v1/automations \ -H "Authorization: Bearer $NOOS_API_KEY"
GET /v1/automations/{id}
Get an automation rule
Read-only, for the same reason as the list endpoint.
Read, or read and write key
curl -X GET https://app.noosletter.com/v1/automations/ID \ -H "Authorization: Bearer $NOOS_API_KEY"
POST /v1/automations/{id}/run
Run an automation
Runs a rule that starts with "Run on selected subscribers" for people who are already your subscribers, the same as "Run automation…" on the Subscribers page. The rule must be on. It never subscribes anyone, and each email step still checks the person can be emailed.
Read and write key · accepts Idempotency-Key
subscriber_ids array of stringemail stringcurl -X POST https://app.noosletter.com/v1/automations/ID/run \
-H "Authorization: Bearer $NOOS_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"email":"ada@example.com"}'GET /v1/webhooks
List this key's webhooks
Only the endpoints this key added. Ones added in Settings → Developers aren't listed.
Read, or read and write key
curl -X GET https://app.noosletter.com/v1/webhooks \ -H "Authorization: Bearer $NOOS_API_KEY"
POST /v1/webhooks
Add a webhook
Sends the chosen events to an https address, signed like every Noosletter webhook. Zapier calls this when a Zap is turned on. A read key can add one: webhooks carry nothing a read key can't already read. API keys can add up to 100 between them, separate from the 10 in Settings. Revoking the key removes every webhook it added.
Read, or read and write key · accepts Idempotency-Key
url string, required. An https:// address on the public internetevents array of string, requiredcurl -X POST https://app.noosletter.com/v1/webhooks \
-H "Authorization: Bearer $NOOS_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"url":"https://hooks.example.com/noosletter","events":["subscriber.created","subscriber.level_changed"]}'DELETE /v1/webhooks/{id}
Remove a webhook
Only one this key added. Zapier calls this when a Zap is turned off.
Read, or read and write key
curl -X DELETE https://app.noosletter.com/v1/webhooks/ID \ -H "Authorization: Bearer $NOOS_API_KEY"
Add an https endpoint in Settings → Developers, or with POST /v1/webhooks (see Webhook endpoints), and choose its events. We POST a JSON body like this, signed with the endpoint's secret:
{
"id": "delivery id",
"type": "subscriber.created",
"created_at": "2026-09-26T09:14:03.120Z",
"data": {
"subscriber": { "id": "…", "email": "ada@example.com", "first_name": "Ada", "last_name": null },
"newsletter": { "id": "…", "name": "The Friday Letter" },
"source": "hosted_form",
"occurred_at": "2026-09-26T09:14:03.100Z"
}
}Events:
subscriber.createdsubscription.createdsubscriber.resubscribedsubscriber.unsubscribedemail.scheduledemail.sentform.submittedsubscriber.invitedsubscriber.level_changedreferral.joinedcomment.createdsubscriber.created is a new subscriber: someone with no active subscription to any of your newsletters before. Someone already subscribed who joins another of your newsletters is subscription.created.
form.submitted fires on every accepted submission. Before confirmation, for anyone who isn't already a signed-in reader. With a form object (id, name) and a submission object (email, first_name, last_name, utm_source, utm_medium, utm_campaign) in place of subscriber/newsletter.
subscriber.invited fires when someone is invited (someone signing themselves up counts only once they confirm, assubscriber.created), with an invite object (email, method, expires_at). subscriber.level_changed carries level and previous_level (number and the newsletter's name for it) and a direction of up or down. referral.joined names the subscriber whose invite link was used and the referred person. comment.created carries the comment, the email it's on, and the subscriber, or null if the commenter isn't one of yours.
There are no open or click events, and no payload says who opened or clicked. Answer with any 2xx within 10 seconds. Anything else is retried after 1 min, 5 min, 30 min, 2 h, 6 h, 12 h, 24 h, then marked failed; you can retry it from the delivery log. Redirects aren't followed.
Check each request came from us with the Noosletter-Signature header (t= time, v1= HMAC-SHA256 of <t>.<raw body>):
import crypto from "node:crypto";
// header: the Noosletter-Signature header, e.g. "t=1760000000,v1=5f2c…"
// body: the raw request body, exactly as received
export function isFromNoosletter(secret, body, header) {
const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
if (Math.abs(Date.now() / 1000 - Number(parts.t)) > 300) return false; // older than 5 minutes
const expected = crypto.createHmac("sha256", secret).update(`${parts.t}.${body}`).digest("hex");
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1 ?? ""));
}noos wraps the API for scripts and quick jobs. It has no logic of its own.
npm install -g @noosletter/cli export NOOS_API_KEY=noos_… noos newsletters noos subscribers add ada@example.com --newsletter NEWSLETTER_ID --consent "Asked at our event" noos emails create --subject "This week" --file issue.md noos emails send EMAIL_ID --yes noos stats EMAIL_ID