Skip to main content

REST API v1

Everything the app can do, as an endpoint.

Manage contacts, build and send campaigns, read reporting, subscribe to webhooks, and call the AI copy tools, from your own systems.

Base URL

https://launch.email/api/v1

Authentication

Authorization: Bearer <your-api-key>

Or the X-Api-Key header. API access is on the Business plan; generate a key in Settings.

Your first call

Confirm the credential works and see what it can reach:

curl https://launch.email/api/v1/me \
  -H "Authorization: Bearer $TWEAK_API_KEY"

Add a contact. The write is an upsert on email address, so re-running it is safe:

curl -X POST https://launch.email/api/v1/contacts \
  -H "Authorization: Bearer $TWEAK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"email":"jane@example.com","first_name":"Jane","tag_ids":[3]}'

A contact who has already unsubscribed keeps that status no matter what you send, so a full-address-book re-sync can never quietly resubscribe someone.

Contacts

Contacts, lists, tags, and saved segments. Upserts key on email address, so a sync job never needs to hold our ids.

GET /contacts List contacts. Filter by status, tag, list, segment, or modification time
POST /contacts Create or upsert by email
POST /contacts/bulk Upsert up to 1,000 at once
GET /contacts/{id|email} Fetch by id or email address
PATCH /contacts/{id|email} Update fields, status, tags, or list membership
DELETE /contacts/{id|email} Soft delete
POST /contacts/{id}/tags Add tags, firing tag-triggered sequences
POST /contacts/{id}/erase GDPR Article 17 erasure
GET /lists Contact lists, with membership endpoints
GET /tags Tags
POST /segments/preview Resolve a segment definition to a count and a sample

Campaigns

Author, review, and send. Every send runs the same gates as the app: verified sending domain, unsubscribe link, plan allowance, abuse screening.

GET /campaigns List campaigns
POST /campaigns Create a draft
PUT /campaigns/{id}/content Set the body, or seed it from a template
POST /campaigns/{id}/variants Configure A/B variants
POST /campaigns/{id}/preflight Dry-run every send check, read-only
POST /campaigns/{id}/test Send test messages to named addresses
POST /campaigns/{id}/send Send now
POST /campaigns/{id}/schedule Send at a future time
POST /campaigns/{id}/cancel Cancel a draft, scheduled, or paused campaign
GET /templates Your templates plus the starter library
GET /sequences Sequences, with enrolment endpoints

Reporting

The read side of the event pipeline. Machine opens (Apple MPP) are excluded by default, so the rates reflect human engagement.

GET /events Every delivery event. Filter by type, campaign, contact, or date
POST /events Ingest events from your own systems
GET /campaigns/{id}/report Delivery and engagement metrics
GET /campaigns/{id}/report/links Per-link click breakdown, bot traffic separated
GET /campaigns/{id}/report/variants Per-variant A/B results
GET /campaigns/{id}/recipients Per-recipient delivery detail
GET /suppressions The do-not-mail list

Transactional & AI

One-off sends through the same infrastructure as campaigns, plus the AI tooling as callable endpoints.

POST /send Send a transactional message with merge variables
POST /ai/polish Rewrite copy for a tone and goal
POST /ai/subject-lines Generate and score subject lines
POST /ai/deliverability Spam score, issues, and a pass/warn/fail verdict
GET /ai/usage Remaining AI and email allowance this period

Webhooks & keys

Subscribe a URL to platform events instead of polling. Manage credentials programmatically for automated rotation.

GET /webhooks/event-types Everything you can subscribe to
POST /webhooks Register an endpoint, returning the signing secret once
GET /webhooks/{id}/deliveries What we sent and what your endpoint answered
POST /webhooks/{id}/test Fire a synthetic event to verify your signature check
GET /api-keys List keys, with masked prefixes
POST /api-keys Mint a scoped key
DELETE /api-keys/{id} Revoke

Idempotency

Send an Idempotency-Key header on any write. A retry with the same key replays the original response instead of executing again.

-H "Idempotency-Key: order-4417-receipt"

Use it on campaign sends especially: a duplicated send is the one mistake here you can't undo. Keys are honoured for 24 hours.

Scoped keys

Issue one key per integration with only the scopes it needs, then revoke that one without disturbing the others.

contacts:read contacts:write campaigns:read campaigns:write campaigns:send events:read events:write suppressions:read suppressions:write transactional:send ai:write webhooks:read webhooks:write

A :write grant implies the matching :read. Sending is its own scope, so a key that drafts campaigns can't put mail in front of customers.

Webhook signatures

Every delivery carries a Tweak-Signature header. Verify it against the raw request body before trusting the payload.

Tweak-Signature: t=1754835600,v1=9f86d0818...

hmac_sha256(secret, "{t}.{raw_body}") == v1

The timestamp is inside the signed material, so a captured payload can't be replayed at you indefinitely. Reject anything older than a few minutes.

Unified event pipeline

Every delivery event, whether from provider webhooks, native sends, or your own API calls, flows through one pipeline, and back out again over GET /events and your webhooks.

  • Campaign stats updated automatically
  • Auto-suppress on bounce, spam, unsubscribe
  • Contact statuses synced in real time
  • Switch providers, keep your history

Reverse ETL

Connect BigQuery, pick an audience without a CSV, and use approved warehouse fields as merge tags at send time.

  • OAuth with read-only BigQuery scope
  • Browse datasets, tables, and columns
  • Map columns to email placeholders
  • Approved fields resolved during sending

Rate limits

Counted per API key, so one integration's burst never eats another's headroom. Every response carries X-RateLimit-Limit and X-RateLimit-Remaining.

Requests (Business)600/min
Events per request1,000
Contacts per bulk call1,000
Records per page100

Error responses

Standard HTTP status codes with JSON error bodies.

401Missing, invalid, revoked, or expired key
403Missing scope, or plan excludes API access
404No such record on your team
422Validation error, or a send gate failed
429Rate limited, see Retry-After

A refused send returns a blockers array naming each unmet requirement. POST /campaigns/{id}/preflight returns the same list without attempting to send.

Business plan

Build on it today

Generate a scoped API key in Settings, point your client at the OpenAPI spec, and ship.

Start free