openapi: 3.0.1 info: title: listmonk API description: >- REST API for listmonk, the free and open-source, self-hosted newsletter and mailing-list manager. All endpoints are served by a self-hosted listmonk instance under the /api path and are secured with HTTP Basic auth using an API user and token (or an equivalent `Authorization: token api_user:token` header). There is no hosted SaaS; replace the server host with your own instance. termsOfService: https://listmonk.app contact: name: listmonk url: https://listmonk.app/docs/apis/apis/ license: name: AGPL-3.0 url: https://github.com/knadh/listmonk/blob/master/LICENSE version: '4.1' servers: - url: http://localhost:9000/api description: Default local self-hosted instance - url: '{host}/api' description: Self-hosted instance variables: host: default: http://localhost:9000 description: Base URL of your listmonk instance security: - BasicAuth: [] - TokenAuth: [] tags: - name: Subscribers - name: Lists - name: Campaigns - name: Templates - name: Media - name: Transactional - name: Import - name: Bounces paths: /subscribers: get: operationId: getSubscribers tags: [Subscribers] summary: Query and retrieve subscribers. parameters: - { name: query, in: query, schema: { type: string }, description: "SQL expression to filter subscribers, e.g. subscribers.name LIKE '%john%'." } - { name: list_id, in: query, schema: { type: array, items: { type: integer } } } - { name: page, in: query, schema: { type: integer } } - { name: per_page, in: query, schema: { type: integer } } responses: '200': description: A paginated list of subscribers. content: application/json: schema: { $ref: '#/components/schemas/SubscribersResponse' } post: operationId: createSubscriber tags: [Subscribers] summary: Create a new subscriber. requestBody: required: true content: application/json: schema: { $ref: '#/components/schemas/SubscriberRequest' } responses: '200': description: The created subscriber. content: application/json: schema: { $ref: '#/components/schemas/SubscriberResponse' } delete: operationId: deleteSubscribers tags: [Subscribers] summary: Delete multiple subscribers by ID. parameters: - { name: id, in: query, schema: { type: array, items: { type: integer } } } responses: '200': { description: Deletion result. } /subscribers/{subscriber_id}: parameters: - { name: subscriber_id, in: path, required: true, schema: { type: integer } } get: operationId: getSubscriber tags: [Subscribers] summary: Retrieve a specific subscriber. responses: '200': description: The subscriber. content: application/json: schema: { $ref: '#/components/schemas/SubscriberResponse' } put: operationId: updateSubscriber tags: [Subscribers] summary: Update a specific subscriber. requestBody: required: true content: application/json: schema: { $ref: '#/components/schemas/SubscriberRequest' } responses: '200': description: The updated subscriber. content: application/json: schema: { $ref: '#/components/schemas/SubscriberResponse' } delete: operationId: deleteSubscriber tags: [Subscribers] summary: Delete a specific subscriber. responses: '200': { description: Deletion result. } /subscribers/{subscriber_id}/optin: post: operationId: sendSubscriberOptin tags: [Subscribers] summary: Send an opt-in confirmation email to a subscriber. parameters: - { name: subscriber_id, in: path, required: true, schema: { type: integer } } responses: '200': { description: Opt-in email queued. } /subscribers/{subscriber_id}/export: get: operationId: exportSubscriber tags: [Subscribers] summary: Export a subscriber's data. parameters: - { name: subscriber_id, in: path, required: true, schema: { type: integer } } responses: '200': { description: Exported subscriber data. } /subscribers/lists: put: operationId: manageSubscriberLists tags: [Subscribers] summary: Add, remove, or unsubscribe subscribers from lists. requestBody: required: true content: application/json: schema: { $ref: '#/components/schemas/SubscriberListsRequest' } responses: '200': { description: List membership updated. } /subscribers/query/lists: put: operationId: manageSubscriberListsByQuery tags: [Subscribers] summary: Add, remove, or unsubscribe subscribers from lists by SQL query. requestBody: required: true content: application/json: schema: { $ref: '#/components/schemas/SubscriberListsRequest' } responses: '200': { description: List membership updated. } /subscribers/{subscriber_id}/blocklist: put: operationId: blocklistSubscriber tags: [Subscribers] summary: Blocklist a single subscriber. parameters: - { name: subscriber_id, in: path, required: true, schema: { type: integer } } responses: '200': { description: Subscriber blocklisted. } /subscribers/blocklist: put: operationId: blocklistSubscribers tags: [Subscribers] summary: Blocklist multiple subscribers by ID. requestBody: content: application/json: schema: type: object properties: ids: { type: array, items: { type: integer } } responses: '200': { description: Subscribers blocklisted. } /subscribers/query/blocklist: put: operationId: blocklistSubscribersByQuery tags: [Subscribers] summary: Blocklist subscribers matching a SQL expression. responses: '200': { description: Subscribers blocklisted. } /subscribers/query/delete: post: operationId: deleteSubscribersByQuery tags: [Subscribers] summary: Delete subscribers matching a SQL expression. responses: '200': { description: Subscribers deleted. } /lists: get: operationId: getLists tags: [Lists] summary: Retrieve all lists. parameters: - { name: query, in: query, schema: { type: string } } - { name: page, in: query, schema: { type: integer } } - { name: per_page, in: query, schema: { type: integer } } responses: '200': description: A paginated list of lists. content: application/json: schema: { $ref: '#/components/schemas/ListsResponse' } post: operationId: createList tags: [Lists] summary: Create a new list. requestBody: required: true content: application/json: schema: { $ref: '#/components/schemas/ListRequest' } responses: '200': description: The created list. content: application/json: schema: { $ref: '#/components/schemas/ListResponse' } delete: operationId: deleteLists tags: [Lists] summary: Delete multiple lists by ID. parameters: - { name: id, in: query, schema: { type: array, items: { type: integer } } } responses: '200': { description: Deletion result. } /lists/{list_id}: parameters: - { name: list_id, in: path, required: true, schema: { type: integer } } get: operationId: getList tags: [Lists] summary: Retrieve a specific list. responses: '200': description: The list. content: application/json: schema: { $ref: '#/components/schemas/ListResponse' } put: operationId: updateList tags: [Lists] summary: Update an existing list. requestBody: required: true content: application/json: schema: { $ref: '#/components/schemas/ListRequest' } responses: '200': description: The updated list. content: application/json: schema: { $ref: '#/components/schemas/ListResponse' } delete: operationId: deleteList tags: [Lists] summary: Delete a specific list. responses: '200': { description: Deletion result. } /public/lists: get: operationId: getPublicLists tags: [Lists] summary: Retrieve public lists (unauthenticated, for subscription forms). security: [] responses: '200': { description: Public lists. } /campaigns: get: operationId: getCampaigns tags: [Campaigns] summary: Retrieve all campaigns. parameters: - { name: query, in: query, schema: { type: string } } - { name: status, in: query, schema: { type: array, items: { type: string } } } - { name: page, in: query, schema: { type: integer } } - { name: per_page, in: query, schema: { type: integer } } responses: '200': description: A paginated list of campaigns. content: application/json: schema: { $ref: '#/components/schemas/CampaignsResponse' } post: operationId: createCampaign tags: [Campaigns] summary: Create a new campaign. requestBody: required: true content: application/json: schema: { $ref: '#/components/schemas/CampaignRequest' } responses: '200': description: The created campaign. content: application/json: schema: { $ref: '#/components/schemas/CampaignResponse' } delete: operationId: deleteCampaigns tags: [Campaigns] summary: Delete multiple campaigns. responses: '200': { description: Deletion result. } /campaigns/{campaign_id}: parameters: - { name: campaign_id, in: path, required: true, schema: { type: integer } } get: operationId: getCampaign tags: [Campaigns] summary: Retrieve a specific campaign. responses: '200': description: The campaign. content: application/json: schema: { $ref: '#/components/schemas/CampaignResponse' } put: operationId: updateCampaign tags: [Campaigns] summary: Update a campaign. requestBody: required: true content: application/json: schema: { $ref: '#/components/schemas/CampaignRequest' } responses: '200': description: The updated campaign. content: application/json: schema: { $ref: '#/components/schemas/CampaignResponse' } delete: operationId: deleteCampaign tags: [Campaigns] summary: Delete an individual campaign. responses: '200': { description: Deletion result. } /campaigns/{campaign_id}/preview: get: operationId: previewCampaign tags: [Campaigns] summary: Retrieve an HTML preview of a campaign. parameters: - { name: campaign_id, in: path, required: true, schema: { type: integer } } responses: '200': { description: Rendered campaign HTML. } /campaigns/{campaign_id}/test: post: operationId: testCampaign tags: [Campaigns] summary: Send a test of the campaign to arbitrary subscribers. parameters: - { name: campaign_id, in: path, required: true, schema: { type: integer } } requestBody: content: application/json: schema: type: object properties: subscribers: { type: array, items: { type: string }, description: List of test recipient emails. } responses: '200': { description: Test message queued. } /campaigns/{campaign_id}/status: put: operationId: updateCampaignStatus tags: [Campaigns] summary: Change the status of a campaign (running, paused, cancelled, scheduled). parameters: - { name: campaign_id, in: path, required: true, schema: { type: integer } } requestBody: required: true content: application/json: schema: type: object properties: status: { type: string, enum: [scheduled, running, paused, cancelled, finished] } responses: '200': { description: Status updated. } /campaigns/{campaign_id}/archive: put: operationId: archiveCampaign tags: [Campaigns] summary: Publish or update a campaign in the public archive. parameters: - { name: campaign_id, in: path, required: true, schema: { type: integer } } responses: '200': { description: Archive settings updated. } /campaigns/running/stats: get: operationId: getRunningCampaignStats tags: [Campaigns] summary: Retrieve stats of running campaigns. parameters: - { name: campaign_id, in: query, schema: { type: array, items: { type: integer } } } responses: '200': { description: Running campaign stats. } /campaigns/analytics/{type}: get: operationId: getCampaignAnalytics tags: [Campaigns] summary: Retrieve view, click, link, or bounce counts for campaigns. parameters: - { name: type, in: path, required: true, schema: { type: string, enum: [views, clicks, links, bounces] } } - { name: id, in: query, schema: { type: array, items: { type: integer } } } - { name: from, in: query, schema: { type: string, format: date } } - { name: to, in: query, schema: { type: string, format: date } } responses: '200': { description: Campaign analytics. } /templates: get: operationId: getTemplates tags: [Templates] summary: Retrieve all templates. responses: '200': description: A list of templates. content: application/json: schema: { $ref: '#/components/schemas/TemplatesResponse' } post: operationId: createTemplate tags: [Templates] summary: Create a template. requestBody: required: true content: application/json: schema: { $ref: '#/components/schemas/TemplateRequest' } responses: '200': description: The created template. content: application/json: schema: { $ref: '#/components/schemas/TemplateResponse' } /templates/{template_id}: parameters: - { name: template_id, in: path, required: true, schema: { type: integer } } get: operationId: getTemplate tags: [Templates] summary: Retrieve a template. responses: '200': description: The template. content: application/json: schema: { $ref: '#/components/schemas/TemplateResponse' } put: operationId: updateTemplate tags: [Templates] summary: Update an existing template. requestBody: required: true content: application/json: schema: { $ref: '#/components/schemas/TemplateRequest' } responses: '200': description: The updated template. content: application/json: schema: { $ref: '#/components/schemas/TemplateResponse' } delete: operationId: deleteTemplate tags: [Templates] summary: Delete a template. responses: '200': { description: Deletion result. } /templates/{template_id}/preview: get: operationId: previewTemplate tags: [Templates] summary: Retrieve the rendered HTML preview of a template. parameters: - { name: template_id, in: path, required: true, schema: { type: integer } } responses: '200': { description: Rendered template HTML. } /templates/{template_id}/default: put: operationId: setDefaultTemplate tags: [Templates] summary: Set a template as the default. parameters: - { name: template_id, in: path, required: true, schema: { type: integer } } responses: '200': { description: Default template set. } /templates/preview: post: operationId: previewTemplateBody tags: [Templates] summary: Render and preview a template body without saving it. requestBody: content: application/json: schema: { $ref: '#/components/schemas/TemplateRequest' } responses: '200': { description: Rendered HTML. } /media: get: operationId: getMedia tags: [Media] summary: Retrieve uploaded media files. responses: '200': description: A list of media files. content: application/json: schema: { $ref: '#/components/schemas/MediaResponse' } post: operationId: uploadMedia tags: [Media] summary: Upload a media file. requestBody: required: true content: multipart/form-data: schema: type: object properties: file: { type: string, format: binary } responses: '200': description: The uploaded media file. content: application/json: schema: { $ref: '#/components/schemas/MediaResponse' } /media/{media_id}: parameters: - { name: media_id, in: path, required: true, schema: { type: integer } } get: operationId: getMediaFile tags: [Media] summary: Retrieve a specific media file. responses: '200': { description: The media file. } delete: operationId: deleteMedia tags: [Media] summary: Delete an uploaded media file. responses: '200': { description: Deletion result. } /tx: post: operationId: sendTransactionalMessage tags: [Transactional] summary: Send a transactional message to one or more subscribers. requestBody: required: true content: application/json: schema: { $ref: '#/components/schemas/TransactionalRequest' } multipart/form-data: schema: type: object properties: data: { type: string, description: JSON-encoded transactional payload. } file: { type: string, format: binary, description: Optional attachment. } responses: '200': { description: Message accepted and queued. } /import/subscribers: get: operationId: getImportStatus tags: [Import] summary: Retrieve the status of an ongoing import. responses: '200': { description: Import status. } post: operationId: importSubscribers tags: [Import] summary: Upload a CSV (optionally ZIP-compressed) file to import subscribers. requestBody: required: true content: multipart/form-data: schema: type: object properties: params: { type: string, description: JSON-encoded import params (mode, lists, delimiter, overwrite). } file: { type: string, format: binary } responses: '200': { description: Import started. } delete: operationId: stopImport tags: [Import] summary: Stop and delete an ongoing import. responses: '200': { description: Import stopped. } /import/subscribers/logs: get: operationId: getImportLogs tags: [Import] summary: Retrieve logs from an ongoing import. responses: '200': { description: Import logs. } /bounces: get: operationId: getBounces tags: [Bounces] summary: Retrieve bounce records. parameters: - { name: campaign_id, in: query, schema: { type: integer } } - { name: page, in: query, schema: { type: integer } } - { name: per_page, in: query, schema: { type: integer } } responses: '200': description: A paginated list of bounce records. content: application/json: schema: { $ref: '#/components/schemas/BouncesResponse' } delete: operationId: deleteBounces tags: [Bounces] summary: Delete bounce records by ID or all. parameters: - { name: id, in: query, schema: { type: array, items: { type: integer } } } - { name: all, in: query, schema: { type: boolean } } responses: '200': { description: Deletion result. } /bounces/{bounce_id}: delete: operationId: deleteBounce tags: [Bounces] summary: Delete a single bounce record. parameters: - { name: bounce_id, in: path, required: true, schema: { type: integer } } responses: '200': { description: Deletion result. } components: securitySchemes: BasicAuth: type: http scheme: basic description: HTTP Basic auth using an API user name and token (api_user:token). TokenAuth: type: apiKey in: header name: Authorization description: "Authorization header in the form: token api_user:token." schemas: SubscriberRequest: type: object properties: email: { type: string, format: email } name: { type: string } status: { type: string, enum: [enabled, disabled, blocklisted] } lists: { type: array, items: { type: integer }, description: List IDs to subscribe to. } attribs: { type: object, additionalProperties: true, description: Arbitrary JSON attributes. } preconfirm_subscriptions: { type: boolean } required: [email] SubscriberResponse: type: object properties: data: { $ref: '#/components/schemas/Subscriber' } SubscribersResponse: type: object properties: data: type: object properties: results: { type: array, items: { $ref: '#/components/schemas/Subscriber' } } total: { type: integer } page: { type: integer } per_page: { type: integer } Subscriber: type: object properties: id: { type: integer } uuid: { type: string } email: { type: string } name: { type: string } status: { type: string } attribs: { type: object, additionalProperties: true } lists: { type: array, items: { type: object } } created_at: { type: string, format: date-time } updated_at: { type: string, format: date-time } SubscriberListsRequest: type: object properties: ids: { type: array, items: { type: integer } } query: { type: string } action: { type: string, enum: [add, remove, unsubscribe] } target_list_ids: { type: array, items: { type: integer } } status: { type: string, enum: [unconfirmed, confirmed, unsubscribed] } ListRequest: type: object properties: name: { type: string } type: { type: string, enum: [public, private] } optin: { type: string, enum: [single, double] } tags: { type: array, items: { type: string } } description: { type: string } required: [name] ListResponse: type: object properties: data: { $ref: '#/components/schemas/List' } ListsResponse: type: object properties: data: type: object properties: results: { type: array, items: { $ref: '#/components/schemas/List' } } total: { type: integer } List: type: object properties: id: { type: integer } uuid: { type: string } name: { type: string } type: { type: string } optin: { type: string } tags: { type: array, items: { type: string } } subscriber_count: { type: integer } created_at: { type: string, format: date-time } CampaignRequest: type: object properties: name: { type: string } subject: { type: string } lists: { type: array, items: { type: integer } } from_email: { type: string } type: { type: string, enum: [regular, optin] } content_type: { type: string, enum: [richtext, html, markdown, plain] } body: { type: string } template_id: { type: integer } messenger: { type: string } tags: { type: array, items: { type: string } } send_at: { type: string, format: date-time } required: [name, subject, lists] CampaignResponse: type: object properties: data: { $ref: '#/components/schemas/Campaign' } CampaignsResponse: type: object properties: data: type: object properties: results: { type: array, items: { $ref: '#/components/schemas/Campaign' } } total: { type: integer } Campaign: type: object properties: id: { type: integer } uuid: { type: string } name: { type: string } subject: { type: string } status: { type: string } type: { type: string } content_type: { type: string } lists: { type: array, items: { type: object } } sent: { type: integer } to_send: { type: integer } created_at: { type: string, format: date-time } TemplateRequest: type: object properties: name: { type: string } type: { type: string, enum: [campaign, campaign_visual, tx] } subject: { type: string } body: { type: string } required: [name, type, body] TemplateResponse: type: object properties: data: { $ref: '#/components/schemas/Template' } TemplatesResponse: type: object properties: data: { type: array, items: { $ref: '#/components/schemas/Template' } } Template: type: object properties: id: { type: integer } name: { type: string } type: { type: string } subject: { type: string } body: { type: string } is_default: { type: boolean } created_at: { type: string, format: date-time } MediaResponse: type: object properties: data: oneOf: - { $ref: '#/components/schemas/Media' } - { type: array, items: { $ref: '#/components/schemas/Media' } } Media: type: object properties: id: { type: integer } uuid: { type: string } filename: { type: string } content_type: { type: string } url: { type: string } thumb_url: { type: string } created_at: { type: string, format: date-time } TransactionalRequest: type: object properties: subscriber_email: { type: string, format: email } subscriber_id: { type: integer } subscriber_emails: { type: array, items: { type: string } } subscriber_ids: { type: array, items: { type: integer } } template_id: { type: integer } subscriber_mode: { type: string, enum: [default, fallback, external] } from_email: { type: string } subject: { type: string } data: { type: object, additionalProperties: true, description: "Custom variables available in templates via {{ .Tx.Data.* }}." } headers: { type: array, items: { type: object, additionalProperties: { type: string } } } messenger: { type: string, default: email } content_type: { type: string, enum: [html, markdown, plain] } altbody: { type: string } required: [template_id] BouncesResponse: type: object properties: data: type: object properties: results: { type: array, items: { $ref: '#/components/schemas/Bounce' } } total: { type: integer } Bounce: type: object properties: id: { type: integer } type: { type: string, enum: [hard, soft, complaint] } source: { type: string } subscriber_id: { type: integer } campaign_id: { type: integer } email: { type: string } created_at: { type: string, format: date-time }