Lnkbase Newsletter Docs

REST API reference

Base URL: https://hive.lnkbase.com/api/v2/publications/{pubId} or the shortcut /api/v2/publication. Authenticate with Authorization: Bearer <API key>. Lists return {data, next_cursor, has_more}. Rate limit 180 requests/minute per key. Machine-readable spec: openapi.json. Guide: API guide.

Publication

GET/Get the publication this key belongs to

Stats

GET/statsSummary: growth, engagement, revenue (plain-English summary included)
Query: days Period in days (default 30)
GET/stats/growthDaily subscriber growth and acquisition sources
Query: days Period in days (default 30)
GET/stats/earningsEarnings report: orders, MRR, network earnings
Query: days Period in days (default 30)

Subscriptions

GET/subscriptionsList subscribers (filter by status, tier, email, source, created range)
Query: limit Page size 1-100 (default 50) · cursor Opaque cursor from next_cursor · status active|pending|unsubscribed|bounced|complained · tier free|premium · source Acquisition source · email Email contains · tag Has tag · created_after ISO date · created_before ISO date
GET/subscriptions/:idGet a subscriber by id or email (includes tags and recent activity)
POST/subscriptionsCreate (or update) a subscriber — validated, double opt-in respected
Body: email string (required) · name string · utm_source string · utm_medium string · utm_campaign string · referral_code Referrer code · custom_fields object · tags string[] · list_ids string[] · tier free|premium · send_welcome_email boolean (default true) · reactivate_existing boolean · double_opt_override "on"|"off" (default: publication setting)
PATCH/subscriptions/:idUpdate a subscriber (name, tier, status, custom fields, tags)
Body: name string · email string · tier free|premium · status active|unsubscribed · custom_fields object (null value deletes a field) · add_tags string[] · remove_tags string[]
DELETE/subscriptions/:idPermanently delete a subscriber

Custom fields

GET/subscriptions/:id/custom_fieldsRead a subscriber's custom field values
PUT/subscriptions/:id/custom_fieldsWrite custom field values on a subscriber (merge; null deletes)
Body: custom_fields object {key: value}
GET/custom_fieldsList custom field definitions
POST/custom_fieldsCreate a custom field
Body: key string · label string · kind text|number|date|boolean|list · options string[] (for list)
PATCH/custom_fields/:idUpdate a custom field label/options
Body: label string · kind string · options string[]
DELETE/custom_fields/:idDelete a custom field definition

Tags

GET/subscriptions/:id/tagsList a subscriber's tags
POST/subscriptions/:id/tagsAdd tags to a subscriber
Body: tags string[]
DELETE/subscriptions/:id/tags/:tagRemove a tag from a subscriber
GET/tagsAll tags with subscriber counts

Referral program

GET/subscriptions/:id/referralsA subscriber's referral stats, referred readers and rewards earned
GET/referral_programRewards/milestones and program totals
GET/referral_program/leaderboardTop referrers
Query: limit 1-100

Subscriber intelligence

GET/subscriptions/:id/insightsValue score, lifetime value, purchase likelihood, churn risk and public signals for a subscriber
GET/insights/top_subscribersMost valuable subscribers (sort: value | clv | purchase | churn)
Query: sort value|clv|purchase|churn · limit 1-100
GET/insights/anomaliesUnusual changes in the last 24 hours vs the trailing 14 days (undismissed, last 7 days)
GET/insights/next_actionsSuggested next steps computed from your data, each with a dashboard link

Segments

GET/segmentsList segments
POST/segmentsCreate a segment from rules (dynamic or static)
Body: name string · description string · kind dynamic|static · rules RuleGroup {op, rules:[{field, cmp, value}]} — see /docs/api#segments
GET/segments/:idGet a segment
GET/segments/:id/subscribersList every subscriber in a segment (cursor paginated)
Query: limit 1-500 (default 100) · cursor next_cursor · status "all" to include inactive (dynamic segments)
POST/segments/:id/recalculateRecalculate a segment now
DELETE/segments/:idDelete a segment

Lists

GET/listsList newsletter lists with member counts
POST/lists/:id/subscribersAdd a subscriber (id or email) to a list
Body: subscriber_id string · email string
DELETE/lists/:id/subscribers/:sidRemove a subscriber from a list

Automations

POST/automationsCreate an automation (saved as a draft; activate=true publishes it and turns it on)
Body: name string · description string · allow_reentry boolean · trigger {type, config, filter?} — types: signup, confirmed, welcome, tag_added, field_updated, list_subscribed, upgraded, downgraded, purchase, event_registered, survey_submitted, poll_voted, email_opened, link_clicked, referral_milestone, segment_entered, date_field, inactive, api, external_purchase, cart_abandoned, webhook · triggers [{type, config, filter?}] — several entry points (subscribers enter when any matches); replaces trigger · steps [{id?, type, config, yes?, no?}] — types: send_email, delay, wait_until, condition, ab_split, add_tag, remove_tag, update_field, add_to_list, remove_from_list, webhook, enroll, grant_premium, notify, unsubscribe, exit; send_email config: {subject, markdown | doc | blocks} · template string — start from a template key (GET /automation_templates); trigger/steps override it · activate boolean
PATCH/automations/:idEdit an automation — trigger/steps go to the draft version; the live version keeps running until published
Body: name string · description string · allow_reentry boolean · trigger {type, config, filter?} — types: signup, confirmed, welcome, tag_added, field_updated, list_subscribed, upgraded, downgraded, purchase, event_registered, survey_submitted, poll_voted, email_opened, link_clicked, referral_milestone, segment_entered, date_field, inactive, api, external_purchase, cart_abandoned, webhook · triggers [{type, config, filter?}] — several entry points (subscribers enter when any matches); replaces trigger · steps [{id?, type, config, yes?, no?}] — types: send_email, delay, wait_until, condition, ab_split, add_tag, remove_tag, update_field, add_to_list, remove_from_list, webhook, enroll, grant_premium, notify, unsubscribe, exit; send_email config: {subject, markdown | doc | blocks}
POST/automations/:id/publishPublish the draft version (running journeys continue on the new version); activate=true also turns it on
Body: activate boolean (default false)
POST/automations/:id/pausePause an active automation (subscribers wait where they are)
POST/automations/:id/resumeResume a paused automation
GET/automationsList automations with journey counts
GET/automations/:idGet an automation with per-email stats
POST/automations/:id/journeysEnroll a subscriber (id or email) into an automation
Body: subscriber_id string · email string (created if new) · data object passed to the journey
GET/automations/:id/journeysList journeys (per-subscriber progress)
Query: limit Page size 1-100 (default 50) · cursor Opaque cursor from next_cursor
GET/automation_templatesList the automation templates library (use the key as `template` when creating an automation)
Query: category string
GET/automations/:id/webhookGet the secret incoming-webhook URL of an automation (POST JSON with an email to it to subscribe + enroll)

Posts

GET/postsList posts (filter by status; expand=stats includes engagement)
Query: limit Page size 1-100 (default 50) · cursor Opaque cursor from next_cursor · status draft|scheduled|published|archived · audience all|free|premium · expand stats,content
GET/posts/:idGet a post with content, stats (opens, clicks, engagement) and provider breakdown
GET/posts/:id/statsEngagement stats for a post (unique, bot-filtered)
GET/posts/:id/htmlRendered HTML: email vs web, free vs premium
Query: format email|web (default email) · audience free|premium (default free) · raw 1 = return text/html
POST/postsCreate a draft post (blocks, HTML, or Markdown; optionally from a template)
Body: title string · subtitle string · blocks Block[] (see Editor document) · html string (wrapped in an HTML block) · markdown string · template_id Start from this template (content is copied; its style stays linked) · email_subject string · preview_text string · platform email|web|both · audience all|free|premium · thumbnail_url string · seo object · segment_ids string[] · author_ids string[]
PATCH/posts/:idUpdate a post (replacing content creates a version)
Body: title string · subtitle string · blocks Block[] · html string · markdown string · email_subject string · preview_text string · slug string · platform string · audience string · seo object · segment_ids string[] · exclude_segment_ids string[] · ab_test object|null
POST/posts/:id/contentAppend or prepend content blocks
Body: position append|prepend (default append) · blocks Block[] · html string · markdown string
DELETE/posts/:idDelete a post
POST/subject-line/checkScore an email subject line (length, preview text, spam words, caps, emoji, personalization) with per-check advice
Body: subject string · preview_text string

Send API

POST/posts/:id/sendPublish/send now or schedule (targeting + subject A/B test)
Body: scheduled_at ISO datetime (omit to send now) · segment_ids string[] send to · exclude_segment_ids string[] · list_id string · audience all|free|premium · platform email|web|both · email_subject string · ab_test {subjects: string[2-5] | variants: [{subject?, preview_text?, from_name?, content: a|b}] (2-4), sample_pct, wait_minutes, metric: opens|clicks} · alt_markdown string — Variant B content for content tests · send_timing {mode: sto} (each subscriber at their usual open hour, within 24h) | {mode: timezone, local_time: "09:00"} | null
POST/posts/:id/unscheduleCancel a scheduled post (back to draft)
POST/posts/:id/testSend a test email (optionally as a simulated subscriber for merge tags)
Body: emails string[] (max 10) · subscriber_id Preview merge tags / dynamic content as this subscriber
GET/posts/:id/sendsSend history for a post

Templates

GET/templatesList templates (publication + built-in library)
Query: kind post|welcome|automation|website_page|website_section|website_block
GET/templates/:idGet a template with content and style tokens
POST/templates/codedCreate a custom-coded template from a full HTML email (sanitized; {{unsubscribe_url}} added when missing)
Body: name string · description string · html string (full HTML document or fragment; merge tags + {{unsubscribe_url}}, {{preferences_url}}, {{web_url}})

Snippets

GET/snippetsList reusable content snippets
GET/snippets/:idGet a snippet with its blocks. Insert `synced_block` into a post to keep it linked, or copy `content.blocks`
POST/snippetsCreate a snippet from editor blocks
Body: name string · description string · blocks Block[] (editor document blocks)
PATCH/snippets/:idUpdate a snippet (synced copies everywhere pick up the change)
Body: name string · description string · blocks Block[]
DELETE/snippets/:idDelete a snippet (synced references render nothing afterwards)

Commerce

GET/products/recommendationsPersonalized product recommendations for a subscriber (what the recommended_products block would show)
Query: subscriber_id Subscriber id (omit for bestsellers) · limit 1-6 (default 3)
GET/ordersList orders (subscriptions, products, tickets…)
Query: limit Page size 1-100 (default 50) · cursor Opaque cursor from next_cursor · kind subscription|product|ticket|gift|group|sponsorship|replay · status pending|paid|refunded|failed
GET/productsList digital products with sales totals

Tiers

GET/tiersList paid tiers
POST/tiersCreate a paid tier
Body: name string · description string · currency usd|eur|… · monthly_cents int · annual_cents int · trial_days int · paid_trial_cents int · benefits string[]
PATCH/tiers/:idUpdate a tier (status active|paused pauses/resumes sales)
Body: name string · monthly_cents int · annual_cents int · status active|paused · benefits string[]
DELETE/tiers/:idArchive a tier
GET/premium_subscriptionsList premium subscriptions
Query: limit Page size 1-100 (default 50) · cursor Opaque cursor from next_cursor · status trialing|active|paused|past_due|canceled
POST/subscriptions/:id/premiumGrant premium (comp) to a subscriber
Body: tier_id string (default: first active tier) · interval month|year · days int (omit for no expiry)
DELETE/subscriptions/:id/premiumCancel premium for a subscriber

Polls & surveys

GET/pollsList polls with vote totals
GET/polls/:idPoll results (live aggregate)
POST/pollsCreate a poll (or a trivia question) to embed in posts
Body: question string · options string[] (2-10) · purpose general|topic|product|pricing · kind standard|trivia · correct_option trivia: 1-based option index · explanation trivia: shown after voting
PATCH/polls/:idClose or reopen a poll
Body: closed boolean
GET/polls/:id/responsesIndividual poll votes tied to subscribers
Query: limit Page size 1-100 (default 50) · cursor Opaque cursor from next_cursor
GET/surveysList surveys with response counts
GET/surveys/:idSurvey with per-question aggregate results
POST/surveysCreate a survey
Body: title string · description string · questions [{label, kind: short|long|single|multi|dropdown|rating|nps|date, options?, required?}] · thank_you string · status active|closed
PATCH/surveys/:idUpdate a survey (title, description, thank-you message, status, questions)
Body: title string · description string · questions array (replaces all) · thank_you string · status active|closed
GET/surveys/:id/responsesIndividual survey responses
Query: limit Page size 1-100 (default 50) · cursor Opaque cursor from next_cursor

Webhooks

GET/webhooksList webhook endpoints
POST/webhooksCreate a webhook endpoint (returns the signing secret once)
Body: url string · events string[] (default ["*"]) · description string · version payload version (default: latest — see GET /webhooks/versions)
GET/webhooks/versionsAvailable payload versions with changelog
PATCH/webhooks/:idUpdate an endpoint (url, events, description, active, or upgrade/downgrade its payload version)
Body: url string · events string[] · description string · active boolean · version payload version
DELETE/webhooks/:idDelete a webhook endpoint
GET/webhooks/:id/deliveriesDelivery log for an endpoint (expand=attempts includes every attempt)
Query: limit Page size 1-100 (default 50) · cursor Opaque cursor from next_cursor · expand attempts
GET/webhooks/:id/deliveries/:didOne delivery: payload and every attempt (status code, response, latency)

Podcasts

GET/podcastsList podcast shows
GET/podcasts/:id/episodesList episodes with download counts
Query: limit Page size 1-100 (default 50) · cursor Opaque cursor from next_cursor

Transactional

POST/transactional/sendSend one transactional email (template or subject + html/markdown/text) with merge vars; idempotent with idempotency_key
Body: to Recipient email (required) · template_id Template id or slug · subject Subject (required without a template) · html HTML body · markdown Markdown body · text Plain-text body · merge_vars Object; {{key}} / {{nested.key}} in subject and body · reply_to Reply-To address · from_name Sender name override · attachments [{filename, content (base64), type}] — 5 MB total · tags string[] for searching the log · idempotency_key Repeat-safe key; a repeat returns the original message · track boolean — open/click tracking (default false)
GET/transactional/messagesSearch the transactional message log
Query: q Recipient, subject or message id · status sent|simulated|failed|suppressed|bounced|complained · tag Tag · limit 1-200 (default 50) · before ISO date: older than
GET/transactional/messages/:idOne transactional message with status, opens and clicks
GET/transactional/templatesList transactional templates
POST/transactional/templatesCreate or update (pass id) a transactional template
Body: id Existing template id (update) · name Name · slug template_id used in send calls · subject Subject with {{merge}} tags · body Markdown or HTML · format markdown|html