Monthly newsletter

Set up a publication, write a post in Markdown, test it, publish it on the web and email it to your subscribers.

Embed
Preview of the card
<a href="https://hermeticor.com/guides/newsletter"><img src="https://hermeticor.com/guides/_api/public/orgs/5fcd8b3c-a27c-4688-972f-de710125592f/spaces/9a3da731-ded5-4536-b84f-8c9a61420ff4/pages/4b6baba0-9643-4fb5-937a-c3b0a0a7454b/social-card.svg?v=3e7ae33eec8b" alt="Monthly newsletter" width="600" height="315"></a>

A publication is your newsletter: a public web archive plus an email to a subscriber list. Each issue is a post.

What you need first

  • A connected email provider (see Connect a sending provider).

  • A list of subscribers who gave marketing consent.

  • A key with newsletter:write.

1. Create the publication

curl -s -X POST "$BASE/v1/newsletter/publications" \
  -H "Authorization: Bearer $HERMETICA_API_KEY" -H "Content-Type: application/json" \
  -d '{"name":"Example Monthly","slug":"example-monthly","tagline":"What we shipped this month",
       "about":"One email a month from the Example Co team.","senderName":"Example Monthly",
       "route":{"connectionId":"<connectionId>"},"listId":"<listId>","language":"en","timezone":"America/New_York"}'

Add who writes it and how issues are grouped:

curl -s -X POST "$BASE/v1/newsletter/publications/<publicationId>/authors" \
  -H "Authorization: Bearer $HERMETICA_API_KEY" -H "Content-Type: application/json" \
  -d '{"name":"The Example Co team"}'
curl -s -X POST "$BASE/v1/newsletter/publications/<publicationId>/sections" \
  -H "Authorization: Bearer $HERMETICA_API_KEY" -H "Content-Type: application/json" \
  -d '{"name":"Releases","slug":"releases"}'

2. Write a post

curl -s -X POST "$BASE/v1/newsletter/posts" \
  -H "Authorization: Bearer $HERMETICA_API_KEY" -H "Content-Type: application/json" \
  -d '{"publicationId":"<publicationId>","title":"November 2026: what is new","slug":"november-2026",
       "markdown":"## Bring your own provider\n\nYou can now send through...","sectionIds":["<sectionId>"],
       "audience":{"kind":"everyone"},"delivery":"both"}'

delivery is both (web and email), web or email.

3. Check it

curl -s -X POST "$BASE/v1/newsletter/posts/<postId>/preview" \
  -H "Authorization: Bearer $HERMETICA_API_KEY" -H "Content-Type: application/json" -d '{}'
curl -s -X POST "$BASE/v1/newsletter/posts/<postId>/test-send" \
  -H "Authorization: Bearer $HERMETICA_API_KEY" -H "Content-Type: application/json" \
  -d '{"emails":["you@example.com"]}'

4. Publish on the web

curl -s -X POST "$BASE/v1/newsletter/posts/<postId>/publish" \
  -H "Authorization: Bearer $HERMETICA_API_KEY" -H "Content-Type: application/json" -d '{}'

The archive is at $BASE/p/n/<workspaceId>.example-monthly, and the post at .../p/november-2026.

5. Email it

curl -s -X POST "$BASE/v1/newsletter/posts/<postId>/email" \
  -H "Authorization: Bearer $HERMETICA_API_KEY" -H "Content-Type: application/json" \
  -d '{"subject":"November: bring your own provider","subjectB":"What we shipped in November",
       "previewText":"Three releases and a webinar.","mode":"draft"}'

This creates a marketing campaign and returns its id, so the usual checks apply: consent, suppression, the unsubscribe link and the postal address in the footer.

  • mode: "draft" lets you review the campaign first. "now" sends it; "schedule" sends it later.

  • With subjectB, a fifth of the list tests both subjects and the winner goes to the rest.

Grow it

  • Sign-up box and pop-up: PUT /v1/newsletter/growth/surfaces/<publicationId> {"listId":"<listId>","enabled":true,"headline":"Get the monthly email","consentText":"One email a month. Unsubscribe any time.","popup":{"mode":"slide_in","delaySeconds":20}}.

  • Referrals: PUT /v1/newsletter/growth/referrals/<publicationId> {"enabled":true,"cookieDays":30}, then rewards with POST /v1/newsletter/growth/referrals/<publicationId>/milestones {"threshold":3,"rewardKind":"merch","rewardLabel":"Sticker pack"}.

  • Results: GET /v1/newsletter/growth/dashboard/<publicationId>.

Comments, reactions and polls

curl -s -X PUT "$BASE/v1/newsletter/engagement/settings?publicationId=<publicationId>" \
  -H "Authorization: Bearer $HERMETICA_API_KEY" -H "Content-Type: application/json" \
  -d '{"commentsMode":"everyone","moderation":"first","holdLinks":true,"reactionsEnabled":true,
       "reactionSet":["πŸ‘","πŸŽ‰"],"maxPerHour":10,"minSecondsBetween":30}'

moderation: "first" holds each reader's first comment for review.

A poll in a post:

curl -s -X POST "$BASE/v1/newsletter/engagement/surveys" \
  -H "Authorization: Bearer $HERMETICA_API_KEY" -H "Content-Type: application/json" \
  -d '{"kind":"poll","publicationId":"<publicationId>","postId":"<postId>","title":"What should we build next?",
       "questions":[{"prompt":"Pick one","kind":"single","options":[
         {"id":"goals","label":"Goals"},{"id":"sms","label":"More SMS"}]}]}'

An option can be a plain label ("options":["Goals","More SMS"]) or { "id", "label" }. Without an id the option gets o1, o2, and so on; give your own id (lowercase letters, digits, - or _) when you want to read results by a stable name.

Next: Events, SMS keywords and other extras.

Updated