From f99fadee7fd06b9a8a2e39bbfbc399ea1b03da36 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 30 Aug 2023 05:21:59 +0000 Subject: [PATCH] deploy: 34d86fc387b73ac6dd6522b24fe9a4749cf87b16 --- docs/installation/index.html | 4 ++++ docs/search/search_index.json | 2 +- docs/sitemap.xml.gz | Bin 127 -> 127 bytes 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/installation/index.html b/docs/installation/index.html index ca0a7771..7da556dc 100644 --- a/docs/installation/index.html +++ b/docs/installation/index.html @@ -914,6 +914,10 @@

Docker

The latest image is available on DockerHub at listmonk/listmonk:latest

+
+

Note

+

Listmonk's docs and scripts use docker compose, which is compatible with the latest version of docker. If you installed docker and docker-compose from your Linux distribution, you probably have an older version and will need to use the docker-compose command instead, or you'll need to update docker manually. More info.

+

Use the sample docker-compose.yml to run listmonk and Postgres DB with docker compose as follows:

Demo

Easy Docker install

diff --git a/docs/search/search_index.json b/docs/search/search_index.json index c2b19a6c..141ada3f 100644 --- a/docs/search/search_index.json +++ b/docs/search/search_index.json @@ -1 +1 @@ -{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Introduction","text":"

listmonk is a self-hosted, high performance mailing list and newsletter manager. It comes as a standalone binary and the only dependency is a Postgres database.

"},{"location":"#developers","title":"Developers","text":"

listmonk is a free and open source software licensed under AGPLv3. If you are interested in contributing, check out the GitHub repository and refer to the developer setup. The backend is written in Go and the frontend is Vue with Buefy for UI.

"},{"location":"archives/","title":"Archives","text":"

A global public archive is maintained on the public web interface. It can be enabled under Settings -> Settings -> General -> Enable public mailing list archive.

To make a campaign available in the public archive (provided it has been enabled in the settings as described above), enable the option 'Publish to public archive' under Campaigns -> Create new -> Archive.

When using template variables that depend on subscriber data (such as any template variable referencing .Subscriber), such data must be supplied as 'Campaign metadata', which is a JSON object that will be used in place of .Subscriber when rendering the archive template and content.

When individual subscriber tracking is enabled, TrackLink requires that a UUID of an existing user is provided as part of the campaign metadata. Any clicks on a TrackLink from the archived campaign will be counted towards that subscriber.

As an example:

{\n\"UUID\": \"5a837423-a186-5623-9a87-82691cbe3631\",\n\"email\": \"example@example.com\",\n\"name\": \"Reader\",\n\"attribs\": {}\n}\n

"},{"location":"bounces/","title":"Bounce processing","text":"

Enable bounce processing in Settings -> Bounces. POP3 bounce scanning and APIs only become available once the setting is enabled.

"},{"location":"bounces/#pop3-bounce-mailbox","title":"POP3 bounce mailbox","text":"

Configure the bounce mailbox in Settings -> Bounces. Either the \"From\" e-mail that is set on a campaign (or in settings) should have a POP3 mailbox behind it to receive bounce e-mails, or you should configure a dedicated POP3 mailbox and add that address as the Return-Path (envelope sender) header in Settings -> SMTP -> Custom headers box. For example:

[\n    {\"Return-Path\": \"your-bounce-inbox@site.com\"}\n]\n

Some mail servers may also return the bounce to the Reply-To address, which can also be added to the header settings.

"},{"location":"bounces/#webhook-api","title":"Webhook API","text":"

The bounce webhook API can be used to record bounce events with custom scripting. This could be by reading a mailbox, a database, or mail server logs.

Method Endpoint Description POST /webhooks/bounce Record a bounce event. Name Data type Required/Optional Description subscriber_uuid String Optional The UUID of the subscriber. Either this or email is required. email String Optional The e-mail of the subscriber. Either this or subscriber_uuid is required. campaign_uuid String Optional UUID of the campaign for which the bounce happened. source String Required A string indicating the source, eg: api, my_script etc. type String Required hard or soft bounce. Currently, this has no effect on how the bounce is treated. meta String Optional An optional escaped JSON string with arbitrary metadata about the bounce event.
curl -u 'username:password' -X POST localhost:9000/webhooks/bounce \\\n-H \"Content-Type: application/json\" \\\n--data '{\"email\": \"user1@mail.com\", \"campaign_uuid\": \"9f86b50d-5711-41c8-ab03-bc91c43d711b\", \"source\": \"api\", \"type\": \"hard\", \"meta\": \"{\\\"additional\\\": \\\"info\\\"}}'\n
"},{"location":"bounces/#external-webhooks","title":"External webhooks","text":"

listmonk supports receiving bounce webhook events from the following SMTP providers.

Endpoint Description More info https://listmonk.yoursite.com/webhooks/service/ses Amazon (AWS) SES You can use these Mautic steps as a general guide, but use your listmonk's endpoint instead. https://listmonk.yoursite.com/webhooks/service/sendgrid Sendgrid / Twilio Signed event webhook More info"},{"location":"bounces/#verification","title":"Verification","text":"

If you're using Amazon SES you can use Amazon's test emails to make sure everything's working: https://docs.aws.amazon.com/ses/latest/dg/send-an-email-from-console.html

success@simulator.amazonses.com\nbounce@simulator.amazonses.com\ncomplaint@simulator.amazonses.com\nsuppressionlist@simulator.amazonses.com\n
They all count as hard bounces.

Exporting bounces: https://github.com/knadh/listmonk/issues/863

"},{"location":"concepts/","title":"Concepts","text":""},{"location":"concepts/#subscriber","title":"Subscriber","text":"

A subscriber is a recipient identified by an e-mail address and name. Subscribers receive e-mails that are sent from listmonk. A subscriber can be added to any number of lists. Subscribers who are not a part of any lists are considered orphan records.

"},{"location":"concepts/#attributes","title":"Attributes","text":"

Attributes are arbitrary properties attached to a subscriber in addition to their e-mail and name. They are represented as a JSON map. It is not necessary for all subscribers to have the same attributes. Subscribers can be queried and segmented into lists based on their attributes, and the attributes can be inserted into the e-mails sent to them. For example:

{\n\"city\": \"Bengaluru\",\n\"likes_tea\": true,\n\"spoken_languages\": [\"English\", \"Malayalam\"],\n\"projects\": 3,\n\"stack\": {\n\"frameworks\": [\"echo\", \"go\"],\n\"languages\": [\"go\", \"python\"],\n\"preferred_language\": \"go\"\n}\n}\n
"},{"location":"concepts/#subscription-statuses","title":"Subscription statuses","text":"

A subscriber can be added to one or more lists, and each such relationship can have one of these statuses.

Status Description unconfirmed The subscriber was added to the list directly without their explicit confirmation. Nonetheless, the subscriber will receive campaign messages sent to single optin campaigns. confirmed The subscriber confirmed their subscription by clicking on 'accept' in the confirmation e-mail. Only confirmed subscribers in opt-in lists will receive campaign messages send to the list. unsubscribed The subscriber is unsubscribed from the list and will not receive any campaign messages sent to the list."},{"location":"concepts/#segmentation","title":"Segmentation","text":"

Segmentation is the process of filtering a large list of subscribers into a smaller group based on arbitrary conditions, primarily based on their attributes. For instance, if an e-mail needs to be sent subscribers who live in a particular city, given their city is described in their attributes, it's possible to quickly filter them out into a new list and e-mail them. Learn more.

"},{"location":"concepts/#list","title":"List","text":"

A list (or a mailing list) is a collection of subscribers grouped under a name, for instance, clients. Lists are used to organise subscribers and send e-mails to specific groups. A list can be single optin or double optin. Subscribers added to double optin lists have to explicitly accept the subscription by clicking on the confirmation e-mail they receive. Until then, they do not receive campaign messages.

"},{"location":"concepts/#campaign","title":"Campaign","text":"

A campaign is an e-mail (or any other kind of messages) that is sent to one or more lists.

"},{"location":"concepts/#transactional-message","title":"Transactional message","text":"

A transactional message is an arbitrary message sent to a subscriber using the transactional message API. For example a welcome e-mail on signing up to a service; an order confirmation e-mail on purchasing an item; a password reset e-mail when a user initiates an online account recovery process.

"},{"location":"concepts/#template","title":"Template","text":"

A template is a re-usable HTML design that can be used across campaigns and when sending arbitrary transactional messages. Most commonly, templates have standard header and footer areas with logos and branding elements, where campaign content is inserted in the middle. listmonk supports Go template expressions that lets you create powerful, dynamic HTML templates. Learn more.

"},{"location":"concepts/#messenger","title":"Messenger","text":"

listmonk supports multiple custom messaging backends in additional to the default SMTP e-mail backend, enabling not just e-mail campaigns, but arbitrary message campaigns such as SMS, FCM notifications etc. A Messenger is a web service that accepts a campaign message pushed to it as a JSON request, which the service can in turn broadcast as SMS, FCM etc. Learn more.

"},{"location":"concepts/#tracking-pixel","title":"Tracking pixel","text":"

The tracking pixel is a tiny, invisible image that is inserted into an e-mail body to track e-mail views. This allows measuring the read rate of e-mails. While this is exceedingly common in e-mail campaigns, it carries privacy implications and should be used in compliance with rules and regulations such as GDPR. It is possible to track reads anonymously without associating an e-mail read to a subscriber.

"},{"location":"concepts/#click-tracking","title":"Click tracking","text":"

It is possible to track the clicks on every link that is sent in an e-mail. This allows measuring the clickthrough rates of links in e-mails. While this is exceedingly common in e-mail campaigns, it carries privacy implications and should be used in compliance with rules and regulations such as GDPR. It is possible to track link clicks anonymously without associating an e-mail read to a subscriber.

"},{"location":"concepts/#bounce","title":"Bounce","text":"

A bounce occurs when an e-mail that is sent to a recipient \"bounces\" back for one of many reasons including the recipient address being invalid, their mailbox being full, or the recipient's e-mail service provider marking the e-mail as spam. listmonk can automatically process such bounce e-mails that land in a configured POP mailbox, or via APIs of SMTP e-mail providers such as AWS SES and Sengrid. Based on settings, subscribers returning bounced e-mails can either be blocklisted or deleted automatically. Learn more.

"},{"location":"configuration/","title":"Configuration","text":""},{"location":"configuration/#toml-configuration-file","title":"TOML Configuration file","text":"

One or more TOML files can be read by passing --config config.toml multiple times. Apart from a few low level configuration variables and the database configuration, all other settings can be managed from the Settings dashboard on the admin UI.

To generate a new sample configuration file, run --listmonk --new-config

"},{"location":"configuration/#environment-variables","title":"Environment variables","text":"

Variables in config.toml can also be provided as environment variables prefixed by LISTMONK_ with periods replaced by __ (double underscore). Example:

Environment variable Example value LISTMONK_app__address \"0.0.0.0:9000\" LISTMONK_app__admin_username listmonk LISTMONK_app__admin_password listmonk LISTMONK_db__host db LISTMONK_db__port 9432 LISTMONK_db__user listmonk LISTMONK_db__password listmonk LISTMONK_db__database listmonk LISTMONK_db__ssl_mode disable"},{"location":"configuration/#customizing-system-templates","title":"Customizing system templates","text":"

Read this

"},{"location":"configuration/#http-routes","title":"HTTP routes","text":"

When configuring auth proxies and web application firewalls, use this table.

"},{"location":"configuration/#private-admin-endpoints","title":"Private admin endpoints.","text":"Methods Route Description * /api/* Admin APIs GET /admin/* Admin UI and HTML pages POST /webhooks/bounce Admin bounce webhook"},{"location":"configuration/#public-endpoints-to-expose-to-the-internet","title":"Public endpoints to expose to the internet.","text":"Methods Route Description GET, POST /subscription/* HTML subscription pages GET, /link/* Tracked link redirection GET /campaign/* Pixel tracking image GET /public/* Static files for HTML subscription pages POST /webhooks/service/* Bounce webhook endpoints for AWS and Sendgrid"},{"location":"configuration/#media-uploads","title":"Media Uploads","text":""},{"location":"configuration/#filesystem","title":"Filesystem","text":"

When configuring docker volume mounts for using filesystem media uploads, you can follow either of two approaches. The second option may be necessary if your setup requires you to use sudo for docker commands.

After making any changes you will need to run sudo docker compose stop ; sudo docker compose up.

And under https://listmonk.mysite.com/admin/settings you put /listmonk/uploads.

"},{"location":"configuration/#using-volumes","title":"Using volumes","text":"

Using docker volumes, you can specify the name of volume and destination for the files to be uploaded inside the container.

app:\n    volumes:\n      - type: volume\n        source: listmonk-uploads\n        target: /listmonk/uploads\n\nvolumes:\n  listmonk-uploads:\n

Note

This volume is managed by docker itself, and you can see find the host path with docker volume inspect listmonk_listmonk-uploads.

"},{"location":"configuration/#using-bind-mounts","title":"Using bind mounts","text":"

  app:\n    volumes:\n      - ./path/on/your/host/:/path/inside/container\n
Eg:
  app:\n    volumes:\n      - ./data/uploads:/listmonk/uploads\n
The files will be available inside /data/uploads directory on the host machine.

To use the default uploads folder:

  app:\n    volumes:\n      - ./listmonk/uploads:/listmonk/uploads\n

"},{"location":"configuration/#time-zone","title":"Time zone","text":"

To change listmonk's time zone (logs, etc.) edit docker-compose.yml:

environment:\n    - TZ=Etc/UTC\n
with any Timezone listed here. Then run sudo docker-compose stop ; sudo docker-compose up after making changes.

"},{"location":"developer-setup/","title":"Developer setup","text":"

The app has two distinct components, the Go backend and the VueJS frontend. In the dev environment, both are run independently.

"},{"location":"developer-setup/#pre-requisites","title":"Pre-requisites","text":""},{"location":"developer-setup/#first-time-setup","title":"First time setup","text":"

git clone https://github.com/knadh/listmonk.git. The project uses go.mod, so it's best to clone it outside the Go src path.

  1. Copy config.toml.sample as config.toml and add your config.
  2. make dist to build the listmonk binary. Once the binary is built, run ./listmonk --install to run the DB setup. For subsequent dev runs, use make run.

mailhog is an excellent standalone mock SMTP server (with a UI) for testing and dev.

"},{"location":"developer-setup/#running-the-dev-environment","title":"Running the dev environment","text":"
  1. Run make run to start the listmonk dev server on :9000.
  2. Run make run-frontend to start the Vue frontend in dev mode using yarn on :8080. All /api/* calls are proxied to the app running on :9000. Refer to the frontend README for an overview on how the frontend is structured.
  3. Visit http://localhost:8080
"},{"location":"developer-setup/#production-build","title":"Production build","text":"

Run make dist to build the Go binary, build the Javascript frontend, and embed the static assets producing a single self-contained binary, listmonk

"},{"location":"external-integration/","title":"Integrating with external systems","text":"

In many environments, a mailing list manager's subscriber database is not run independently but as a part of an existing customer database or a CRM. There are multiple ways of keeping listmonk in sync with external systems.

"},{"location":"external-integration/#using-apis","title":"Using APIs","text":"

The subscriber APIs offers several APIs to manipulate the subscribers database, like addition, updation, and deletion. For bulk synchronisation, a CSV can be generated (and optionally zipped) and posted to the import API.

"},{"location":"external-integration/#interacting-directly-with-the-db","title":"Interacting directly with the DB","text":"

listmonk uses tables with simple schemas to represent subscribers (subscribers), lists (lists), and subscriptions (subscriber_lists). It is easy to add, update, and delete subscriber information directly with the database tables for advanced usecases. See the table schemas for more information.

"},{"location":"i18n/","title":"Internationalization (i18n)","text":"

listmonk comes available in multiple languages thanks to language packs contributed by volunteers. A language pack is a JSON file with a map of keys and corresponding translations. The bundled languages can be viewed here.

"},{"location":"i18n/#additional-language-packs","title":"Additional language packs","text":"

These additional language packs can be downloaded and passed to listmonk with the --i18n-dir flag as described in the next section.

Language Description Deutsch (formal) German language with formal pronouns"},{"location":"i18n/#customizing-languages","title":"Customizing languages","text":"

To customize an existing language or to load a new language, put one or more .json language files in a directory, and pass the directory path to listmonk with the--i18n-dir=/path/to/dir flag.

"},{"location":"i18n/#contributing-a-new-language","title":"Contributing a new language","text":""},{"location":"i18n/#using-the-basic-editor","title":"Using the basic editor","text":""},{"location":"i18n/#using-inlang-external-service","title":"Using InLang (external service)","text":""},{"location":"installation/","title":"Installation","text":"

listmonk requires Postgres \u2a7e 12.

See the \"Tutorials\" section at the bottom for detailed guides.

"},{"location":"installation/#binary","title":"Binary","text":""},{"location":"installation/#docker","title":"Docker","text":"

The latest image is available on DockerHub at listmonk/listmonk:latest

Use the sample docker-compose.yml to run listmonk and Postgres DB with docker compose as follows:

"},{"location":"installation/#demo","title":"Demo","text":""},{"location":"installation/#easy-docker-install","title":"Easy Docker install","text":"
mkdir listmonk-demo\nsh -c \"$(curl -fsSL https://raw.githubusercontent.com/knadh/listmonk/master/install-demo.sh)\"\n
"},{"location":"installation/#manual-docker-install","title":"Manual Docker install","text":"
wget -O docker-compose.yml https://raw.githubusercontent.com/knadh/listmonk/master/docker-compose.yml\ndocker compose up -d demo-db demo-app\n

Warning

The demo does not persist Postgres after the containers are removed. DO NOT use this demo setup in production.

"},{"location":"installation/#production","title":"Production","text":""},{"location":"installation/#easy-docker-install_1","title":"Easy Docker install","text":"

This setup is recommended if you want to quickly setup listmonk in production.

mkdir listmonk\nsh -c \"$(curl -fsSL https://raw.githubusercontent.com/knadh/listmonk/master/install-prod.sh)\"\n

The above shell script performs the following actions:

Note

It's recommended to examine the contents of the shell script, before running in your environment.

"},{"location":"installation/#manual-docker-install_1","title":"Manual Docker install","text":"

The following workflow is recommended to setup listmonk manually using docker compose. You are encouraged to customise the contents of docker-compose.yml to your needs. The overall setup looks like:

"},{"location":"installation/#mounting-a-custom-configtoml","title":"Mounting a custom config.toml","text":"

To mount a local config.toml file, add the following section to docker-compose.yml:

  app:\n    <<: *app-defaults\n    depends_on:\n      - db\n    volumes:\n    - ./path/on/your/host/config.toml:/listmonk/config.toml\n

Note

Some common changes done inside config.toml for Docker based setups:

Here's a sample config.toml you can use:

[app]\naddress = \"0.0.0.0:9000\"\nadmin_username = \"listmonk\"\nadmin_password = \"listmonk\"\n\n# Database.\n[db]\nhost = \"listmonk_db\"\nport = 5432\nuser = \"listmonk\"\npassword = \"listmonk\"\ndatabase = \"listmonk\"\nssl_mode = \"disable\"\nmax_open = 25\nmax_idle = 25\nmax_lifetime = \"300s\"\n

Mount the local config.toml inside the container at listmonk/config.toml.

Tip

Info

The example docker-compose.yml file works with Docker Engine 24.0.5+ and Docker Compose version v2.20.2+.

"},{"location":"installation/#compiling-from-source","title":"Compiling from source","text":"

To compile the latest unreleased version (master branch):

  1. Make sure go, nodejs, and yarn are installed on your system.
  2. git clone git@github.com:knadh/listmonk.git
  3. cd listmonk && make dist. This will generate the listmonk binary.
"},{"location":"installation/#release-candidate-rc","title":"Release candidate (RC)","text":"

The master branch with bleeding edge changes is periodically built and published as listmonk/listmonk:rc on DockerHub. To run the latest pre-release version, replace all instances of listmonk/listmonk:latest with listmonk/listmonk:rc in the docker-compose.yml file and follow the Docker installation steps above. While it is generally safe to run release candidate versions, they may have issues that only get resolved in a general release.

"},{"location":"installation/#3rd-party-hosting","title":"3rd party hosting","text":""},{"location":"installation/#tutorials","title":"Tutorials","text":""},{"location":"messengers/","title":"Messengers","text":"

listmonk supports multiple custom messaging backends in additional to the default SMTP e-mail backend, enabling not just e-mail campaigns, but arbitrary message campaigns such as SMS, FCM notifications etc.

A Messenger is a web service that accepts a campaign message pushed to it as a JSON request, which the service can in turn broadcast as SMS, FCM etc. Messengers are registered in the Settings -> Messengers UI, and can be selected on individual campaigns.

Messengers support optional BasicAuth authentication. Plain text format for campaign content is ideal for messengers such as SMS and FCM.

When a campaign starts, listmonk POSTs messages in the following format to the selected messenger's endpoint. The endpoint should return a 200 OK response in case of a successful request.

The address required to broadcast the message, for instance, a phone number or an FCM ID, is expected to be stored and relayed as subscriber attributes.

{\n\"subject\": \"Welcome to listmonk\",\n\"body\": \"The message body\",\n\"content_type\": \"plain\",\n\"recipients\": [{\n\"uuid\": \"e44b4135-1e1d-40c5-8a30-0f9a886c2884\",\n\"email\": \"anon@example.com\",\n\"name\": \"Anon Doe\",\n\"attribs\": {\n\"phone\": \"123123123\",\n\"fcm_id\": \"2e7e4b512e7e4b512e7e4b51\",\n\"city\": \"Bengaluru\"\n},\n\"status\": \"enabled\"\n}],\n\"campaign\": {\n\"uuid\": \"2e7e4b51-f31b-418a-a120-e41800cb689f\",\n\"name\": \"Test campaign\",\n\"tags\": [\"test-campaign\"]\n}\n}\n
"},{"location":"messengers/#messenger-implementations","title":"Messenger implementations","text":"

Following is a list of HTTP messenger servers that connect to various backends.

Name Backend listmonk-messenger AWS Pinpoint SMS"},{"location":"querying-and-segmentation/","title":"Querying and segmenting subscribers","text":"

listmonk allows the writing of partial Postgres SQL expressions to query, filter, and segment subscribers.

"},{"location":"querying-and-segmentation/#database-fields","title":"Database fields","text":"

These are the fields in the subscriber database that can be queried.

Field Description subscribers.uuid The randomly generated unique ID of the subscriber subscribers.email E-mail ID of the subscriber subscribers.name Name of the subscriber subscribers.status Status of the subscriber (enabled, disabled, blocklisted) subscribers.attribs Map of arbitrary attributes represented as JSON. Accessed via the -> and ->> Postgres operator. subscribers.created_at Timestamp when the subscriber was first added subscribers.updated_at Timestamp when the subscriber was modified"},{"location":"querying-and-segmentation/#sample-attributes","title":"Sample attributes","text":"

Here's a sample JSON map of attributes assigned to an imaginary subscriber.

{\n\"city\": \"Bengaluru\",\n\"likes_tea\": true,\n\"spoken_languages\": [\"English\", \"Malayalam\"],\n\"projects\": 3,\n\"stack\": {\n\"frameworks\": [\"echo\", \"go\"],\n\"languages\": [\"go\", \"python\"],\n\"preferred_language\": \"go\"\n}\n}\n

"},{"location":"querying-and-segmentation/#sample-sql-query-expressions","title":"Sample SQL query expressions","text":""},{"location":"querying-and-segmentation/#find-a-subscriber-by-e-mail","title":"Find a subscriber by e-mail","text":"
-- Exact match\nsubscribers.email = 'some@domain.com'\n\n-- Partial match to find e-mails that end in @domain.com.\nsubscribers.email LIKE '%@domain.com'\n
"},{"location":"querying-and-segmentation/#find-a-subscriber-by-name","title":"Find a subscriber by name","text":"
-- Find all subscribers whose name start with John.\nsubscribers.email LIKE 'John%'\n
"},{"location":"querying-and-segmentation/#multiple-conditions","title":"Multiple conditions","text":"
-- Find all Johns who have been blocklisted.\nsubscribers.email LIKE 'John%' AND status = 'blocklisted'\n
"},{"location":"querying-and-segmentation/#querying-attributes","title":"Querying attributes","text":"
-- The ->> operator returns the value as text. Find all subscribers\n-- who live in Bengaluru and have done more than 3 projects.\n-- Here 'projects' is cast into an integer so that we can apply the\n-- numerical operator >\nsubscribers.attribs->>'city' = 'Bengaluru' AND\n(subscribers.attribs->>'projects')::INT > 3\n
"},{"location":"querying-and-segmentation/#querying-nested-attributes","title":"Querying nested attributes","text":"
-- Find all blocklisted subscribers who like to drink tea, can code Python\n-- and prefer coding Go.\n--\n-- The -> operator returns the value as a structure. Here, the \"languages\" field\n-- The ? operator checks for the existence of a value in a list.\nsubscribers.status = 'blocklisted' AND\n(subscribers.attribs->>'likes_tea')::BOOLEAN = true AND\nsubscribers.attribs->'stack'->'languages' ? 'python' AND\nsubscribers.attribs->'stack'->>'preferred_language' = 'go'\n

To learn how to write SQL expressions to do advancd querying on JSON attributes, refer to the Postgres JSONB documentation.

"},{"location":"templating/","title":"Templating","text":"

A template is a re-usable HTML design that can be used across campaigns and transactional messages. Most commonly, templates have standard header and footer areas with logos and branding elements, where campaign content is inserted in the middle. listmonk supports Go template expressions that lets you create powerful, dynamic HTML templates.

listmonk supports Go template expressions that lets you create powerful, dynamic HTML templates. It also integrates 100+ useful Sprig template functions.

"},{"location":"templating/#campaign-templates","title":"Campaign templates","text":"

Campaign templates are used in an e-mail campaigns. These template are created and managed on the UI under Campaigns -> Templates, and are selected when creating new campaigns.

"},{"location":"templating/#transactional-templates","title":"Transactional templates","text":"

Transactional templates are used for sending arbitrary transactional messages using the transactional API. These template are created and managed on the UI under Campaigns -> Templates.

"},{"location":"templating/#template-expressions","title":"Template expressions","text":"

There are several template functions and expressions that can be used in campaign and template bodies. They are written in the form {{ .Subscriber.Email }}, that is, an expression between double curly braces {{ and }}.

"},{"location":"templating/#subscriber-fields","title":"Subscriber fields","text":"Expression Description {{ .Subscriber.UUID }} The randomly generated unique ID of the subscriber {{ .Subscriber.Email }} E-mail ID of the subscriber {{ .Subscriber.Name }} Name of the subscriber {{ .Subscriber.FirstName }} First name of the subscriber (automatically extracted from the name) {{ .Subscriber.LastName }} Last name of the subscriber (automatically extracted from the name) {{ .Subscriber.Status }} Status of the subscriber (enabled, disabled, blocklisted) {{ .Subscriber.Attribs }} Map of arbitrary attributes. Fields can be accessed with ., eg: .Subscriber.Attribs.city {{ .Subscriber.CreatedAt }} Timestamp when the subscriber was first added {{ .Subscriber.UpdatedAt }} Timestamp when the subscriber was modified Expression Description {{ .Campaign.UUID }} The randomly generated unique ID of the campaign {{ .Campaign.Name }} Internal name of the campaign {{ .Campaign.Subject }} E-mail subject of the campaign {{ .Campaign.FromEmail }} The e-mail address from which the campaign is being sent"},{"location":"templating/#functions","title":"Functions","text":"Function Description {{ Date \"2006-01-01\" }} Prints the current datetime for the given format expressed as a Go date layout {{ TrackLink \"https://link.com\" }} Takes a URL and generates a tracking URL over it. For use in campaign bodies and templates. https://link.com@TrackLink Shorthand for TrackLink. Eg: <a href=\"https://link.com@TrackLink\">Link</a> {{ TrackView }} Inserts a single tracking pixel. Should only be used once, ideally in the template footer. {{ UnsubscribeURL }} Unsubscription and Manage preferences URL. Ideal for use in the template footer. {{ MessageURL }} URL to view the hosted version of an e-mail message. {{ OptinURL }} URL to the double-optin confirmation page. {{ Safe \"<!-- comment -->\" }} Add any HTML code as it is."},{"location":"templating/#sprig-functions","title":"Sprig functions","text":"

listmonk integrates the Sprig library that offers 100+ utility functions for working with strings, numbers, dates etc. that can be used in templating. Refer to the Sprig documentation for the full list of functions.

"},{"location":"templating/#example-template","title":"Example template","text":"

The expression {{ template \"content\" . }} should appear exactly once in every template denoting the spot where an e-mail's content is inserted. Here's a sample HTML e-mail that has a fixed header and footer that inserts the content in the middle.

<!DOCTYPE html>\n<html>\n  <head>\n    <style>\nbody {\nbackground: #eee;\nfont-family: Arial, sans-serif;\nfont-size: 6px;\ncolor: #111;\n}\nheader {\nborder-bottom: 1px solid #ddd;\npadding-bottom: 30px;\nmargin-bottom: 30px;\n}\n.container {\nbackground: #fff;\nwidth: 450px;\nmargin: 0 auto;\npadding: 30px;\n}\n</style>\n  </head>\n  <body>\n    <section class=\"container\">\n      <header>\n        <!-- This will appear in the header of all e-mails.\n             The subscriber's name will be automatically inserted here. //-->\n        Hi {{ .Subscriber.FirstName }}!\n      </header>\n\n      <!-- This is where the e-mail body will be inserted //-->\n      <div class=\"content\">\n        {{ template \"content\" . }}\n      </div>\n\n      <footer>\n        Copyright 2019. All rights Reserved.\n      </footer>\n\n      <!-- The tracking pixel will be inserted here //-->\n      {{ TrackView }}\n    </section>\n  </body>\n</html>\n

Info

For use with plaintext campaigns, create a template with no HTML content and just the placeholder {{ template \"content\" . }}

"},{"location":"templating/#example-campaign-body","title":"Example campaign body","text":"

Campaign bodies can be composed using the built-in WYSIWYG editor or as raw HTML documents. Assuming that the subscriber has a set of attributes defined, this example shows how to render those values in a campaign.

Hey, did you notice how the template showed your first name?\nYour last name is {{.Subscriber.LastName }}.\n\nYou have done {{ .Subscriber.Attribs.projects }} projects.\n\n\n{{ if eq .Subscriber.Attribs.city \"Bengaluru\" }}\n  You live in Bangalore!\n{{ else }}\n  Where do you live?\n{{ end }}\n\n\nHere is a link for you to click that will be tracked.\n<a href=\"{{ TrackLink \"https://google.com\" }}\">Google</a>\n

The above example uses an if condition to show one of two messages depending on the value of a subscriber attribute. Many such dynamic expressions are possible with Go templating expressions.

"},{"location":"templating/#system-templates","title":"System templates","text":"

System templates are used for rendering public user facing pages such as the subscription management page, and in automatically generated system e-mails such as the opt-in confirmation e-mail. These are bundled into listmonk but can be customized by copying the static directory locally, and passing its path to listmonk with the ./listmonk --static-dir=your/custom/path flag.

"},{"location":"templating/#public-pages","title":"Public pages","text":"/static/public/ index.html Base template with the header and footer that all pages use. home.html Landing page on the root domain with the login button. message.html Generic success / failure message page. optin.html Opt-in confirmation page. subscription.html Subscription management page with options for data export and wipe. subscription-form.html List selection and subscription form page.

To edit the appearance of the public pages using CSS and Javascript, head to Settings > Appearance > Public:

"},{"location":"templating/#system-e-mails","title":"System e-mails","text":"/static/email-templates/ base.html Base template with the header and footer that all system generated e-mails use. campaign-status.html E-mail notification that is sent to admins on campaign start, completion etc. import-status.html E-mail notification that is sent to admins on finish of an import job. subscriber-data.html E-mail that is sent to subscribers when they request a full dump of their private data. subscriber-optin.html Automatic opt-in confirmation e-mail that is sent to an unconfirmed subscriber when they are added. subscriber-optin-campaign.html E-mail content that's inserted into a campaign body when starting an opt-in campaign from the lists page. default.tpl Default campaign template that is created in Campaigns -> Templates when listmonk is first installed. This is not used after that.

Info

To turn system e-mail templates to plaintext, remove <!doctype html> from base.html and remove all HTML tags from the templates while retaining the Go templating code.

"},{"location":"upgrade/","title":"Upgrade","text":"

Some versions may require changes to the database. These changes or database \"migrations\" are applied automatically and safely, but, it is recommended to take a backup of the Postgres database before running the --upgrade option, especially if you have made customizations to the database tables.

"},{"location":"upgrade/#binary","title":"Binary","text":""},{"location":"upgrade/#docker","title":"Docker","text":""},{"location":"upgrade/#railway","title":"Railway","text":""},{"location":"upgrade/#downgrade","title":"Downgrade","text":"

To restore a previous version, you have to restore the DB for that particular version. DBs that have been upgraded with a particular version shouldn't be used with older versions. There may be DB changes that a new version brings that are incompatible with previous versions.

General steps:

  1. Stop listmonk.
  2. Restore your pre-upgrade database.
  3. If you're using docker compose, edit docker-compose.yml and change listmonk:latest to listmonk:v2.4.0 (for example).
  4. Restart.

Example with docker:

  1. Stop listmonk (app):
    sudo docker stop listmonk_app\n
  2. Restore your pre-upgrade db (required) (be careful, this will wipe your existing DB):
    psql -h 127.0.0.1 -p 9432 -U listmonk\ndrop schema public cascade;\ncreate schema public;\n\\q\npsql -h 127.0.0.1 -p 9432 -U listmonk -W listmonk < listmonk-preupgrade-db.sql\n
  3. Edit the docker-compose.yml:
    x-app-defaults: &app-defaults\n  restart: unless-stopped\n  image: listmonk/listmonk:v2.4.0\n
  4. Restart: sudo docker compose up -d app db nginx certbot
"},{"location":"apis/apis/","title":"APIs","text":"

All features that are available on the listmonk dashboard are also available as REST-like HTTP APIs that can be interacted with directly. Request and response bodies are JSON. This allows easy scripting of listmonk and integration with other systems, for instance, synchronisation with external subscriber databases.

API requests require BasicAuth authentication with the admin credentials.

The API section is a work in progress. There may be API calls that are yet to be documented. Please consider contributing to docs.

"},{"location":"apis/apis/#openapi-swagger-spec","title":"OpenAPI (Swagger) spec","text":"

The auto-generated OpenAPI (Swagger) specification site for the APIs are available at listmonk.app/docs/swagger

"},{"location":"apis/apis/#response-structure","title":"Response structure","text":""},{"location":"apis/apis/#successful-request","title":"Successful request","text":"
HTTP/1.1 200 OK\nContent-Type: application/json\n\n{\n\"data\": {}\n}\n

All responses from the API server are JSON with the content-type application/json unless explicitly stated otherwise. A successful 200 OK response always has a JSON response body with a status key with the value success. The data key contains the full response payload.

"},{"location":"apis/apis/#failed-request","title":"Failed request","text":"
HTTP/1.1 500 Server error\nContent-Type: application/json\n\n{\n\"message\": \"Error message\"\n}\n

A failure response is preceded by the corresponding 40x or 50x HTTP header. There may be an optional data key with additional payload.

"},{"location":"apis/apis/#timestamps","title":"Timestamps","text":"

All timestamp fields are in the format 2019-01-01T09:00:00.000000+05:30. The seconds component is suffixed by the milliseconds, followed by the + and the timezone offset.

"},{"location":"apis/apis/#common-http-error-codes","title":"Common HTTP error codes","text":"code 400 Missing or bad request parameters or values 403 Session expired or invalidate. Must relogin 404 Request resource was not found 405 Request method (GET, POST etc.) is not allowed on the requested endpoint 410 The requested resource is gone permanently 429 Too many requests to the API (rate limiting) 500 Something unexpected went wrong 502 The backend OMS is down and the API is unable to communicate with it 503 Service unavailable; the API is down 504 Gateway timeout; the API is unreachable"},{"location":"apis/campaigns/","title":"API / Campaigns","text":"Method Endpoint Description GET /api/campaigns Gets all campaigns. GET /api/campaigns/:campaign_id Gets a single campaign. GET /api/campaigns/:campaign_id/preview Gets the HTML preview of a campaign body. GET /api/campaigns/running/stats Gets the stats of a given set of campaigns. POST /api/campaigns Creates a new campaign. POST /api/campaigns/:campaign_id/test Posts campaign message to arbitrary subscribers for testing. PUT /api/campaigns/:campaign_id Modifies a campaign. PUT /api/campaigns/:campaign_id/status Start / pause / cancel / schedule a campaign. DELETE /api/campaigns/:campaign_id Deletes a campaign."},{"location":"apis/campaigns/#get-apicampaigns","title":"GET /api/campaigns","text":"

Gets all campaigns.

"},{"location":"apis/campaigns/#example-request","title":"Example Request","text":"
 curl -u \"username:password\" -X GET 'http://localhost:9000/api/campaigns?page=1&per_page=100'\n
"},{"location":"apis/campaigns/#parameters","title":"Parameters","text":"

Name | Type | Required/Optional | Description --------|--------------------|-------------|---------------------|--------------------- query | string | Optional | Optional string to search a list by name. order_by | string | Optional | Field to sort results by. name|status|created_at|updated_at order | string | Optional | ASC|DESCSort by ascending or descending order. page | number | Optional | Page number for paginated results. per_page | number | Optional | Results to return per page. Setting this to all skips pagination and returns all results.

"},{"location":"apis/campaigns/#example-response","title":"Example Response","text":"
{\n\"data\": {\n\"results\": [\n{\n\"id\": 1,\n\"created_at\": \"2020-03-14T17:36:41.29451+01:00\",\n\"updated_at\": \"2020-03-14T17:36:41.29451+01:00\",\n\"CampaignID\": 0,\n\"views\": 0,\n\"clicks\": 0,\n\"lists\": [\n{\n\"id\": 1,\n\"name\": \"Default list\"\n}\n],\n\"started_at\": null,\n\"to_send\": 0,\n\"sent\": 0,\n\"uuid\": \"57702beb-6fae-4355-a324-c2fd5b59a549\",\n\"type\": \"regular\",\n\"name\": \"Test campaign\",\n\"subject\": \"Welcome to listmonk\",\n\"from_email\": \"No Reply <noreply@yoursite.com>\",\n\"body\": \"<h3>Hi {{ .Subscriber.FirstName }}!</h3>\\n\\t\\t\\tThis is a test e-mail campaign. Your second name is {{ .Subscriber.LastName }} and you are from {{ .Subscriber.Attribs.city }}.\",\n\"send_at\": \"2020-03-15T17:36:41.293233+01:00\",\n\"status\": \"draft\",\n\"content_type\": \"richtext\",\n\"tags\": [\n\"test-campaign\"\n],\n\"template_id\": 1,\n\"messenger\": \"email\"\n}\n],\n\"query\": \"\",\n\"total\": 1,\n\"per_page\": 20,\n\"page\": 1\n}\n}\n
"},{"location":"apis/campaigns/#get-apicampaignscampaign_id","title":"GET /api/campaigns/:campaign_id","text":"

Gets a single campaign.

"},{"location":"apis/campaigns/#parameters_1","title":"Parameters","text":"Name Parameter Type Data Type Required/Optional Description campaign_id Path Parameter Number Required The id value of the campaign you want to get."},{"location":"apis/campaigns/#example-request_1","title":"Example Request","text":"
curl -u \"username:password\" -X GET 'http://localhost:9000/api/campaigns/1'\n
"},{"location":"apis/campaigns/#example-response_1","title":"Example Response","text":"
{\n\"data\": {\n\"id\": 1,\n\"created_at\": \"2020-03-14T17:36:41.29451+01:00\",\n\"updated_at\": \"2020-03-14T17:36:41.29451+01:00\",\n\"CampaignID\": 0,\n\"views\": 0,\n\"clicks\": 0,\n\"lists\": [\n{\n\"id\": 1,\n\"name\": \"Default list\"\n}\n],\n\"started_at\": null,\n\"to_send\": 0,\n\"sent\": 0,\n\"uuid\": \"57702beb-6fae-4355-a324-c2fd5b59a549\",\n\"type\": \"regular\",\n\"name\": \"Test campaign\",\n\"subject\": \"Welcome to listmonk\",\n\"from_email\": \"No Reply <noreply@yoursite.com>\",\n\"body\": \"<h3>Hi {{ .Subscriber.FirstName }}!</h3>\\n\\t\\t\\tThis is a test e-mail campaign. Your second name is {{ .Subscriber.LastName }} and you are from {{ .Subscriber.Attribs.city }}.\",\n\"send_at\": \"2020-03-15T17:36:41.293233+01:00\",\n\"status\": \"draft\",\n\"content_type\": \"richtext\",\n\"tags\": [\n\"test-campaign\"\n],\n\"template_id\": 1,\n\"messenger\": \"email\"\n}\n}\n
"},{"location":"apis/campaigns/#get-apicampaignscampaign_idpreview","title":"GET /api/campaigns/:campaign_id/preview","text":"

Gets the html preview of a campaign body.

"},{"location":"apis/campaigns/#parameters_2","title":"Parameters","text":"Name Parameter Type Data Type Required/Optional Description campaign_id Path Parameter Number Required The id value of the campaign to be previewed."},{"location":"apis/campaigns/#example-request_2","title":"Example Request","text":"
curl -u \"username:password\" -X GET 'http://localhost:9000/api/campaigns/1/preview'\n
"},{"location":"apis/campaigns/#example-response_2","title":"Example Response","text":"
<h3>Hi John!</h3>\nThis is a test e-mail campaign. Your second name is Doe and you are from Bengaluru.\n
"},{"location":"apis/campaigns/#get-apicampaignsrunningstats","title":"GET /api/campaigns/running/stats","text":"

Gets the running stat of a given set of campaigns.

"},{"location":"apis/campaigns/#parameters_3","title":"Parameters","text":"Name Parameter Type Data Type Required/Optional Description campaign_id Query Parameters Number Required The id values of the campaigns whose stat you want to get."},{"location":"apis/campaigns/#example-request_3","title":"Example Request","text":"
curl -u \"username:password\" -X GET 'http://localhost:9000/api/campaigns/running/stats?campaign_id=1'\n
"},{"location":"apis/campaigns/#example-response_3","title":"Example Response","text":"
{\n\"data\": []\n}\n
"},{"location":"apis/campaigns/#post-apicampaigns","title":"POST /api/campaigns","text":"

Creates a new campaign.

"},{"location":"apis/campaigns/#parameters_4","title":"Parameters","text":"Name Data type Required/Optional Description name String Required Name of the campaign. subject String Required (E-mail) subject of the campaign. lists []Number Required Array of list IDs to send the campaign to. from_email String Optional From e-mail to show on the campaign e-mails. If left empty, the default value from settings is used. type String Required regular or optin campaign. content_type String Required richtext, html, markdown, plain body String Required Campaign content body. altbody String Optional Alternate plain text body for HTML (and richtext) e-mails. send_at String Optional A timestamp to schedule the campaign at. Eg: 2021-12-25T06:00:00 (YYYY-MM-DDTHH:MM:SS) messenger String Optional email or a custom messenger defined in the settings. If left empty, email is used. template_id Number Optional ID of the template to use. If left empty, the default template is used. tags []String Optional Array of string tags to mark the campaign."},{"location":"apis/campaigns/#example-request_4","title":"Example request","text":"
curl -u \"username:password\" 'http://localhost:9000/api/campaigns' -X POST -H 'Content-Type: application/json;charset=utf-8' --data-raw '{\"name\":\"Test campaign\",\"subject\":\"Hello, world\",\"lists\":[1],\"from_email\":\"listmonk <noreply@listmonk.yoursite.com>\",\"content_type\":\"richtext\",\"messenger\":\"email\",\"type\":\"regular\",\"tags\":[\"test\"],\"template_id\":1}'\n
"},{"location":"apis/campaigns/#example-response_4","title":"Example response","text":"
{\n\"data\": {\n\"id\": 1,\n\"created_at\": \"2021-12-27T11:50:23.333485Z\",\n\"updated_at\": \"2021-12-27T11:50:23.333485Z\",\n\"views\": 0,\n\"clicks\": 0,\n\"bounces\": 0,\n\"lists\": [{\n\"id\": 1,\n\"name\": \"Default list\"\n}],\n\"started_at\": null,\n\"to_send\": 1,\n\"sent\": 0,\n\"uuid\": \"90c889cc-3728-4064-bbcb-5c1c446633b3\",\n\"type\": \"regular\",\n\"name\": \"Test campaign\",\n\"subject\": \"Hello, world\",\n\"from_email\": \"listmonk \\u003cnoreply@listmonk.yoursite.com\\u003e\",\n\"body\": \"\",\n\"altbody\": null,\n\"send_at\": null,\n\"status\": \"draft\",\n\"content_type\": \"richtext\",\n\"tags\": [\"test\"],\n\"template_id\": 1,\n\"messenger\": \"email\"\n}\n}\n
"},{"location":"apis/campaigns/#put-apicampaignscampaign_idstatus","title":"PUT /api/campaigns/:campaign_id/status","text":"

Modifies a campaign status to start, pause, cancel, or schedule a campaign.

"},{"location":"apis/campaigns/#parameters_5","title":"Parameters","text":"Name Parameter Type Data Type Required/Optional Description campaign_id Path Parameter Number Required The id value of the campaign whose status is to be modified. status Request Body String Required scheduled, running, paused, cancelled."},{"location":"apis/campaigns/#note","title":"Note:","text":""},{"location":"apis/campaigns/#example-request_5","title":"Example Request","text":"
curl -u \"username:password\" -X PUT 'http://localhost:9000/api/campaigns/1/status' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{\"status\":\"scheduled\"}'\n
"},{"location":"apis/campaigns/#example-response_5","title":"Example Response","text":"
{\n\"data\": {\n\"id\": 1,\n\"created_at\": \"2020-03-14T17:36:41.29451+01:00\",\n\"updated_at\": \"2020-04-08T19:35:17.331867+01:00\",\n\"CampaignID\": 0,\n\"views\": 0,\n\"clicks\": 0,\n\"lists\": [\n{\n\"id\": 1,\n\"name\": \"Default list\"\n}\n],\n\"started_at\": null,\n\"to_send\": 0,\n\"sent\": 0,\n\"uuid\": \"57702beb-6fae-4355-a324-c2fd5b59a549\",\n\"type\": \"regular\",\n\"name\": \"Test campaign\",\n\"subject\": \"Welcome to listmonk\",\n\"from_email\": \"No Reply <noreply@yoursite.com>\",\n\"body\": \"<h3>Hi {{ .Subscriber.FirstName }}!</h3>\\n\\t\\t\\tThis is a test e-mail campaign. Your second name is {{ .Subscriber.LastName }} and you are from {{ .Subscriber.Attribs.city }}.\",\n\"send_at\": \"2020-03-15T17:36:41.293233+01:00\",\n\"status\": \"scheduled\",\n\"content_type\": \"richtext\",\n\"tags\": [\n\"test-campaign\"\n],\n\"template_id\": 1,\n\"messenger\": \"email\"\n}\n}\n
"},{"location":"apis/campaigns/#delete-apicampaignscampaign_id","title":"DELETE /api/campaigns/:campaign_id","text":"

Deletes a campaign, only scheduled campaigns that have not yet been started can be deleted.

"},{"location":"apis/campaigns/#parameters_6","title":"Parameters","text":"Name Parameter Type Data Type Required/Optional Description campaign_id Path Parameter Number Required The id value of the campaign you want to delete."},{"location":"apis/campaigns/#example-request_6","title":"Example Request","text":"
curl -u \"username:password\" -X DELETE 'http://localhost:9000/api/campaigns/34'\n
"},{"location":"apis/campaigns/#example-response_6","title":"Example Response","text":"
{\n\"data\": true\n}\n
"},{"location":"apis/import/","title":"API / Import","text":"Method Endpoint Description GET api/import/subscribers Gets a import statistics. GET api/import/subscribers/logs Get a import statistics . POST api/import/subscribers Upload a ZIP file or CSV file to bulk import subscribers. DELETE api/import/subscribers Stops and deletes a import."},{"location":"apis/import/#get-apiimportsubscribers","title":"GET api/import/subscribers","text":"

Gets import status.

"},{"location":"apis/import/#example-request","title":"Example Request","text":"
curl -u \"username:username\" -X GET 'http://localhost:9000/api/import/subscribers'\n
"},{"location":"apis/import/#example-response","title":"Example Response","text":"
{\n\"data\": {\n\"name\": \"\",\n\"total\": 0,\n\"imported\": 0,\n\"status\": \"none\"\n}\n}\n
"},{"location":"apis/import/#get-apiimportsubscriberslogs","title":"GET api/import/subscribers/logs","text":"

Gets import logs.

"},{"location":"apis/import/#example-request_1","title":"Example Request","text":"
curl -u \"username:username\" -X GET 'http://localhost:9000/api/import/subscribers/logs'\n
"},{"location":"apis/import/#example-response_1","title":"Example Response","text":"
{\n\"data\": \"2020/04/08 21:55:20 processing 'import.csv'\\n2020/04/08 21:55:21 imported finished\\n\"\n}\n
"},{"location":"apis/import/#post-apiimportsubscribers","title":"POST api/import/subscribers","text":"

Post a CSV (optionally zipped) file to do a bulk import. The request should be a multipart form POST.

"},{"location":"apis/import/#parameters","title":"Parameters","text":"Name Parameter type Data type Required/Optional Description params Request body String Required Stringified JSON with import params file Request body File Required File to upload

params (JSON string)

    {\n\"mode\": \"subscribe\", // subscribe or blocklist\n\"delim\": \",\",        // delimiter in the uploaded file\n\"lists\":[1],         // array of list IDs to import into\n\"overwrite\": true    // overwrite existing entries or skip them?\n}\n
"},{"location":"apis/import/#delete-apiimportsubscribers","title":"DELETE api/import/subscribers","text":"

Stops and deletes an import.

"},{"location":"apis/import/#example-request_2","title":"Example Request","text":"
curl -u \"username:username\" -X DELETE 'http://localhost:9000/api/import/subscribers' 
"},{"location":"apis/import/#example-response_2","title":"Example Response","text":"
{\n\"data\": {\n\"name\": \"\",\n\"total\": 0,\n\"imported\": 0,\n\"status\": \"none\"\n}\n}\n
"},{"location":"apis/lists/","title":"API / Lists","text":"Method Endpoint Description GET /api/lists Gets all lists. GET /api/lists/:list_id Gets a single list. POST /api/lists Creates a new list. PUT /api/lists/:list_id Modifies a list. DELETE /api/lists/:list_id Deletes a list."},{"location":"apis/lists/#get-apilists","title":"GET /api/lists","text":"

Gets lists.

"},{"location":"apis/lists/#parameters","title":"Parameters","text":"Name Type Required/Optional Description query string Optional Optional string to search a list by name. order_by string Optional Field to sort results by. name|status|created_at|updated_at order string Optional ASC|DESCSort by ascending or descending order. page number Optional Page number for paginated results. per_page number Optional Results to return per page. Setting this to all skips pagination and returns all results."},{"location":"apis/lists/#example-request","title":"Example Request","text":"
curl -u \"username:username\" -X GET 'http://localhost:9000/api/lists?page=1&per_page=100'\n
"},{"location":"apis/lists/#example-response","title":"Example Response","text":"
{\n\"data\": {\n\"results\": [\n{\n\"id\": 1,\n\"created_at\": \"2020-02-10T23:07:16.194843+01:00\",\n\"updated_at\": \"2020-03-06T22:32:01.118327+01:00\",\n\"uuid\": \"ce13e971-c2ed-4069-bd0c-240e9a9f56f9\",\n\"name\": \"Default list\",\n\"type\": \"public\",\n\"optin\": \"double\",\n\"tags\": [\n\"test\"\n],\n\"subscriber_count\": 2\n},\n{\n\"id\": 2,\n\"created_at\": \"2020-03-04T21:12:09.555013+01:00\",\n\"updated_at\": \"2020-03-06T22:34:46.405031+01:00\",\n\"uuid\": \"f20a2308-dfb5-4420-a56d-ecf0618a102d\",\n\"name\": \"get\",\n\"type\": \"private\",\n\"optin\": \"single\",\n\"tags\": [],\n\"subscriber_count\": 0\n}\n],\n\"total\": 5,\n\"per_page\": 20,\n\"page\": 1\n}\n}\n
"},{"location":"apis/lists/#get-apilistslist_id","title":"GET /api/lists/:list_id","text":"

Gets a single list.

"},{"location":"apis/lists/#parameters_1","title":"Parameters","text":"Name Parameter type Data type Required/Optional Description list_id Path parameter number Required The id value of the list you want to get."},{"location":"apis/lists/#example-request_1","title":"Example Request","text":"
curl -u \"username:username\" -X GET 'http://localhost:9000/api/lists/5'\n
"},{"location":"apis/lists/#example-response_1","title":"Example Response","text":"
{\n\"data\": {\n\"id\": 5,\n\"created_at\": \"2020-03-07T06:31:06.072483+01:00\",\n\"updated_at\": \"2020-03-07T06:31:06.072483+01:00\",\n\"uuid\": \"1bb246ab-7417-4cef-bddc-8fc8fc941d3a\",\n\"name\": \"Test list\",\n\"type\": \"public\",\n\"optin\": \"double\",\n\"tags\": [],\n\"subscriber_count\": 0\n}\n}\n
"},{"location":"apis/lists/#post-apilists","title":"POST /api/lists","text":"

Creates a new list.

"},{"location":"apis/lists/#parameters_2","title":"Parameters","text":"Name Parameter type Data type Required/Optional Description name Request body string Required The new list name. type Request body string Required List type, can be set to private or public. optin Request body string Required single or double optin. tags Request body string[] Optional The tags associated with the list."},{"location":"apis/lists/#example-request_2","title":"Example Request","text":"
curl -u \"username:username\" -X POST 'http://localhost:9000/api/lists'\n
"},{"location":"apis/lists/#example-response_2","title":"Example Response","text":"
{\n\"data\": {\n\"id\": 5,\n\"created_at\": \"2020-03-07T06:31:06.072483+01:00\",\n\"updated_at\": \"2020-03-07T06:31:06.072483+01:00\",\n\"uuid\": \"1bb246ab-7417-4cef-bddc-8fc8fc941d3a\",\n\"name\": \"Test list\",\n\"type\": \"public\",\n\"tags\": [],\n\"subscriber_count\": 0\n}\n}\nnull\n
"},{"location":"apis/lists/#put-apilistslist_id","title":"PUT /api/lists/list_id","text":"

Modifies a list.

"},{"location":"apis/lists/#parameters_3","title":"Parameters","text":"Name Parameter type Data type Required/Optional Description list_id Path parameter number Required The id of the list to be modified. name Request body string Optional The name which the old name will be modified to. type Request body string Optional List type, can be set to private or public. optin Request body string Optional single or double optin. tags Request body string[] Optional The tags associated with the list."},{"location":"apis/lists/#example-request_3","title":"Example Request","text":"
curl -u \"username:username\" -X PUT 'http://localhost:9000/api/lists/5' \\\n--form 'name=modified test list' \\\n--form 'type=private'\n
"},{"location":"apis/lists/#example-response_3","title":"Example Response","text":"
{\n\"data\": {\n\"id\": 5,\n\"created_at\": \"2020-03-07T06:31:06.072483+01:00\",\n\"updated_at\": \"2020-03-07T06:52:15.208075+01:00\",\n\"uuid\": \"1bb246ab-7417-4cef-bddc-8fc8fc941d3a\",\n\"name\": \"modified test list\",\n\"type\": \"private\",\n\"optin\": \"single\",\n\"tags\": [],\n\"subscriber_count\": 0\n}\n}\n
"},{"location":"apis/media/","title":"API / Media","text":"Method Endpoint Description GET /api/media Gets an uploaded media file. POST /api/media Uploads a media file. DELETE /api/media/:media_id Deletes uploaded media files."},{"location":"apis/media/#get-apimedia","title":"GET /api/media","text":"

Gets an uploaded media file.

"},{"location":"apis/media/#example-request","title":"Example Request","text":"
curl -u \"username:username\" -X GET 'http://localhost:9000/api/media' \\\n--header 'Content-Type: multipart/form-data; boundary=--------------------------093715978792575906250298'\n
"},{"location":"apis/media/#example-response","title":"Example Response","text":"
{\n\"data\": [\n{\n\"id\": 1,\n\"uuid\": \"ec7b45ce-1408-4e5c-924e-965326a20287\",\n\"filename\": \"Media file\",\n\"created_at\": \"2020-04-08T22:43:45.080058+01:00\",\n\"thumb_url\": \"/uploads/image_thumb.jpg\",\n\"uri\": \"/uploads/image.jpg\"\n}\n]\n}\n

Response definitions The following table describes each item in the response.

Response item Description Data type data Array of the media file objects, which contains an information about the uploaded media files array id Media file object ID number (int) uuid Media file uuid string (uuid) filename Name of the media file string created_at Date and time, when the media file object was created String (localDateTime) thumb_uri The thumbnail URI of the media file string uri URI of the media file string"},{"location":"apis/media/#post-apimedia","title":"POST /api/media","text":"

Uploads a media file.

"},{"location":"apis/media/#parameters","title":"Parameters","text":"Name Parameter Type Data Type Required/Optional Description file Request body Media file Required The media file to be uploaded."},{"location":"apis/media/#example-request_1","title":"Example Request","text":"
curl -u \"username:username\" -X POST 'http://localhost:9000/api/media' \\\n--header 'Content-Type: multipart/form-data; boundary=--------------------------183679989870526937212428' \\\n--form 'file=@/path/to/image.jpg'\n
"},{"location":"apis/media/#example-response_1","title":"Example Response","text":"

{\n\"data\": {\n\"id\": 1,\n\"uuid\": \"ec7b45ce-1408-4e5c-924e-965326a20287\",\n\"filename\": \"Media file\",\n\"created_at\": \"2020-04-08T22:43:45.080058+01:00\",\n\"thumb_uri\": \"/uploads/image_thumb.jpg\",\n\"uri\": \"/uploads/image.jpg\"\n}\n}\n
Response definitions

Response item Description Data type data True means that the media file was successfully uploaded boolean"},{"location":"apis/media/#delete-apimediamedia_id","title":"DELETE /api/media/:media_id","text":"

Deletes an uploaded media file.

"},{"location":"apis/media/#parameters_1","title":"Parameters","text":"Name Parameter Type Data Type Required/Optional Description Media_id Path Parameter Number Required The id of the media file you want to delete."},{"location":"apis/media/#example-request_2","title":"Example Request","text":"
curl -u \"username:username\" -X DELETE 'http://localhost:9000/api/media/1'\n
"},{"location":"apis/media/#example-response_2","title":"Example Response","text":"
{\n\"data\": true\n}\n

Response definitions

Response item Description Data type data True means that the media file was successfully deleted boolean"},{"location":"apis/subscribers/","title":"API / Subscribers","text":"Method Endpoint Description GET /api/subscribers Gets all subscribers. GET /api/subscribers/:id Gets a single subscriber. GET /api/subscribers/lists/:id Gets subscribers in a list. GET /api/subscribers Gets subscribers in one or more lists. GET /api/subscribers Gets subscribers filtered by an arbitrary SQL expression. POST /api/subscribers Creates a new subscriber. POST /api/subscribers Unauthenticated API that enables public subscription. PUT /api/subscribers/lists Modify subscribers' list memberships. PUT /api/subscribers/:id Updates a subscriber by ID. PUT /api/subscribers/:id/blocklist Blocklists a single subscriber. PUT /api/subscribers/blocklist Blocklists one or more subscribers. PUT /api/subscribers/query/blocklist Blocklists subscribers with an arbitrary SQL expression. DELETE /api/subscribers/:id Deletes a single subscriber. DELETE /api/subscribers Deletes one or more subscribers . POST /api/subscribers/query/delete Deletes subscribers with an arbitrary SQL expression."},{"location":"apis/subscribers/#get-apisubscribers","title":"GET /api/subscribers","text":"

Gets all subscribers.

"},{"location":"apis/subscribers/#example-request","title":"Example Request","text":"
curl -u 'username:password' 'http://localhost:9000/api/subscribers?page=1&per_page=100' 

To skip pagination and retrieve all records, pass per_page=all.

"},{"location":"apis/subscribers/#example-response","title":"Example Response","text":"
{\n\"data\": {\n\"results\": [\n{\n\"id\": 1,\n\"created_at\": \"2020-02-10T23:07:16.199433+01:00\",\n\"updated_at\": \"2020-02-10T23:07:16.199433+01:00\",\n\"uuid\": \"ea06b2e7-4b08-4697-bcfc-2a5c6dde8f1c\",\n\"email\": \"john@example.com\",\n\"name\": \"John Doe\",\n\"attribs\": {\n\"city\": \"Bengaluru\",\n\"good\": true,\n\"type\": \"known\"\n},\n\"status\": \"enabled\",\n\"lists\": [\n{\n\"subscription_status\": \"unconfirmed\",\n\"id\": 1,\n\"uuid\": \"ce13e971-c2ed-4069-bd0c-240e9a9f56f9\",\n\"name\": \"Default list\",\n\"type\": \"public\",\n\"tags\": [\n\"test\"\n],\n\"created_at\": \"2020-02-10T23:07:16.194843+01:00\",\n\"updated_at\": \"2020-02-10T23:07:16.194843+01:00\"\n}\n]\n},\n{\n\"id\": 2,\n\"created_at\": \"2020-02-18T21:10:17.218979+01:00\",\n\"updated_at\": \"2020-02-18T21:10:17.218979+01:00\",\n\"uuid\": \"ccf66172-f87f-4509-b7af-e8716f739860\",\n\"email\": \"quadri@example.com\",\n\"name\": \"quadri\",\n\"attribs\": {},\n\"status\": \"enabled\",\n\"lists\": [\n{\n\"subscription_status\": \"unconfirmed\",\n\"id\": 1,\n\"uuid\": \"ce13e971-c2ed-4069-bd0c-240e9a9f56f9\",\n\"name\": \"Default list\",\n\"type\": \"public\",\n\"tags\": [\n\"test\"\n],\n\"created_at\": \"2020-02-10T23:07:16.194843+01:00\",\n\"updated_at\": \"2020-02-10T23:07:16.194843+01:00\"\n}\n]\n},\n{\n\"id\": 3,\n\"created_at\": \"2020-02-19T19:10:49.36636+01:00\",\n\"updated_at\": \"2020-02-19T19:10:49.36636+01:00\",\n\"uuid\": \"5d940585-3cc8-4add-b9c5-76efba3c6edd\",\n\"email\": \"sugar@example.com\",\n\"name\": \"sugar\",\n\"attribs\": {},\n\"status\": \"enabled\",\n\"lists\": []\n}\n],\n\"query\": \"\",\n\"total\": 3,\n\"per_page\": 20,\n\"page\": 1\n}\n}\n
"},{"location":"apis/subscribers/#get-apisubscribersid","title":"GET /api/subscribers/:id","text":"

Gets a single subscriber.

"},{"location":"apis/subscribers/#parameters","title":"Parameters","text":"Name Parameter type Data type Required/Optional Description id Path parameter Number Required The id value of the subscriber you want to get."},{"location":"apis/subscribers/#example-request_1","title":"Example Request","text":"
curl -u 'username:password' 'http://localhost:9000/api/subscribers/1' 
"},{"location":"apis/subscribers/#example-response_1","title":"Example Response","text":"
{\n\"data\": {\n\"id\": 1,\n\"created_at\": \"2020-02-10T23:07:16.199433+01:00\",\n\"updated_at\": \"2020-02-10T23:07:16.199433+01:00\",\n\"uuid\": \"ea06b2e7-4b08-4697-bcfc-2a5c6dde8f1c\",\n\"email\": \"john@example.com\",\n\"name\": \"John Doe\",\n\"attribs\": {\n\"city\": \"Bengaluru\",\n\"good\": true,\n\"type\": \"known\"\n},\n\"status\": \"enabled\",\n\"lists\": [\n{\n\"subscription_status\": \"unconfirmed\",\n\"id\": 1,\n\"uuid\": \"ce13e971-c2ed-4069-bd0c-240e9a9f56f9\",\n\"name\": \"Default list\",\n\"type\": \"public\",\n\"tags\": [\n\"test\"\n],\n\"created_at\": \"2020-02-10T23:07:16.194843+01:00\",\n\"updated_at\": \"2020-02-10T23:07:16.194843+01:00\"\n}\n]\n}\n}\n
"},{"location":"apis/subscribers/#get-apisubscribers_1","title":"GET /api/subscribers","text":"

Gets subscribers in one or more lists.

"},{"location":"apis/subscribers/#parameters_1","title":"Parameters","text":"Name Parameter type Data type Required/Optional Description List_id Request body Number Required ID of the list to fetch subscribers from."},{"location":"apis/subscribers/#example-request_2","title":"Example Request","text":"
curl -u 'username:password' 'http://localhost:9000/api/subscribers?list_id=1&list_id=2&page=1&per_page=100'\n

To skip pagination and retrieve all records, pass per_page=all.

"},{"location":"apis/subscribers/#example-response_2","title":"Example Response","text":"
{\n\"data\": {\n\"results\": [\n{\n\"id\": 1,\n\"created_at\": \"2019-06-26T16:51:54.37065+05:30\",\n\"updated_at\": \"2019-07-03T11:53:53.839692+05:30\",\n\"uuid\": \"5e91dda1-1c16-467d-9bf9-2a21bf22ae21\",\n\"email\": \"test@test.com\",\n\"name\": \"Test Subscriber\",\n\"attribs\": {\n\"city\": \"Bengaluru\",\n\"projects\": 3,\n\"stack\": {\n\"languages\": [\"go\", \"python\"]\n}\n},\n\"status\": \"enabled\",\n\"lists\": [\n{\n\"subscription_status\": \"unconfirmed\",\n\"id\": 1,\n\"uuid\": \"41badaf2-7905-4116-8eac-e8817c6613e4\",\n\"name\": \"Default list\",\n\"type\": \"public\",\n\"tags\": [\"test\"],\n\"created_at\": \"2019-06-26T16:51:54.367719+05:30\",\n\"updated_at\": \"2019-06-26T16:51:54.367719+05:30\"\n}\n]\n}\n],\n\"query\": \"\",\n\"total\": 1,\n\"per_page\": 20,\n\"page\": 1\n}\n}\n
"},{"location":"apis/subscribers/#get-apisubscribers_2","title":"GET /api/subscribers","text":"

Gets subscribers with an SQL expression.

"},{"location":"apis/subscribers/#example-request_3","title":"Example Request","text":"
curl -u 'username:password' -X GET 'http://localhost:9000/api/subscribers' \\\n--url-query 'page=1' \\\n--url-query 'per_page=100' \\\n--url-query \"query=subscribers.name LIKE 'Test%' AND subscribers.attribs->>'city' = 'Bengaluru'\"\n

To skip pagination and retrieve all records, pass per_page=all.

Refer to the querying and segmentation section for more information on how to query subscribers with SQL expressions.

"},{"location":"apis/subscribers/#example-response_3","title":"Example Response","text":"
{\n\"data\": {\n\"results\": [\n{\n\"id\": 1,\n\"created_at\": \"2019-06-26T16:51:54.37065+05:30\",\n\"updated_at\": \"2019-07-03T11:53:53.839692+05:30\",\n\"uuid\": \"5e91dda1-1c16-467d-9bf9-2a21bf22ae21\",\n\"email\": \"test@test.com\",\n\"name\": \"Test Subscriber\",\n\"attribs\": {\n\"city\": \"Bengaluru\",\n\"projects\": 3,\n\"stack\": {\n\"frameworks\": [\"echo\", \"go\"],\n\"languages\": [\"go\", \"python\"]\n}\n},\n\"status\": \"enabled\",\n\"lists\": [\n{\n\"subscription_status\": \"unconfirmed\",\n\"id\": 1,\n\"uuid\": \"41badaf2-7905-4116-8eac-e8817c6613e4\",\n\"name\": \"Default list\",\n\"type\": \"public\",\n\"tags\": [\"test\"],\n\"created_at\": \"2019-06-26T16:51:54.367719+05:30\",\n\"updated_at\": \"2019-06-26T16:51:54.367719+05:30\"\n}\n]\n}\n],\n\"query\": \"subscribers.name LIKE 'Test%' AND subscribers.attribs-\\u003e\\u003e'city' = 'Bengaluru'\",\n\"total\": 1,\n\"per_page\": 20,\n\"page\": 1\n}\n}\n
"},{"location":"apis/subscribers/#post-apisubscribers","title":"POST /api/subscribers","text":"

Creates a new subscriber.

"},{"location":"apis/subscribers/#parameters_2","title":"Parameters","text":"Name Parameter type Data type Required/Optional Description email Request body String Required The email address of the new subscriber. name Request body String Required The name of the new subscriber. status Request body String Required The status of the new subscriber. Can be enabled, disabled or blocklisted. lists Request body Numbers Optional Array of list IDs to subscribe to (marked as unconfirmed by default). attribs Request body json Optional JSON list containing new subscriber's attributes. preconfirm_subscriptions Request body Bool Optional If true, marks subscriptions as confirmed and no-optin e-mails are sent for double opt-in lists."},{"location":"apis/subscribers/#example-request_4","title":"Example Request","text":"
curl -u 'username:password' 'http://localhost:9000/api/subscribers' -H 'Content-Type: application/json' \\\n--data '{\"email\":\"subsriber@domain.com\",\"name\":\"The Subscriber\",\"status\":\"enabled\",\"lists\":[1],\"attribs\":{\"city\":\"Bengaluru\",\"projects\":3,\"stack\":{\"languages\":[\"go\",\"python\"]}}}'\n
"},{"location":"apis/subscribers/#example-response_4","title":"Example Response","text":"
{\n\"data\": {\n\"id\": 3,\n\"created_at\": \"2019-07-03T12:17:29.735507+05:30\",\n\"updated_at\": \"2019-07-03T12:17:29.735507+05:30\",\n\"uuid\": \"eb420c55-4cfb-4972-92ba-c93c34ba475d\",\n\"email\": \"subsriber@domain.com\",\n\"name\": \"The Subscriber\",\n\"attribs\": {\n\"city\": \"Bengaluru\",\n\"projects\": 3,\n\"stack\": { \"languages\": [\"go\", \"python\"] }\n},\n\"status\": \"enabled\",\n\"lists\": [1]\n}\n}\n
"},{"location":"apis/subscribers/#post-apipublicsubscription","title":"POST /api/public/subscription","text":"

This is a public, unauthenticated API meant for directly integrating forms for public subscription. The API supports both form encoded or a JSON encoded body.

"},{"location":"apis/subscribers/#parameters_3","title":"Parameters","text":"Name Parameter type Data type Required/Optional Description email Request body String Required The email address of the subscriber. name Request body String Optional The name of the new subscriber. list_uuids Request body Strings Required Array of list UUIDs."},{"location":"apis/subscribers/#example-json-request","title":"Example JSON Request","text":"
curl -u 'http://localhost:9000/api/public/subscription' -H 'Content-Type: application/json' \\\n--data '{\"email\":\"subsriber@domain.com\",\"name\":\"The Subscriber\", \"lists\": [\"eb420c55-4cfb-4972-92ba-c93c34ba475d\", \"0c554cfb-eb42-4972-92ba-c93c34ba475d\"]}'\n
"},{"location":"apis/subscribers/#example-form-request","title":"Example Form Request","text":"
curl -u 'http://localhost:9000/api/public/subscription' \\\n-d 'email=subsriber@domain.com' -d 'name=The Subscriber' -d 'l=eb420c55-4cfb-4972-92ba-c93c34ba475d' -d 'l=0c554cfb-eb42-4972-92ba-c93c34ba475d'\n

Notice that in form request, there param is l that is repeated for multiple lists, and not lists like in JSON.

"},{"location":"apis/subscribers/#example-response_5","title":"Example Response","text":"
{\n\"data\": true\n}\n
"},{"location":"apis/subscribers/#put-apisubscriberslists","title":"PUT /api/subscribers/lists","text":"

Modify subscribers list memberships.

"},{"location":"apis/subscribers/#parameters_4","title":"Parameters","text":"Name Parameter type Data type Required/Optional Description ids Request body Numbers Required The ids of the subscribers to be modified. action Request body String Required Whether to add, remove, or unsubscribe the users. target_list_ids Request body Numbers Required The ids of the lists to be modified. status Request body String Required for add confirmed, unconfirmed, or unsubscribed status."},{"location":"apis/subscribers/#example-request_5","title":"Example Request","text":"

To subscribe users 1, 2, and 3 to lists 4, 5, and 6:

curl -u 'username:password' -X PUT 'http://localhost:9000/api/subscribers/lists' \\\n--data-raw '{\"ids\": [1, 2, 3], \"action\": \"add\", \"target_list_ids\": [4, 5, 6], \"status\": \"confirmed\"}'\n
"},{"location":"apis/subscribers/#example-response_6","title":"Example Response","text":"
{\n\"data\": true\n} 
"},{"location":"apis/subscribers/#put-apisubscribersid","title":"PUT /api/subscribers/:id","text":"

Updates a single subscriber.

"},{"location":"apis/subscribers/#parameters_5","title":"Parameters","text":"

Parameters are the same as POST /api/subscribers used for subscriber creation.

Please note that this is a PUT request, so all the parameters have to be set. For example if you don't provide lists, the subscriber will be deleted from all the lists he was previously signed on.

"},{"location":"apis/subscribers/#put-apisubscribersidblocklist","title":"PUT /api/subscribers/:id/blocklist","text":"

Blocklists a single subscriber.

"},{"location":"apis/subscribers/#parameters_6","title":"Parameters","text":"Name Parameter type Data type Required/Optional Description id Path parameter Number Required The id value of the subscriber you want to blocklist."},{"location":"apis/subscribers/#example-request_6","title":"Example Request","text":"
curl -u 'username:password' -X PUT 'http://localhost:9000/api/subscribers/9/blocklist'\n
"},{"location":"apis/subscribers/#example-response_7","title":"Example Response","text":"
{\n\"data\": true\n} 
"},{"location":"apis/subscribers/#put-apisubscribersqueryblocklist","title":"PUT /api/subscribers/query/blocklist","text":"

Blocklists subscribers with an arbitrary sql expression.

"},{"location":"apis/subscribers/#example-request_7","title":"Example Request","text":"
curl -u 'username:password' -X PUT 'http://localhost:9000/api/subscribers/query/blocklist' \\\n--data-raw '\"query=subscribers.name LIKE '\\''John Doe'\\'' AND subscribers.attribs->>'\\''city'\\'' = '\\''Bengaluru'\\''\"'\n

Refer to the querying and segmentation section for more information on how to query subscribers with SQL expressions.

"},{"location":"apis/subscribers/#example-response_8","title":"Example Response","text":"
{\n\"data\": true\n}\n
"},{"location":"apis/subscribers/#delete-apisubscribersid","title":"DELETE /api/subscribers/:id","text":"

Deletes a single subscriber.

"},{"location":"apis/subscribers/#parameters_7","title":"Parameters","text":"Name Parameter type Data type Required/Optional Description id Path parameter Number Required The id of the subscriber you want to delete."},{"location":"apis/subscribers/#example-request_8","title":"Example Request","text":"
curl -u 'username:password' -X DELETE 'http://localhost:9000/api/subscribers/9'\n
"},{"location":"apis/subscribers/#example-response_9","title":"Example Response","text":"
{\n\"data\": true\n}\n
"},{"location":"apis/subscribers/#delete-apisubscribers","title":"DELETE /api/subscribers","text":"

Deletes one or more subscribers.

"},{"location":"apis/subscribers/#parameters_8","title":"Parameters","text":"Name Parameter type Data type Required/Optional Description id Query parameters Number Required The id of the subscribers you want to delete."},{"location":"apis/subscribers/#example-request_9","title":"Example Request","text":"
curl -u 'username:password' -X DELETE 'http://localhost:9000/api/subscribers?id=10&id=11'\n
"},{"location":"apis/subscribers/#example-response_10","title":"Example Response","text":"
{\n\"data\": true\n}\n
"},{"location":"apis/subscribers/#post-apisubscribersquerydelete","title":"POST /api/subscribers/query/delete","text":"

Deletes subscribers with an arbitrary SQL expression.

"},{"location":"apis/subscribers/#example-request_10","title":"Example Request","text":"
curl -u 'username:password' -X POST 'http://localhost:9000/api/subscribers/query/delete' \\\n--data-raw '\"query=subscribers.name LIKE '\\''John Doe'\\'' AND subscribers.attribs->>'\\''city'\\'' = '\\''Bengaluru'\\''\"'\n

Refer to the querying and segmentation section for more information on how to query subscribers with SQL expressions.

"},{"location":"apis/subscribers/#example-response_11","title":"Example Response","text":"
{\n\"data\": true\n}\n
"},{"location":"apis/templates/","title":"API / Templates","text":"Method Endpoint Description GET /api/templates Gets all templates. GET /api/templates/:template_id Gets a single template. GET /api/templates/:template_id/preview Gets the HTML preview of a template. POST /api/templates/preview POST /api/templates Creates a template. PUT /api/templates/:template_id Modifies a template. PUT /api/templates/:template_id/default Sets a template to the default template. DELETE /api/templates/:template_id Deletes a template."},{"location":"apis/templates/#get-apitemplates","title":"GET /api/templates","text":"

Gets all templates.

"},{"location":"apis/templates/#example-request","title":"Example Request","text":"
curl -u \"username:username\" -X GET 'http://localhost:9000/api/templates'\n
"},{"location":"apis/templates/#example-response","title":"Example Response","text":"
{\n\"data\": [\n{\n\"id\": 1,\n\"created_at\": \"2020-03-14T17:36:41.288578+01:00\",\n\"updated_at\": \"2020-03-14T17:36:41.288578+01:00\",\n\"name\": \"Default template\",\n\"body\": \"{{ template \\\"content\\\" . }}\",\n\"type\": \"campaign\",\n\"is_default\": true\n}\n]\n}\n
"},{"location":"apis/templates/#get-apitemplatestemplate_id","title":"GET /api/templates/:template_id","text":"

Gets a single template.

"},{"location":"apis/templates/#parameters","title":"Parameters","text":"Name Parameter Type Data Type Required/Optional Description template_id Path Parameter Number Required The id value of the template you want to get."},{"location":"apis/templates/#example-request_1","title":"Example Request","text":"
curl -u \"username:username\" -X GET 'http://localhost:9000/api/templates/1'\n
"},{"location":"apis/templates/#example-response_1","title":"Example Response","text":"
{\n\"data\": {\n\"id\": 1,\n\"created_at\": \"2020-03-14T17:36:41.288578+01:00\",\n\"updated_at\": \"2020-03-14T17:36:41.288578+01:00\",\n\"name\": \"Default template\",\n\"body\": \"{{ template \\\"content\\\" . }}\",\n\"type\": \"campaign\",\n\"is_default\": true\n}\n}\n
"},{"location":"apis/templates/#get-apitemplatestemplate_idpreview","title":"GET /api/templates/:template_id/preview","text":"

Gets the HTML preview of a template body.

"},{"location":"apis/templates/#parameters_1","title":"Parameters","text":"Name Parameter Type Data Type Required/Optional Description template_id Path Parameter Number Required The id value of the template whose html preview you want to get."},{"location":"apis/templates/#example-request_2","title":"Example Request","text":"
curl -u \"username:username\" -X GET 'http://localhost:9000/api/templates/1/preview'\n
"},{"location":"apis/templates/#example-response_2","title":"Example Response","text":"
<p>Hi there</p>\n<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis et elit ac elit sollicitudin condimentum non a magna.\n    Sed tempor mauris in facilisis vehicula. Aenean nisl urna, accumsan ac tincidunt vitae, interdum cursus massa.\n    Interdum et malesuada fames ac ante ipsum primis in faucibus. Aliquam varius turpis et turpis lacinia placerat.\n    Aenean id ligula a orci lacinia blandit at eu felis. Phasellus vel lobortis lacus. Suspendisse leo elit, luctus sed\n    erat ut, venenatis fermentum ipsum. Donec bibendum neque quis.</p>\n\n<h3>Sub heading</h3>\n<p>Nam luctus dui non placerat mattis. Morbi non accumsan orci, vel interdum urna. Duis faucibus id nunc ut euismod.\n    Curabitur et eros id erat feugiat fringilla in eget neque. Aliquam accumsan cursus eros sed faucibus.</p>\n\n<p>Here is a link to <a href=\"https://listmonk.app\" target=\"_blank\">listmonk</a>.</p>\n
"},{"location":"apis/templates/#put-apitemplatestemplate_iddefault","title":"PUT /api/templates/:template_id/default","text":"

Sets a template to the default template.

"},{"location":"apis/templates/#parameters_2","title":"Parameters","text":"Name Parameter Type Data Type Required/Optional Description template_id Path Parameter Number Required The id value of the template you want to set to the default template."},{"location":"apis/templates/#example-request_3","title":"Example Request","text":"
curl -u \"username:username\" -X PUT 'http://localhost:9000/api/templates/1/default'\n
"},{"location":"apis/templates/#example-response_3","title":"Example Response","text":"
{\n\"data\": {\n\"id\": 1,\n\"created_at\": \"2020-03-14T17:36:41.288578+01:00\",\n\"updated_at\": \"2020-03-14T17:36:41.288578+01:00\",\n\"name\": \"Default template\",\n\"body\": \"{{ template \\\"content\\\" . }}\",\n\"type\": \"campaign\",\n\"is_default\": true\n}\n}\n
"},{"location":"apis/templates/#delete-apitemplatestemplate_id","title":"DELETE /api/templates/:template_id","text":"

Deletes a template.

"},{"location":"apis/templates/#parameters_3","title":"Parameters","text":"Name Parameter Type Data Type Required/Optional Description template_id Path Parameter Number Required The id value of the template you want to delete."},{"location":"apis/templates/#example-request_4","title":"Example Request","text":"
curl -u \"username:username\" -X DELETE 'http://localhost:9000/api/templates/35'\n
"},{"location":"apis/templates/#example-response_4","title":"Example Response","text":"
{\n\"data\": true\n}\n
"},{"location":"apis/transactional/","title":"API / Transactional","text":"Method Endpoint Description POST /api/tx"},{"location":"apis/transactional/#post-apitx","title":"POST /api/tx","text":"

Send a transactional message to one or multiple subscribers using a predefined transactional template.

"},{"location":"apis/transactional/#parameters","title":"Parameters","text":"Name Data Type Optional Description subscriber_email String Optional E-mail of the subscriber. Either this or subscriber_id should be passed. subscriber_id Number Optional ID of the subscriber. Either this or subscriber_email should be passed. subscriber_emails []String Optional E-mails of the subscribers. This is an alternative to subscriber_email for multiple recipients. [\"email1@example.com\", \"emailX@example.com\"] subscriber_ids []Number Optional IDs of the subscribers. This is an alternative to subscriber_id for multiple recipients. [1,2,3] template_id Number Required ID of the transactional template to use in the message. from_email String Optional Optional from email. eg: Company <email@company.com> data Map Optional Optional data in {} nested map. Available in the template as {{ .Tx.Data.* }} headers []Map Optional Optional array of mail headers. [{\"key\": \"value\"}, {\"key\": \"value\"}] messenger String Optional Messenger to use to send the message. Default value is email. content_type String Optional html, markdown, plain"},{"location":"apis/transactional/#request","title":"Request","text":"
curl -u \"username:password\" \"http://localhost:9000/api/tx\" -X POST \\\n-H 'Content-Type: application/json; charset=utf-8' \\\n--data-binary @- << EOF\n    {\n        \"subscriber_email\": \"user@test.com\",\n        \"template_id\": 2,\n        \"data\": {\"order_id\": \"1234\", \"date\": \"2022-07-30\", \"items\": [1, 2, 3]},\n        \"content_type\": \"html\"\n    }\nEOF\n
"},{"location":"apis/transactional/#response","title":"Response","text":"
{\n\"data\": true\n}\n
"},{"location":"apis/transactional/#file-attachments","title":"File Attachments","text":"

To include file attachments in a transactional message, use Content-Type multipart/form-data. Use the parameters described above as a JSON object via the data form key and include an arbitrary number of attachments via the file key.

curl -u \"username:password\" \"http://localhost:9000/api/tx\" -X POST \\\n-F 'data=\\\"{\n    \\\"subscriber_email\\\": \\\"user@test.com\\\",\n    \\\"template_id\\\": 4\n}\"' \\\n-F 'file=@\"/path/to/attachment.pdf\"' \\\n-F 'file=@\"/path/to/attachment2.pdf\"'\n
"}]} \ No newline at end of file +{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Introduction","text":"

listmonk is a self-hosted, high performance mailing list and newsletter manager. It comes as a standalone binary and the only dependency is a Postgres database.

"},{"location":"#developers","title":"Developers","text":"

listmonk is a free and open source software licensed under AGPLv3. If you are interested in contributing, check out the GitHub repository and refer to the developer setup. The backend is written in Go and the frontend is Vue with Buefy for UI.

"},{"location":"archives/","title":"Archives","text":"

A global public archive is maintained on the public web interface. It can be enabled under Settings -> Settings -> General -> Enable public mailing list archive.

To make a campaign available in the public archive (provided it has been enabled in the settings as described above), enable the option 'Publish to public archive' under Campaigns -> Create new -> Archive.

When using template variables that depend on subscriber data (such as any template variable referencing .Subscriber), such data must be supplied as 'Campaign metadata', which is a JSON object that will be used in place of .Subscriber when rendering the archive template and content.

When individual subscriber tracking is enabled, TrackLink requires that a UUID of an existing user is provided as part of the campaign metadata. Any clicks on a TrackLink from the archived campaign will be counted towards that subscriber.

As an example:

{\n\"UUID\": \"5a837423-a186-5623-9a87-82691cbe3631\",\n\"email\": \"example@example.com\",\n\"name\": \"Reader\",\n\"attribs\": {}\n}\n

"},{"location":"bounces/","title":"Bounce processing","text":"

Enable bounce processing in Settings -> Bounces. POP3 bounce scanning and APIs only become available once the setting is enabled.

"},{"location":"bounces/#pop3-bounce-mailbox","title":"POP3 bounce mailbox","text":"

Configure the bounce mailbox in Settings -> Bounces. Either the \"From\" e-mail that is set on a campaign (or in settings) should have a POP3 mailbox behind it to receive bounce e-mails, or you should configure a dedicated POP3 mailbox and add that address as the Return-Path (envelope sender) header in Settings -> SMTP -> Custom headers box. For example:

[\n    {\"Return-Path\": \"your-bounce-inbox@site.com\"}\n]\n

Some mail servers may also return the bounce to the Reply-To address, which can also be added to the header settings.

"},{"location":"bounces/#webhook-api","title":"Webhook API","text":"

The bounce webhook API can be used to record bounce events with custom scripting. This could be by reading a mailbox, a database, or mail server logs.

Method Endpoint Description POST /webhooks/bounce Record a bounce event. Name Data type Required/Optional Description subscriber_uuid String Optional The UUID of the subscriber. Either this or email is required. email String Optional The e-mail of the subscriber. Either this or subscriber_uuid is required. campaign_uuid String Optional UUID of the campaign for which the bounce happened. source String Required A string indicating the source, eg: api, my_script etc. type String Required hard or soft bounce. Currently, this has no effect on how the bounce is treated. meta String Optional An optional escaped JSON string with arbitrary metadata about the bounce event.
curl -u 'username:password' -X POST localhost:9000/webhooks/bounce \\\n-H \"Content-Type: application/json\" \\\n--data '{\"email\": \"user1@mail.com\", \"campaign_uuid\": \"9f86b50d-5711-41c8-ab03-bc91c43d711b\", \"source\": \"api\", \"type\": \"hard\", \"meta\": \"{\\\"additional\\\": \\\"info\\\"}}'\n
"},{"location":"bounces/#external-webhooks","title":"External webhooks","text":"

listmonk supports receiving bounce webhook events from the following SMTP providers.

Endpoint Description More info https://listmonk.yoursite.com/webhooks/service/ses Amazon (AWS) SES You can use these Mautic steps as a general guide, but use your listmonk's endpoint instead. https://listmonk.yoursite.com/webhooks/service/sendgrid Sendgrid / Twilio Signed event webhook More info"},{"location":"bounces/#verification","title":"Verification","text":"

If you're using Amazon SES you can use Amazon's test emails to make sure everything's working: https://docs.aws.amazon.com/ses/latest/dg/send-an-email-from-console.html

success@simulator.amazonses.com\nbounce@simulator.amazonses.com\ncomplaint@simulator.amazonses.com\nsuppressionlist@simulator.amazonses.com\n
They all count as hard bounces.

Exporting bounces: https://github.com/knadh/listmonk/issues/863

"},{"location":"concepts/","title":"Concepts","text":""},{"location":"concepts/#subscriber","title":"Subscriber","text":"

A subscriber is a recipient identified by an e-mail address and name. Subscribers receive e-mails that are sent from listmonk. A subscriber can be added to any number of lists. Subscribers who are not a part of any lists are considered orphan records.

"},{"location":"concepts/#attributes","title":"Attributes","text":"

Attributes are arbitrary properties attached to a subscriber in addition to their e-mail and name. They are represented as a JSON map. It is not necessary for all subscribers to have the same attributes. Subscribers can be queried and segmented into lists based on their attributes, and the attributes can be inserted into the e-mails sent to them. For example:

{\n\"city\": \"Bengaluru\",\n\"likes_tea\": true,\n\"spoken_languages\": [\"English\", \"Malayalam\"],\n\"projects\": 3,\n\"stack\": {\n\"frameworks\": [\"echo\", \"go\"],\n\"languages\": [\"go\", \"python\"],\n\"preferred_language\": \"go\"\n}\n}\n
"},{"location":"concepts/#subscription-statuses","title":"Subscription statuses","text":"

A subscriber can be added to one or more lists, and each such relationship can have one of these statuses.

Status Description unconfirmed The subscriber was added to the list directly without their explicit confirmation. Nonetheless, the subscriber will receive campaign messages sent to single optin campaigns. confirmed The subscriber confirmed their subscription by clicking on 'accept' in the confirmation e-mail. Only confirmed subscribers in opt-in lists will receive campaign messages send to the list. unsubscribed The subscriber is unsubscribed from the list and will not receive any campaign messages sent to the list."},{"location":"concepts/#segmentation","title":"Segmentation","text":"

Segmentation is the process of filtering a large list of subscribers into a smaller group based on arbitrary conditions, primarily based on their attributes. For instance, if an e-mail needs to be sent subscribers who live in a particular city, given their city is described in their attributes, it's possible to quickly filter them out into a new list and e-mail them. Learn more.

"},{"location":"concepts/#list","title":"List","text":"

A list (or a mailing list) is a collection of subscribers grouped under a name, for instance, clients. Lists are used to organise subscribers and send e-mails to specific groups. A list can be single optin or double optin. Subscribers added to double optin lists have to explicitly accept the subscription by clicking on the confirmation e-mail they receive. Until then, they do not receive campaign messages.

"},{"location":"concepts/#campaign","title":"Campaign","text":"

A campaign is an e-mail (or any other kind of messages) that is sent to one or more lists.

"},{"location":"concepts/#transactional-message","title":"Transactional message","text":"

A transactional message is an arbitrary message sent to a subscriber using the transactional message API. For example a welcome e-mail on signing up to a service; an order confirmation e-mail on purchasing an item; a password reset e-mail when a user initiates an online account recovery process.

"},{"location":"concepts/#template","title":"Template","text":"

A template is a re-usable HTML design that can be used across campaigns and when sending arbitrary transactional messages. Most commonly, templates have standard header and footer areas with logos and branding elements, where campaign content is inserted in the middle. listmonk supports Go template expressions that lets you create powerful, dynamic HTML templates. Learn more.

"},{"location":"concepts/#messenger","title":"Messenger","text":"

listmonk supports multiple custom messaging backends in additional to the default SMTP e-mail backend, enabling not just e-mail campaigns, but arbitrary message campaigns such as SMS, FCM notifications etc. A Messenger is a web service that accepts a campaign message pushed to it as a JSON request, which the service can in turn broadcast as SMS, FCM etc. Learn more.

"},{"location":"concepts/#tracking-pixel","title":"Tracking pixel","text":"

The tracking pixel is a tiny, invisible image that is inserted into an e-mail body to track e-mail views. This allows measuring the read rate of e-mails. While this is exceedingly common in e-mail campaigns, it carries privacy implications and should be used in compliance with rules and regulations such as GDPR. It is possible to track reads anonymously without associating an e-mail read to a subscriber.

"},{"location":"concepts/#click-tracking","title":"Click tracking","text":"

It is possible to track the clicks on every link that is sent in an e-mail. This allows measuring the clickthrough rates of links in e-mails. While this is exceedingly common in e-mail campaigns, it carries privacy implications and should be used in compliance with rules and regulations such as GDPR. It is possible to track link clicks anonymously without associating an e-mail read to a subscriber.

"},{"location":"concepts/#bounce","title":"Bounce","text":"

A bounce occurs when an e-mail that is sent to a recipient \"bounces\" back for one of many reasons including the recipient address being invalid, their mailbox being full, or the recipient's e-mail service provider marking the e-mail as spam. listmonk can automatically process such bounce e-mails that land in a configured POP mailbox, or via APIs of SMTP e-mail providers such as AWS SES and Sengrid. Based on settings, subscribers returning bounced e-mails can either be blocklisted or deleted automatically. Learn more.

"},{"location":"configuration/","title":"Configuration","text":""},{"location":"configuration/#toml-configuration-file","title":"TOML Configuration file","text":"

One or more TOML files can be read by passing --config config.toml multiple times. Apart from a few low level configuration variables and the database configuration, all other settings can be managed from the Settings dashboard on the admin UI.

To generate a new sample configuration file, run --listmonk --new-config

"},{"location":"configuration/#environment-variables","title":"Environment variables","text":"

Variables in config.toml can also be provided as environment variables prefixed by LISTMONK_ with periods replaced by __ (double underscore). Example:

Environment variable Example value LISTMONK_app__address \"0.0.0.0:9000\" LISTMONK_app__admin_username listmonk LISTMONK_app__admin_password listmonk LISTMONK_db__host db LISTMONK_db__port 9432 LISTMONK_db__user listmonk LISTMONK_db__password listmonk LISTMONK_db__database listmonk LISTMONK_db__ssl_mode disable"},{"location":"configuration/#customizing-system-templates","title":"Customizing system templates","text":"

Read this

"},{"location":"configuration/#http-routes","title":"HTTP routes","text":"

When configuring auth proxies and web application firewalls, use this table.

"},{"location":"configuration/#private-admin-endpoints","title":"Private admin endpoints.","text":"Methods Route Description * /api/* Admin APIs GET /admin/* Admin UI and HTML pages POST /webhooks/bounce Admin bounce webhook"},{"location":"configuration/#public-endpoints-to-expose-to-the-internet","title":"Public endpoints to expose to the internet.","text":"Methods Route Description GET, POST /subscription/* HTML subscription pages GET, /link/* Tracked link redirection GET /campaign/* Pixel tracking image GET /public/* Static files for HTML subscription pages POST /webhooks/service/* Bounce webhook endpoints for AWS and Sendgrid"},{"location":"configuration/#media-uploads","title":"Media Uploads","text":""},{"location":"configuration/#filesystem","title":"Filesystem","text":"

When configuring docker volume mounts for using filesystem media uploads, you can follow either of two approaches. The second option may be necessary if your setup requires you to use sudo for docker commands.

After making any changes you will need to run sudo docker compose stop ; sudo docker compose up.

And under https://listmonk.mysite.com/admin/settings you put /listmonk/uploads.

"},{"location":"configuration/#using-volumes","title":"Using volumes","text":"

Using docker volumes, you can specify the name of volume and destination for the files to be uploaded inside the container.

app:\n    volumes:\n      - type: volume\n        source: listmonk-uploads\n        target: /listmonk/uploads\n\nvolumes:\n  listmonk-uploads:\n

Note

This volume is managed by docker itself, and you can see find the host path with docker volume inspect listmonk_listmonk-uploads.

"},{"location":"configuration/#using-bind-mounts","title":"Using bind mounts","text":"

  app:\n    volumes:\n      - ./path/on/your/host/:/path/inside/container\n
Eg:
  app:\n    volumes:\n      - ./data/uploads:/listmonk/uploads\n
The files will be available inside /data/uploads directory on the host machine.

To use the default uploads folder:

  app:\n    volumes:\n      - ./listmonk/uploads:/listmonk/uploads\n

"},{"location":"configuration/#time-zone","title":"Time zone","text":"

To change listmonk's time zone (logs, etc.) edit docker-compose.yml:

environment:\n    - TZ=Etc/UTC\n
with any Timezone listed here. Then run sudo docker-compose stop ; sudo docker-compose up after making changes.

"},{"location":"developer-setup/","title":"Developer setup","text":"

The app has two distinct components, the Go backend and the VueJS frontend. In the dev environment, both are run independently.

"},{"location":"developer-setup/#pre-requisites","title":"Pre-requisites","text":""},{"location":"developer-setup/#first-time-setup","title":"First time setup","text":"

git clone https://github.com/knadh/listmonk.git. The project uses go.mod, so it's best to clone it outside the Go src path.

  1. Copy config.toml.sample as config.toml and add your config.
  2. make dist to build the listmonk binary. Once the binary is built, run ./listmonk --install to run the DB setup. For subsequent dev runs, use make run.

mailhog is an excellent standalone mock SMTP server (with a UI) for testing and dev.

"},{"location":"developer-setup/#running-the-dev-environment","title":"Running the dev environment","text":"
  1. Run make run to start the listmonk dev server on :9000.
  2. Run make run-frontend to start the Vue frontend in dev mode using yarn on :8080. All /api/* calls are proxied to the app running on :9000. Refer to the frontend README for an overview on how the frontend is structured.
  3. Visit http://localhost:8080
"},{"location":"developer-setup/#production-build","title":"Production build","text":"

Run make dist to build the Go binary, build the Javascript frontend, and embed the static assets producing a single self-contained binary, listmonk

"},{"location":"external-integration/","title":"Integrating with external systems","text":"

In many environments, a mailing list manager's subscriber database is not run independently but as a part of an existing customer database or a CRM. There are multiple ways of keeping listmonk in sync with external systems.

"},{"location":"external-integration/#using-apis","title":"Using APIs","text":"

The subscriber APIs offers several APIs to manipulate the subscribers database, like addition, updation, and deletion. For bulk synchronisation, a CSV can be generated (and optionally zipped) and posted to the import API.

"},{"location":"external-integration/#interacting-directly-with-the-db","title":"Interacting directly with the DB","text":"

listmonk uses tables with simple schemas to represent subscribers (subscribers), lists (lists), and subscriptions (subscriber_lists). It is easy to add, update, and delete subscriber information directly with the database tables for advanced usecases. See the table schemas for more information.

"},{"location":"i18n/","title":"Internationalization (i18n)","text":"

listmonk comes available in multiple languages thanks to language packs contributed by volunteers. A language pack is a JSON file with a map of keys and corresponding translations. The bundled languages can be viewed here.

"},{"location":"i18n/#additional-language-packs","title":"Additional language packs","text":"

These additional language packs can be downloaded and passed to listmonk with the --i18n-dir flag as described in the next section.

Language Description Deutsch (formal) German language with formal pronouns"},{"location":"i18n/#customizing-languages","title":"Customizing languages","text":"

To customize an existing language or to load a new language, put one or more .json language files in a directory, and pass the directory path to listmonk with the--i18n-dir=/path/to/dir flag.

"},{"location":"i18n/#contributing-a-new-language","title":"Contributing a new language","text":""},{"location":"i18n/#using-the-basic-editor","title":"Using the basic editor","text":""},{"location":"i18n/#using-inlang-external-service","title":"Using InLang (external service)","text":""},{"location":"installation/","title":"Installation","text":"

listmonk requires Postgres \u2a7e 12.

See the \"Tutorials\" section at the bottom for detailed guides.

"},{"location":"installation/#binary","title":"Binary","text":""},{"location":"installation/#docker","title":"Docker","text":"

The latest image is available on DockerHub at listmonk/listmonk:latest

Note

Listmonk's docs and scripts use docker compose, which is compatible with the latest version of docker. If you installed docker and docker-compose from your Linux distribution, you probably have an older version and will need to use the docker-compose command instead, or you'll need to update docker manually. More info.

Use the sample docker-compose.yml to run listmonk and Postgres DB with docker compose as follows:

"},{"location":"installation/#demo","title":"Demo","text":""},{"location":"installation/#easy-docker-install","title":"Easy Docker install","text":"
mkdir listmonk-demo\nsh -c \"$(curl -fsSL https://raw.githubusercontent.com/knadh/listmonk/master/install-demo.sh)\"\n
"},{"location":"installation/#manual-docker-install","title":"Manual Docker install","text":"
wget -O docker-compose.yml https://raw.githubusercontent.com/knadh/listmonk/master/docker-compose.yml\ndocker compose up -d demo-db demo-app\n

Warning

The demo does not persist Postgres after the containers are removed. DO NOT use this demo setup in production.

"},{"location":"installation/#production","title":"Production","text":""},{"location":"installation/#easy-docker-install_1","title":"Easy Docker install","text":"

This setup is recommended if you want to quickly setup listmonk in production.

mkdir listmonk\nsh -c \"$(curl -fsSL https://raw.githubusercontent.com/knadh/listmonk/master/install-prod.sh)\"\n

The above shell script performs the following actions:

Note

It's recommended to examine the contents of the shell script, before running in your environment.

"},{"location":"installation/#manual-docker-install_1","title":"Manual Docker install","text":"

The following workflow is recommended to setup listmonk manually using docker compose. You are encouraged to customise the contents of docker-compose.yml to your needs. The overall setup looks like:

"},{"location":"installation/#mounting-a-custom-configtoml","title":"Mounting a custom config.toml","text":"

To mount a local config.toml file, add the following section to docker-compose.yml:

  app:\n    <<: *app-defaults\n    depends_on:\n      - db\n    volumes:\n    - ./path/on/your/host/config.toml:/listmonk/config.toml\n

Note

Some common changes done inside config.toml for Docker based setups:

Here's a sample config.toml you can use:

[app]\naddress = \"0.0.0.0:9000\"\nadmin_username = \"listmonk\"\nadmin_password = \"listmonk\"\n\n# Database.\n[db]\nhost = \"listmonk_db\"\nport = 5432\nuser = \"listmonk\"\npassword = \"listmonk\"\ndatabase = \"listmonk\"\nssl_mode = \"disable\"\nmax_open = 25\nmax_idle = 25\nmax_lifetime = \"300s\"\n

Mount the local config.toml inside the container at listmonk/config.toml.

Tip

Info

The example docker-compose.yml file works with Docker Engine 24.0.5+ and Docker Compose version v2.20.2+.

"},{"location":"installation/#compiling-from-source","title":"Compiling from source","text":"

To compile the latest unreleased version (master branch):

  1. Make sure go, nodejs, and yarn are installed on your system.
  2. git clone git@github.com:knadh/listmonk.git
  3. cd listmonk && make dist. This will generate the listmonk binary.
"},{"location":"installation/#release-candidate-rc","title":"Release candidate (RC)","text":"

The master branch with bleeding edge changes is periodically built and published as listmonk/listmonk:rc on DockerHub. To run the latest pre-release version, replace all instances of listmonk/listmonk:latest with listmonk/listmonk:rc in the docker-compose.yml file and follow the Docker installation steps above. While it is generally safe to run release candidate versions, they may have issues that only get resolved in a general release.

"},{"location":"installation/#3rd-party-hosting","title":"3rd party hosting","text":""},{"location":"installation/#tutorials","title":"Tutorials","text":""},{"location":"messengers/","title":"Messengers","text":"

listmonk supports multiple custom messaging backends in additional to the default SMTP e-mail backend, enabling not just e-mail campaigns, but arbitrary message campaigns such as SMS, FCM notifications etc.

A Messenger is a web service that accepts a campaign message pushed to it as a JSON request, which the service can in turn broadcast as SMS, FCM etc. Messengers are registered in the Settings -> Messengers UI, and can be selected on individual campaigns.

Messengers support optional BasicAuth authentication. Plain text format for campaign content is ideal for messengers such as SMS and FCM.

When a campaign starts, listmonk POSTs messages in the following format to the selected messenger's endpoint. The endpoint should return a 200 OK response in case of a successful request.

The address required to broadcast the message, for instance, a phone number or an FCM ID, is expected to be stored and relayed as subscriber attributes.

{\n\"subject\": \"Welcome to listmonk\",\n\"body\": \"The message body\",\n\"content_type\": \"plain\",\n\"recipients\": [{\n\"uuid\": \"e44b4135-1e1d-40c5-8a30-0f9a886c2884\",\n\"email\": \"anon@example.com\",\n\"name\": \"Anon Doe\",\n\"attribs\": {\n\"phone\": \"123123123\",\n\"fcm_id\": \"2e7e4b512e7e4b512e7e4b51\",\n\"city\": \"Bengaluru\"\n},\n\"status\": \"enabled\"\n}],\n\"campaign\": {\n\"uuid\": \"2e7e4b51-f31b-418a-a120-e41800cb689f\",\n\"name\": \"Test campaign\",\n\"tags\": [\"test-campaign\"]\n}\n}\n
"},{"location":"messengers/#messenger-implementations","title":"Messenger implementations","text":"

Following is a list of HTTP messenger servers that connect to various backends.

Name Backend listmonk-messenger AWS Pinpoint SMS"},{"location":"querying-and-segmentation/","title":"Querying and segmenting subscribers","text":"

listmonk allows the writing of partial Postgres SQL expressions to query, filter, and segment subscribers.

"},{"location":"querying-and-segmentation/#database-fields","title":"Database fields","text":"

These are the fields in the subscriber database that can be queried.

Field Description subscribers.uuid The randomly generated unique ID of the subscriber subscribers.email E-mail ID of the subscriber subscribers.name Name of the subscriber subscribers.status Status of the subscriber (enabled, disabled, blocklisted) subscribers.attribs Map of arbitrary attributes represented as JSON. Accessed via the -> and ->> Postgres operator. subscribers.created_at Timestamp when the subscriber was first added subscribers.updated_at Timestamp when the subscriber was modified"},{"location":"querying-and-segmentation/#sample-attributes","title":"Sample attributes","text":"

Here's a sample JSON map of attributes assigned to an imaginary subscriber.

{\n\"city\": \"Bengaluru\",\n\"likes_tea\": true,\n\"spoken_languages\": [\"English\", \"Malayalam\"],\n\"projects\": 3,\n\"stack\": {\n\"frameworks\": [\"echo\", \"go\"],\n\"languages\": [\"go\", \"python\"],\n\"preferred_language\": \"go\"\n}\n}\n

"},{"location":"querying-and-segmentation/#sample-sql-query-expressions","title":"Sample SQL query expressions","text":""},{"location":"querying-and-segmentation/#find-a-subscriber-by-e-mail","title":"Find a subscriber by e-mail","text":"
-- Exact match\nsubscribers.email = 'some@domain.com'\n\n-- Partial match to find e-mails that end in @domain.com.\nsubscribers.email LIKE '%@domain.com'\n
"},{"location":"querying-and-segmentation/#find-a-subscriber-by-name","title":"Find a subscriber by name","text":"
-- Find all subscribers whose name start with John.\nsubscribers.email LIKE 'John%'\n
"},{"location":"querying-and-segmentation/#multiple-conditions","title":"Multiple conditions","text":"
-- Find all Johns who have been blocklisted.\nsubscribers.email LIKE 'John%' AND status = 'blocklisted'\n
"},{"location":"querying-and-segmentation/#querying-attributes","title":"Querying attributes","text":"
-- The ->> operator returns the value as text. Find all subscribers\n-- who live in Bengaluru and have done more than 3 projects.\n-- Here 'projects' is cast into an integer so that we can apply the\n-- numerical operator >\nsubscribers.attribs->>'city' = 'Bengaluru' AND\n(subscribers.attribs->>'projects')::INT > 3\n
"},{"location":"querying-and-segmentation/#querying-nested-attributes","title":"Querying nested attributes","text":"
-- Find all blocklisted subscribers who like to drink tea, can code Python\n-- and prefer coding Go.\n--\n-- The -> operator returns the value as a structure. Here, the \"languages\" field\n-- The ? operator checks for the existence of a value in a list.\nsubscribers.status = 'blocklisted' AND\n(subscribers.attribs->>'likes_tea')::BOOLEAN = true AND\nsubscribers.attribs->'stack'->'languages' ? 'python' AND\nsubscribers.attribs->'stack'->>'preferred_language' = 'go'\n

To learn how to write SQL expressions to do advancd querying on JSON attributes, refer to the Postgres JSONB documentation.

"},{"location":"templating/","title":"Templating","text":"

A template is a re-usable HTML design that can be used across campaigns and transactional messages. Most commonly, templates have standard header and footer areas with logos and branding elements, where campaign content is inserted in the middle. listmonk supports Go template expressions that lets you create powerful, dynamic HTML templates.

listmonk supports Go template expressions that lets you create powerful, dynamic HTML templates. It also integrates 100+ useful Sprig template functions.

"},{"location":"templating/#campaign-templates","title":"Campaign templates","text":"

Campaign templates are used in an e-mail campaigns. These template are created and managed on the UI under Campaigns -> Templates, and are selected when creating new campaigns.

"},{"location":"templating/#transactional-templates","title":"Transactional templates","text":"

Transactional templates are used for sending arbitrary transactional messages using the transactional API. These template are created and managed on the UI under Campaigns -> Templates.

"},{"location":"templating/#template-expressions","title":"Template expressions","text":"

There are several template functions and expressions that can be used in campaign and template bodies. They are written in the form {{ .Subscriber.Email }}, that is, an expression between double curly braces {{ and }}.

"},{"location":"templating/#subscriber-fields","title":"Subscriber fields","text":"Expression Description {{ .Subscriber.UUID }} The randomly generated unique ID of the subscriber {{ .Subscriber.Email }} E-mail ID of the subscriber {{ .Subscriber.Name }} Name of the subscriber {{ .Subscriber.FirstName }} First name of the subscriber (automatically extracted from the name) {{ .Subscriber.LastName }} Last name of the subscriber (automatically extracted from the name) {{ .Subscriber.Status }} Status of the subscriber (enabled, disabled, blocklisted) {{ .Subscriber.Attribs }} Map of arbitrary attributes. Fields can be accessed with ., eg: .Subscriber.Attribs.city {{ .Subscriber.CreatedAt }} Timestamp when the subscriber was first added {{ .Subscriber.UpdatedAt }} Timestamp when the subscriber was modified Expression Description {{ .Campaign.UUID }} The randomly generated unique ID of the campaign {{ .Campaign.Name }} Internal name of the campaign {{ .Campaign.Subject }} E-mail subject of the campaign {{ .Campaign.FromEmail }} The e-mail address from which the campaign is being sent"},{"location":"templating/#functions","title":"Functions","text":"Function Description {{ Date \"2006-01-01\" }} Prints the current datetime for the given format expressed as a Go date layout {{ TrackLink \"https://link.com\" }} Takes a URL and generates a tracking URL over it. For use in campaign bodies and templates. https://link.com@TrackLink Shorthand for TrackLink. Eg: <a href=\"https://link.com@TrackLink\">Link</a> {{ TrackView }} Inserts a single tracking pixel. Should only be used once, ideally in the template footer. {{ UnsubscribeURL }} Unsubscription and Manage preferences URL. Ideal for use in the template footer. {{ MessageURL }} URL to view the hosted version of an e-mail message. {{ OptinURL }} URL to the double-optin confirmation page. {{ Safe \"<!-- comment -->\" }} Add any HTML code as it is."},{"location":"templating/#sprig-functions","title":"Sprig functions","text":"

listmonk integrates the Sprig library that offers 100+ utility functions for working with strings, numbers, dates etc. that can be used in templating. Refer to the Sprig documentation for the full list of functions.

"},{"location":"templating/#example-template","title":"Example template","text":"

The expression {{ template \"content\" . }} should appear exactly once in every template denoting the spot where an e-mail's content is inserted. Here's a sample HTML e-mail that has a fixed header and footer that inserts the content in the middle.

<!DOCTYPE html>\n<html>\n  <head>\n    <style>\nbody {\nbackground: #eee;\nfont-family: Arial, sans-serif;\nfont-size: 6px;\ncolor: #111;\n}\nheader {\nborder-bottom: 1px solid #ddd;\npadding-bottom: 30px;\nmargin-bottom: 30px;\n}\n.container {\nbackground: #fff;\nwidth: 450px;\nmargin: 0 auto;\npadding: 30px;\n}\n</style>\n  </head>\n  <body>\n    <section class=\"container\">\n      <header>\n        <!-- This will appear in the header of all e-mails.\n             The subscriber's name will be automatically inserted here. //-->\n        Hi {{ .Subscriber.FirstName }}!\n      </header>\n\n      <!-- This is where the e-mail body will be inserted //-->\n      <div class=\"content\">\n        {{ template \"content\" . }}\n      </div>\n\n      <footer>\n        Copyright 2019. All rights Reserved.\n      </footer>\n\n      <!-- The tracking pixel will be inserted here //-->\n      {{ TrackView }}\n    </section>\n  </body>\n</html>\n

Info

For use with plaintext campaigns, create a template with no HTML content and just the placeholder {{ template \"content\" . }}

"},{"location":"templating/#example-campaign-body","title":"Example campaign body","text":"

Campaign bodies can be composed using the built-in WYSIWYG editor or as raw HTML documents. Assuming that the subscriber has a set of attributes defined, this example shows how to render those values in a campaign.

Hey, did you notice how the template showed your first name?\nYour last name is {{.Subscriber.LastName }}.\n\nYou have done {{ .Subscriber.Attribs.projects }} projects.\n\n\n{{ if eq .Subscriber.Attribs.city \"Bengaluru\" }}\n  You live in Bangalore!\n{{ else }}\n  Where do you live?\n{{ end }}\n\n\nHere is a link for you to click that will be tracked.\n<a href=\"{{ TrackLink \"https://google.com\" }}\">Google</a>\n

The above example uses an if condition to show one of two messages depending on the value of a subscriber attribute. Many such dynamic expressions are possible with Go templating expressions.

"},{"location":"templating/#system-templates","title":"System templates","text":"

System templates are used for rendering public user facing pages such as the subscription management page, and in automatically generated system e-mails such as the opt-in confirmation e-mail. These are bundled into listmonk but can be customized by copying the static directory locally, and passing its path to listmonk with the ./listmonk --static-dir=your/custom/path flag.

"},{"location":"templating/#public-pages","title":"Public pages","text":"/static/public/ index.html Base template with the header and footer that all pages use. home.html Landing page on the root domain with the login button. message.html Generic success / failure message page. optin.html Opt-in confirmation page. subscription.html Subscription management page with options for data export and wipe. subscription-form.html List selection and subscription form page.

To edit the appearance of the public pages using CSS and Javascript, head to Settings > Appearance > Public:

"},{"location":"templating/#system-e-mails","title":"System e-mails","text":"/static/email-templates/ base.html Base template with the header and footer that all system generated e-mails use. campaign-status.html E-mail notification that is sent to admins on campaign start, completion etc. import-status.html E-mail notification that is sent to admins on finish of an import job. subscriber-data.html E-mail that is sent to subscribers when they request a full dump of their private data. subscriber-optin.html Automatic opt-in confirmation e-mail that is sent to an unconfirmed subscriber when they are added. subscriber-optin-campaign.html E-mail content that's inserted into a campaign body when starting an opt-in campaign from the lists page. default.tpl Default campaign template that is created in Campaigns -> Templates when listmonk is first installed. This is not used after that.

Info

To turn system e-mail templates to plaintext, remove <!doctype html> from base.html and remove all HTML tags from the templates while retaining the Go templating code.

"},{"location":"upgrade/","title":"Upgrade","text":"

Some versions may require changes to the database. These changes or database \"migrations\" are applied automatically and safely, but, it is recommended to take a backup of the Postgres database before running the --upgrade option, especially if you have made customizations to the database tables.

"},{"location":"upgrade/#binary","title":"Binary","text":""},{"location":"upgrade/#docker","title":"Docker","text":""},{"location":"upgrade/#railway","title":"Railway","text":""},{"location":"upgrade/#downgrade","title":"Downgrade","text":"

To restore a previous version, you have to restore the DB for that particular version. DBs that have been upgraded with a particular version shouldn't be used with older versions. There may be DB changes that a new version brings that are incompatible with previous versions.

General steps:

  1. Stop listmonk.
  2. Restore your pre-upgrade database.
  3. If you're using docker compose, edit docker-compose.yml and change listmonk:latest to listmonk:v2.4.0 (for example).
  4. Restart.

Example with docker:

  1. Stop listmonk (app):
    sudo docker stop listmonk_app\n
  2. Restore your pre-upgrade db (required) (be careful, this will wipe your existing DB):
    psql -h 127.0.0.1 -p 9432 -U listmonk\ndrop schema public cascade;\ncreate schema public;\n\\q\npsql -h 127.0.0.1 -p 9432 -U listmonk -W listmonk < listmonk-preupgrade-db.sql\n
  3. Edit the docker-compose.yml:
    x-app-defaults: &app-defaults\n  restart: unless-stopped\n  image: listmonk/listmonk:v2.4.0\n
  4. Restart: sudo docker compose up -d app db nginx certbot
"},{"location":"apis/apis/","title":"APIs","text":"

All features that are available on the listmonk dashboard are also available as REST-like HTTP APIs that can be interacted with directly. Request and response bodies are JSON. This allows easy scripting of listmonk and integration with other systems, for instance, synchronisation with external subscriber databases.

API requests require BasicAuth authentication with the admin credentials.

The API section is a work in progress. There may be API calls that are yet to be documented. Please consider contributing to docs.

"},{"location":"apis/apis/#openapi-swagger-spec","title":"OpenAPI (Swagger) spec","text":"

The auto-generated OpenAPI (Swagger) specification site for the APIs are available at listmonk.app/docs/swagger

"},{"location":"apis/apis/#response-structure","title":"Response structure","text":""},{"location":"apis/apis/#successful-request","title":"Successful request","text":"
HTTP/1.1 200 OK\nContent-Type: application/json\n\n{\n\"data\": {}\n}\n

All responses from the API server are JSON with the content-type application/json unless explicitly stated otherwise. A successful 200 OK response always has a JSON response body with a status key with the value success. The data key contains the full response payload.

"},{"location":"apis/apis/#failed-request","title":"Failed request","text":"
HTTP/1.1 500 Server error\nContent-Type: application/json\n\n{\n\"message\": \"Error message\"\n}\n

A failure response is preceded by the corresponding 40x or 50x HTTP header. There may be an optional data key with additional payload.

"},{"location":"apis/apis/#timestamps","title":"Timestamps","text":"

All timestamp fields are in the format 2019-01-01T09:00:00.000000+05:30. The seconds component is suffixed by the milliseconds, followed by the + and the timezone offset.

"},{"location":"apis/apis/#common-http-error-codes","title":"Common HTTP error codes","text":"code 400 Missing or bad request parameters or values 403 Session expired or invalidate. Must relogin 404 Request resource was not found 405 Request method (GET, POST etc.) is not allowed on the requested endpoint 410 The requested resource is gone permanently 429 Too many requests to the API (rate limiting) 500 Something unexpected went wrong 502 The backend OMS is down and the API is unable to communicate with it 503 Service unavailable; the API is down 504 Gateway timeout; the API is unreachable"},{"location":"apis/campaigns/","title":"API / Campaigns","text":"Method Endpoint Description GET /api/campaigns Gets all campaigns. GET /api/campaigns/:campaign_id Gets a single campaign. GET /api/campaigns/:campaign_id/preview Gets the HTML preview of a campaign body. GET /api/campaigns/running/stats Gets the stats of a given set of campaigns. POST /api/campaigns Creates a new campaign. POST /api/campaigns/:campaign_id/test Posts campaign message to arbitrary subscribers for testing. PUT /api/campaigns/:campaign_id Modifies a campaign. PUT /api/campaigns/:campaign_id/status Start / pause / cancel / schedule a campaign. DELETE /api/campaigns/:campaign_id Deletes a campaign."},{"location":"apis/campaigns/#get-apicampaigns","title":"GET /api/campaigns","text":"

Gets all campaigns.

"},{"location":"apis/campaigns/#example-request","title":"Example Request","text":"
 curl -u \"username:password\" -X GET 'http://localhost:9000/api/campaigns?page=1&per_page=100'\n
"},{"location":"apis/campaigns/#parameters","title":"Parameters","text":"

Name | Type | Required/Optional | Description --------|--------------------|-------------|---------------------|--------------------- query | string | Optional | Optional string to search a list by name. order_by | string | Optional | Field to sort results by. name|status|created_at|updated_at order | string | Optional | ASC|DESCSort by ascending or descending order. page | number | Optional | Page number for paginated results. per_page | number | Optional | Results to return per page. Setting this to all skips pagination and returns all results.

"},{"location":"apis/campaigns/#example-response","title":"Example Response","text":"
{\n\"data\": {\n\"results\": [\n{\n\"id\": 1,\n\"created_at\": \"2020-03-14T17:36:41.29451+01:00\",\n\"updated_at\": \"2020-03-14T17:36:41.29451+01:00\",\n\"CampaignID\": 0,\n\"views\": 0,\n\"clicks\": 0,\n\"lists\": [\n{\n\"id\": 1,\n\"name\": \"Default list\"\n}\n],\n\"started_at\": null,\n\"to_send\": 0,\n\"sent\": 0,\n\"uuid\": \"57702beb-6fae-4355-a324-c2fd5b59a549\",\n\"type\": \"regular\",\n\"name\": \"Test campaign\",\n\"subject\": \"Welcome to listmonk\",\n\"from_email\": \"No Reply <noreply@yoursite.com>\",\n\"body\": \"<h3>Hi {{ .Subscriber.FirstName }}!</h3>\\n\\t\\t\\tThis is a test e-mail campaign. Your second name is {{ .Subscriber.LastName }} and you are from {{ .Subscriber.Attribs.city }}.\",\n\"send_at\": \"2020-03-15T17:36:41.293233+01:00\",\n\"status\": \"draft\",\n\"content_type\": \"richtext\",\n\"tags\": [\n\"test-campaign\"\n],\n\"template_id\": 1,\n\"messenger\": \"email\"\n}\n],\n\"query\": \"\",\n\"total\": 1,\n\"per_page\": 20,\n\"page\": 1\n}\n}\n
"},{"location":"apis/campaigns/#get-apicampaignscampaign_id","title":"GET /api/campaigns/:campaign_id","text":"

Gets a single campaign.

"},{"location":"apis/campaigns/#parameters_1","title":"Parameters","text":"Name Parameter Type Data Type Required/Optional Description campaign_id Path Parameter Number Required The id value of the campaign you want to get."},{"location":"apis/campaigns/#example-request_1","title":"Example Request","text":"
curl -u \"username:password\" -X GET 'http://localhost:9000/api/campaigns/1'\n
"},{"location":"apis/campaigns/#example-response_1","title":"Example Response","text":"
{\n\"data\": {\n\"id\": 1,\n\"created_at\": \"2020-03-14T17:36:41.29451+01:00\",\n\"updated_at\": \"2020-03-14T17:36:41.29451+01:00\",\n\"CampaignID\": 0,\n\"views\": 0,\n\"clicks\": 0,\n\"lists\": [\n{\n\"id\": 1,\n\"name\": \"Default list\"\n}\n],\n\"started_at\": null,\n\"to_send\": 0,\n\"sent\": 0,\n\"uuid\": \"57702beb-6fae-4355-a324-c2fd5b59a549\",\n\"type\": \"regular\",\n\"name\": \"Test campaign\",\n\"subject\": \"Welcome to listmonk\",\n\"from_email\": \"No Reply <noreply@yoursite.com>\",\n\"body\": \"<h3>Hi {{ .Subscriber.FirstName }}!</h3>\\n\\t\\t\\tThis is a test e-mail campaign. Your second name is {{ .Subscriber.LastName }} and you are from {{ .Subscriber.Attribs.city }}.\",\n\"send_at\": \"2020-03-15T17:36:41.293233+01:00\",\n\"status\": \"draft\",\n\"content_type\": \"richtext\",\n\"tags\": [\n\"test-campaign\"\n],\n\"template_id\": 1,\n\"messenger\": \"email\"\n}\n}\n
"},{"location":"apis/campaigns/#get-apicampaignscampaign_idpreview","title":"GET /api/campaigns/:campaign_id/preview","text":"

Gets the html preview of a campaign body.

"},{"location":"apis/campaigns/#parameters_2","title":"Parameters","text":"Name Parameter Type Data Type Required/Optional Description campaign_id Path Parameter Number Required The id value of the campaign to be previewed."},{"location":"apis/campaigns/#example-request_2","title":"Example Request","text":"
curl -u \"username:password\" -X GET 'http://localhost:9000/api/campaigns/1/preview'\n
"},{"location":"apis/campaigns/#example-response_2","title":"Example Response","text":"
<h3>Hi John!</h3>\nThis is a test e-mail campaign. Your second name is Doe and you are from Bengaluru.\n
"},{"location":"apis/campaigns/#get-apicampaignsrunningstats","title":"GET /api/campaigns/running/stats","text":"

Gets the running stat of a given set of campaigns.

"},{"location":"apis/campaigns/#parameters_3","title":"Parameters","text":"Name Parameter Type Data Type Required/Optional Description campaign_id Query Parameters Number Required The id values of the campaigns whose stat you want to get."},{"location":"apis/campaigns/#example-request_3","title":"Example Request","text":"
curl -u \"username:password\" -X GET 'http://localhost:9000/api/campaigns/running/stats?campaign_id=1'\n
"},{"location":"apis/campaigns/#example-response_3","title":"Example Response","text":"
{\n\"data\": []\n}\n
"},{"location":"apis/campaigns/#post-apicampaigns","title":"POST /api/campaigns","text":"

Creates a new campaign.

"},{"location":"apis/campaigns/#parameters_4","title":"Parameters","text":"Name Data type Required/Optional Description name String Required Name of the campaign. subject String Required (E-mail) subject of the campaign. lists []Number Required Array of list IDs to send the campaign to. from_email String Optional From e-mail to show on the campaign e-mails. If left empty, the default value from settings is used. type String Required regular or optin campaign. content_type String Required richtext, html, markdown, plain body String Required Campaign content body. altbody String Optional Alternate plain text body for HTML (and richtext) e-mails. send_at String Optional A timestamp to schedule the campaign at. Eg: 2021-12-25T06:00:00 (YYYY-MM-DDTHH:MM:SS) messenger String Optional email or a custom messenger defined in the settings. If left empty, email is used. template_id Number Optional ID of the template to use. If left empty, the default template is used. tags []String Optional Array of string tags to mark the campaign."},{"location":"apis/campaigns/#example-request_4","title":"Example request","text":"
curl -u \"username:password\" 'http://localhost:9000/api/campaigns' -X POST -H 'Content-Type: application/json;charset=utf-8' --data-raw '{\"name\":\"Test campaign\",\"subject\":\"Hello, world\",\"lists\":[1],\"from_email\":\"listmonk <noreply@listmonk.yoursite.com>\",\"content_type\":\"richtext\",\"messenger\":\"email\",\"type\":\"regular\",\"tags\":[\"test\"],\"template_id\":1}'\n
"},{"location":"apis/campaigns/#example-response_4","title":"Example response","text":"
{\n\"data\": {\n\"id\": 1,\n\"created_at\": \"2021-12-27T11:50:23.333485Z\",\n\"updated_at\": \"2021-12-27T11:50:23.333485Z\",\n\"views\": 0,\n\"clicks\": 0,\n\"bounces\": 0,\n\"lists\": [{\n\"id\": 1,\n\"name\": \"Default list\"\n}],\n\"started_at\": null,\n\"to_send\": 1,\n\"sent\": 0,\n\"uuid\": \"90c889cc-3728-4064-bbcb-5c1c446633b3\",\n\"type\": \"regular\",\n\"name\": \"Test campaign\",\n\"subject\": \"Hello, world\",\n\"from_email\": \"listmonk \\u003cnoreply@listmonk.yoursite.com\\u003e\",\n\"body\": \"\",\n\"altbody\": null,\n\"send_at\": null,\n\"status\": \"draft\",\n\"content_type\": \"richtext\",\n\"tags\": [\"test\"],\n\"template_id\": 1,\n\"messenger\": \"email\"\n}\n}\n
"},{"location":"apis/campaigns/#put-apicampaignscampaign_idstatus","title":"PUT /api/campaigns/:campaign_id/status","text":"

Modifies a campaign status to start, pause, cancel, or schedule a campaign.

"},{"location":"apis/campaigns/#parameters_5","title":"Parameters","text":"Name Parameter Type Data Type Required/Optional Description campaign_id Path Parameter Number Required The id value of the campaign whose status is to be modified. status Request Body String Required scheduled, running, paused, cancelled."},{"location":"apis/campaigns/#note","title":"Note:","text":""},{"location":"apis/campaigns/#example-request_5","title":"Example Request","text":"
curl -u \"username:password\" -X PUT 'http://localhost:9000/api/campaigns/1/status' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{\"status\":\"scheduled\"}'\n
"},{"location":"apis/campaigns/#example-response_5","title":"Example Response","text":"
{\n\"data\": {\n\"id\": 1,\n\"created_at\": \"2020-03-14T17:36:41.29451+01:00\",\n\"updated_at\": \"2020-04-08T19:35:17.331867+01:00\",\n\"CampaignID\": 0,\n\"views\": 0,\n\"clicks\": 0,\n\"lists\": [\n{\n\"id\": 1,\n\"name\": \"Default list\"\n}\n],\n\"started_at\": null,\n\"to_send\": 0,\n\"sent\": 0,\n\"uuid\": \"57702beb-6fae-4355-a324-c2fd5b59a549\",\n\"type\": \"regular\",\n\"name\": \"Test campaign\",\n\"subject\": \"Welcome to listmonk\",\n\"from_email\": \"No Reply <noreply@yoursite.com>\",\n\"body\": \"<h3>Hi {{ .Subscriber.FirstName }}!</h3>\\n\\t\\t\\tThis is a test e-mail campaign. Your second name is {{ .Subscriber.LastName }} and you are from {{ .Subscriber.Attribs.city }}.\",\n\"send_at\": \"2020-03-15T17:36:41.293233+01:00\",\n\"status\": \"scheduled\",\n\"content_type\": \"richtext\",\n\"tags\": [\n\"test-campaign\"\n],\n\"template_id\": 1,\n\"messenger\": \"email\"\n}\n}\n
"},{"location":"apis/campaigns/#delete-apicampaignscampaign_id","title":"DELETE /api/campaigns/:campaign_id","text":"

Deletes a campaign, only scheduled campaigns that have not yet been started can be deleted.

"},{"location":"apis/campaigns/#parameters_6","title":"Parameters","text":"Name Parameter Type Data Type Required/Optional Description campaign_id Path Parameter Number Required The id value of the campaign you want to delete."},{"location":"apis/campaigns/#example-request_6","title":"Example Request","text":"
curl -u \"username:password\" -X DELETE 'http://localhost:9000/api/campaigns/34'\n
"},{"location":"apis/campaigns/#example-response_6","title":"Example Response","text":"
{\n\"data\": true\n}\n
"},{"location":"apis/import/","title":"API / Import","text":"Method Endpoint Description GET api/import/subscribers Gets a import statistics. GET api/import/subscribers/logs Get a import statistics . POST api/import/subscribers Upload a ZIP file or CSV file to bulk import subscribers. DELETE api/import/subscribers Stops and deletes a import."},{"location":"apis/import/#get-apiimportsubscribers","title":"GET api/import/subscribers","text":"

Gets import status.

"},{"location":"apis/import/#example-request","title":"Example Request","text":"
curl -u \"username:username\" -X GET 'http://localhost:9000/api/import/subscribers'\n
"},{"location":"apis/import/#example-response","title":"Example Response","text":"
{\n\"data\": {\n\"name\": \"\",\n\"total\": 0,\n\"imported\": 0,\n\"status\": \"none\"\n}\n}\n
"},{"location":"apis/import/#get-apiimportsubscriberslogs","title":"GET api/import/subscribers/logs","text":"

Gets import logs.

"},{"location":"apis/import/#example-request_1","title":"Example Request","text":"
curl -u \"username:username\" -X GET 'http://localhost:9000/api/import/subscribers/logs'\n
"},{"location":"apis/import/#example-response_1","title":"Example Response","text":"
{\n\"data\": \"2020/04/08 21:55:20 processing 'import.csv'\\n2020/04/08 21:55:21 imported finished\\n\"\n}\n
"},{"location":"apis/import/#post-apiimportsubscribers","title":"POST api/import/subscribers","text":"

Post a CSV (optionally zipped) file to do a bulk import. The request should be a multipart form POST.

"},{"location":"apis/import/#parameters","title":"Parameters","text":"Name Parameter type Data type Required/Optional Description params Request body String Required Stringified JSON with import params file Request body File Required File to upload

params (JSON string)

    {\n\"mode\": \"subscribe\", // subscribe or blocklist\n\"delim\": \",\",        // delimiter in the uploaded file\n\"lists\":[1],         // array of list IDs to import into\n\"overwrite\": true    // overwrite existing entries or skip them?\n}\n
"},{"location":"apis/import/#delete-apiimportsubscribers","title":"DELETE api/import/subscribers","text":"

Stops and deletes an import.

"},{"location":"apis/import/#example-request_2","title":"Example Request","text":"
curl -u \"username:username\" -X DELETE 'http://localhost:9000/api/import/subscribers' 
"},{"location":"apis/import/#example-response_2","title":"Example Response","text":"
{\n\"data\": {\n\"name\": \"\",\n\"total\": 0,\n\"imported\": 0,\n\"status\": \"none\"\n}\n}\n
"},{"location":"apis/lists/","title":"API / Lists","text":"Method Endpoint Description GET /api/lists Gets all lists. GET /api/lists/:list_id Gets a single list. POST /api/lists Creates a new list. PUT /api/lists/:list_id Modifies a list. DELETE /api/lists/:list_id Deletes a list."},{"location":"apis/lists/#get-apilists","title":"GET /api/lists","text":"

Gets lists.

"},{"location":"apis/lists/#parameters","title":"Parameters","text":"Name Type Required/Optional Description query string Optional Optional string to search a list by name. order_by string Optional Field to sort results by. name|status|created_at|updated_at order string Optional ASC|DESCSort by ascending or descending order. page number Optional Page number for paginated results. per_page number Optional Results to return per page. Setting this to all skips pagination and returns all results."},{"location":"apis/lists/#example-request","title":"Example Request","text":"
curl -u \"username:username\" -X GET 'http://localhost:9000/api/lists?page=1&per_page=100'\n
"},{"location":"apis/lists/#example-response","title":"Example Response","text":"
{\n\"data\": {\n\"results\": [\n{\n\"id\": 1,\n\"created_at\": \"2020-02-10T23:07:16.194843+01:00\",\n\"updated_at\": \"2020-03-06T22:32:01.118327+01:00\",\n\"uuid\": \"ce13e971-c2ed-4069-bd0c-240e9a9f56f9\",\n\"name\": \"Default list\",\n\"type\": \"public\",\n\"optin\": \"double\",\n\"tags\": [\n\"test\"\n],\n\"subscriber_count\": 2\n},\n{\n\"id\": 2,\n\"created_at\": \"2020-03-04T21:12:09.555013+01:00\",\n\"updated_at\": \"2020-03-06T22:34:46.405031+01:00\",\n\"uuid\": \"f20a2308-dfb5-4420-a56d-ecf0618a102d\",\n\"name\": \"get\",\n\"type\": \"private\",\n\"optin\": \"single\",\n\"tags\": [],\n\"subscriber_count\": 0\n}\n],\n\"total\": 5,\n\"per_page\": 20,\n\"page\": 1\n}\n}\n
"},{"location":"apis/lists/#get-apilistslist_id","title":"GET /api/lists/:list_id","text":"

Gets a single list.

"},{"location":"apis/lists/#parameters_1","title":"Parameters","text":"Name Parameter type Data type Required/Optional Description list_id Path parameter number Required The id value of the list you want to get."},{"location":"apis/lists/#example-request_1","title":"Example Request","text":"
curl -u \"username:username\" -X GET 'http://localhost:9000/api/lists/5'\n
"},{"location":"apis/lists/#example-response_1","title":"Example Response","text":"
{\n\"data\": {\n\"id\": 5,\n\"created_at\": \"2020-03-07T06:31:06.072483+01:00\",\n\"updated_at\": \"2020-03-07T06:31:06.072483+01:00\",\n\"uuid\": \"1bb246ab-7417-4cef-bddc-8fc8fc941d3a\",\n\"name\": \"Test list\",\n\"type\": \"public\",\n\"optin\": \"double\",\n\"tags\": [],\n\"subscriber_count\": 0\n}\n}\n
"},{"location":"apis/lists/#post-apilists","title":"POST /api/lists","text":"

Creates a new list.

"},{"location":"apis/lists/#parameters_2","title":"Parameters","text":"Name Parameter type Data type Required/Optional Description name Request body string Required The new list name. type Request body string Required List type, can be set to private or public. optin Request body string Required single or double optin. tags Request body string[] Optional The tags associated with the list."},{"location":"apis/lists/#example-request_2","title":"Example Request","text":"
curl -u \"username:username\" -X POST 'http://localhost:9000/api/lists'\n
"},{"location":"apis/lists/#example-response_2","title":"Example Response","text":"
{\n\"data\": {\n\"id\": 5,\n\"created_at\": \"2020-03-07T06:31:06.072483+01:00\",\n\"updated_at\": \"2020-03-07T06:31:06.072483+01:00\",\n\"uuid\": \"1bb246ab-7417-4cef-bddc-8fc8fc941d3a\",\n\"name\": \"Test list\",\n\"type\": \"public\",\n\"tags\": [],\n\"subscriber_count\": 0\n}\n}\nnull\n
"},{"location":"apis/lists/#put-apilistslist_id","title":"PUT /api/lists/list_id","text":"

Modifies a list.

"},{"location":"apis/lists/#parameters_3","title":"Parameters","text":"Name Parameter type Data type Required/Optional Description list_id Path parameter number Required The id of the list to be modified. name Request body string Optional The name which the old name will be modified to. type Request body string Optional List type, can be set to private or public. optin Request body string Optional single or double optin. tags Request body string[] Optional The tags associated with the list."},{"location":"apis/lists/#example-request_3","title":"Example Request","text":"
curl -u \"username:username\" -X PUT 'http://localhost:9000/api/lists/5' \\\n--form 'name=modified test list' \\\n--form 'type=private'\n
"},{"location":"apis/lists/#example-response_3","title":"Example Response","text":"
{\n\"data\": {\n\"id\": 5,\n\"created_at\": \"2020-03-07T06:31:06.072483+01:00\",\n\"updated_at\": \"2020-03-07T06:52:15.208075+01:00\",\n\"uuid\": \"1bb246ab-7417-4cef-bddc-8fc8fc941d3a\",\n\"name\": \"modified test list\",\n\"type\": \"private\",\n\"optin\": \"single\",\n\"tags\": [],\n\"subscriber_count\": 0\n}\n}\n
"},{"location":"apis/media/","title":"API / Media","text":"Method Endpoint Description GET /api/media Gets an uploaded media file. POST /api/media Uploads a media file. DELETE /api/media/:media_id Deletes uploaded media files."},{"location":"apis/media/#get-apimedia","title":"GET /api/media","text":"

Gets an uploaded media file.

"},{"location":"apis/media/#example-request","title":"Example Request","text":"
curl -u \"username:username\" -X GET 'http://localhost:9000/api/media' \\\n--header 'Content-Type: multipart/form-data; boundary=--------------------------093715978792575906250298'\n
"},{"location":"apis/media/#example-response","title":"Example Response","text":"
{\n\"data\": [\n{\n\"id\": 1,\n\"uuid\": \"ec7b45ce-1408-4e5c-924e-965326a20287\",\n\"filename\": \"Media file\",\n\"created_at\": \"2020-04-08T22:43:45.080058+01:00\",\n\"thumb_url\": \"/uploads/image_thumb.jpg\",\n\"uri\": \"/uploads/image.jpg\"\n}\n]\n}\n

Response definitions The following table describes each item in the response.

Response item Description Data type data Array of the media file objects, which contains an information about the uploaded media files array id Media file object ID number (int) uuid Media file uuid string (uuid) filename Name of the media file string created_at Date and time, when the media file object was created String (localDateTime) thumb_uri The thumbnail URI of the media file string uri URI of the media file string"},{"location":"apis/media/#post-apimedia","title":"POST /api/media","text":"

Uploads a media file.

"},{"location":"apis/media/#parameters","title":"Parameters","text":"Name Parameter Type Data Type Required/Optional Description file Request body Media file Required The media file to be uploaded."},{"location":"apis/media/#example-request_1","title":"Example Request","text":"
curl -u \"username:username\" -X POST 'http://localhost:9000/api/media' \\\n--header 'Content-Type: multipart/form-data; boundary=--------------------------183679989870526937212428' \\\n--form 'file=@/path/to/image.jpg'\n
"},{"location":"apis/media/#example-response_1","title":"Example Response","text":"

{\n\"data\": {\n\"id\": 1,\n\"uuid\": \"ec7b45ce-1408-4e5c-924e-965326a20287\",\n\"filename\": \"Media file\",\n\"created_at\": \"2020-04-08T22:43:45.080058+01:00\",\n\"thumb_uri\": \"/uploads/image_thumb.jpg\",\n\"uri\": \"/uploads/image.jpg\"\n}\n}\n
Response definitions

Response item Description Data type data True means that the media file was successfully uploaded boolean"},{"location":"apis/media/#delete-apimediamedia_id","title":"DELETE /api/media/:media_id","text":"

Deletes an uploaded media file.

"},{"location":"apis/media/#parameters_1","title":"Parameters","text":"Name Parameter Type Data Type Required/Optional Description Media_id Path Parameter Number Required The id of the media file you want to delete."},{"location":"apis/media/#example-request_2","title":"Example Request","text":"
curl -u \"username:username\" -X DELETE 'http://localhost:9000/api/media/1'\n
"},{"location":"apis/media/#example-response_2","title":"Example Response","text":"
{\n\"data\": true\n}\n

Response definitions

Response item Description Data type data True means that the media file was successfully deleted boolean"},{"location":"apis/subscribers/","title":"API / Subscribers","text":"Method Endpoint Description GET /api/subscribers Gets all subscribers. GET /api/subscribers/:id Gets a single subscriber. GET /api/subscribers/lists/:id Gets subscribers in a list. GET /api/subscribers Gets subscribers in one or more lists. GET /api/subscribers Gets subscribers filtered by an arbitrary SQL expression. POST /api/subscribers Creates a new subscriber. POST /api/subscribers Unauthenticated API that enables public subscription. PUT /api/subscribers/lists Modify subscribers' list memberships. PUT /api/subscribers/:id Updates a subscriber by ID. PUT /api/subscribers/:id/blocklist Blocklists a single subscriber. PUT /api/subscribers/blocklist Blocklists one or more subscribers. PUT /api/subscribers/query/blocklist Blocklists subscribers with an arbitrary SQL expression. DELETE /api/subscribers/:id Deletes a single subscriber. DELETE /api/subscribers Deletes one or more subscribers . POST /api/subscribers/query/delete Deletes subscribers with an arbitrary SQL expression."},{"location":"apis/subscribers/#get-apisubscribers","title":"GET /api/subscribers","text":"

Gets all subscribers.

"},{"location":"apis/subscribers/#example-request","title":"Example Request","text":"
curl -u 'username:password' 'http://localhost:9000/api/subscribers?page=1&per_page=100' 

To skip pagination and retrieve all records, pass per_page=all.

"},{"location":"apis/subscribers/#example-response","title":"Example Response","text":"
{\n\"data\": {\n\"results\": [\n{\n\"id\": 1,\n\"created_at\": \"2020-02-10T23:07:16.199433+01:00\",\n\"updated_at\": \"2020-02-10T23:07:16.199433+01:00\",\n\"uuid\": \"ea06b2e7-4b08-4697-bcfc-2a5c6dde8f1c\",\n\"email\": \"john@example.com\",\n\"name\": \"John Doe\",\n\"attribs\": {\n\"city\": \"Bengaluru\",\n\"good\": true,\n\"type\": \"known\"\n},\n\"status\": \"enabled\",\n\"lists\": [\n{\n\"subscription_status\": \"unconfirmed\",\n\"id\": 1,\n\"uuid\": \"ce13e971-c2ed-4069-bd0c-240e9a9f56f9\",\n\"name\": \"Default list\",\n\"type\": \"public\",\n\"tags\": [\n\"test\"\n],\n\"created_at\": \"2020-02-10T23:07:16.194843+01:00\",\n\"updated_at\": \"2020-02-10T23:07:16.194843+01:00\"\n}\n]\n},\n{\n\"id\": 2,\n\"created_at\": \"2020-02-18T21:10:17.218979+01:00\",\n\"updated_at\": \"2020-02-18T21:10:17.218979+01:00\",\n\"uuid\": \"ccf66172-f87f-4509-b7af-e8716f739860\",\n\"email\": \"quadri@example.com\",\n\"name\": \"quadri\",\n\"attribs\": {},\n\"status\": \"enabled\",\n\"lists\": [\n{\n\"subscription_status\": \"unconfirmed\",\n\"id\": 1,\n\"uuid\": \"ce13e971-c2ed-4069-bd0c-240e9a9f56f9\",\n\"name\": \"Default list\",\n\"type\": \"public\",\n\"tags\": [\n\"test\"\n],\n\"created_at\": \"2020-02-10T23:07:16.194843+01:00\",\n\"updated_at\": \"2020-02-10T23:07:16.194843+01:00\"\n}\n]\n},\n{\n\"id\": 3,\n\"created_at\": \"2020-02-19T19:10:49.36636+01:00\",\n\"updated_at\": \"2020-02-19T19:10:49.36636+01:00\",\n\"uuid\": \"5d940585-3cc8-4add-b9c5-76efba3c6edd\",\n\"email\": \"sugar@example.com\",\n\"name\": \"sugar\",\n\"attribs\": {},\n\"status\": \"enabled\",\n\"lists\": []\n}\n],\n\"query\": \"\",\n\"total\": 3,\n\"per_page\": 20,\n\"page\": 1\n}\n}\n
"},{"location":"apis/subscribers/#get-apisubscribersid","title":"GET /api/subscribers/:id","text":"

Gets a single subscriber.

"},{"location":"apis/subscribers/#parameters","title":"Parameters","text":"Name Parameter type Data type Required/Optional Description id Path parameter Number Required The id value of the subscriber you want to get."},{"location":"apis/subscribers/#example-request_1","title":"Example Request","text":"
curl -u 'username:password' 'http://localhost:9000/api/subscribers/1' 
"},{"location":"apis/subscribers/#example-response_1","title":"Example Response","text":"
{\n\"data\": {\n\"id\": 1,\n\"created_at\": \"2020-02-10T23:07:16.199433+01:00\",\n\"updated_at\": \"2020-02-10T23:07:16.199433+01:00\",\n\"uuid\": \"ea06b2e7-4b08-4697-bcfc-2a5c6dde8f1c\",\n\"email\": \"john@example.com\",\n\"name\": \"John Doe\",\n\"attribs\": {\n\"city\": \"Bengaluru\",\n\"good\": true,\n\"type\": \"known\"\n},\n\"status\": \"enabled\",\n\"lists\": [\n{\n\"subscription_status\": \"unconfirmed\",\n\"id\": 1,\n\"uuid\": \"ce13e971-c2ed-4069-bd0c-240e9a9f56f9\",\n\"name\": \"Default list\",\n\"type\": \"public\",\n\"tags\": [\n\"test\"\n],\n\"created_at\": \"2020-02-10T23:07:16.194843+01:00\",\n\"updated_at\": \"2020-02-10T23:07:16.194843+01:00\"\n}\n]\n}\n}\n
"},{"location":"apis/subscribers/#get-apisubscribers_1","title":"GET /api/subscribers","text":"

Gets subscribers in one or more lists.

"},{"location":"apis/subscribers/#parameters_1","title":"Parameters","text":"Name Parameter type Data type Required/Optional Description List_id Request body Number Required ID of the list to fetch subscribers from."},{"location":"apis/subscribers/#example-request_2","title":"Example Request","text":"
curl -u 'username:password' 'http://localhost:9000/api/subscribers?list_id=1&list_id=2&page=1&per_page=100'\n

To skip pagination and retrieve all records, pass per_page=all.

"},{"location":"apis/subscribers/#example-response_2","title":"Example Response","text":"
{\n\"data\": {\n\"results\": [\n{\n\"id\": 1,\n\"created_at\": \"2019-06-26T16:51:54.37065+05:30\",\n\"updated_at\": \"2019-07-03T11:53:53.839692+05:30\",\n\"uuid\": \"5e91dda1-1c16-467d-9bf9-2a21bf22ae21\",\n\"email\": \"test@test.com\",\n\"name\": \"Test Subscriber\",\n\"attribs\": {\n\"city\": \"Bengaluru\",\n\"projects\": 3,\n\"stack\": {\n\"languages\": [\"go\", \"python\"]\n}\n},\n\"status\": \"enabled\",\n\"lists\": [\n{\n\"subscription_status\": \"unconfirmed\",\n\"id\": 1,\n\"uuid\": \"41badaf2-7905-4116-8eac-e8817c6613e4\",\n\"name\": \"Default list\",\n\"type\": \"public\",\n\"tags\": [\"test\"],\n\"created_at\": \"2019-06-26T16:51:54.367719+05:30\",\n\"updated_at\": \"2019-06-26T16:51:54.367719+05:30\"\n}\n]\n}\n],\n\"query\": \"\",\n\"total\": 1,\n\"per_page\": 20,\n\"page\": 1\n}\n}\n
"},{"location":"apis/subscribers/#get-apisubscribers_2","title":"GET /api/subscribers","text":"

Gets subscribers with an SQL expression.

"},{"location":"apis/subscribers/#example-request_3","title":"Example Request","text":"
curl -u 'username:password' -X GET 'http://localhost:9000/api/subscribers' \\\n--url-query 'page=1' \\\n--url-query 'per_page=100' \\\n--url-query \"query=subscribers.name LIKE 'Test%' AND subscribers.attribs->>'city' = 'Bengaluru'\"\n

To skip pagination and retrieve all records, pass per_page=all.

Refer to the querying and segmentation section for more information on how to query subscribers with SQL expressions.

"},{"location":"apis/subscribers/#example-response_3","title":"Example Response","text":"
{\n\"data\": {\n\"results\": [\n{\n\"id\": 1,\n\"created_at\": \"2019-06-26T16:51:54.37065+05:30\",\n\"updated_at\": \"2019-07-03T11:53:53.839692+05:30\",\n\"uuid\": \"5e91dda1-1c16-467d-9bf9-2a21bf22ae21\",\n\"email\": \"test@test.com\",\n\"name\": \"Test Subscriber\",\n\"attribs\": {\n\"city\": \"Bengaluru\",\n\"projects\": 3,\n\"stack\": {\n\"frameworks\": [\"echo\", \"go\"],\n\"languages\": [\"go\", \"python\"]\n}\n},\n\"status\": \"enabled\",\n\"lists\": [\n{\n\"subscription_status\": \"unconfirmed\",\n\"id\": 1,\n\"uuid\": \"41badaf2-7905-4116-8eac-e8817c6613e4\",\n\"name\": \"Default list\",\n\"type\": \"public\",\n\"tags\": [\"test\"],\n\"created_at\": \"2019-06-26T16:51:54.367719+05:30\",\n\"updated_at\": \"2019-06-26T16:51:54.367719+05:30\"\n}\n]\n}\n],\n\"query\": \"subscribers.name LIKE 'Test%' AND subscribers.attribs-\\u003e\\u003e'city' = 'Bengaluru'\",\n\"total\": 1,\n\"per_page\": 20,\n\"page\": 1\n}\n}\n
"},{"location":"apis/subscribers/#post-apisubscribers","title":"POST /api/subscribers","text":"

Creates a new subscriber.

"},{"location":"apis/subscribers/#parameters_2","title":"Parameters","text":"Name Parameter type Data type Required/Optional Description email Request body String Required The email address of the new subscriber. name Request body String Required The name of the new subscriber. status Request body String Required The status of the new subscriber. Can be enabled, disabled or blocklisted. lists Request body Numbers Optional Array of list IDs to subscribe to (marked as unconfirmed by default). attribs Request body json Optional JSON list containing new subscriber's attributes. preconfirm_subscriptions Request body Bool Optional If true, marks subscriptions as confirmed and no-optin e-mails are sent for double opt-in lists."},{"location":"apis/subscribers/#example-request_4","title":"Example Request","text":"
curl -u 'username:password' 'http://localhost:9000/api/subscribers' -H 'Content-Type: application/json' \\\n--data '{\"email\":\"subsriber@domain.com\",\"name\":\"The Subscriber\",\"status\":\"enabled\",\"lists\":[1],\"attribs\":{\"city\":\"Bengaluru\",\"projects\":3,\"stack\":{\"languages\":[\"go\",\"python\"]}}}'\n
"},{"location":"apis/subscribers/#example-response_4","title":"Example Response","text":"
{\n\"data\": {\n\"id\": 3,\n\"created_at\": \"2019-07-03T12:17:29.735507+05:30\",\n\"updated_at\": \"2019-07-03T12:17:29.735507+05:30\",\n\"uuid\": \"eb420c55-4cfb-4972-92ba-c93c34ba475d\",\n\"email\": \"subsriber@domain.com\",\n\"name\": \"The Subscriber\",\n\"attribs\": {\n\"city\": \"Bengaluru\",\n\"projects\": 3,\n\"stack\": { \"languages\": [\"go\", \"python\"] }\n},\n\"status\": \"enabled\",\n\"lists\": [1]\n}\n}\n
"},{"location":"apis/subscribers/#post-apipublicsubscription","title":"POST /api/public/subscription","text":"

This is a public, unauthenticated API meant for directly integrating forms for public subscription. The API supports both form encoded or a JSON encoded body.

"},{"location":"apis/subscribers/#parameters_3","title":"Parameters","text":"Name Parameter type Data type Required/Optional Description email Request body String Required The email address of the subscriber. name Request body String Optional The name of the new subscriber. list_uuids Request body Strings Required Array of list UUIDs."},{"location":"apis/subscribers/#example-json-request","title":"Example JSON Request","text":"
curl -u 'http://localhost:9000/api/public/subscription' -H 'Content-Type: application/json' \\\n--data '{\"email\":\"subsriber@domain.com\",\"name\":\"The Subscriber\", \"lists\": [\"eb420c55-4cfb-4972-92ba-c93c34ba475d\", \"0c554cfb-eb42-4972-92ba-c93c34ba475d\"]}'\n
"},{"location":"apis/subscribers/#example-form-request","title":"Example Form Request","text":"
curl -u 'http://localhost:9000/api/public/subscription' \\\n-d 'email=subsriber@domain.com' -d 'name=The Subscriber' -d 'l=eb420c55-4cfb-4972-92ba-c93c34ba475d' -d 'l=0c554cfb-eb42-4972-92ba-c93c34ba475d'\n

Notice that in form request, there param is l that is repeated for multiple lists, and not lists like in JSON.

"},{"location":"apis/subscribers/#example-response_5","title":"Example Response","text":"
{\n\"data\": true\n}\n
"},{"location":"apis/subscribers/#put-apisubscriberslists","title":"PUT /api/subscribers/lists","text":"

Modify subscribers list memberships.

"},{"location":"apis/subscribers/#parameters_4","title":"Parameters","text":"Name Parameter type Data type Required/Optional Description ids Request body Numbers Required The ids of the subscribers to be modified. action Request body String Required Whether to add, remove, or unsubscribe the users. target_list_ids Request body Numbers Required The ids of the lists to be modified. status Request body String Required for add confirmed, unconfirmed, or unsubscribed status."},{"location":"apis/subscribers/#example-request_5","title":"Example Request","text":"

To subscribe users 1, 2, and 3 to lists 4, 5, and 6:

curl -u 'username:password' -X PUT 'http://localhost:9000/api/subscribers/lists' \\\n--data-raw '{\"ids\": [1, 2, 3], \"action\": \"add\", \"target_list_ids\": [4, 5, 6], \"status\": \"confirmed\"}'\n
"},{"location":"apis/subscribers/#example-response_6","title":"Example Response","text":"
{\n\"data\": true\n} 
"},{"location":"apis/subscribers/#put-apisubscribersid","title":"PUT /api/subscribers/:id","text":"

Updates a single subscriber.

"},{"location":"apis/subscribers/#parameters_5","title":"Parameters","text":"

Parameters are the same as POST /api/subscribers used for subscriber creation.

Please note that this is a PUT request, so all the parameters have to be set. For example if you don't provide lists, the subscriber will be deleted from all the lists he was previously signed on.

"},{"location":"apis/subscribers/#put-apisubscribersidblocklist","title":"PUT /api/subscribers/:id/blocklist","text":"

Blocklists a single subscriber.

"},{"location":"apis/subscribers/#parameters_6","title":"Parameters","text":"Name Parameter type Data type Required/Optional Description id Path parameter Number Required The id value of the subscriber you want to blocklist."},{"location":"apis/subscribers/#example-request_6","title":"Example Request","text":"
curl -u 'username:password' -X PUT 'http://localhost:9000/api/subscribers/9/blocklist'\n
"},{"location":"apis/subscribers/#example-response_7","title":"Example Response","text":"
{\n\"data\": true\n} 
"},{"location":"apis/subscribers/#put-apisubscribersqueryblocklist","title":"PUT /api/subscribers/query/blocklist","text":"

Blocklists subscribers with an arbitrary sql expression.

"},{"location":"apis/subscribers/#example-request_7","title":"Example Request","text":"
curl -u 'username:password' -X PUT 'http://localhost:9000/api/subscribers/query/blocklist' \\\n--data-raw '\"query=subscribers.name LIKE '\\''John Doe'\\'' AND subscribers.attribs->>'\\''city'\\'' = '\\''Bengaluru'\\''\"'\n

Refer to the querying and segmentation section for more information on how to query subscribers with SQL expressions.

"},{"location":"apis/subscribers/#example-response_8","title":"Example Response","text":"
{\n\"data\": true\n}\n
"},{"location":"apis/subscribers/#delete-apisubscribersid","title":"DELETE /api/subscribers/:id","text":"

Deletes a single subscriber.

"},{"location":"apis/subscribers/#parameters_7","title":"Parameters","text":"Name Parameter type Data type Required/Optional Description id Path parameter Number Required The id of the subscriber you want to delete."},{"location":"apis/subscribers/#example-request_8","title":"Example Request","text":"
curl -u 'username:password' -X DELETE 'http://localhost:9000/api/subscribers/9'\n
"},{"location":"apis/subscribers/#example-response_9","title":"Example Response","text":"
{\n\"data\": true\n}\n
"},{"location":"apis/subscribers/#delete-apisubscribers","title":"DELETE /api/subscribers","text":"

Deletes one or more subscribers.

"},{"location":"apis/subscribers/#parameters_8","title":"Parameters","text":"Name Parameter type Data type Required/Optional Description id Query parameters Number Required The id of the subscribers you want to delete."},{"location":"apis/subscribers/#example-request_9","title":"Example Request","text":"
curl -u 'username:password' -X DELETE 'http://localhost:9000/api/subscribers?id=10&id=11'\n
"},{"location":"apis/subscribers/#example-response_10","title":"Example Response","text":"
{\n\"data\": true\n}\n
"},{"location":"apis/subscribers/#post-apisubscribersquerydelete","title":"POST /api/subscribers/query/delete","text":"

Deletes subscribers with an arbitrary SQL expression.

"},{"location":"apis/subscribers/#example-request_10","title":"Example Request","text":"
curl -u 'username:password' -X POST 'http://localhost:9000/api/subscribers/query/delete' \\\n--data-raw '\"query=subscribers.name LIKE '\\''John Doe'\\'' AND subscribers.attribs->>'\\''city'\\'' = '\\''Bengaluru'\\''\"'\n

Refer to the querying and segmentation section for more information on how to query subscribers with SQL expressions.

"},{"location":"apis/subscribers/#example-response_11","title":"Example Response","text":"
{\n\"data\": true\n}\n
"},{"location":"apis/templates/","title":"API / Templates","text":"Method Endpoint Description GET /api/templates Gets all templates. GET /api/templates/:template_id Gets a single template. GET /api/templates/:template_id/preview Gets the HTML preview of a template. POST /api/templates/preview POST /api/templates Creates a template. PUT /api/templates/:template_id Modifies a template. PUT /api/templates/:template_id/default Sets a template to the default template. DELETE /api/templates/:template_id Deletes a template."},{"location":"apis/templates/#get-apitemplates","title":"GET /api/templates","text":"

Gets all templates.

"},{"location":"apis/templates/#example-request","title":"Example Request","text":"
curl -u \"username:username\" -X GET 'http://localhost:9000/api/templates'\n
"},{"location":"apis/templates/#example-response","title":"Example Response","text":"
{\n\"data\": [\n{\n\"id\": 1,\n\"created_at\": \"2020-03-14T17:36:41.288578+01:00\",\n\"updated_at\": \"2020-03-14T17:36:41.288578+01:00\",\n\"name\": \"Default template\",\n\"body\": \"{{ template \\\"content\\\" . }}\",\n\"type\": \"campaign\",\n\"is_default\": true\n}\n]\n}\n
"},{"location":"apis/templates/#get-apitemplatestemplate_id","title":"GET /api/templates/:template_id","text":"

Gets a single template.

"},{"location":"apis/templates/#parameters","title":"Parameters","text":"Name Parameter Type Data Type Required/Optional Description template_id Path Parameter Number Required The id value of the template you want to get."},{"location":"apis/templates/#example-request_1","title":"Example Request","text":"
curl -u \"username:username\" -X GET 'http://localhost:9000/api/templates/1'\n
"},{"location":"apis/templates/#example-response_1","title":"Example Response","text":"
{\n\"data\": {\n\"id\": 1,\n\"created_at\": \"2020-03-14T17:36:41.288578+01:00\",\n\"updated_at\": \"2020-03-14T17:36:41.288578+01:00\",\n\"name\": \"Default template\",\n\"body\": \"{{ template \\\"content\\\" . }}\",\n\"type\": \"campaign\",\n\"is_default\": true\n}\n}\n
"},{"location":"apis/templates/#get-apitemplatestemplate_idpreview","title":"GET /api/templates/:template_id/preview","text":"

Gets the HTML preview of a template body.

"},{"location":"apis/templates/#parameters_1","title":"Parameters","text":"Name Parameter Type Data Type Required/Optional Description template_id Path Parameter Number Required The id value of the template whose html preview you want to get."},{"location":"apis/templates/#example-request_2","title":"Example Request","text":"
curl -u \"username:username\" -X GET 'http://localhost:9000/api/templates/1/preview'\n
"},{"location":"apis/templates/#example-response_2","title":"Example Response","text":"
<p>Hi there</p>\n<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis et elit ac elit sollicitudin condimentum non a magna.\n    Sed tempor mauris in facilisis vehicula. Aenean nisl urna, accumsan ac tincidunt vitae, interdum cursus massa.\n    Interdum et malesuada fames ac ante ipsum primis in faucibus. Aliquam varius turpis et turpis lacinia placerat.\n    Aenean id ligula a orci lacinia blandit at eu felis. Phasellus vel lobortis lacus. Suspendisse leo elit, luctus sed\n    erat ut, venenatis fermentum ipsum. Donec bibendum neque quis.</p>\n\n<h3>Sub heading</h3>\n<p>Nam luctus dui non placerat mattis. Morbi non accumsan orci, vel interdum urna. Duis faucibus id nunc ut euismod.\n    Curabitur et eros id erat feugiat fringilla in eget neque. Aliquam accumsan cursus eros sed faucibus.</p>\n\n<p>Here is a link to <a href=\"https://listmonk.app\" target=\"_blank\">listmonk</a>.</p>\n
"},{"location":"apis/templates/#put-apitemplatestemplate_iddefault","title":"PUT /api/templates/:template_id/default","text":"

Sets a template to the default template.

"},{"location":"apis/templates/#parameters_2","title":"Parameters","text":"Name Parameter Type Data Type Required/Optional Description template_id Path Parameter Number Required The id value of the template you want to set to the default template."},{"location":"apis/templates/#example-request_3","title":"Example Request","text":"
curl -u \"username:username\" -X PUT 'http://localhost:9000/api/templates/1/default'\n
"},{"location":"apis/templates/#example-response_3","title":"Example Response","text":"
{\n\"data\": {\n\"id\": 1,\n\"created_at\": \"2020-03-14T17:36:41.288578+01:00\",\n\"updated_at\": \"2020-03-14T17:36:41.288578+01:00\",\n\"name\": \"Default template\",\n\"body\": \"{{ template \\\"content\\\" . }}\",\n\"type\": \"campaign\",\n\"is_default\": true\n}\n}\n
"},{"location":"apis/templates/#delete-apitemplatestemplate_id","title":"DELETE /api/templates/:template_id","text":"

Deletes a template.

"},{"location":"apis/templates/#parameters_3","title":"Parameters","text":"Name Parameter Type Data Type Required/Optional Description template_id Path Parameter Number Required The id value of the template you want to delete."},{"location":"apis/templates/#example-request_4","title":"Example Request","text":"
curl -u \"username:username\" -X DELETE 'http://localhost:9000/api/templates/35'\n
"},{"location":"apis/templates/#example-response_4","title":"Example Response","text":"
{\n\"data\": true\n}\n
"},{"location":"apis/transactional/","title":"API / Transactional","text":"Method Endpoint Description POST /api/tx"},{"location":"apis/transactional/#post-apitx","title":"POST /api/tx","text":"

Send a transactional message to one or multiple subscribers using a predefined transactional template.

"},{"location":"apis/transactional/#parameters","title":"Parameters","text":"Name Data Type Optional Description subscriber_email String Optional E-mail of the subscriber. Either this or subscriber_id should be passed. subscriber_id Number Optional ID of the subscriber. Either this or subscriber_email should be passed. subscriber_emails []String Optional E-mails of the subscribers. This is an alternative to subscriber_email for multiple recipients. [\"email1@example.com\", \"emailX@example.com\"] subscriber_ids []Number Optional IDs of the subscribers. This is an alternative to subscriber_id for multiple recipients. [1,2,3] template_id Number Required ID of the transactional template to use in the message. from_email String Optional Optional from email. eg: Company <email@company.com> data Map Optional Optional data in {} nested map. Available in the template as {{ .Tx.Data.* }} headers []Map Optional Optional array of mail headers. [{\"key\": \"value\"}, {\"key\": \"value\"}] messenger String Optional Messenger to use to send the message. Default value is email. content_type String Optional html, markdown, plain"},{"location":"apis/transactional/#request","title":"Request","text":"
curl -u \"username:password\" \"http://localhost:9000/api/tx\" -X POST \\\n-H 'Content-Type: application/json; charset=utf-8' \\\n--data-binary @- << EOF\n    {\n        \"subscriber_email\": \"user@test.com\",\n        \"template_id\": 2,\n        \"data\": {\"order_id\": \"1234\", \"date\": \"2022-07-30\", \"items\": [1, 2, 3]},\n        \"content_type\": \"html\"\n    }\nEOF\n
"},{"location":"apis/transactional/#response","title":"Response","text":"
{\n\"data\": true\n}\n
"},{"location":"apis/transactional/#file-attachments","title":"File Attachments","text":"

To include file attachments in a transactional message, use Content-Type multipart/form-data. Use the parameters described above as a JSON object via the data form key and include an arbitrary number of attachments via the file key.

curl -u \"username:password\" \"http://localhost:9000/api/tx\" -X POST \\\n-F 'data=\\\"{\n    \\\"subscriber_email\\\": \\\"user@test.com\\\",\n    \\\"template_id\\\": 4\n}\"' \\\n-F 'file=@\"/path/to/attachment.pdf\"' \\\n-F 'file=@\"/path/to/attachment2.pdf\"'\n
"}]} \ No newline at end of file diff --git a/docs/sitemap.xml.gz b/docs/sitemap.xml.gz index 87cf377ace6b72786258c652db31adc2d3827f83..6cc2df3a848885b83b722b0b326d5f8025c8b712 100644 GIT binary patch delta 13 Ucmb=gXP58h;P`a$-9+{Z03!qifdBvi delta 13 Ucmb=gXP58h;8?in%|!MJ03dq>4*&oF