Built for your next integration

A small API. Clear boundaries.

The current Newsly API manages newsletter workspaces, sender identities, domain claims, and current subscribers.

Owner-management API ยท v1

Start with an owned workspace.

These endpoints power the authenticated Newsly dashboard. Public subscription integrations and campaign sending are not available yet.

  1. Sign in to Newsly and open the dashboard.
  2. Create or select a tenant.
  3. Use the owner session from the configured frontend origin.

API origin for this build: https://integration.newsly.dev.

const response = await fetch('https://integration.newsly.dev/v1/tenants', {
  credentials: 'include',
});

if (!response.ok) throw new Error('Tenant request failed.');
const { tenants } = await response.json();

Your session is your authentication.

All /v1/ endpoints require the WorkOS session cookie __Host-newsly-session. Use credentials: 'include' for browser requests.

The cookie is HTTP-only. Do not read it in JavaScript, put it in source code, or share it in support requests.

POST, PUT, and DELETE require an Origin equal to the configured frontend origin. Browsers supply this header automatically.

Start sign-in at /auth/login?return_to=%2Fdashboard. WorkOS returns to /auth/callback. Sign out with POST /auth/logout.

Failed sign-in returns to the homepage with a fixed error code, a retry action, and a prefilled support action. Provider details and authentication secrets are not included.

Backend subscription keys are separate planned work. These owner endpoints do not accept a bearer API key.

Available endpoints

Replace path parameters such as :id with an owned record ID. A tenant outside your account is not accessible.

Account and health

MethodPathPurpose
GET/healthWorker health. No sign-in required.
GET/health/dbDatabase health. No sign-in required.
GET/v1/meThe signed-in owner.

Sending domains

MethodPathPurpose
GET/v1/sending-domainsList your claimed sending domains.
GET/v1/sending-domains/:domain/availabilityCheck availability and existing ownership.
POST/v1/sending-domainsClaim a domain or reuse an existing owned claim.
DELETE/v1/sending-domains/:domainRelease an unused domain claim.

Tenant workspaces

MethodPathPurpose
GET/v1/tenantsList your tenant workspaces.
POST/v1/tenantsCreate a tenant with its domain and sender identity.
GET/v1/tenants/:idGet one owned tenant.
PUT/v1/tenants/:id/profileSave the complete tenant profile.
PUT/v1/tenants/:id/senderSave both sender identity fields.
PUT/v1/tenants/:id/sending-domainSave the profile and sending domain together.

Current subscribers

MethodPathPurpose
GET/v1/tenants/:id/subscribersSearch and filter the current subscriber list.
GET/v1/tenants/:id/subscribers/exportExport all matching current subscribers as CSV.
GET/v1/tenants/:id/subscribers/analyticsGet current-record counts, sources, and trends.
DELETE/v1/tenants/:id/subscribers/:subscriberIdPermanently remove one current subscriber.

Add ?includeUsage=true to the domain list for inUse flags. An in-use domain claim cannot be deleted.

Create a tenant

Creation requires a name, sending domain, sender display name, and sender local part. The business name and postal address are optional during creation.

const response = await fetch('https://integration.newsly.dev/v1/tenants', {
  method: 'POST',
  credentials: 'include',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    name: 'The Sunday Letter',
    businessName: 'Sunday Studio',
    postalAddress: '123 Example Street',
    sendingDomain: 'sunday.newsly.dev',
    senderDisplayName: 'Sunday Studio',
    senderLocalPart: 'hello',
  }),
});

A successful creation returns HTTP 201 with { "tenant": { ... } }. A list returns { "tenants": [...] }.

The sending domain must use the configured Newsly suffix. An unclaimed domain becomes an owned claim in the same transaction.

A profile update requires name, businessName, and postalAddress. A sender update requires senderDisplayName and senderLocalPart.

A domain update requires the complete profile plus sendingDomain. It retains the sender identity and previous domain claim.

Search the current audience.

The list and export combine all supplied filters. Bounced subscribers remain active and visible. There is no manual creation, import, or email-edit endpoint.

search
A literal email substring, without case or surrounding-space differences.
source
email_confirmation or backend.
bounced
true or false.
startDate and endDate
Inclusive UTC dates in YYYY-MM-DD format.
page
List only. Starts at 1, with at most 50 subscribers per page.

List responses contain subscribers, total, page, pageSize, and timeZone.

Export includes all matching pages. An empty export returns HTTP 404 with NO_SUBSCRIBERS_TO_EXPORT.

Analytics accept period=7, 30, 90, or all. They use UTC calendar boundaries and ignore list filters.

Removal also changes past analytics because all results use current records. Confirm permanent removal before you send a DELETE request.

Errors that tell you what to do next.

Error responses contain an error code. Some also include a message and per-field validation errors.

400
Correct invalid fields, query parameters, or a self-service limit.
401
Sign in again. The owner session is missing or invalid.
403
Use the configured frontend origin for mutations.
404
The record is missing or not owned by you. Exports also use 404 for an empty result.
409
Resolve a duplicate tenant name, unavailable domain, or in-use domain claim.
503
The operation is unavailable. Read the message before you retry.

Each owner can create five tenants and hold five domain claims. Reusing an owned domain does not use another claim slot.

Prepare a support request