# Systeme.io API

> Every Systeme.io endpoint on Cotlet: inputs, JSON Schema, cURL, Python and Node.js examples and an example response for each call.

Source: https://cotlet.dev/docs/api/systeme-io

Docs sections: [Get started](https://cotlet.dev/docs.md) · [REST API](https://cotlet.dev/docs/api.md) · [MCP](https://cotlet.dev/docs/mcp.md) · [SDKs & CLI](https://cotlet.dev/docs/sdks.md) · [Integrations](https://cotlet.dev/docs/integrations.md)

13 endpoints for Systeme.io. Each one is a POST with a JSON body, called with your API key.

- Base URL: `https://cotlet.dev/api/v1/systeme-io`
- Connects with: Your own Systeme.io account
- Integration page: https://cotlet.dev/integrations/systeme-io-api-mcp-server

## Endpoints

| Endpoint | Access | Description |
|---|---|---|
| `list_transactions` | read | Sales from the Transactions page, with customer, offer, amount and transaction type. |
| `get_transaction` | read | One sale with customer, offer, amount, payment processor charge ID and refund status. |
| `export_transactions` | read | Starts a CSV export of transactions; Systeme.io emails the download link to your account address. |
| `list_funnel_steps` | read | Your sales funnels with their steps: name, type, URL path and page ID. |
| `get_page_content` | read | Text elements of a funnel page (headlines, paragraphs, buttons) with an ID per element. |
| `list_blog_posts` | read | Posts of a blog with title, URL path, categories and whether each is active. |
| `update_page_text` | write | Change the text of chosen elements on a funnel page and save it; the rest of the page stays as it is. |
| `duplicate_funnel_step` | write | Copy a step below the original, with "(copy)" in its name; set a new URL path for the copy. |
| `remove_funnel_step` | write | Permanently delete a step and its page from a funnel. |
| `refund_transaction` | write | Refund a sale in full through its payment gateway; an invoice with a negative amount is created. |
| `send_invoice` | write | Email the invoice of a transaction to its customer. |
| `create_blog_post` | write | New blog post from Markdown, saved inactive so nobody sees it until you activate it. |
| `activate_blog_post` | write | Show a post on your blog. |

## List transactions

`POST https://cotlet.dev/api/v1/systeme-io/list_transactions`

Access: read.

Lists transactions with the same filters as the Transactions page: customer email, offer, transaction type, date range, customer country and customer type (company or individual). Results are newest first. Pass next_cursor back as cursor for the next page.

### Parameters

| Name | Type | Required | Description |
|---|---|---|---|
| `customer_email` | string | no | Only this customer. |
| `offer` | string | no | Only sales of this offer (name or ID). |
| `type` | string | no | Transaction type, as in the Transactions filter. |
| `from` | date | no | Start of the date range. |
| `to` | date | no | End of the date range. |
| `customer_country` | string | no | Two-letter country code. |
| `customer_type` | enum | no | company or individual. |
| `limit` | integer | no | 1 to 100. Default: 50. |
| `cursor` | string | no | Next page cursor from the previous call. |

### Request

**cURL**

```bash
curl -X POST https://cotlet.dev/api/v1/systeme-io/list_transactions \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"from":"2026-09-01","to":"2026-09-30","customer_type":"company","limit":100}'
```

**Python**

```python
result = client.call("systeme-io", "list_transactions", {"from":"2026-09-01","to":"2026-09-30","customer_type":"company","limit":100})
```

**Node.js**

```js
const result = await cotlet.call('systeme-io', 'list_transactions', {"from":"2026-09-01","to":"2026-09-30","customer_type":"company","limit":100});
```

**CLI**

```bash
cotlet call systeme-io list_transactions --data '{"from":"2026-09-01","to":"2026-09-30","customer_type":"company","limit":100}'
```

### Example response

```json
{
  "transactions": [
    {
      "transaction_id": "tr_20931",
      "customer_email": "hans@example.com",
      "offer": "Starter course",
      "amount": 97,
      "currency": "EUR",
      "type": "sale",
      "customer_country": "DE",
      "customer_type": "individual",
      "occurred_at": "2026-10-08T09:12:00Z"
    },
    {
      "transaction_id": "tr_20944",
      "customer_email": "office@example.de",
      "offer": "Pro membership",
      "amount": 49,
      "currency": "EUR",
      "type": "sale",
      "customer_country": "DE",
      "customer_type": "company",
      "occurred_at": "2026-10-09T15:40:00Z"
    }
  ],
  "next_cursor": null
}
```

## Get transaction

`POST https://cotlet.dev/api/v1/systeme-io/get_transaction`

Access: read.

Returns one transaction as listed on the Transactions page, with the payment processor charge ID and whether it was refunded. Use it before refund_transaction to check the amount and the customer.

### Parameters

| Name | Type | Required | Description |
|---|---|---|---|
| `transaction_id` | string | yes | Transaction ID from list_transactions. |

### Request

**cURL**

```bash
curl -X POST https://cotlet.dev/api/v1/systeme-io/get_transaction \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"transaction_id":"transaction_8c41d2"}'
```

**Python**

```python
result = client.call("systeme-io", "get_transaction", {"transaction_id":"transaction_8c41d2"})
```

**Node.js**

```js
const result = await cotlet.call('systeme-io', 'get_transaction', {"transaction_id":"transaction_8c41d2"});
```

**CLI**

```bash
cotlet call systeme-io get_transaction --data '{"transaction_id":"transaction_8c41d2"}'
```

### Example response

```json
{
  "transaction_id": "tr_20931",
  "customer_email": "hans@example.com",
  "offer": "Starter course",
  "amount": 97,
  "currency": "EUR",
  "type": "sale",
  "processor_charge_id": "ch_3Q9xExample",
  "refunded": false,
  "occurred_at": "2026-10-08T09:12:00Z"
}
```

## Export transactions

`POST https://cotlet.dev/api/v1/systeme-io/export_transactions`

Access: read.

Starts the same CSV export as the Transactions page, for transactions in an optional date range. Systeme.io emails the download link to the address of your account, so the call returns only a confirmation. The export reaches only you.

### Parameters

| Name | Type | Required | Description |
|---|---|---|---|
| `from` | date | no | Start of the date range. |
| `to` | date | no | End of the date range. |
| `delimiter` | string | no | Column separator for the CSV file, as offered in the export popup. |

### Request

**cURL**

```bash
curl -X POST https://cotlet.dev/api/v1/systeme-io/export_transactions \
  -H "Authorization: Bearer $COTLET_API_KEY"
```

**Python**

```python
result = client.call("systeme-io", "export_transactions")
```

**Node.js**

```js
const result = await cotlet.call('systeme-io', 'export_transactions');
```

**CLI**

```bash
cotlet call systeme-io export_transactions
```

### Example response

```json
{
  "status": "started",
  "delivery": "email to your account address"
}
```

## List funnel steps

`POST https://cotlet.dev/api/v1/systeme-io/list_funnel_steps`

Access: read.

Lists funnels with their steps in funnel order. Each step has the ID that the page tools take as step_id. Leave funnel_id out to list every funnel.

### Parameters

| Name | Type | Required | Description |
|---|---|---|---|
| `funnel_id` | string | no | Only this funnel. Default: all funnels. |

### Request

**cURL**

```bash
curl -X POST https://cotlet.dev/api/v1/systeme-io/list_funnel_steps \
  -H "Authorization: Bearer $COTLET_API_KEY"
```

**Python**

```python
result = client.call("systeme-io", "list_funnel_steps")
```

**Node.js**

```js
const result = await cotlet.call('systeme-io', 'list_funnel_steps');
```

**CLI**

```bash
cotlet call systeme-io list_funnel_steps
```

### Example response

```json
{
  "funnels": [
    {
      "funnel_id": "f_1204",
      "name": "Webinar funnel",
      "steps": [
        {
          "step_id": "8841207",
          "name": "Webinar sales page",
          "type": "sales page",
          "path": "webinar"
        },
        {
          "step_id": "8841219",
          "name": "Thank you",
          "type": "thank you page",
          "path": "webinar-thanks"
        }
      ]
    }
  ]
}
```

## Get page content

`POST https://cotlet.dev/api/v1/systeme-io/get_page_content`

Access: read.

Returns the text elements of one funnel page in page order, each with an element ID. Pass those IDs to update_page_text. Images and layout settings are not included.

### Parameters

| Name | Type | Required | Description |
|---|---|---|---|
| `step_id` | string | yes | Funnel step ID from list_funnel_steps. |

### Request

**cURL**

```bash
curl -X POST https://cotlet.dev/api/v1/systeme-io/get_page_content \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"step_id":"step_8c41d2"}'
```

**Python**

```python
result = client.call("systeme-io", "get_page_content", {"step_id":"step_8c41d2"})
```

**Node.js**

```js
const result = await cotlet.call('systeme-io', 'get_page_content', {"step_id":"step_8c41d2"});
```

**CLI**

```bash
cotlet call systeme-io get_page_content --data '{"step_id":"step_8c41d2"}'
```

### Example response

```json
{
  "step_id": "8841207",
  "elements": [
    {
      "element_id": "headline-1a2b",
      "kind": "headline",
      "text": "Free webinar: launch your first course"
    },
    {
      "element_id": "button-9f3c",
      "kind": "button",
      "text": "Register now"
    }
  ]
}
```

## List blog posts

`POST https://cotlet.dev/api/v1/systeme-io/list_blog_posts`

Access: read.

Lists the posts of one blog, with the ID that activate_blog_post takes as post_id. The blog_id of your blog is also returned, for create_blog_post. Active posts are visible on the blog; inactive ones are not.

### Parameters

| Name | Type | Required | Description |
|---|---|---|---|
| `blog_id` | string | no | Blog to read. Default: your first blog. |
| `limit` | integer | no | 1 to 100. Default: 50. |

### Request

**cURL**

```bash
curl -X POST https://cotlet.dev/api/v1/systeme-io/list_blog_posts \
  -H "Authorization: Bearer $COTLET_API_KEY"
```

**Python**

```python
result = client.call("systeme-io", "list_blog_posts")
```

**Node.js**

```js
const result = await cotlet.call('systeme-io', 'list_blog_posts');
```

**CLI**

```bash
cotlet call systeme-io list_blog_posts
```

### Example response

```json
{
  "blog_id": "blog_3302",
  "posts": [
    {
      "post_id": "bp_5498",
      "title": "Five launch mistakes",
      "path": "five-launch-mistakes",
      "categories": [
        "Marketing"
      ],
      "active": true
    }
  ],
  "next_cursor": null
}
```

## Update page text

`POST https://cotlet.dev/api/v1/systeme-io/update_page_text`

Access: write. Confirm: waits for the user's OK before it runs.

Changes the text of the elements you name and saves the page. Other elements, images and settings are not touched. On a live funnel visitors see the change at once. By default you confirm each call; you can switch that off for this tool.

### Parameters

| Name | Type | Required | Description |
|---|---|---|---|
| `step_id` | string | yes | Funnel step ID from list_funnel_steps. |
| `changes` | object | yes | Map of element_id from get_page_content to new text. |

### Request

**cURL**

```bash
curl -X POST https://cotlet.dev/api/v1/systeme-io/update_page_text \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"step_id":"8841207","changes":{"headline-1a2b":"Live training: Thursday 7 PM","button-9f3c":"Save my seat"}}'
```

**Python**

```python
result = client.call("systeme-io", "update_page_text", {"step_id":"8841207","changes":{"headline-1a2b":"Live training: Thursday 7 PM","button-9f3c":"Save my seat"}})
```

**Node.js**

```js
const result = await cotlet.call('systeme-io', 'update_page_text', {"step_id":"8841207","changes":{"headline-1a2b":"Live training: Thursday 7 PM","button-9f3c":"Save my seat"}});
```

**CLI**

```bash
cotlet call systeme-io update_page_text --data '{"step_id":"8841207","changes":{"headline-1a2b":"Live training: Thursday 7 PM","button-9f3c":"Save my seat"}}'
```

### Example response

```json
{
  "step_id": "8841207",
  "updated_elements": 2,
  "saved_at": "2026-10-11T14:05:12+02:00"
}
```

## Duplicate funnel step

`POST https://cotlet.dev/api/v1/systeme-io/duplicate_funnel_step`

Access: write.

Duplicates a funnel page and places the copy below the original, named with "(copy)". Pass path to give the copy its own URL. The copy reaches no one until you link to it, and remove_funnel_step undoes it, so this call runs without asking.

### Parameters

| Name | Type | Required | Description |
|---|---|---|---|
| `step_id` | string | yes | Funnel step ID from list_funnel_steps. |
| `path` | string | no | URL path for the copy. |

### Request

**cURL**

```bash
curl -X POST https://cotlet.dev/api/v1/systeme-io/duplicate_funnel_step \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"step_id":"step_8c41d2"}'
```

**Python**

```python
result = client.call("systeme-io", "duplicate_funnel_step", {"step_id":"step_8c41d2"})
```

**Node.js**

```js
const result = await cotlet.call('systeme-io', 'duplicate_funnel_step', {"step_id":"step_8c41d2"});
```

**CLI**

```bash
cotlet call systeme-io duplicate_funnel_step --data '{"step_id":"step_8c41d2"}'
```

### Example response

```json
{
  "step_id": "8841260",
  "name": "Webinar sales page (copy)",
  "path": "webinar-b",
  "copied_from": "8841207"
}
```

## Remove funnel step

`POST https://cotlet.dev/api/v1/systeme-io/remove_funnel_step`

Access: write. Confirm: waits for the user's OK before it runs.

Deletes one step and its page from a funnel. This cannot be undone, and visitors lose the page. By default you confirm each call; you can switch that off for this tool.

### Parameters

| Name | Type | Required | Description |
|---|---|---|---|
| `step_id` | string | yes | Funnel step ID from list_funnel_steps. |

### Request

**cURL**

```bash
curl -X POST https://cotlet.dev/api/v1/systeme-io/remove_funnel_step \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"step_id":"step_8c41d2"}'
```

**Python**

```python
result = client.call("systeme-io", "remove_funnel_step", {"step_id":"step_8c41d2"})
```

**Node.js**

```js
const result = await cotlet.call('systeme-io', 'remove_funnel_step', {"step_id":"step_8c41d2"});
```

**CLI**

```bash
cotlet call systeme-io remove_funnel_step --data '{"step_id":"step_8c41d2"}'
```

### Example response

```json
{
  "step_id": "8841219",
  "status": "removed"
}
```

## Refund transaction

`POST https://cotlet.dev/api/v1/systeme-io/refund_transaction`

Access: write. Confirm: waits for the user's OK before it runs.

Refunds the whole sale; Systeme.io does not support partial refunds. It depends on your payment gateway: the balance must cover the refund. Afterwards the transaction shows an invoice with a negative amount, which send_invoice can email to the customer. By default you confirm each call; you can switch that off for this tool.

### Parameters

| Name | Type | Required | Description |
|---|---|---|---|
| `transaction_id` | string | yes | Transaction ID from list_transactions. |

### Request

**cURL**

```bash
curl -X POST https://cotlet.dev/api/v1/systeme-io/refund_transaction \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"transaction_id":"tr_20931"}'
```

**Python**

```python
result = client.call("systeme-io", "refund_transaction", {"transaction_id":"tr_20931"})
```

**Node.js**

```js
const result = await cotlet.call('systeme-io', 'refund_transaction', {"transaction_id":"tr_20931"});
```

**CLI**

```bash
cotlet call systeme-io refund_transaction --data '{"transaction_id":"tr_20931"}'
```

### Example response

```json
{
  "transaction_id": "tr_20931",
  "status": "refunded",
  "refunded_amount": 97,
  "currency": "EUR"
}
```

## Send invoice

`POST https://cotlet.dev/api/v1/systeme-io/send_invoice`

Access: write. Confirm: waits for the user's OK before it runs.

Sends the invoice of one transaction to the customer, as the Send invoice to customer action does. After a refund it sends the invoice with the negative amount. Invoices go out one at a time. By default you confirm each call; you can switch that off for this tool.

### Parameters

| Name | Type | Required | Description |
|---|---|---|---|
| `transaction_id` | string | yes | Transaction ID from list_transactions. |

### Request

**cURL**

```bash
curl -X POST https://cotlet.dev/api/v1/systeme-io/send_invoice \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"transaction_id":"transaction_8c41d2"}'
```

**Python**

```python
result = client.call("systeme-io", "send_invoice", {"transaction_id":"transaction_8c41d2"})
```

**Node.js**

```js
const result = await cotlet.call('systeme-io', 'send_invoice', {"transaction_id":"transaction_8c41d2"});
```

**CLI**

```bash
cotlet call systeme-io send_invoice --data '{"transaction_id":"transaction_8c41d2"}'
```

### Example response

```json
{
  "transaction_id": "tr_20931",
  "status": "sent",
  "sent_to": "hans@example.com"
}
```

## Create blog post

`POST https://cotlet.dev/api/v1/systeme-io/create_blog_post`

Access: write.

Creates a post with a title, short description, URL path, main image and categories, and fills it with your Markdown. Categories must already exist in the blog. The post is saved inactive, so it reaches no one until activate_blog_post runs; this call runs without asking.

### Parameters

| Name | Type | Required | Description |
|---|---|---|---|
| `blog_id` | string | yes | Blog ID from list_blog_posts. |
| `title` | string | yes | Post title. |
| `body_markdown` | string | yes | Post content. Images by URL. |
| `description` | string | no | Short description shown on listing pages. |
| `path` | string | no | URL path. Default: made from the title. |
| `categories` | string[] | no | Names of categories that already exist in the blog. |
| `image_url` | string | no | Main image. |

### Request

**cURL**

```bash
curl -X POST https://cotlet.dev/api/v1/systeme-io/create_blog_post \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"blog_id":"blog_3302","title":"Five email mistakes before a launch","body_markdown":"Most launches lose sales in the emails, not the page...","description":"Five fixes to make before your next launch email goes out.","categories":["Marketing"]}'
```

**Python**

```python
result = client.call("systeme-io", "create_blog_post", {"blog_id":"blog_3302","title":"Five email mistakes before a launch","body_markdown":"Most launches lose sales in the emails, not the page...","description":"Five fixes to make before your next launch email goes out.","categories":["Marketing"]})
```

**Node.js**

```js
const result = await cotlet.call('systeme-io', 'create_blog_post', {"blog_id":"blog_3302","title":"Five email mistakes before a launch","body_markdown":"Most launches lose sales in the emails, not the page...","description":"Five fixes to make before your next launch email goes out.","categories":["Marketing"]});
```

**CLI**

```bash
cotlet call systeme-io create_blog_post --data '{"blog_id":"blog_3302","title":"Five email mistakes before a launch","body_markdown":"Most launches lose sales in the emails, not the page...","description":"Five fixes to make before your next launch email goes out.","categories":["Marketing"]}'
```

### Example response

```json
{
  "post_id": "bp_5521",
  "blog_id": "blog_3302",
  "title": "How we cut onboarding time in half",
  "categories": [
    "Marketing"
  ],
  "active": false
}
```

## Activate blog post

`POST https://cotlet.dev/api/v1/systeme-io/activate_blog_post`

Access: write. Confirm: waits for the user's OK before it runs.

Activates one post so visitors can read it on your blog. By default you confirm each call; you can switch that off for this tool.

### Parameters

| Name | Type | Required | Description |
|---|---|---|---|
| `post_id` | string | yes | Blog post ID from list_blog_posts. |

### Request

**cURL**

```bash
curl -X POST https://cotlet.dev/api/v1/systeme-io/activate_blog_post \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"post_id":"post_8c41d2"}'
```

**Python**

```python
result = client.call("systeme-io", "activate_blog_post", {"post_id":"post_8c41d2"})
```

**Node.js**

```js
const result = await cotlet.call('systeme-io', 'activate_blog_post', {"post_id":"post_8c41d2"});
```

**CLI**

```bash
cotlet call systeme-io activate_blog_post --data '{"post_id":"post_8c41d2"}'
```

### Example response

```json
{
  "post_id": "bp_5521",
  "active": true
}
```
