Access the Systeme.io API with managed OAuth authentication. Manage contacts, tags, courses, communities, and subscriptions.
# List contacts
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/systeme/api/contacts')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
https://api.maton.ai/systeme/{native-api-path}
Maton proxies requests to api.systeme.io and automatically injects your API key.
All requests require the Maton API key in the Authorization header:
Authorization: Bearer $MATON_API_KEY
Environment Variable: Set your API key as MATON_API_KEY:
export MATON_API_KEY="YOUR_API_KEY"
Manage your Systeme.io connections at https://api.maton.ai.
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/connections?app=systeme&status=ACTIVE')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
python <<'EOF'
import urllib.request, os, json
data = json.dumps({'app': 'systeme'}).encode()
req = urllib.request.Request('https://api.maton.ai/connections', data=data, method='POST')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Content-Type', 'application/json')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/connections/{connection_id}')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
Response:
{
"connection": {
"connection_id": "{connection_id}",
"status": "ACTIVE",
"creation_time": "2025-12-08T07:20:53.488460Z",
"last_updated_time": "2026-01-31T20:03:32.593153Z",
"url": "https://connect.maton.ai/?session_token=...",
"app": "systeme",
"metadata": {}
}
}
Open the returned url in a browser to complete OAuth authorization.
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/connections/{connection_id}', method='DELETE')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
If you have multiple Systeme.io connections, specify which one to use with the Maton-Connection header:
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/systeme/api/contacts')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Maton-Connection', '{connection_id}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
If you have multiple connections, always include this header to ensure requests go to the intended account.
GET /systeme/api/contacts
Query Parameters:
limit - Number of items per page (10-100, optional)startingAfter - ID of last received item for pagination (optional)order - Sort order: asc or desc (default: desc, optional)GET /systeme/api/contacts/{id}
POST /systeme/api/contacts
Content-Type: application/json
{
"email": "john@example.com",
"firstName": "John",
"lastName": "Doe",
"phoneNumber": "+1234567890",
"locale": "en",
"fields": [
{
"slug": "custom_field_slug",
"value": "custom value"
}
]
}
PATCH /systeme/api/contacts/{id}
Content-Type: application/merge-patch+json
{
"firstName": "Jane",
"lastName": "Smith"
}
DELETE /systeme/api/contacts/{id}
GET /systeme/api/tags
GET /systeme/api/tags/{id}
POST /systeme/api/tags
Content-Type: application/json
{
"name": "VIP Customer"
}
PUT /systeme/api/tags/{id}
Content-Type: application/json
{
"name": "Premium Customer"
}
DELETE /systeme/api/tags/{id}
POST /systeme/api/contacts/{id}/tags
Content-Type: application/json
{
"tagId": 12345
}
DELETE /systeme/api/contacts/{id}/tags/{tagId}
GET /systeme/api/contact_fields
POST /systeme/api/contact_fields
Content-Type: application/json
{
"name": "Company Name",
"slug": "company_name"
}
PATCH /systeme/api/contact_fields/{slug}
Content-Type: application/merge-patch+json
{
"name": "Organization Name"
}
DELETE /systeme/api/contact_fields/{slug}
GET /systeme/api/school/courses
GET /systeme/api/school/enrollments
POST /systeme/api/school/courses/{courseId}/enrollments
Content-Type: application/json
{
"contactId": 12345,
"accessType": "full_access"
}
Required Fields:
contactId - The ID of the contact to enrollaccessType - Access type: full_access, partial_access, or dripping_contentNote: If accessType is partial_access, you must also provide a modules array with module IDs.
DELETE /systeme/api/school/enrollments/{id}
GET /systeme/api/community/communities
GET /systeme/api/community/memberships
POST /systeme/api/community/communities/{communityId}/memberships
Content-Type: application/json
{
"contactId": 12345
}
DELETE /systeme/api/community/memberships/{id}
GET /systeme/api/payment/subscriptions
POST /systeme/api/payment/subscriptions/{id}/cancel
Systeme.io uses cursor-based pagination with the following parameters:
GET /systeme/api/contacts?limit=50&startingAfter=12345&order=asc
Parameters:
limit - Number of items per page (10-100)startingAfter - ID of the last item from the previous pageorder - Sort order: asc or desc (default: desc)Response:
{
"items": [...],
"hasMore": true
}
When hasMore is true, use the ID of the last item in items as startingAfter to get the next page.
const response = await fetch(
'https://api.maton.ai/systeme/api/contacts',
{
headers: {
'Authorization': `Bearer ${process.env.MATON_API_KEY}`
}
}
);
const data = await response.json();
import os
import requests
response = requests.get(
'https://api.maton.ai/systeme/api/contacts',
headers={'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}'}
)
data = response.json()
import os
import requests
# Create contact
contact = requests.post(
'https://api.maton.ai/systeme/api/contacts',
headers={
'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}',
'Content-Type': 'application/json'
},
json={
'email': 'new@example.com',
'firstName': 'New',
'lastName': 'Contact'
}
).json()
# Assign tag
requests.post(
f'https://api.maton.ai/systeme/api/contacts/{contact["id"]}/tags',
headers={
'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}',
'Content-Type': 'application/json'
},
json={'tagId': 12345}
)
X-API-Key header natively)application/merge-patch+json content type for PATCH requestsX-RateLimit-* headers/api/payment/subscriptions) may return 404 if payment features are not configuredcurl -g when URLs contain brackets to disable glob parsingjq or other commands, environment variables like $MATON_API_KEY may not expand correctly in some shell environments| Status | Meaning |
|---|---|
| -------- | --------- |
| 400 | Missing Systeme.io connection or bad request |
| 401 | Invalid or missing Maton API key |
| 429 | Rate limited (check Retry-After header) |
| 4xx/5xx | Passthrough error from Systeme.io API |
MATON_API_KEY environment variable is set:echo $MATON_API_KEY
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/connections')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
systeme. For example:https://api.maton.ai/systeme/api/contactshttps://api.maton.ai/api/contacts共 2 个版本