REST API reference
Systeme.io API
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
- Systeme.io
| 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
readPOST https://cotlet.dev/api/v1/systeme-io/list_transactions
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 | Description |
|---|---|---|
| customer_email | string | Only this customer. |
| offer | string | Only sales of this offer (name or ID). |
| type | string | Transaction type, as in the Transactions filter. |
| from | date | Start of the date range. |
| to | date | End of the date range. |
| customer_country | string | Two-letter country code. |
| customer_type | enum | company or individual. |
| limit | integer | 1 to 100. Default: 50. |
| cursor | string | Next page cursor from the previous call. |
Request
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}' result = client.call("systeme-io", "list_transactions", {"from":"2026-09-01","to":"2026-09-30","customer_type":"company","limit":100}) const result = await cotlet.call('systeme-io', 'list_transactions', {"from":"2026-09-01","to":"2026-09-30","customer_type":"company","limit":100}); cotlet call systeme-io list_transactions --data '{"from":"2026-09-01","to":"2026-09-30","customer_type":"company","limit":100}' Example response
{
"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
readPOST https://cotlet.dev/api/v1/systeme-io/get_transaction
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 | Description |
|---|---|---|
| transaction_id required | string | Transaction ID from list_transactions. |
Request
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"}' result = client.call("systeme-io", "get_transaction", {"transaction_id":"transaction_8c41d2"}) const result = await cotlet.call('systeme-io', 'get_transaction', {"transaction_id":"transaction_8c41d2"}); cotlet call systeme-io get_transaction --data '{"transaction_id":"transaction_8c41d2"}' Example response
{
"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
readPOST https://cotlet.dev/api/v1/systeme-io/export_transactions
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 | Description |
|---|---|---|
| from | date | Start of the date range. |
| to | date | End of the date range. |
| delimiter | string | Column separator for the CSV file, as offered in the export popup. |
Request
curl -X POST https://cotlet.dev/api/v1/systeme-io/export_transactions \
-H "Authorization: Bearer $COTLET_API_KEY" result = client.call("systeme-io", "export_transactions") const result = await cotlet.call('systeme-io', 'export_transactions'); cotlet call systeme-io export_transactions Example response
{
"status": "started",
"delivery": "email to your account address"
} List funnel steps
readPOST https://cotlet.dev/api/v1/systeme-io/list_funnel_steps
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 | Description |
|---|---|---|
| funnel_id | string | Only this funnel. Default: all funnels. |
Request
curl -X POST https://cotlet.dev/api/v1/systeme-io/list_funnel_steps \
-H "Authorization: Bearer $COTLET_API_KEY" result = client.call("systeme-io", "list_funnel_steps") const result = await cotlet.call('systeme-io', 'list_funnel_steps'); cotlet call systeme-io list_funnel_steps Example response
{
"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
readPOST https://cotlet.dev/api/v1/systeme-io/get_page_content
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 | Description |
|---|---|---|
| step_id required | string | Funnel step ID from list_funnel_steps. |
Request
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"}' result = client.call("systeme-io", "get_page_content", {"step_id":"step_8c41d2"}) const result = await cotlet.call('systeme-io', 'get_page_content', {"step_id":"step_8c41d2"}); cotlet call systeme-io get_page_content --data '{"step_id":"step_8c41d2"}' Example response
{
"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
readPOST https://cotlet.dev/api/v1/systeme-io/list_blog_posts
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 | Description |
|---|---|---|
| blog_id | string | Blog to read. Default: your first blog. |
| limit | integer | 1 to 100. Default: 50. |
Request
curl -X POST https://cotlet.dev/api/v1/systeme-io/list_blog_posts \
-H "Authorization: Bearer $COTLET_API_KEY" result = client.call("systeme-io", "list_blog_posts") const result = await cotlet.call('systeme-io', 'list_blog_posts'); cotlet call systeme-io list_blog_posts Example response
{
"blog_id": "blog_3302",
"posts": [
{
"post_id": "bp_5498",
"title": "Five launch mistakes",
"path": "five-launch-mistakes",
"categories": [
"Marketing"
],
"active": true
}
],
"next_cursor": null
} POST https://cotlet.dev/api/v1/systeme-io/update_page_text
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 | Description |
|---|---|---|
| step_id required | string | Funnel step ID from list_funnel_steps. |
| changes required | object | Map of element_id from get_page_content to new text. |
Request
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"}}' result = client.call("systeme-io", "update_page_text", {"step_id":"8841207","changes":{"headline-1a2b":"Live training: Thursday 7 PM","button-9f3c":"Save my seat"}}) 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"}}); 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
{
"step_id": "8841207",
"updated_elements": 2,
"saved_at": "2026-10-11T14:05:12+02:00"
} Duplicate funnel step
writePOST https://cotlet.dev/api/v1/systeme-io/duplicate_funnel_step
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 | Description |
|---|---|---|
| step_id required | string | Funnel step ID from list_funnel_steps. |
| path | string | URL path for the copy. |
Request
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"}' result = client.call("systeme-io", "duplicate_funnel_step", {"step_id":"step_8c41d2"}) const result = await cotlet.call('systeme-io', 'duplicate_funnel_step', {"step_id":"step_8c41d2"}); cotlet call systeme-io duplicate_funnel_step --data '{"step_id":"step_8c41d2"}' Example response
{
"step_id": "8841260",
"name": "Webinar sales page (copy)",
"path": "webinar-b",
"copied_from": "8841207"
} POST https://cotlet.dev/api/v1/systeme-io/remove_funnel_step
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 | Description |
|---|---|---|
| step_id required | string | Funnel step ID from list_funnel_steps. |
Request
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"}' result = client.call("systeme-io", "remove_funnel_step", {"step_id":"step_8c41d2"}) const result = await cotlet.call('systeme-io', 'remove_funnel_step', {"step_id":"step_8c41d2"}); cotlet call systeme-io remove_funnel_step --data '{"step_id":"step_8c41d2"}' Example response
{
"step_id": "8841219",
"status": "removed"
} POST https://cotlet.dev/api/v1/systeme-io/refund_transaction
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 | Description |
|---|---|---|
| transaction_id required | string | Transaction ID from list_transactions. |
Request
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"}' result = client.call("systeme-io", "refund_transaction", {"transaction_id":"tr_20931"}) const result = await cotlet.call('systeme-io', 'refund_transaction', {"transaction_id":"tr_20931"}); cotlet call systeme-io refund_transaction --data '{"transaction_id":"tr_20931"}' Example response
{
"transaction_id": "tr_20931",
"status": "refunded",
"refunded_amount": 97,
"currency": "EUR"
} POST https://cotlet.dev/api/v1/systeme-io/send_invoice
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 | Description |
|---|---|---|
| transaction_id required | string | Transaction ID from list_transactions. |
Request
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"}' result = client.call("systeme-io", "send_invoice", {"transaction_id":"transaction_8c41d2"}) const result = await cotlet.call('systeme-io', 'send_invoice', {"transaction_id":"transaction_8c41d2"}); cotlet call systeme-io send_invoice --data '{"transaction_id":"transaction_8c41d2"}' Example response
{
"transaction_id": "tr_20931",
"status": "sent",
"sent_to": "hans@example.com"
} Create blog post
writePOST https://cotlet.dev/api/v1/systeme-io/create_blog_post
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 | Description |
|---|---|---|
| blog_id required | string | Blog ID from list_blog_posts. |
| title required | string | Post title. |
| body_markdown required | string | Post content. Images by URL. |
| description | string | Short description shown on listing pages. |
| path | string | URL path. Default: made from the title. |
| categories | string[] | Names of categories that already exist in the blog. |
| image_url | string | Main image. |
Request
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"]}' 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"]}) 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"]}); 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
{
"post_id": "bp_5521",
"blog_id": "blog_3302",
"title": "How we cut onboarding time in half",
"categories": [
"Marketing"
],
"active": false
} POST https://cotlet.dev/api/v1/systeme-io/activate_blog_post
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 | Description |
|---|---|---|
| post_id required | string | Blog post ID from list_blog_posts. |
Request
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"}' result = client.call("systeme-io", "activate_blog_post", {"post_id":"post_8c41d2"}) const result = await cotlet.call('systeme-io', 'activate_blog_post', {"post_id":"post_8c41d2"}); cotlet call systeme-io activate_blog_post --data '{"post_id":"post_8c41d2"}' Example response
{
"post_id": "bp_5521",
"active": true
}