Email Subscription API (1.1.0)

Download OpenAPI specification:

License: MIT

Secure email subscription API with double opt-in, unsubscribe, and admin operations. This file is the single source of truth for the API surface.

Public

Public subscription/unsubscribe flows

Submit a double opt-in subscription request

Kick off the double opt-in flow for a given email and listId.

Authentication & Permissions

  • Requires an API key with canSubscribe: true.
  • Send authentication using either X-API-Key: sk_... or Authorization: Bearer sk_....
  • The Origin header must match the API key’s websiteOrigin (unless the key supports server-to-server requests).
  • Subject to the standard rate limit of 10 requests/minute per IP.

Typical Workflow

  1. Collect the subscriber’s email on your site.
  2. Call this endpoint from your server, forwarding metadata if you track campaign sources.
  3. If the email is new, a subscriber is created in PENDING state and a confirmation email is sent.
  4. If the email is already CONFIRMED, the call returns 400. If PENDING, the confirmation token is refreshed and resent.
  5. The recipient follows /api/confirm/{token} to complete activation.

Common Errors

  • 400 — validation failed or address already confirmed.
  • 403 — API key not authorised for the list or origin mismatch.
  • 404 — list ID does not exist.
  • 429 — caller exceeded the rate limit.
Authorizations:
ApiKeyAuth
header Parameters
Origin
string <uri>

Must match the API key's websiteOrigin for browser-initiated requests.

Request Body schema: application/json
required

Email address and list to subscribe. Optional metadata is stored verbatim.

email
required
string <email>
listId
required
string
metadata
any

Responses

Request samples

Content type
application/json
{
  • "email": "user@example.com",
  • "listId": "cln123456789",
  • "metadata": {
    }
}

Response samples

Content type
application/json
{
  • "success": true,
  • "message": "Confirmation email resent"
}

Confirm a subscriber using the email token

Finalises the double opt-in flow. This endpoint renders an HTML confirmation page and does not require authentication.

When to Use

  • Triggered by the “Confirm subscription” link included in emails sent from POST /api/subscribe.
  • Can be used by automated integration tests to validate end-to-end flows.

Behaviour

  • Succeeds with 200 when the token is valid and not expired.
  • Returns 404 if the token is invalid or already used.
  • Returns 410 when the token has expired.
path Parameters
token
required
string

Confirmation token from the subscription email.

Responses

Unsubscribe a subscriber via API key and email

Remove a subscriber using their email address instead of the one-click token. Useful for “manage preferences” pages or admin actions.

Authentication & Permissions

  • Requires an API key with canUnsubscribe: true.
  • Send authentication using either X-API-Key: sk_... or Authorization: Bearer sk_....
  • Origin must match the API key’s websiteOrigin unless the key is server-to-server.
  • Rate limited to 10 requests/minute per IP.

Behaviour

  • Returns 200 and sends a confirmation email when the subscriber transitions to UNSUBSCRIBED.
  • Returns 400 if the subscriber is already unsubscribed.
  • Returns 404 if the email/list combination does not exist.

Common Errors

  • 400 — already unsubscribed or validation failure.
  • 403 — API key lacks permission or targets a different list.
  • 404 — subscription not found.
  • 429 — caller exceeded the rate limit.
Authorizations:
ApiKeyAuth
header Parameters
Origin
string <uri>

Must match the API key's websiteOrigin for browser-initiated requests.

Request Body schema: application/json
required

Email and list identifier to unsubscribe.

email
required
string <email>
listId
required
string

Responses

Request samples

Content type
application/json
{
  • "email": "user@example.com",
  • "listId": "cln123456789"
}

Response samples

Content type
application/json
{
  • "success": true,
  • "message": "Successfully unsubscribed"
}

Complete a one-click unsubscribe from the email link

Handles one-click unsubscribe links embedded in transactional emails. Renders an HTML page that reflects the outcome of the operation.

Behaviour

  • Returns 200 with an HTML confirmation message when the token is valid.
  • Returns 404 if the token is invalid, expired, or already used.

Usage Tips

  • The URL is GET /api/unsubscribe/{token} where {token} comes from the email.
  • You can customise the HTML page in the underlying template if you need branded messaging.
path Parameters
token
required
string

Permanent unsubscribe token contained in the email.

Responses

Admin

Administrative endpoints (admin bearer key)

List all email lists for the account

Retrieve every mailing list configured for your project. Useful for populating dropdowns or management dashboards.

Authentication

  • Requires the admin bearer token (klemailgw_ADMIN_API_KEY).
  • Recommended to cache results client-side; list metadata changes infrequently.

Common Errors

  • 401 — admin key missing or invalid.
  • 403 — admin key disabled.
Authorizations:
AdminBearerAuth

Responses

Response samples

Content type
application/json
{
  • "success": true,
  • "data": {
    }
}

Create a new email list

Provision a new mailing list identified by name and websiteOrigin. The origin acts as an allowlist for API keys.

Behaviour

  • Returns 201 with the newly created list.
  • Fails with 400 if required fields are missing or invalid.

Best Practices

  • Use descriptive names with environment prefixes (PROD - …, STAGE - …) so UI integrations can display intent.
  • Keep websiteOrigin aligned with the domains you expect API keys to use.
Authorizations:
AdminBearerAuth
Request Body schema: application/json
required

Attributes for the list.

name
required
string
description
string
websiteOrigin
required
string <uri>

Responses

Request samples

Content type
application/json
{}

Response samples

Content type
application/json
{
  • "success": true,
  • "data": {
    },
  • "message": "List created successfully"
}

List API keys without exposing raw secrets

Enumerate existing API keys for auditing or UI management. Secrets are never returned—only metadata and prefixes.

Typical Use Cases

  • Display keys in an admin dashboard with their permissions.
  • Monitor when keys were last used (lastUsedAt).

Common Errors

  • 401 / 403 — admin key missing, invalid, or disabled.
Authorizations:
AdminBearerAuth

Responses

Response samples

Content type
application/json
{
  • "success": true,
  • "data": {
    }
}

Create a new API key and return the secret once

Generate a new API key and return the raw secret exactly once. Store the secret immediately—after the response it cannot be recovered.

Behaviour

  • Returns 201 with both the hashed record and apiKey secret.
  • Fails with 400 if required fields are missing or invalid.

Best Practices

  • Use allowServerToServer: true only when you control the caller and no browser Origin will be present.
  • Configure permissions narrowly (e.g., unsubscribe-only webhooks).
Authorizations:
AdminBearerAuth
Request Body schema: application/json
required

Key metadata, including optional permissions.

name
required
string
websiteOrigin
required
string
allowServerToServer
boolean
Default: false
object

Responses

Request samples

Content type
application/json
{
  • "name": "string",
  • "websiteOrigin": "string",
  • "allowServerToServer": false,
  • "permissions": {
    }
}

Response samples

Content type
application/json
{
  • "success": true,
  • "data": {
    },
  • "message": "API key created successfully. Save this key securely - it will not be shown again."
}

Retrieve subscribers with optional filters and pagination

Fetch subscribers for reporting or CRM synchronisation. Supports pagination and filtering by status and list.

Authentication

  • Requires the admin bearer token.

Query Parameters

  • listId — limit results to a specific mailing list.
  • status — filter by PENDING, CONFIRMED, or UNSUBSCRIBED.
  • page / limit — standard pagination controls.

Common Errors

  • 401 / 403 — admin token missing or invalid.
  • 400 — invalid query parameter values.
Authorizations:
AdminBearerAuth
query Parameters
listId
string

Return only subscribers belonging to this list.

status
string
Enum: "PENDING" "CONFIRMED" "UNSUBSCRIBED"

Filter by subscription status.

page
integer >= 1

1-based page index.

limit
integer [ 1 .. 100 ]

Number of items per page (max 100).

Responses

Response samples

Content type
application/json
{
  • "success": true,
  • "data": {
    }
}

Campaigns

Bulk sending/campaign operations (admin)

List campaigns with status filters and pagination

Inspect past and in-flight campaigns. Useful for dashboards or auditing.

Filters

  • listId — return only campaigns for a specific mailing list.
  • status — limit to QUEUED, IN_PROGRESS, COMPLETED, or FAILED.
  • page / limit — standard pagination.

Common Errors

  • 401 / 403 — admin token missing or invalid.
Authorizations:
AdminBearerAuth
query Parameters
listId
string

Only return campaigns for this list.

status
string
Enum: "QUEUED" "IN_PROGRESS" "COMPLETED" "FAILED"

Filter campaigns by current status.

page
integer >= 1

1-based page index.

limit
integer [ 1 .. 100 ]

Number of items per page (max 100).

Responses

Response samples

Content type
application/json
{
  • "success": true,
  • "data": {
    }
}

Create a campaign or resume an existing idempotent request

Schedule a bulk campaign or retry an idempotent request. The first call typically returns 202 while the send is processed asynchronously.

Behaviour

  • Provide an optional idempotencyKey to safely retry requests.
  • Returns 202 when a campaign is queued/started, 200 when reusing an existing idempotent record.
  • Use /api/admin/campaigns/{id} to monitor progress.

Common Errors

  • 400 — missing subject/HTML or invalid payload.
  • 403 — admin token lacks permission.
  • 404 — target list not found.
Authorizations:
AdminBearerAuth
Request Body schema: application/json
required
listId
required
string
subject
required
string
html
string
text
string
previewOnly
boolean
Default: false
batchSize
integer [ 1 .. 500 ]
Default: 100
idempotencyKey
string <= 100 characters

Responses

Request samples

Content type
application/json
{
  • "listId": "string",
  • "subject": "string",
  • "html": "string",
  • "text": "string",
  • "previewOnly": false,
  • "batchSize": 100,
  • "idempotencyKey": "string"
}

Response samples

Content type
application/json
{
  • "success": true,
  • "data": {
    },
  • "message": "Campaign in progress"
}

Get the current status of a campaign

Retrieve progress information for a specific campaign, including totals and timestamps.

When to Use

  • Poll this endpoint after invoking the create/send operations to update dashboards.
  • Combine with campaign.sends data for detailed delivery metrics.

Common Errors

  • 404 — campaign ID not found.
  • 401 / 403 — admin token missing or invalid.
Authorizations:
AdminBearerAuth
path Parameters
id
required
string

Campaign identifier returned by the create/send endpoints.

Responses

Response samples

Content type
application/json
{
  • "success": true,
  • "data": {
    }
}

Process the next batch for an in-progress campaign

Manually advance a campaign by sending the next batch. Use this when you want fine-grained control over pacing or to resume sending after a pause.

Behaviour

  • Accepts an optional batchSize (default 100, max 500).
  • Returns 202 while work continues in the background.
  • Use GET /api/admin/campaigns/{id} to check updated counts.

Common Errors

  • 404 — campaign not found.
  • 409 — (future) if campaign is not in a resumable state.
  • 400 — invalid batchSize.
Authorizations:
AdminBearerAuth
path Parameters
id
required
string

Campaign identifier to advance.

Request Body schema: application/json
batchSize
integer [ 1 .. 500 ]
Default: 100

Responses

Request samples

Content type
application/json
{
  • "batchSize": 100
}

Response samples

Content type
application/json
{
  • "success": true,
  • "data": {
    }
}

Resume a paused or completed campaign if batches remain

Resume processing for a campaign that was paused or reached a terminal state but still has unsent recipients (e.g., after recovering from an error).

Behaviour

  • Returns 200 if the campaign is immediately marked IN_PROGRESS or COMPLETED.
  • Returns 202 if the system needs additional time to requeue work.

Common Errors

  • 404 — campaign ID not found.
  • 409 — (future) campaign cannot be resumed (e.g., already in progress).
Authorizations:
AdminBearerAuth
path Parameters
id
required
string

Campaign identifier to resume.

Responses

Response samples

Content type
application/json
{
  • "success": true,
  • "data": null,
  • "message": "string"
}