
What you need
- Email Center active on your account. Turn it on in the portal, on the Transactional email page. Without it, the API responds with
403, the codeforbiddenand the reasonemail_account_requiredindetails.reason. - A key with the
email_center:writepermission to send and make changes, andemail_center:readto look things up. See Permissions. Theemail:readandemail:writepermissions are different: they are for the mailboxes of a hosting service. - A verified sender domain. You can only send from addresses of that domain or of a subdomain.
The sender domain
Add the domain with POST /v1/email/domains:
curl
curl -X POST "https://api.interweb.co.mz/v1/email/domains" \
-H "Authorization: Bearer $RLX_API_KEY" \
-H "Accept-Language: en" \
-H "Idempotency-Key: 9f1c2d3e-example" \
-H "Content-Type: application/json" \
-d '{"domain": "example.com"}'PHP
<?php
$ch = curl_init('https://api.interweb.co.mz/v1/email/domains');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_POSTFIELDS => '{"domain": "example.com"}',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('RLX_API_KEY'),
'Accept-Language: en',
'Idempotency-Key: 9f1c2d3e-example',
'Content-Type: application/json',
],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo $status, PHP_EOL, $body, PHP_EOL;Python
import os
import requests
headers = {
"Authorization": "Bearer " + os.environ["RLX_API_KEY"],
"Accept-Language": "en",
"Idempotency-Key": "9f1c2d3e-example",
}
payload = {"domain": "example.com"}
r = requests.post("https://api.interweb.co.mz/v1/email/domains", headers=headers, json=payload, timeout=30)
print(r.status_code)
print(r.text)JavaScript
const response = await fetch("https://api.interweb.co.mz/v1/email/domains", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.RLX_API_KEY}`,
"Accept-Language": "en",
"Idempotency-Key": "9f1c2d3e-example",
"Content-Type": "application/json",
},
body: JSON.stringify({"domain": "example.com"}),
});
console.log(response.status);
console.log(await response.text());The response has, in dns_records, the records to add to the DNS of the domain:
- three DKIM
CNAMErecords, which sign your emails (required); - an SPF
TXTrecord, which authorises our sending (recommended); - a DMARC
TXTrecord, the policy of the domain (recommended).
Once they are in place, call POST /v1/email/domains/{domain}/verify. DNS can take a few hours to spread. When the DKIM records are live, the domain becomes verified. The found field of each record says whether it has been found yet.
If you want the return path to use your domain too, set a subdomain with PUT /v1/email/domains/{domain}/mail-from, for example bounce. An extra MX and TXT record then appear for you to add.
Sending
Use POST /v1/email/messages with the sender, the recipients, the subject and the content in html, in text or in both:
curl
curl -X POST "https://api.interweb.co.mz/v1/email/messages" \
-H "Authorization: Bearer $RLX_API_KEY" \
-H "Accept-Language: en" \
-H "Idempotency-Key: 9f1c2d3e-example" \
-H "Content-Type: application/json" \
-d '{"from": "Example Ltd <[email protected]>", "to": ["[email protected]"], "reply_to": "[email protected]", "template_id": 7, "variables": {"name": "Ana", "order": "1234"}}'PHP
<?php
$ch = curl_init('https://api.interweb.co.mz/v1/email/messages');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_POSTFIELDS => '{"from": "Example Ltd <[email protected]>", "to": ["[email protected]"], "reply_to": "[email protected]", "template_id": 7, "variables": {"name": "Ana", "order": "1234"}}',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('RLX_API_KEY'),
'Accept-Language: en',
'Idempotency-Key: 9f1c2d3e-example',
'Content-Type: application/json',
],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo $status, PHP_EOL, $body, PHP_EOL;Python
import os
import requests
headers = {
"Authorization": "Bearer " + os.environ["RLX_API_KEY"],
"Accept-Language": "en",
"Idempotency-Key": "9f1c2d3e-example",
}
payload = {"from": "Example Ltd <[email protected]>", "to": ["[email protected]"], "reply_to": "[email protected]", "template_id": 7, "variables": {"name": "Ana", "order": "1234"}}
r = requests.post("https://api.interweb.co.mz/v1/email/messages", headers=headers, json=payload, timeout=30)
print(r.status_code)
print(r.text)JavaScript
const response = await fetch("https://api.interweb.co.mz/v1/email/messages", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.RLX_API_KEY}`,
"Accept-Language": "en",
"Idempotency-Key": "9f1c2d3e-example",
"Content-Type": "application/json",
},
body: JSON.stringify({"from": "Example Ltd <[email protected]>", "to": ["[email protected]"], "reply_to": "[email protected]", "template_id": 7, "variables": {"name": "Ana", "order": "1234"}}),
});
console.log(response.status);
console.log(await response.text());to,ccandbcctake one address, a comma-separated list or an array. At most 50 recipients per email.- Each recipient counts as one email and uses one credit.
- Without
send_at, the email goes out right away and the response has its real status. - Attachments go in
attachments, in base64, up to 5 MB in total. Executable files are refused.
Send the Idempotency-Key header so a retry never sends twice. See Retries.
Templates and variables
Create templates with POST /v1/email/templates, with the subject and the HTML or the text. Write variables as {{name}}.
When sending, give the template_id and the values in variables. The subject, html and text you leave out come from the template. In the HTML, values are escaped, so a name with < or & shows as text.
Scheduled and batch sending
To send the email later, add send_at in ISO 8601 with the time zone, for example 2026-11-20T09:30:00+02:00, up to 30 days ahead. Credits are only taken when the email goes out. To change your mind, use POST /v1/email/messages/{id}/cancel before that time.
For many emails at once, use POST /v1/email/messages/batch. There is no limit on the number of messages, only on the request size (8 MB). Fields outside messages apply to all of them, and each message has its own to and variables. results says what happened to each one.
Statuses and events
GET /v1/email/messages/{id} shows the status and the events of each recipient:
sent: it went out to the receiving servers;delivered: the recipient's server accepted it;bounced: it bounced. If the bounce is permanent, the address joins the suppression list;complained: the recipient marked it as spam, and the address joins the suppression list;failed: it did not go out, and the credits go back to the balance.
The content of emails is kept for 30 days. After that, html and text are null and only the log remains.
Suppressions
Addresses on the suppression list never receive your emails: they are removed before sending, are not charged, and are listed in suppressed in the response. If no recipient is left, the API responds with 422 and the reason all_recipients_suppressed.
See the list with GET /v1/email/suppressions, add addresses with POST /v1/email/suppressions and remove them with DELETE /v1/email/suppressions/{email}, with the address URL-encoded in the path (ana%40example.org).
Webhook notifications
Save an HTTPS address with PUT /v1/email/webhook and choose the events: email.sent, email.delivered, email.bounced, email.complained and email.failed. This webhook is different from the SMS webhook.
Each notification is signed in the same way as the SMS ones, in the X-Webhook-Signature header. See the SMS webhook to check the signature.
Sandbox and Production
- With a
sandbox_key, nothing is sent or charged. The email issimulated, with the simulated events. Other changes (domains, templates, suppressions) are only simulated. - To try bounces and complaints, send to
[email protected]or[email protected]. - While Email Center is in test mode,
prod_keys also simulate:GET /v1/email/balancetells you so intest_mode.
SMTP Relay
In the portal, on the SMTP page, you create usernames and passwords to send from your own program or server, on ports 587 (STARTTLS) and 465 (TLS). The password is shown only once. The SMTP server is still being set up: until then, use the API.
Email marketing
Besides transactional email, Email Center sends campaigns to your contacts: the SMS contacts that have an email address and the email-only contacts. Each recipient uses one credit, like any other email.
- Add contacts with
POST /v1/email/contacts, with their groups ingroups. The groups are the same as for SMS contacts: see them atGET /v1/email/groups. - Create the campaign with
POST /v1/email/campaigns, with the blocks inblocks(header,text,image,button,dividerandfooter) or with a ready template intemplate. If you like, ask the AI for a proposal first withPOST /v1/email/campaigns/generate. - Choose the audience in
target: groups, who opened or clicked before, and the date they joined. - Check the result of
GET /v1/email/campaigns/{id}/spam-checkand send a test withPOST /v1/email/campaigns/{id}/test. - Send it now with
POST /v1/email/campaigns/{id}/sendor schedule it withPOST /v1/email/campaigns/{id}/schedule.
curl
curl -X POST "https://api.interweb.co.mz/v1/email/campaigns" \
-H "Authorization: Bearer $RLX_API_KEY" \
-H "Accept-Language: en" \
-H "Idempotency-Key: 9f1c2d3e-example" \
-H "Content-Type: application/json" \
-d '{"name": "November news", "template": "comercio", "from": "[email protected]", "from_name": "Example Ltd", "target": {"groups": [3]}}'PHP
<?php
$ch = curl_init('https://api.interweb.co.mz/v1/email/campaigns');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_POSTFIELDS => '{"name": "November news", "template": "comercio", "from": "[email protected]", "from_name": "Example Ltd", "target": {"groups": [3]}}',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('RLX_API_KEY'),
'Accept-Language: en',
'Idempotency-Key: 9f1c2d3e-example',
'Content-Type: application/json',
],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo $status, PHP_EOL, $body, PHP_EOL;Python
import os
import requests
headers = {
"Authorization": "Bearer " + os.environ["RLX_API_KEY"],
"Accept-Language": "en",
"Idempotency-Key": "9f1c2d3e-example",
}
payload = {"name": "November news", "template": "comercio", "from": "[email protected]", "from_name": "Example Ltd", "target": {"groups": [3]}}
r = requests.post("https://api.interweb.co.mz/v1/email/campaigns", headers=headers, json=payload, timeout=30)
print(r.status_code)
print(r.text)JavaScript
const response = await fetch("https://api.interweb.co.mz/v1/email/campaigns", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.RLX_API_KEY}`,
"Accept-Language": "en",
"Idempotency-Key": "9f1c2d3e-example",
"Content-Type": "application/json",
},
body: JSON.stringify({"name": "November news", "template": "comercio", "from": "[email protected]", "from_name": "Example Ltd", "target": {"groups": [3]}}),
});
console.log(response.status);
console.log(await response.text());In the texts you can use {{first_name}}, {{name}}, {{company}} and {{email}} of each contact.
Subscription and unsubscribing
Every campaign email ends with the address and an unsubscribe link, and carries the List-Unsubscribe header so email programs show their unsubscribe button. Whoever unsubscribes stops receiving your campaigns, and so do addresses on the suppression list. See and change the status with PUT /v1/email/contacts/{email}/subscription.
Statistics
GET /v1/email/campaigns/{id}/stats gives delivered emails, opens, clicks, unsubscribes and bounces. GET /v1/email/campaigns/{id}/recipients shows what each contact did. In test mode the numbers are examples and come with simulated set to true.
Operations
43 operations in this area. Click an operation to see its parameters, examples and responses, or to try it in the Playground, without leaving the page.
GETList emails
/v1/email/messages
https://api.interweb.co.mz/v1/email/messagesNeeds email_center:read. Newest first, without the content (see GET /v1/email/messages/{id}).
Authentication
Needs a valid key in the Authorization: Bearer header. Required permission: email_center:read.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
status | query | string | no | One of: queued, scheduled, sending, sent, delivered, bounced, complained, failed, simulated, cancelled. |
from | query | string | no | From this day, YYYY-MM-DD. |
to | query | string | no | Up to this day, YYYY-MM-DD. |
recipient | query | string | no | Only emails to this address (to, cc or bcc). |
page | query | integer | no | The page number. The first is 1. |
per_page | query | integer | no | Results per page, from 1 to 100. The default is 10. |
X-API-Mode | header | string: sandbox, production | no | Optional. If it does not match the mode of the key, the request is refused with invalid_request and reason mode_mismatch. Use it to make sure a program never runs with the wrong key. |
Examples
curl
curl "https://api.interweb.co.mz/v1/email/messages" \
-H "Authorization: Bearer $RLX_API_KEY" \
-H "Accept-Language: en"PHP
<?php
$ch = curl_init('https://api.interweb.co.mz/v1/email/messages');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('RLX_API_KEY'),
'Accept-Language: en',
],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo $status, PHP_EOL, $body, PHP_EOL;Python
import os
import requests
headers = {
"Authorization": "Bearer " + os.environ["RLX_API_KEY"],
"Accept-Language": "en",
}
r = requests.get("https://api.interweb.co.mz/v1/email/messages", headers=headers, timeout=30)
print(r.status_code)
print(r.text)JavaScript
const response = await fetch("https://api.interweb.co.mz/v1/email/messages", {
headers: {
Authorization: `Bearer ${process.env.RLX_API_KEY}`,
"Accept-Language": "en",
},
});
console.log(response.status);
console.log(await response.text());Responses
200
List emails.
{
"data": [
{
"id": "5120",
"status": "delivered",
"simulated": false,
"from": "[email protected]",
"to": [
"[email protected]"
],
"cc": [],
"bcc": [],
"reply_to": [
"[email protected]"
],
"subject": "Your order 1234 is ready",
"recipients": 1,
"credits": 1.0,
"charged": true,
"source": "api",
"template_id": 7,
"attachments": [],
"error": null,
"scheduled_for": null,
"created_at": "2026-11-12T10:30:00+02:00",
"sent_at": "2026-11-12T10:30:01+02:00",
"from_name": "Example Ltd"
}
],
"meta": {
"page": 1,
"per_page": 10,
"total": 1,
"total_pages": 1
}
}| Header | Description |
|---|---|
X-Correlation-ID | Identifier of this request. Give it to support when you report a problem. |
X-RateLimit-Limit | Requests allowed per minute. |
X-RateLimit-Remaining | Requests left in the current minute. |
X-RateLimit-Reset | When the minute ends, as a Unix timestamp in seconds. |
X-API-Mode | The mode of the key that made the request: sandbox or production. |
401
The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account.
{
"error": {
"code": "unauthorized",
"message": "Missing or invalid API key.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}403
The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope).
{
"error": {
"code": "forbidden",
"message": "This account does not have Email Center active. Turn it on in the portal.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"reason": "email_account_required"
}
}
}422
Some of the data is not valid.
{
"error": {
"code": "validation_failed",
"message": "Some of the data is not valid.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}429
Too many requests. Wait for the time in Retry-After.
{
"error": {
"code": "rate_limited",
"message": "Too many requests. Please try again shortly.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"retry_after": 42
}
}
}| Header | Description |
|---|---|
Retry-After | Seconds to wait before trying again. |
500
An internal error occurred. Give the correlation_id to support.
{
"error": {
"code": "internal_error",
"message": "An internal error occurred. Please give the correlation_id to support.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}503
The API is turned off.
{
"error": {
"code": "disabled",
"message": "The API is currently turned off.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}Errors
| Status | Code | Meaning |
|---|---|---|
| 401 | unauthorized | The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account. |
| 403 | forbidden, insufficient_scope | The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope). |
| 422 | validation_failed | Some of the data is not valid. |
| 429 | rate_limited | Too many requests. Wait for the time in Retry-After. |
| 500 | internal_error | An internal error occurred. Give the correlation_id to support. |
| 503 | disabled | The API is turned off. |
The error format is explained in Errors.
POSTSend an email
/v1/email/messages
https://api.interweb.co.mz/v1/email/messagesNeeds email_center:write. Each recipient (to, cc and bcc, up to 50) is one email and one credit. Addresses on the suppression list are removed and listed in suppressed; if none is left, the API answers 422 all_recipients_suppressed. Without send_at the email goes out straight away and the answer has the real status. With a sandbox key, or while Email Center is in test mode, nothing is sent or charged: the email is simulated and the simulated events are recorded ([email protected] simulates a bounce, [email protected] a complaint). Send Idempotency-Key so a retry never sends twice.
Authentication
Needs a valid key in the Authorization: Bearer header. Required permission: email_center:write.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
Idempotency-Key | header | string | no | Any unique value, up to 255 visible characters. Valid for 24 hours per key. Repeating the same request returns the saved answer; a different body, or a first request still in progress, returns 409. |
X-API-Mode | header | string: sandbox, production | no | Optional. If it does not match the mode of the key, the request is refused with invalid_request and reason mode_mismatch. Use it to make sure a program never runs with the wrong key. |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
from | string | yes | Sender at a verified domain (or a subdomain of it): [email protected] or Example Ltd <[email protected]>. |
from_name | string | no | Optional display name. |
to | any | yes | One address, a comma-separated list or an array. |
cc | any | no | |
bcc | any | no | |
reply_to | any | no | Up to 5 addresses. |
subject | string | no | Up to 998 characters. May use {{variables}}. |
html | string | no | HTML body. Values of {{variables}} are HTML-escaped. |
text | string | no | Plain text body. |
template_id | integer | no | A template of this account; empty subject, html and text come from it. |
variables | object | no | Values for {{name}} placeholders, as an object. |
attachments | array<object> | no | Base64 files; 5 MB in total by default, executables refused. |
send_at | string | no | Optional, ISO 8601 with time zone, up to 30 days ahead by default. |
Examples
curl
curl -X POST "https://api.interweb.co.mz/v1/email/messages" \
-H "Authorization: Bearer $RLX_API_KEY" \
-H "Accept-Language: en" \
-H "Idempotency-Key: 9f1c2d3e-example" \
-H "Content-Type: application/json" \
-d '{"from": "Example Ltd <[email protected]>", "to": ["[email protected]"], "reply_to": "[email protected]", "template_id": 7, "variables": {"name": "Ana", "order": "1234"}}'PHP
<?php
$ch = curl_init('https://api.interweb.co.mz/v1/email/messages');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_POSTFIELDS => '{"from": "Example Ltd <[email protected]>", "to": ["[email protected]"], "reply_to": "[email protected]", "template_id": 7, "variables": {"name": "Ana", "order": "1234"}}',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('RLX_API_KEY'),
'Accept-Language: en',
'Idempotency-Key: 9f1c2d3e-example',
'Content-Type: application/json',
],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo $status, PHP_EOL, $body, PHP_EOL;Python
import os
import requests
headers = {
"Authorization": "Bearer " + os.environ["RLX_API_KEY"],
"Accept-Language": "en",
"Idempotency-Key": "9f1c2d3e-example",
}
payload = {"from": "Example Ltd <[email protected]>", "to": ["[email protected]"], "reply_to": "[email protected]", "template_id": 7, "variables": {"name": "Ana", "order": "1234"}}
r = requests.post("https://api.interweb.co.mz/v1/email/messages", headers=headers, json=payload, timeout=30)
print(r.status_code)
print(r.text)JavaScript
const response = await fetch("https://api.interweb.co.mz/v1/email/messages", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.RLX_API_KEY}`,
"Accept-Language": "en",
"Idempotency-Key": "9f1c2d3e-example",
"Content-Type": "application/json",
},
body: JSON.stringify({"from": "Example Ltd <[email protected]>", "to": ["[email protected]"], "reply_to": "[email protected]", "template_id": 7, "variables": {"name": "Ana", "order": "1234"}}),
});
console.log(response.status);
console.log(await response.text());Responses
201
Send an email.
{
"data": {
"id": "5120",
"status": "sent",
"simulated": false,
"from": "[email protected]",
"to": [
"[email protected]"
],
"cc": [],
"bcc": [],
"reply_to": [
"[email protected]"
],
"subject": "Your order 1234 is ready",
"recipients": 1,
"credits": 1.0,
"charged": true,
"source": "api",
"template_id": 7,
"attachments": [],
"error": null,
"scheduled_for": null,
"created_at": "2026-11-12T10:30:00+02:00",
"sent_at": "2026-11-12T10:30:01+02:00",
"from_name": "Example Ltd",
"suppressed": []
},
"meta": {}
}| Field | Type | Description |
|---|---|---|
data.recipients | integer | Recipients after the suppression list; each one is one credit. |
data.source | string | portal, api or smtp. |
| Header | Description |
|---|---|
X-Correlation-ID | Identifier of this request. Give it to support when you report a problem. |
X-RateLimit-Limit | Requests allowed per minute. |
X-RateLimit-Remaining | Requests left in the current minute. |
X-RateLimit-Reset | When the minute ends, as a Unix timestamp in seconds. |
X-API-Mode | The mode of the key that made the request: sandbox or production. |
400
The request is not valid, for example the body is not JSON or the connection is not HTTPS.
{
"error": {
"code": "invalid_request",
"message": "The request is not valid.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}401
The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account.
{
"error": {
"code": "unauthorized",
"message": "Missing or invalid API key.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}403
The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope).
{
"error": {
"code": "forbidden",
"message": "This account does not have Email Center active. Turn it on in the portal.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"reason": "email_account_required"
}
}
}409
The operation cannot be done in the current state. See details.reason.
{
"error": {
"code": "conflict",
"message": "This operation only works on an active domain.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"reason": "domain_not_active"
}
}
}422
Some of the data is not valid.
{
"error": {
"code": "validation_failed",
"message": "Some of the data is not valid.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}429
Too many requests. Wait for the time in Retry-After.
{
"error": {
"code": "rate_limited",
"message": "Too many requests. Please try again shortly.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"retry_after": 42
}
}
}| Header | Description |
|---|---|
Retry-After | Seconds to wait before trying again. |
500
An internal error occurred. Give the correlation_id to support.
{
"error": {
"code": "internal_error",
"message": "An internal error occurred. Please give the correlation_id to support.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}503
The API is turned off.
{
"error": {
"code": "disabled",
"message": "The API is currently turned off.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}Errors
| Status | Code | Meaning |
|---|---|---|
| 400 | invalid_request | The request is not valid, for example the body is not JSON or the connection is not HTTPS. |
| 401 | unauthorized | The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account. |
| 403 | forbidden, insufficient_scope | The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope). |
| 409 | conflict | The operation cannot be done in the current state. See details.reason. |
| 422 | validation_failed | Some of the data is not valid. |
| 429 | rate_limited | Too many requests. Wait for the time in Retry-After. |
| 500 | internal_error | An internal error occurred. Give the correlation_id to support. |
| 503 | disabled | The API is turned off. |
The error format is explained in Errors.
POSTSend emails in a batch
/v1/email/messages/batch
https://api.interweb.co.mz/v1/email/messages/batchNeeds email_center:write. No limit on the number of messages, only on the request size (8 MB). Fields outside messages (from, subject, html, text, template_id, reply_to, send_at) apply to all; each message can change them and has its own to and variables. Each one follows the rules of POST /v1/email/messages and results says what happened to it (error uses the same reasons). Up to 20 go out straight away; the rest join the queue (every minute). Without credits or at the daily limit, the rest are rejected.
Authentication
Needs a valid key in the Authorization: Bearer header. Required permission: email_center:write.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
Idempotency-Key | header | string | no | Any unique value, up to 255 visible characters. Valid for 24 hours per key. Repeating the same request returns the saved answer; a different body, or a first request still in progress, returns 409. |
X-API-Mode | header | string: sandbox, production | no | Optional. If it does not match the mode of the key, the request is refused with invalid_request and reason mode_mismatch. Use it to make sure a program never runs with the wrong key. |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
from | string | no | Sender at a verified domain (or a subdomain of it): [email protected] or Example Ltd <[email protected]>. |
from_name | string | no | Optional display name. |
to | any | no | One address, a comma-separated list or an array. |
cc | any | no | |
bcc | any | no | |
reply_to | any | no | Up to 5 addresses. |
subject | string | no | Up to 998 characters. May use {{variables}}. |
html | string | no | HTML body. Values of {{variables}} are HTML-escaped. |
text | string | no | Plain text body. |
template_id | integer | no | A template of this account; empty subject, html and text come from it. |
variables | object | no | Values for {{name}} placeholders, as an object. |
attachments | array<object> | no | Base64 files; 5 MB in total by default, executables refused. |
send_at | string | no | Optional, ISO 8601 with time zone, up to 30 days ahead by default. |
messages | array<object> | yes |
Examples
curl
curl -X POST "https://api.interweb.co.mz/v1/email/messages/batch" \
-H "Authorization: Bearer $RLX_API_KEY" \
-H "Accept-Language: en" \
-H "Idempotency-Key: 9f1c2d3e-example" \
-H "Content-Type: application/json" \
-d '{"from": "Example Ltd <[email protected]>", "subject": "Hello {{name}}", "text": "Hi {{name}}, your invoice is ready.", "messages": [{"to": "[email protected]", "variables": {"name": "Ana"}}, {"to": "[email protected]", "variables": {"name": "Rui"}}, {"to": "not-an-email"}]}'PHP
<?php
$ch = curl_init('https://api.interweb.co.mz/v1/email/messages/batch');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_POSTFIELDS => '{"from": "Example Ltd <[email protected]>", "subject": "Hello {{name}}", "text": "Hi {{name}}, your invoice is ready.", "messages": [{"to": "[email protected]", "variables": {"name": "Ana"}}, {"to": "[email protected]", "variables": {"name": "Rui"}}, {"to": "not-an-email"}]}',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('RLX_API_KEY'),
'Accept-Language: en',
'Idempotency-Key: 9f1c2d3e-example',
'Content-Type: application/json',
],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo $status, PHP_EOL, $body, PHP_EOL;Python
import os
import requests
headers = {
"Authorization": "Bearer " + os.environ["RLX_API_KEY"],
"Accept-Language": "en",
"Idempotency-Key": "9f1c2d3e-example",
}
payload = {"from": "Example Ltd <[email protected]>", "subject": "Hello {{name}}", "text": "Hi {{name}}, your invoice is ready.", "messages": [{"to": "[email protected]", "variables": {"name": "Ana"}}, {"to": "[email protected]", "variables": {"name": "Rui"}}, {"to": "not-an-email"}]}
r = requests.post("https://api.interweb.co.mz/v1/email/messages/batch", headers=headers, json=payload, timeout=30)
print(r.status_code)
print(r.text)JavaScript
const response = await fetch("https://api.interweb.co.mz/v1/email/messages/batch", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.RLX_API_KEY}`,
"Accept-Language": "en",
"Idempotency-Key": "9f1c2d3e-example",
"Content-Type": "application/json",
},
body: JSON.stringify({"from": "Example Ltd <[email protected]>", "subject": "Hello {{name}}", "text": "Hi {{name}}, your invoice is ready.", "messages": [{"to": "[email protected]", "variables": {"name": "Ana"}}, {"to": "[email protected]", "variables": {"name": "Rui"}}, {"to": "not-an-email"}]}),
});
console.log(response.status);
console.log(await response.text());Responses
201
Send emails in a batch.
{
"data": {
"total": 3,
"accepted": 2,
"rejected": 1,
"credits": 2.0,
"simulated": false,
"results": [
{
"index": 0,
"id": "5121",
"status": "sent",
"recipients": 1,
"suppressed": []
},
{
"index": 1,
"id": "5122",
"status": "sent",
"recipients": 1,
"suppressed": []
},
{
"index": 2,
"id": null,
"status": "rejected",
"error": "invalid_recipient",
"field": "to"
}
]
},
"meta": {}
}| Header | Description |
|---|---|
X-Correlation-ID | Identifier of this request. Give it to support when you report a problem. |
X-RateLimit-Limit | Requests allowed per minute. |
X-RateLimit-Remaining | Requests left in the current minute. |
X-RateLimit-Reset | When the minute ends, as a Unix timestamp in seconds. |
X-API-Mode | The mode of the key that made the request: sandbox or production. |
400
The request is not valid, for example the body is not JSON or the connection is not HTTPS.
{
"error": {
"code": "invalid_request",
"message": "The request is not valid.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}401
The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account.
{
"error": {
"code": "unauthorized",
"message": "Missing or invalid API key.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}403
The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope).
{
"error": {
"code": "forbidden",
"message": "This account does not have Email Center active. Turn it on in the portal.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"reason": "email_account_required"
}
}
}422
Some of the data is not valid.
{
"error": {
"code": "validation_failed",
"message": "Some of the data is not valid.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}429
Too many requests. Wait for the time in Retry-After.
{
"error": {
"code": "rate_limited",
"message": "Too many requests. Please try again shortly.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"retry_after": 42
}
}
}| Header | Description |
|---|---|
Retry-After | Seconds to wait before trying again. |
500
An internal error occurred. Give the correlation_id to support.
{
"error": {
"code": "internal_error",
"message": "An internal error occurred. Please give the correlation_id to support.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}503
The API is turned off.
{
"error": {
"code": "disabled",
"message": "The API is currently turned off.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}Errors
| Status | Code | Meaning |
|---|---|---|
| 400 | invalid_request | The request is not valid, for example the body is not JSON or the connection is not HTTPS. |
| 401 | unauthorized | The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account. |
| 403 | forbidden, insufficient_scope | The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope). |
| 422 | validation_failed | Some of the data is not valid. |
| 429 | rate_limited | Too many requests. Wait for the time in Retry-After. |
| 500 | internal_error | An internal error occurred. Give the correlation_id to support. |
| 503 | disabled | The API is turned off. |
The error format is explained in Errors.
GETSee an email
/v1/email/messages/{id}
https://api.interweb.co.mz/v1/email/messages/{id}Needs email_center:read. With the events of each recipient and the content (kept for 30 days by default; then html and text are null).
Authentication
Needs a valid key in the Authorization: Bearer header. Required permission: email_center:read.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | yes | The id returned when the email was sent. |
X-API-Mode | header | string: sandbox, production | no | Optional. If it does not match the mode of the key, the request is refused with invalid_request and reason mode_mismatch. Use it to make sure a program never runs with the wrong key. |
Examples
curl
curl "https://api.interweb.co.mz/v1/email/messages/00000000-0000-4000-8000-000000000000" \
-H "Authorization: Bearer $RLX_API_KEY" \
-H "Accept-Language: en"PHP
<?php
$ch = curl_init('https://api.interweb.co.mz/v1/email/messages/00000000-0000-4000-8000-000000000000');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('RLX_API_KEY'),
'Accept-Language: en',
],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo $status, PHP_EOL, $body, PHP_EOL;Python
import os
import requests
headers = {
"Authorization": "Bearer " + os.environ["RLX_API_KEY"],
"Accept-Language": "en",
}
r = requests.get("https://api.interweb.co.mz/v1/email/messages/00000000-0000-4000-8000-000000000000", headers=headers, timeout=30)
print(r.status_code)
print(r.text)JavaScript
const response = await fetch("https://api.interweb.co.mz/v1/email/messages/00000000-0000-4000-8000-000000000000", {
headers: {
Authorization: `Bearer ${process.env.RLX_API_KEY}`,
"Accept-Language": "en",
},
});
console.log(response.status);
console.log(await response.text());Responses
200
See an email.
{
"data": {
"id": "5120",
"status": "delivered",
"simulated": false,
"from": "[email protected]",
"to": [
"[email protected]"
],
"cc": [],
"bcc": [],
"reply_to": [
"[email protected]"
],
"subject": "Your order 1234 is ready",
"recipients": 1,
"credits": 1.0,
"charged": true,
"source": "api",
"template_id": 7,
"attachments": [],
"error": null,
"scheduled_for": null,
"created_at": "2026-11-12T10:30:00+02:00",
"sent_at": "2026-11-12T10:30:01+02:00",
"from_name": "Example Ltd",
"html": "<p>Hello Ana, your order 1234 is ready.</p>",
"text": "Hello Ana, your order 1234 is ready.",
"events": [
{
"type": "sent",
"recipient": null,
"detail": null,
"simulated": false,
"created_at": "2026-11-12T10:30:01+02:00"
},
{
"type": "delivered",
"recipient": "[email protected]",
"detail": null,
"simulated": false,
"created_at": "2026-11-12T10:30:03+02:00"
}
]
},
"meta": {}
}| Field | Type | Description |
|---|---|---|
data.recipients | integer | Recipients after the suppression list; each one is one credit. |
data.source | string | portal, api or smtp. |
| Header | Description |
|---|---|
X-Correlation-ID | Identifier of this request. Give it to support when you report a problem. |
X-RateLimit-Limit | Requests allowed per minute. |
X-RateLimit-Remaining | Requests left in the current minute. |
X-RateLimit-Reset | When the minute ends, as a Unix timestamp in seconds. |
X-API-Mode | The mode of the key that made the request: sandbox or production. |
401
The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account.
{
"error": {
"code": "unauthorized",
"message": "Missing or invalid API key.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}403
The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope).
{
"error": {
"code": "forbidden",
"message": "This account does not have Email Center active. Turn it on in the portal.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"reason": "email_account_required"
}
}
}404
Not found.
{
"error": {
"code": "not_found",
"message": "Not found.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}429
Too many requests. Wait for the time in Retry-After.
{
"error": {
"code": "rate_limited",
"message": "Too many requests. Please try again shortly.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"retry_after": 42
}
}
}| Header | Description |
|---|---|
Retry-After | Seconds to wait before trying again. |
500
An internal error occurred. Give the correlation_id to support.
{
"error": {
"code": "internal_error",
"message": "An internal error occurred. Please give the correlation_id to support.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}503
The API is turned off.
{
"error": {
"code": "disabled",
"message": "The API is currently turned off.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}Errors
| Status | Code | Meaning |
|---|---|---|
| 401 | unauthorized | The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account. |
| 403 | forbidden, insufficient_scope | The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope). |
| 404 | not_found | Not found. |
| 429 | rate_limited | Too many requests. Wait for the time in Retry-After. |
| 500 | internal_error | An internal error occurred. Give the correlation_id to support. |
| 503 | disabled | The API is turned off. |
The error format is explained in Errors.
POSTCancel a scheduled email
/v1/email/messages/{id}/cancel
https://api.interweb.co.mz/v1/email/messages/{id}/cancelNeeds email_center:write. Only scheduled emails that have not gone out yet; credits already taken go back (credits_returned). Otherwise 409 not_cancellable.
Authentication
Needs a valid key in the Authorization: Bearer header. Required permission: email_center:write.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | yes | The id returned when the email was sent. |
Idempotency-Key | header | string | no | Any unique value, up to 255 visible characters. Valid for 24 hours per key. Repeating the same request returns the saved answer; a different body, or a first request still in progress, returns 409. |
X-API-Mode | header | string: sandbox, production | no | Optional. If it does not match the mode of the key, the request is refused with invalid_request and reason mode_mismatch. Use it to make sure a program never runs with the wrong key. |
Examples
curl
curl -X POST "https://api.interweb.co.mz/v1/email/messages/00000000-0000-4000-8000-000000000000/cancel" \
-H "Authorization: Bearer $RLX_API_KEY" \
-H "Accept-Language: en" \
-H "Idempotency-Key: 9f1c2d3e-example"PHP
<?php
$ch = curl_init('https://api.interweb.co.mz/v1/email/messages/00000000-0000-4000-8000-000000000000/cancel');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('RLX_API_KEY'),
'Accept-Language: en',
'Idempotency-Key: 9f1c2d3e-example',
],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo $status, PHP_EOL, $body, PHP_EOL;Python
import os
import requests
headers = {
"Authorization": "Bearer " + os.environ["RLX_API_KEY"],
"Accept-Language": "en",
"Idempotency-Key": "9f1c2d3e-example",
}
r = requests.post("https://api.interweb.co.mz/v1/email/messages/00000000-0000-4000-8000-000000000000/cancel", headers=headers, timeout=30)
print(r.status_code)
print(r.text)JavaScript
const response = await fetch("https://api.interweb.co.mz/v1/email/messages/00000000-0000-4000-8000-000000000000/cancel", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.RLX_API_KEY}`,
"Accept-Language": "en",
"Idempotency-Key": "9f1c2d3e-example",
},
});
console.log(response.status);
console.log(await response.text());Responses
200
Cancel a scheduled email.
{
"data": {
"id": "5120",
"status": "cancelled",
"simulated": false,
"from": "[email protected]",
"to": [
"[email protected]"
],
"cc": [],
"bcc": [],
"reply_to": [
"[email protected]"
],
"subject": "Your order 1234 is ready",
"recipients": 1,
"credits": 1.0,
"charged": true,
"source": "api",
"template_id": 7,
"attachments": [],
"error": null,
"scheduled_for": "2026-11-20T09:30:00+02:00",
"created_at": "2026-11-12T10:30:00+02:00",
"sent_at": null,
"from_name": "Example Ltd",
"credits_returned": 0.0
},
"meta": {}
}| Field | Type | Description |
|---|---|---|
data.recipients | integer | Recipients after the suppression list; each one is one credit. |
data.source | string | portal, api or smtp. |
| Header | Description |
|---|---|
X-Correlation-ID | Identifier of this request. Give it to support when you report a problem. |
X-RateLimit-Limit | Requests allowed per minute. |
X-RateLimit-Remaining | Requests left in the current minute. |
X-RateLimit-Reset | When the minute ends, as a Unix timestamp in seconds. |
X-API-Mode | The mode of the key that made the request: sandbox or production. |
401
The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account.
{
"error": {
"code": "unauthorized",
"message": "Missing or invalid API key.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}403
The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope).
{
"error": {
"code": "forbidden",
"message": "This account does not have Email Center active. Turn it on in the portal.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"reason": "email_account_required"
}
}
}404
Not found.
{
"error": {
"code": "not_found",
"message": "Not found.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}409
The operation cannot be done in the current state. See details.reason.
{
"error": {
"code": "conflict",
"message": "This operation only works on an active domain.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"reason": "domain_not_active"
}
}
}429
Too many requests. Wait for the time in Retry-After.
{
"error": {
"code": "rate_limited",
"message": "Too many requests. Please try again shortly.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"retry_after": 42
}
}
}| Header | Description |
|---|---|
Retry-After | Seconds to wait before trying again. |
500
An internal error occurred. Give the correlation_id to support.
{
"error": {
"code": "internal_error",
"message": "An internal error occurred. Please give the correlation_id to support.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}503
The API is turned off.
{
"error": {
"code": "disabled",
"message": "The API is currently turned off.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}Errors
| Status | Code | Meaning |
|---|---|---|
| 401 | unauthorized | The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account. |
| 403 | forbidden, insufficient_scope | The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope). |
| 404 | not_found | Not found. |
| 409 | conflict | The operation cannot be done in the current state. See details.reason. |
| 429 | rate_limited | Too many requests. Wait for the time in Retry-After. |
| 500 | internal_error | An internal error occurred. Give the correlation_id to support. |
| 503 | disabled | The API is turned off. |
The error format is explained in Errors.
GETSee the email balance
/v1/email/balance
https://api.interweb.co.mz/v1/email/balanceNeeds email_center:read. One credit is one email to one recipient. test_mode is true while Email Center does not send for real.
Authentication
Needs a valid key in the Authorization: Bearer header. Required permission: email_center:read.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-API-Mode | header | string: sandbox, production | no | Optional. If it does not match the mode of the key, the request is refused with invalid_request and reason mode_mismatch. Use it to make sure a program never runs with the wrong key. |
Examples
curl
curl "https://api.interweb.co.mz/v1/email/balance" \
-H "Authorization: Bearer $RLX_API_KEY" \
-H "Accept-Language: en"PHP
<?php
$ch = curl_init('https://api.interweb.co.mz/v1/email/balance');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('RLX_API_KEY'),
'Accept-Language: en',
],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo $status, PHP_EOL, $body, PHP_EOL;Python
import os
import requests
headers = {
"Authorization": "Bearer " + os.environ["RLX_API_KEY"],
"Accept-Language": "en",
}
r = requests.get("https://api.interweb.co.mz/v1/email/balance", headers=headers, timeout=30)
print(r.status_code)
print(r.text)JavaScript
const response = await fetch("https://api.interweb.co.mz/v1/email/balance", {
headers: {
Authorization: `Bearer ${process.env.RLX_API_KEY}`,
"Accept-Language": "en",
},
});
console.log(response.status);
console.log(await response.text());Responses
200
See the email balance.
{
"data": {
"balance": 9850.0,
"unit": "emails",
"scheduled_credits": 0.0,
"daily_limit": 500,
"sent_today": 42,
"mode": "production",
"test_mode": false
},
"meta": {}
}| Header | Description |
|---|---|
X-Correlation-ID | Identifier of this request. Give it to support when you report a problem. |
X-RateLimit-Limit | Requests allowed per minute. |
X-RateLimit-Remaining | Requests left in the current minute. |
X-RateLimit-Reset | When the minute ends, as a Unix timestamp in seconds. |
X-API-Mode | The mode of the key that made the request: sandbox or production. |
401
The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account.
{
"error": {
"code": "unauthorized",
"message": "Missing or invalid API key.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}403
The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope).
{
"error": {
"code": "forbidden",
"message": "This account does not have Email Center active. Turn it on in the portal.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"reason": "email_account_required"
}
}
}429
Too many requests. Wait for the time in Retry-After.
{
"error": {
"code": "rate_limited",
"message": "Too many requests. Please try again shortly.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"retry_after": 42
}
}
}| Header | Description |
|---|---|
Retry-After | Seconds to wait before trying again. |
500
An internal error occurred. Give the correlation_id to support.
{
"error": {
"code": "internal_error",
"message": "An internal error occurred. Please give the correlation_id to support.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}503
The API is turned off.
{
"error": {
"code": "disabled",
"message": "The API is currently turned off.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}Errors
| Status | Code | Meaning |
|---|---|---|
| 401 | unauthorized | The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account. |
| 403 | forbidden, insufficient_scope | The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope). |
| 429 | rate_limited | Too many requests. Wait for the time in Retry-After. |
| 500 | internal_error | An internal error occurred. Give the correlation_id to support. |
| 503 | disabled | The API is turned off. |
The error format is explained in Errors.
GETSee email statistics
/v1/email/stats
https://api.interweb.co.mz/v1/email/statsNeeds email_center:read. By status and by day. Delivered, bounced and complained count recipients; the rates are over the recipients. Default: the last 30 days; at most 366.
Authentication
Needs a valid key in the Authorization: Bearer header. Required permission: email_center:read.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
from | query | string | no | YYYY-MM-DD. |
to | query | string | no | YYYY-MM-DD. |
X-API-Mode | header | string: sandbox, production | no | Optional. If it does not match the mode of the key, the request is refused with invalid_request and reason mode_mismatch. Use it to make sure a program never runs with the wrong key. |
Examples
curl
curl "https://api.interweb.co.mz/v1/email/stats" \
-H "Authorization: Bearer $RLX_API_KEY" \
-H "Accept-Language: en"PHP
<?php
$ch = curl_init('https://api.interweb.co.mz/v1/email/stats');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('RLX_API_KEY'),
'Accept-Language: en',
],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo $status, PHP_EOL, $body, PHP_EOL;Python
import os
import requests
headers = {
"Authorization": "Bearer " + os.environ["RLX_API_KEY"],
"Accept-Language": "en",
}
r = requests.get("https://api.interweb.co.mz/v1/email/stats", headers=headers, timeout=30)
print(r.status_code)
print(r.text)JavaScript
const response = await fetch("https://api.interweb.co.mz/v1/email/stats", {
headers: {
Authorization: `Bearer ${process.env.RLX_API_KEY}`,
"Accept-Language": "en",
},
});
console.log(response.status);
console.log(await response.text());Responses
200
See email statistics.
{
"data": {
"from": "2026-10-14",
"to": "2026-11-12",
"messages": 320,
"recipients": 340,
"credits_spent": 338.0,
"by_status": {
"delivered": 300,
"bounced": 4,
"complained": 0,
"sent": 14,
"failed": 2
},
"events": {
"delivered": 330,
"bounced": 4,
"complained": 0
},
"delivery_rate": 97.06,
"bounce_rate": 1.18,
"complaint_rate": 0.0,
"by_day": [
{
"date": "2026-11-12",
"messages": 12,
"recipients": 12,
"delivered": 12,
"bounced": 0,
"complained": 0,
"credits": 12.0
}
]
},
"meta": {}
}| Header | Description |
|---|---|
X-Correlation-ID | Identifier of this request. Give it to support when you report a problem. |
X-RateLimit-Limit | Requests allowed per minute. |
X-RateLimit-Remaining | Requests left in the current minute. |
X-RateLimit-Reset | When the minute ends, as a Unix timestamp in seconds. |
X-API-Mode | The mode of the key that made the request: sandbox or production. |
401
The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account.
{
"error": {
"code": "unauthorized",
"message": "Missing or invalid API key.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}403
The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope).
{
"error": {
"code": "forbidden",
"message": "This account does not have Email Center active. Turn it on in the portal.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"reason": "email_account_required"
}
}
}422
Some of the data is not valid.
{
"error": {
"code": "validation_failed",
"message": "Some of the data is not valid.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}429
Too many requests. Wait for the time in Retry-After.
{
"error": {
"code": "rate_limited",
"message": "Too many requests. Please try again shortly.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"retry_after": 42
}
}
}| Header | Description |
|---|---|
Retry-After | Seconds to wait before trying again. |
500
An internal error occurred. Give the correlation_id to support.
{
"error": {
"code": "internal_error",
"message": "An internal error occurred. Please give the correlation_id to support.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}503
The API is turned off.
{
"error": {
"code": "disabled",
"message": "The API is currently turned off.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}Errors
| Status | Code | Meaning |
|---|---|---|
| 401 | unauthorized | The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account. |
| 403 | forbidden, insufficient_scope | The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope). |
| 422 | validation_failed | Some of the data is not valid. |
| 429 | rate_limited | Too many requests. Wait for the time in Retry-After. |
| 500 | internal_error | An internal error occurred. Give the correlation_id to support. |
| 503 | disabled | The API is turned off. |
The error format is explained in Errors.
GETList sender domains
/v1/email/domains
https://api.interweb.co.mz/v1/email/domainsNeeds email_center:read. In alphabetical order.
Authentication
Needs a valid key in the Authorization: Bearer header. Required permission: email_center:read.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
page | query | integer | no | The page number. The first is 1. |
per_page | query | integer | no | Results per page, from 1 to 100. The default is 10. |
X-API-Mode | header | string: sandbox, production | no | Optional. If it does not match the mode of the key, the request is refused with invalid_request and reason mode_mismatch. Use it to make sure a program never runs with the wrong key. |
Examples
curl
curl "https://api.interweb.co.mz/v1/email/domains" \
-H "Authorization: Bearer $RLX_API_KEY" \
-H "Accept-Language: en"PHP
<?php
$ch = curl_init('https://api.interweb.co.mz/v1/email/domains');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('RLX_API_KEY'),
'Accept-Language: en',
],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo $status, PHP_EOL, $body, PHP_EOL;Python
import os
import requests
headers = {
"Authorization": "Bearer " + os.environ["RLX_API_KEY"],
"Accept-Language": "en",
}
r = requests.get("https://api.interweb.co.mz/v1/email/domains", headers=headers, timeout=30)
print(r.status_code)
print(r.text)JavaScript
const response = await fetch("https://api.interweb.co.mz/v1/email/domains", {
headers: {
Authorization: `Bearer ${process.env.RLX_API_KEY}`,
"Accept-Language": "en",
},
});
console.log(response.status);
console.log(await response.text());Responses
200
List sender domains.
{
"data": [
{
"id": 12,
"domain": "example.com",
"status": "verified",
"mail_from": null,
"verified_at": "2026-11-12T10:00:00+02:00",
"last_checked_at": "2026-11-12T10:00:00+02:00",
"created_at": "2026-11-12T09:40:00+02:00"
}
],
"meta": {
"page": 1,
"per_page": 10,
"total": 1,
"total_pages": 1
}
}| Header | Description |
|---|---|
X-Correlation-ID | Identifier of this request. Give it to support when you report a problem. |
X-RateLimit-Limit | Requests allowed per minute. |
X-RateLimit-Remaining | Requests left in the current minute. |
X-RateLimit-Reset | When the minute ends, as a Unix timestamp in seconds. |
X-API-Mode | The mode of the key that made the request: sandbox or production. |
401
The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account.
{
"error": {
"code": "unauthorized",
"message": "Missing or invalid API key.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}403
The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope).
{
"error": {
"code": "forbidden",
"message": "This account does not have Email Center active. Turn it on in the portal.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"reason": "email_account_required"
}
}
}422
Some of the data is not valid.
{
"error": {
"code": "validation_failed",
"message": "Some of the data is not valid.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}429
Too many requests. Wait for the time in Retry-After.
{
"error": {
"code": "rate_limited",
"message": "Too many requests. Please try again shortly.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"retry_after": 42
}
}
}| Header | Description |
|---|---|
Retry-After | Seconds to wait before trying again. |
500
An internal error occurred. Give the correlation_id to support.
{
"error": {
"code": "internal_error",
"message": "An internal error occurred. Please give the correlation_id to support.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}503
The API is turned off.
{
"error": {
"code": "disabled",
"message": "The API is currently turned off.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}Errors
| Status | Code | Meaning |
|---|---|---|
| 401 | unauthorized | The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account. |
| 403 | forbidden, insufficient_scope | The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope). |
| 422 | validation_failed | Some of the data is not valid. |
| 429 | rate_limited | Too many requests. Wait for the time in Retry-After. |
| 500 | internal_error | An internal error occurred. Give the correlation_id to support. |
| 503 | disabled | The API is turned off. |
The error format is explained in Errors.
POSTAdd a sender domain
/v1/email/domains
https://api.interweb.co.mz/v1/email/domainsNeeds email_center:write. Add the records of dns_records to the DNS of the domain: three DKIM CNAME records (required), SPF and DMARC (recommended) and, with MAIL FROM, an MX and a TXT. Then call verify; DNS can take a few hours. Only verified domains can send, from any address of the domain or of a subdomain. Free mailbox domains (gmail.com and others) are refused. With a sandbox key nothing is saved.
Authentication
Needs a valid key in the Authorization: Bearer header. Required permission: email_center:write.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
Idempotency-Key | header | string | no | Any unique value, up to 255 visible characters. Valid for 24 hours per key. Repeating the same request returns the saved answer; a different body, or a first request still in progress, returns 409. |
X-API-Mode | header | string: sandbox, production | no | Optional. If it does not match the mode of the key, the request is refused with invalid_request and reason mode_mismatch. Use it to make sure a program never runs with the wrong key. |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
domain | string | yes |
Examples
curl
curl -X POST "https://api.interweb.co.mz/v1/email/domains" \
-H "Authorization: Bearer $RLX_API_KEY" \
-H "Accept-Language: en" \
-H "Idempotency-Key: 9f1c2d3e-example" \
-H "Content-Type: application/json" \
-d '{"domain": "example.com"}'PHP
<?php
$ch = curl_init('https://api.interweb.co.mz/v1/email/domains');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_POSTFIELDS => '{"domain": "example.com"}',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('RLX_API_KEY'),
'Accept-Language: en',
'Idempotency-Key: 9f1c2d3e-example',
'Content-Type: application/json',
],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo $status, PHP_EOL, $body, PHP_EOL;Python
import os
import requests
headers = {
"Authorization": "Bearer " + os.environ["RLX_API_KEY"],
"Accept-Language": "en",
"Idempotency-Key": "9f1c2d3e-example",
}
payload = {"domain": "example.com"}
r = requests.post("https://api.interweb.co.mz/v1/email/domains", headers=headers, json=payload, timeout=30)
print(r.status_code)
print(r.text)JavaScript
const response = await fetch("https://api.interweb.co.mz/v1/email/domains", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.RLX_API_KEY}`,
"Accept-Language": "en",
"Idempotency-Key": "9f1c2d3e-example",
"Content-Type": "application/json",
},
body: JSON.stringify({"domain": "example.com"}),
});
console.log(response.status);
console.log(await response.text());Responses
201
Add a sender domain.
{
"data": {
"id": 12,
"domain": "example.com",
"status": "pending",
"mail_from": null,
"verified_at": null,
"last_checked_at": null,
"created_at": "2026-11-12T09:40:00+02:00",
"dns_records": [
{
"type": "CNAME",
"name": "k3jd8s0a1b2c3d4e5f6a7b8c9d0e1f2a._domainkey.example.com",
"value": "k3jd8s0a1b2c3d4e5f6a7b8c9d0e1f2a.dkim.example-brand.com",
"priority": null,
"purpose": "dkim",
"required": true,
"found": null
},
{
"type": "TXT",
"name": "example.com",
"value": "v=spf1 include:_spf.example-brand.com ~all",
"priority": null,
"purpose": "spf",
"required": false,
"found": null
},
{
"type": "TXT",
"name": "_dmarc.example.com",
"value": "v=DMARC1; p=none; adkim=r; aspf=r",
"priority": null,
"purpose": "dmarc",
"required": false,
"found": null
}
],
"test_mode_accepted": false,
"simulated": false
},
"meta": {}
}| Header | Description |
|---|---|
X-Correlation-ID | Identifier of this request. Give it to support when you report a problem. |
X-RateLimit-Limit | Requests allowed per minute. |
X-RateLimit-Remaining | Requests left in the current minute. |
X-RateLimit-Reset | When the minute ends, as a Unix timestamp in seconds. |
X-API-Mode | The mode of the key that made the request: sandbox or production. |
401
The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account.
{
"error": {
"code": "unauthorized",
"message": "Missing or invalid API key.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}403
The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope).
{
"error": {
"code": "forbidden",
"message": "This account does not have Email Center active. Turn it on in the portal.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"reason": "email_account_required"
}
}
}409
The operation cannot be done in the current state. See details.reason.
{
"error": {
"code": "conflict",
"message": "This operation only works on an active domain.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"reason": "domain_not_active"
}
}
}422
Some of the data is not valid.
{
"error": {
"code": "validation_failed",
"message": "Some of the data is not valid.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}429
Too many requests. Wait for the time in Retry-After.
{
"error": {
"code": "rate_limited",
"message": "Too many requests. Please try again shortly.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"retry_after": 42
}
}
}| Header | Description |
|---|---|
Retry-After | Seconds to wait before trying again. |
500
An internal error occurred. Give the correlation_id to support.
{
"error": {
"code": "internal_error",
"message": "An internal error occurred. Please give the correlation_id to support.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}503
The API is turned off.
{
"error": {
"code": "disabled",
"message": "The API is currently turned off.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}Errors
| Status | Code | Meaning |
|---|---|---|
| 401 | unauthorized | The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account. |
| 403 | forbidden, insufficient_scope | The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope). |
| 409 | conflict | The operation cannot be done in the current state. See details.reason. |
| 422 | validation_failed | Some of the data is not valid. |
| 429 | rate_limited | Too many requests. Wait for the time in Retry-After. |
| 500 | internal_error | An internal error occurred. Give the correlation_id to support. |
| 503 | disabled | The API is turned off. |
The error format is explained in Errors.
GETSee a sender domain
/v1/email/domains/{domain}
https://api.interweb.co.mz/v1/email/domains/{domain}Needs email_center:read. With the DNS records to add and whether each one was found at the last check.
Authentication
Needs a valid key in the Authorization: Bearer header. Required permission: email_center:read.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
domain | path | string | yes | The domain name (example.com) or its id. |
X-API-Mode | header | string: sandbox, production | no | Optional. If it does not match the mode of the key, the request is refused with invalid_request and reason mode_mismatch. Use it to make sure a program never runs with the wrong key. |
Examples
curl
curl "https://api.interweb.co.mz/v1/email/domains/VALUE" \
-H "Authorization: Bearer $RLX_API_KEY" \
-H "Accept-Language: en"PHP
<?php
$ch = curl_init('https://api.interweb.co.mz/v1/email/domains/VALUE');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('RLX_API_KEY'),
'Accept-Language: en',
],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo $status, PHP_EOL, $body, PHP_EOL;Python
import os
import requests
headers = {
"Authorization": "Bearer " + os.environ["RLX_API_KEY"],
"Accept-Language": "en",
}
r = requests.get("https://api.interweb.co.mz/v1/email/domains/VALUE", headers=headers, timeout=30)
print(r.status_code)
print(r.text)JavaScript
const response = await fetch("https://api.interweb.co.mz/v1/email/domains/VALUE", {
headers: {
Authorization: `Bearer ${process.env.RLX_API_KEY}`,
"Accept-Language": "en",
},
});
console.log(response.status);
console.log(await response.text());Responses
200
See a sender domain.
{
"data": {
"id": 12,
"domain": "example.com",
"status": "verified",
"mail_from": null,
"verified_at": "2026-11-12T10:00:00+02:00",
"last_checked_at": "2026-11-12T10:00:00+02:00",
"created_at": "2026-11-12T09:40:00+02:00",
"dns_records": [
{
"type": "CNAME",
"name": "k3jd8s0a1b2c3d4e5f6a7b8c9d0e1f2a._domainkey.example.com",
"value": "k3jd8s0a1b2c3d4e5f6a7b8c9d0e1f2a.dkim.example-brand.com",
"priority": null,
"purpose": "dkim",
"required": true,
"found": true
},
{
"type": "TXT",
"name": "example.com",
"value": "v=spf1 include:_spf.example-brand.com ~all",
"priority": null,
"purpose": "spf",
"required": false,
"found": true
},
{
"type": "TXT",
"name": "_dmarc.example.com",
"value": "v=DMARC1; p=none; adkim=r; aspf=r",
"priority": null,
"purpose": "dmarc",
"required": false,
"found": false
}
],
"test_mode_accepted": false,
"simulated": false
},
"meta": {}
}| Header | Description |
|---|---|
X-Correlation-ID | Identifier of this request. Give it to support when you report a problem. |
X-RateLimit-Limit | Requests allowed per minute. |
X-RateLimit-Remaining | Requests left in the current minute. |
X-RateLimit-Reset | When the minute ends, as a Unix timestamp in seconds. |
X-API-Mode | The mode of the key that made the request: sandbox or production. |
401
The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account.
{
"error": {
"code": "unauthorized",
"message": "Missing or invalid API key.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}403
The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope).
{
"error": {
"code": "forbidden",
"message": "This account does not have Email Center active. Turn it on in the portal.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"reason": "email_account_required"
}
}
}404
Not found.
{
"error": {
"code": "not_found",
"message": "Not found.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}429
Too many requests. Wait for the time in Retry-After.
{
"error": {
"code": "rate_limited",
"message": "Too many requests. Please try again shortly.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"retry_after": 42
}
}
}| Header | Description |
|---|---|
Retry-After | Seconds to wait before trying again. |
500
An internal error occurred. Give the correlation_id to support.
{
"error": {
"code": "internal_error",
"message": "An internal error occurred. Please give the correlation_id to support.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}503
The API is turned off.
{
"error": {
"code": "disabled",
"message": "The API is currently turned off.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}Errors
| Status | Code | Meaning |
|---|---|---|
| 401 | unauthorized | The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account. |
| 403 | forbidden, insufficient_scope | The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope). |
| 404 | not_found | Not found. |
| 429 | rate_limited | Too many requests. Wait for the time in Retry-After. |
| 500 | internal_error | An internal error occurred. Give the correlation_id to support. |
| 503 | disabled | The API is turned off. |
The error format is explained in Errors.
DELETEDelete a sender domain
/v1/email/domains/{domain}
https://api.interweb.co.mz/v1/email/domains/{domain}Needs email_center:write. The domain can no longer send. Emails already sent stay in the log.
Authentication
Needs a valid key in the Authorization: Bearer header. Required permission: email_center:write.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
domain | path | string | yes | The domain name (example.com) or its id. |
X-API-Mode | header | string: sandbox, production | no | Optional. If it does not match the mode of the key, the request is refused with invalid_request and reason mode_mismatch. Use it to make sure a program never runs with the wrong key. |
Examples
curl
curl -X DELETE "https://api.interweb.co.mz/v1/email/domains/VALUE" \
-H "Authorization: Bearer $RLX_API_KEY" \
-H "Accept-Language: en"PHP
<?php
$ch = curl_init('https://api.interweb.co.mz/v1/email/domains/VALUE');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'DELETE',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('RLX_API_KEY'),
'Accept-Language: en',
],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo $status, PHP_EOL, $body, PHP_EOL;Python
import os
import requests
headers = {
"Authorization": "Bearer " + os.environ["RLX_API_KEY"],
"Accept-Language": "en",
}
r = requests.delete("https://api.interweb.co.mz/v1/email/domains/VALUE", headers=headers, timeout=30)
print(r.status_code)
print(r.text)JavaScript
const response = await fetch("https://api.interweb.co.mz/v1/email/domains/VALUE", {
method: "DELETE",
headers: {
Authorization: `Bearer ${process.env.RLX_API_KEY}`,
"Accept-Language": "en",
},
});
console.log(response.status);
console.log(await response.text());Responses
200
Delete a sender domain.
{
"data": {
"id": 12,
"domain": "example.com",
"deleted": true,
"simulated": false
},
"meta": {}
}| Header | Description |
|---|---|
X-Correlation-ID | Identifier of this request. Give it to support when you report a problem. |
X-RateLimit-Limit | Requests allowed per minute. |
X-RateLimit-Remaining | Requests left in the current minute. |
X-RateLimit-Reset | When the minute ends, as a Unix timestamp in seconds. |
X-API-Mode | The mode of the key that made the request: sandbox or production. |
401
The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account.
{
"error": {
"code": "unauthorized",
"message": "Missing or invalid API key.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}403
The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope).
{
"error": {
"code": "forbidden",
"message": "This account does not have Email Center active. Turn it on in the portal.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"reason": "email_account_required"
}
}
}404
Not found.
{
"error": {
"code": "not_found",
"message": "Not found.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}429
Too many requests. Wait for the time in Retry-After.
{
"error": {
"code": "rate_limited",
"message": "Too many requests. Please try again shortly.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"retry_after": 42
}
}
}| Header | Description |
|---|---|
Retry-After | Seconds to wait before trying again. |
500
An internal error occurred. Give the correlation_id to support.
{
"error": {
"code": "internal_error",
"message": "An internal error occurred. Please give the correlation_id to support.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}503
The API is turned off.
{
"error": {
"code": "disabled",
"message": "The API is currently turned off.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}Errors
| Status | Code | Meaning |
|---|---|---|
| 401 | unauthorized | The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account. |
| 403 | forbidden, insufficient_scope | The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope). |
| 404 | not_found | Not found. |
| 429 | rate_limited | Too many requests. Wait for the time in Retry-After. |
| 500 | internal_error | An internal error occurred. Give the correlation_id to support. |
| 503 | disabled | The API is turned off. |
The error format is explained in Errors.
POSTVerify a sender domain
/v1/email/domains/{domain}/verify
https://api.interweb.co.mz/v1/email/domains/{domain}/verifyNeeds email_center:write. Checks the DKIM records now and returns the new status. With a sandbox key the result is not saved.
Authentication
Needs a valid key in the Authorization: Bearer header. Required permission: email_center:write.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
domain | path | string | yes | The domain name (example.com) or its id. |
X-API-Mode | header | string: sandbox, production | no | Optional. If it does not match the mode of the key, the request is refused with invalid_request and reason mode_mismatch. Use it to make sure a program never runs with the wrong key. |
Idempotency-Key | header | string | no | A unique identifier for this request, so it can be repeated without duplicating it. |
Examples
curl
curl -X POST "https://api.interweb.co.mz/v1/email/domains/VALUE/verify" \
-H "Authorization: Bearer $RLX_API_KEY" \
-H "Accept-Language: en" \
-H "Idempotency-Key: 9f1c2d3e-example"PHP
<?php
$ch = curl_init('https://api.interweb.co.mz/v1/email/domains/VALUE/verify');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('RLX_API_KEY'),
'Accept-Language: en',
'Idempotency-Key: 9f1c2d3e-example',
],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo $status, PHP_EOL, $body, PHP_EOL;Python
import os
import requests
headers = {
"Authorization": "Bearer " + os.environ["RLX_API_KEY"],
"Accept-Language": "en",
"Idempotency-Key": "9f1c2d3e-example",
}
r = requests.post("https://api.interweb.co.mz/v1/email/domains/VALUE/verify", headers=headers, timeout=30)
print(r.status_code)
print(r.text)JavaScript
const response = await fetch("https://api.interweb.co.mz/v1/email/domains/VALUE/verify", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.RLX_API_KEY}`,
"Accept-Language": "en",
"Idempotency-Key": "9f1c2d3e-example",
},
});
console.log(response.status);
console.log(await response.text());Responses
200
Verify a sender domain.
{
"data": {
"id": 12,
"domain": "example.com",
"status": "verified",
"mail_from": null,
"verified_at": "2026-11-12T10:00:00+02:00",
"last_checked_at": "2026-11-12T10:00:00+02:00",
"created_at": "2026-11-12T09:40:00+02:00",
"dns_records": [
{
"type": "CNAME",
"name": "k3jd8s0a1b2c3d4e5f6a7b8c9d0e1f2a._domainkey.example.com",
"value": "k3jd8s0a1b2c3d4e5f6a7b8c9d0e1f2a.dkim.example-brand.com",
"priority": null,
"purpose": "dkim",
"required": true,
"found": true
},
{
"type": "TXT",
"name": "example.com",
"value": "v=spf1 include:_spf.example-brand.com ~all",
"priority": null,
"purpose": "spf",
"required": false,
"found": true
},
{
"type": "TXT",
"name": "_dmarc.example.com",
"value": "v=DMARC1; p=none; adkim=r; aspf=r",
"priority": null,
"purpose": "dmarc",
"required": false,
"found": false
}
],
"test_mode_accepted": false,
"simulated": false
},
"meta": {}
}| Header | Description |
|---|---|
X-Correlation-ID | Identifier of this request. Give it to support when you report a problem. |
X-RateLimit-Limit | Requests allowed per minute. |
X-RateLimit-Remaining | Requests left in the current minute. |
X-RateLimit-Reset | When the minute ends, as a Unix timestamp in seconds. |
X-API-Mode | The mode of the key that made the request: sandbox or production. |
401
The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account.
{
"error": {
"code": "unauthorized",
"message": "Missing or invalid API key.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}403
The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope).
{
"error": {
"code": "forbidden",
"message": "This account does not have Email Center active. Turn it on in the portal.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"reason": "email_account_required"
}
}
}404
Not found.
{
"error": {
"code": "not_found",
"message": "Not found.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}429
Too many requests. Wait for the time in Retry-After.
{
"error": {
"code": "rate_limited",
"message": "Too many requests. Please try again shortly.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"retry_after": 42
}
}
}| Header | Description |
|---|---|
Retry-After | Seconds to wait before trying again. |
500
An internal error occurred. Give the correlation_id to support.
{
"error": {
"code": "internal_error",
"message": "An internal error occurred. Please give the correlation_id to support.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}503
The API is turned off.
{
"error": {
"code": "disabled",
"message": "The API is currently turned off.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}Errors
| Status | Code | Meaning |
|---|---|---|
| 401 | unauthorized | The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account. |
| 403 | forbidden, insufficient_scope | The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope). |
| 404 | not_found | Not found. |
| 429 | rate_limited | Too many requests. Wait for the time in Retry-After. |
| 500 | internal_error | An internal error occurred. Give the correlation_id to support. |
| 503 | disabled | The API is turned off. |
The error format is explained in Errors.
PUTSet the MAIL FROM subdomain
/v1/email/domains/{domain}/mail-from
https://api.interweb.co.mz/v1/email/domains/{domain}/mail-fromNeeds email_center:write. Optional: a subdomain of yours for the return path (for example bounce), so SPF aligns with your domain for DMARC. An empty value goes back to ours. Add the MX and TXT records that appear in dns_records.
Authentication
Needs a valid key in the Authorization: Bearer header. Required permission: email_center:write.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
domain | path | string | yes | The domain name (example.com) or its id. |
X-API-Mode | header | string: sandbox, production | no | Optional. If it does not match the mode of the key, the request is refused with invalid_request and reason mode_mismatch. Use it to make sure a program never runs with the wrong key. |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
subdomain | string, null | yes |
Examples
curl
curl -X PUT "https://api.interweb.co.mz/v1/email/domains/VALUE/mail-from" \
-H "Authorization: Bearer $RLX_API_KEY" \
-H "Accept-Language: en" \
-H "Content-Type: application/json" \
-d '{"subdomain": "bounce"}'PHP
<?php
$ch = curl_init('https://api.interweb.co.mz/v1/email/domains/VALUE/mail-from');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'PUT',
CURLOPT_POSTFIELDS => '{"subdomain": "bounce"}',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('RLX_API_KEY'),
'Accept-Language: en',
'Content-Type: application/json',
],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo $status, PHP_EOL, $body, PHP_EOL;Python
import os
import requests
headers = {
"Authorization": "Bearer " + os.environ["RLX_API_KEY"],
"Accept-Language": "en",
}
payload = {"subdomain": "bounce"}
r = requests.put("https://api.interweb.co.mz/v1/email/domains/VALUE/mail-from", headers=headers, json=payload, timeout=30)
print(r.status_code)
print(r.text)JavaScript
const response = await fetch("https://api.interweb.co.mz/v1/email/domains/VALUE/mail-from", {
method: "PUT",
headers: {
Authorization: `Bearer ${process.env.RLX_API_KEY}`,
"Accept-Language": "en",
"Content-Type": "application/json",
},
body: JSON.stringify({"subdomain": "bounce"}),
});
console.log(response.status);
console.log(await response.text());Responses
200
Set the MAIL FROM subdomain.
{
"data": {
"id": 12,
"domain": "example.com",
"status": "verified",
"mail_from": "bounce.example.com",
"verified_at": "2026-11-12T10:00:00+02:00",
"last_checked_at": "2026-11-12T10:00:00+02:00",
"created_at": "2026-11-12T09:40:00+02:00",
"dns_records": [
{
"type": "CNAME",
"name": "k3jd8s0a1b2c3d4e5f6a7b8c9d0e1f2a._domainkey.example.com",
"value": "k3jd8s0a1b2c3d4e5f6a7b8c9d0e1f2a.dkim.example-brand.com",
"priority": null,
"purpose": "dkim",
"required": true,
"found": true
},
{
"type": "TXT",
"name": "example.com",
"value": "v=spf1 include:_spf.example-brand.com ~all",
"priority": null,
"purpose": "spf",
"required": false,
"found": true
},
{
"type": "TXT",
"name": "_dmarc.example.com",
"value": "v=DMARC1; p=none; adkim=r; aspf=r",
"priority": null,
"purpose": "dmarc",
"required": false,
"found": false
}
],
"test_mode_accepted": false,
"simulated": false
},
"meta": {}
}| Header | Description |
|---|---|
X-Correlation-ID | Identifier of this request. Give it to support when you report a problem. |
X-RateLimit-Limit | Requests allowed per minute. |
X-RateLimit-Remaining | Requests left in the current minute. |
X-RateLimit-Reset | When the minute ends, as a Unix timestamp in seconds. |
X-API-Mode | The mode of the key that made the request: sandbox or production. |
401
The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account.
{
"error": {
"code": "unauthorized",
"message": "Missing or invalid API key.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}403
The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope).
{
"error": {
"code": "forbidden",
"message": "This account does not have Email Center active. Turn it on in the portal.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"reason": "email_account_required"
}
}
}404
Not found.
{
"error": {
"code": "not_found",
"message": "Not found.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}422
Some of the data is not valid.
{
"error": {
"code": "validation_failed",
"message": "Some of the data is not valid.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}429
Too many requests. Wait for the time in Retry-After.
{
"error": {
"code": "rate_limited",
"message": "Too many requests. Please try again shortly.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"retry_after": 42
}
}
}| Header | Description |
|---|---|
Retry-After | Seconds to wait before trying again. |
500
An internal error occurred. Give the correlation_id to support.
{
"error": {
"code": "internal_error",
"message": "An internal error occurred. Please give the correlation_id to support.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}503
The API is turned off.
{
"error": {
"code": "disabled",
"message": "The API is currently turned off.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}Errors
| Status | Code | Meaning |
|---|---|---|
| 401 | unauthorized | The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account. |
| 403 | forbidden, insufficient_scope | The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope). |
| 404 | not_found | Not found. |
| 422 | validation_failed | Some of the data is not valid. |
| 429 | rate_limited | Too many requests. Wait for the time in Retry-After. |
| 500 | internal_error | An internal error occurred. Give the correlation_id to support. |
| 503 | disabled | The API is turned off. |
The error format is explained in Errors.
GETList email templates
/v1/email/templates
https://api.interweb.co.mz/v1/email/templatesNeeds email_center:read. By name.
Authentication
Needs a valid key in the Authorization: Bearer header. Required permission: email_center:read.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
page | query | integer | no | The page number. The first is 1. |
per_page | query | integer | no | Results per page, from 1 to 100. The default is 10. |
X-API-Mode | header | string: sandbox, production | no | Optional. If it does not match the mode of the key, the request is refused with invalid_request and reason mode_mismatch. Use it to make sure a program never runs with the wrong key. |
Examples
curl
curl "https://api.interweb.co.mz/v1/email/templates" \
-H "Authorization: Bearer $RLX_API_KEY" \
-H "Accept-Language: en"PHP
<?php
$ch = curl_init('https://api.interweb.co.mz/v1/email/templates');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('RLX_API_KEY'),
'Accept-Language: en',
],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo $status, PHP_EOL, $body, PHP_EOL;Python
import os
import requests
headers = {
"Authorization": "Bearer " + os.environ["RLX_API_KEY"],
"Accept-Language": "en",
}
r = requests.get("https://api.interweb.co.mz/v1/email/templates", headers=headers, timeout=30)
print(r.status_code)
print(r.text)JavaScript
const response = await fetch("https://api.interweb.co.mz/v1/email/templates", {
headers: {
Authorization: `Bearer ${process.env.RLX_API_KEY}`,
"Accept-Language": "en",
},
});
console.log(response.status);
console.log(await response.text());Responses
200
List email templates.
{
"data": [
{
"id": 7,
"name": "Order ready",
"subject": "Your order {{order}} is ready",
"html": "<p>Hello {{name}}, your order {{order}} is ready.</p>",
"text": "Hello {{name}}, your order {{order}} is ready.",
"variables": [
"order",
"name"
],
"created_at": "2026-11-12T09:00:00+02:00",
"updated_at": "2026-11-12T09:00:00+02:00"
}
],
"meta": {
"page": 1,
"per_page": 10,
"total": 1,
"total_pages": 1
}
}| Header | Description |
|---|---|
X-Correlation-ID | Identifier of this request. Give it to support when you report a problem. |
X-RateLimit-Limit | Requests allowed per minute. |
X-RateLimit-Remaining | Requests left in the current minute. |
X-RateLimit-Reset | When the minute ends, as a Unix timestamp in seconds. |
X-API-Mode | The mode of the key that made the request: sandbox or production. |
401
The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account.
{
"error": {
"code": "unauthorized",
"message": "Missing or invalid API key.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}403
The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope).
{
"error": {
"code": "forbidden",
"message": "This account does not have Email Center active. Turn it on in the portal.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"reason": "email_account_required"
}
}
}422
Some of the data is not valid.
{
"error": {
"code": "validation_failed",
"message": "Some of the data is not valid.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}429
Too many requests. Wait for the time in Retry-After.
{
"error": {
"code": "rate_limited",
"message": "Too many requests. Please try again shortly.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"retry_after": 42
}
}
}| Header | Description |
|---|---|
Retry-After | Seconds to wait before trying again. |
500
An internal error occurred. Give the correlation_id to support.
{
"error": {
"code": "internal_error",
"message": "An internal error occurred. Please give the correlation_id to support.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}503
The API is turned off.
{
"error": {
"code": "disabled",
"message": "The API is currently turned off.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}Errors
| Status | Code | Meaning |
|---|---|---|
| 401 | unauthorized | The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account. |
| 403 | forbidden, insufficient_scope | The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope). |
| 422 | validation_failed | Some of the data is not valid. |
| 429 | rate_limited | Too many requests. Wait for the time in Retry-After. |
| 500 | internal_error | An internal error occurred. Give the correlation_id to support. |
| 503 | disabled | The API is turned off. |
The error format is explained in Errors.
POSTCreate an email template
/v1/email/templates
https://api.interweb.co.mz/v1/email/templatesNeeds email_center:write. Subject and html or text, with {{name}} placeholders filled from variables when sending.
Authentication
Needs a valid key in the Authorization: Bearer header. Required permission: email_center:write.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
Idempotency-Key | header | string | no | Any unique value, up to 255 visible characters. Valid for 24 hours per key. Repeating the same request returns the saved answer; a different body, or a first request still in progress, returns 409. |
X-API-Mode | header | string: sandbox, production | no | Optional. If it does not match the mode of the key, the request is refused with invalid_request and reason mode_mismatch. Use it to make sure a program never runs with the wrong key. |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
name | string | yes | Up to 100 characters, unique in the account. |
subject | string | yes | |
html | string | no | |
text | string | no |
Examples
curl
curl -X POST "https://api.interweb.co.mz/v1/email/templates" \
-H "Authorization: Bearer $RLX_API_KEY" \
-H "Accept-Language: en" \
-H "Idempotency-Key: 9f1c2d3e-example" \
-H "Content-Type: application/json" \
-d '{"name": "Order ready", "subject": "Your order {{order}} is ready", "html": "<p>Hello {{name}}, your order {{order}} is ready.</p>", "text": "Hello {{name}}, your order {{order}} is ready."}'PHP
<?php
$ch = curl_init('https://api.interweb.co.mz/v1/email/templates');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_POSTFIELDS => '{"name": "Order ready", "subject": "Your order {{order}} is ready", "html": "<p>Hello {{name}}, your order {{order}} is ready.</p>", "text": "Hello {{name}}, your order {{order}} is ready."}',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('RLX_API_KEY'),
'Accept-Language: en',
'Idempotency-Key: 9f1c2d3e-example',
'Content-Type: application/json',
],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo $status, PHP_EOL, $body, PHP_EOL;Python
import os
import requests
headers = {
"Authorization": "Bearer " + os.environ["RLX_API_KEY"],
"Accept-Language": "en",
"Idempotency-Key": "9f1c2d3e-example",
}
payload = {"name": "Order ready", "subject": "Your order {{order}} is ready", "html": "<p>Hello {{name}}, your order {{order}} is ready.</p>", "text": "Hello {{name}}, your order {{order}} is ready."}
r = requests.post("https://api.interweb.co.mz/v1/email/templates", headers=headers, json=payload, timeout=30)
print(r.status_code)
print(r.text)JavaScript
const response = await fetch("https://api.interweb.co.mz/v1/email/templates", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.RLX_API_KEY}`,
"Accept-Language": "en",
"Idempotency-Key": "9f1c2d3e-example",
"Content-Type": "application/json",
},
body: JSON.stringify({"name": "Order ready", "subject": "Your order {{order}} is ready", "html": "<p>Hello {{name}}, your order {{order}} is ready.</p>", "text": "Hello {{name}}, your order {{order}} is ready."}),
});
console.log(response.status);
console.log(await response.text());Responses
201
Create an email template.
{
"data": {
"id": 7,
"name": "Order ready",
"subject": "Your order {{order}} is ready",
"html": "<p>Hello {{name}}, your order {{order}} is ready.</p>",
"text": "Hello {{name}}, your order {{order}} is ready.",
"variables": [
"order",
"name"
],
"created_at": "2026-11-12T09:00:00+02:00",
"updated_at": "2026-11-12T09:00:00+02:00"
},
"meta": {}
}| Header | Description |
|---|---|
X-Correlation-ID | Identifier of this request. Give it to support when you report a problem. |
X-RateLimit-Limit | Requests allowed per minute. |
X-RateLimit-Remaining | Requests left in the current minute. |
X-RateLimit-Reset | When the minute ends, as a Unix timestamp in seconds. |
X-API-Mode | The mode of the key that made the request: sandbox or production. |
401
The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account.
{
"error": {
"code": "unauthorized",
"message": "Missing or invalid API key.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}403
The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope).
{
"error": {
"code": "forbidden",
"message": "This account does not have Email Center active. Turn it on in the portal.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"reason": "email_account_required"
}
}
}409
The operation cannot be done in the current state. See details.reason.
{
"error": {
"code": "conflict",
"message": "This operation only works on an active domain.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"reason": "domain_not_active"
}
}
}422
Some of the data is not valid.
{
"error": {
"code": "validation_failed",
"message": "Some of the data is not valid.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}429
Too many requests. Wait for the time in Retry-After.
{
"error": {
"code": "rate_limited",
"message": "Too many requests. Please try again shortly.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"retry_after": 42
}
}
}| Header | Description |
|---|---|
Retry-After | Seconds to wait before trying again. |
500
An internal error occurred. Give the correlation_id to support.
{
"error": {
"code": "internal_error",
"message": "An internal error occurred. Please give the correlation_id to support.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}503
The API is turned off.
{
"error": {
"code": "disabled",
"message": "The API is currently turned off.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}Errors
| Status | Code | Meaning |
|---|---|---|
| 401 | unauthorized | The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account. |
| 403 | forbidden, insufficient_scope | The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope). |
| 409 | conflict | The operation cannot be done in the current state. See details.reason. |
| 422 | validation_failed | Some of the data is not valid. |
| 429 | rate_limited | Too many requests. Wait for the time in Retry-After. |
| 500 | internal_error | An internal error occurred. Give the correlation_id to support. |
| 503 | disabled | The API is turned off. |
The error format is explained in Errors.
GETSee an email template
/v1/email/templates/{id}
https://api.interweb.co.mz/v1/email/templates/{id}Needs email_center:read. With the variables it uses.
Authentication
Needs a valid key in the Authorization: Bearer header. Required permission: email_center:read.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | yes | The template id (the same as template_id when sending). |
X-API-Mode | header | string: sandbox, production | no | Optional. If it does not match the mode of the key, the request is refused with invalid_request and reason mode_mismatch. Use it to make sure a program never runs with the wrong key. |
Examples
curl
curl "https://api.interweb.co.mz/v1/email/templates/00000000-0000-4000-8000-000000000000" \
-H "Authorization: Bearer $RLX_API_KEY" \
-H "Accept-Language: en"PHP
<?php
$ch = curl_init('https://api.interweb.co.mz/v1/email/templates/00000000-0000-4000-8000-000000000000');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('RLX_API_KEY'),
'Accept-Language: en',
],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo $status, PHP_EOL, $body, PHP_EOL;Python
import os
import requests
headers = {
"Authorization": "Bearer " + os.environ["RLX_API_KEY"],
"Accept-Language": "en",
}
r = requests.get("https://api.interweb.co.mz/v1/email/templates/00000000-0000-4000-8000-000000000000", headers=headers, timeout=30)
print(r.status_code)
print(r.text)JavaScript
const response = await fetch("https://api.interweb.co.mz/v1/email/templates/00000000-0000-4000-8000-000000000000", {
headers: {
Authorization: `Bearer ${process.env.RLX_API_KEY}`,
"Accept-Language": "en",
},
});
console.log(response.status);
console.log(await response.text());Responses
200
See an email template.
{
"data": {
"id": 7,
"name": "Order ready",
"subject": "Your order {{order}} is ready",
"html": "<p>Hello {{name}}, your order {{order}} is ready.</p>",
"text": "Hello {{name}}, your order {{order}} is ready.",
"variables": [
"order",
"name"
],
"created_at": "2026-11-12T09:00:00+02:00",
"updated_at": "2026-11-12T09:00:00+02:00"
},
"meta": {}
}| Header | Description |
|---|---|
X-Correlation-ID | Identifier of this request. Give it to support when you report a problem. |
X-RateLimit-Limit | Requests allowed per minute. |
X-RateLimit-Remaining | Requests left in the current minute. |
X-RateLimit-Reset | When the minute ends, as a Unix timestamp in seconds. |
X-API-Mode | The mode of the key that made the request: sandbox or production. |
401
The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account.
{
"error": {
"code": "unauthorized",
"message": "Missing or invalid API key.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}403
The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope).
{
"error": {
"code": "forbidden",
"message": "This account does not have Email Center active. Turn it on in the portal.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"reason": "email_account_required"
}
}
}404
Not found.
{
"error": {
"code": "not_found",
"message": "Not found.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}429
Too many requests. Wait for the time in Retry-After.
{
"error": {
"code": "rate_limited",
"message": "Too many requests. Please try again shortly.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"retry_after": 42
}
}
}| Header | Description |
|---|---|
Retry-After | Seconds to wait before trying again. |
500
An internal error occurred. Give the correlation_id to support.
{
"error": {
"code": "internal_error",
"message": "An internal error occurred. Please give the correlation_id to support.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}503
The API is turned off.
{
"error": {
"code": "disabled",
"message": "The API is currently turned off.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}Errors
| Status | Code | Meaning |
|---|---|---|
| 401 | unauthorized | The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account. |
| 403 | forbidden, insufficient_scope | The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope). |
| 404 | not_found | Not found. |
| 429 | rate_limited | Too many requests. Wait for the time in Retry-After. |
| 500 | internal_error | An internal error occurred. Give the correlation_id to support. |
| 503 | disabled | The API is turned off. |
The error format is explained in Errors.
PATCHChange an email template
/v1/email/templates/{id}
https://api.interweb.co.mz/v1/email/templates/{id}Needs email_center:write. Only the fields sent change.
Authentication
Needs a valid key in the Authorization: Bearer header. Required permission: email_center:write.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | yes | The template id (the same as template_id when sending). |
X-API-Mode | header | string: sandbox, production | no | Optional. If it does not match the mode of the key, the request is refused with invalid_request and reason mode_mismatch. Use it to make sure a program never runs with the wrong key. |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
name | string | no | Up to 100 characters, unique in the account. |
subject | string | no | |
html | string | no | |
text | string | no |
Examples
curl
curl -X PATCH "https://api.interweb.co.mz/v1/email/templates/00000000-0000-4000-8000-000000000000" \
-H "Authorization: Bearer $RLX_API_KEY" \
-H "Accept-Language: en" \
-H "Content-Type: application/json" \
-d '{"subject": "Order {{order}}: ready for pickup"}'PHP
<?php
$ch = curl_init('https://api.interweb.co.mz/v1/email/templates/00000000-0000-4000-8000-000000000000');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'PATCH',
CURLOPT_POSTFIELDS => '{"subject": "Order {{order}}: ready for pickup"}',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('RLX_API_KEY'),
'Accept-Language: en',
'Content-Type: application/json',
],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo $status, PHP_EOL, $body, PHP_EOL;Python
import os
import requests
headers = {
"Authorization": "Bearer " + os.environ["RLX_API_KEY"],
"Accept-Language": "en",
}
payload = {"subject": "Order {{order}}: ready for pickup"}
r = requests.patch("https://api.interweb.co.mz/v1/email/templates/00000000-0000-4000-8000-000000000000", headers=headers, json=payload, timeout=30)
print(r.status_code)
print(r.text)JavaScript
const response = await fetch("https://api.interweb.co.mz/v1/email/templates/00000000-0000-4000-8000-000000000000", {
method: "PATCH",
headers: {
Authorization: `Bearer ${process.env.RLX_API_KEY}`,
"Accept-Language": "en",
"Content-Type": "application/json",
},
body: JSON.stringify({"subject": "Order {{order}}: ready for pickup"}),
});
console.log(response.status);
console.log(await response.text());Responses
200
Change an email template.
{
"data": {
"id": 7,
"name": "Order ready",
"subject": "Your order {{order}} is ready",
"html": "<p>Hello {{name}}, your order {{order}} is ready.</p>",
"text": "Hello {{name}}, your order {{order}} is ready.",
"variables": [
"order",
"name"
],
"created_at": "2026-11-12T09:00:00+02:00",
"updated_at": "2026-11-12T09:00:00+02:00"
},
"meta": {}
}| Header | Description |
|---|---|
X-Correlation-ID | Identifier of this request. Give it to support when you report a problem. |
X-RateLimit-Limit | Requests allowed per minute. |
X-RateLimit-Remaining | Requests left in the current minute. |
X-RateLimit-Reset | When the minute ends, as a Unix timestamp in seconds. |
X-API-Mode | The mode of the key that made the request: sandbox or production. |
401
The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account.
{
"error": {
"code": "unauthorized",
"message": "Missing or invalid API key.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}403
The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope).
{
"error": {
"code": "forbidden",
"message": "This account does not have Email Center active. Turn it on in the portal.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"reason": "email_account_required"
}
}
}404
Not found.
{
"error": {
"code": "not_found",
"message": "Not found.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}409
The operation cannot be done in the current state. See details.reason.
{
"error": {
"code": "conflict",
"message": "This operation only works on an active domain.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"reason": "domain_not_active"
}
}
}422
Some of the data is not valid.
{
"error": {
"code": "validation_failed",
"message": "Some of the data is not valid.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}429
Too many requests. Wait for the time in Retry-After.
{
"error": {
"code": "rate_limited",
"message": "Too many requests. Please try again shortly.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"retry_after": 42
}
}
}| Header | Description |
|---|---|
Retry-After | Seconds to wait before trying again. |
500
An internal error occurred. Give the correlation_id to support.
{
"error": {
"code": "internal_error",
"message": "An internal error occurred. Please give the correlation_id to support.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}503
The API is turned off.
{
"error": {
"code": "disabled",
"message": "The API is currently turned off.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}Errors
| Status | Code | Meaning |
|---|---|---|
| 401 | unauthorized | The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account. |
| 403 | forbidden, insufficient_scope | The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope). |
| 404 | not_found | Not found. |
| 409 | conflict | The operation cannot be done in the current state. See details.reason. |
| 422 | validation_failed | Some of the data is not valid. |
| 429 | rate_limited | Too many requests. Wait for the time in Retry-After. |
| 500 | internal_error | An internal error occurred. Give the correlation_id to support. |
| 503 | disabled | The API is turned off. |
The error format is explained in Errors.
DELETEDelete an email template
/v1/email/templates/{id}
https://api.interweb.co.mz/v1/email/templates/{id}Needs email_center:write. Emails already sent are not affected.
Authentication
Needs a valid key in the Authorization: Bearer header. Required permission: email_center:write.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | yes | The template id (the same as template_id when sending). |
X-API-Mode | header | string: sandbox, production | no | Optional. If it does not match the mode of the key, the request is refused with invalid_request and reason mode_mismatch. Use it to make sure a program never runs with the wrong key. |
Examples
curl
curl -X DELETE "https://api.interweb.co.mz/v1/email/templates/00000000-0000-4000-8000-000000000000" \
-H "Authorization: Bearer $RLX_API_KEY" \
-H "Accept-Language: en"PHP
<?php
$ch = curl_init('https://api.interweb.co.mz/v1/email/templates/00000000-0000-4000-8000-000000000000');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'DELETE',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('RLX_API_KEY'),
'Accept-Language: en',
],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo $status, PHP_EOL, $body, PHP_EOL;Python
import os
import requests
headers = {
"Authorization": "Bearer " + os.environ["RLX_API_KEY"],
"Accept-Language": "en",
}
r = requests.delete("https://api.interweb.co.mz/v1/email/templates/00000000-0000-4000-8000-000000000000", headers=headers, timeout=30)
print(r.status_code)
print(r.text)JavaScript
const response = await fetch("https://api.interweb.co.mz/v1/email/templates/00000000-0000-4000-8000-000000000000", {
method: "DELETE",
headers: {
Authorization: `Bearer ${process.env.RLX_API_KEY}`,
"Accept-Language": "en",
},
});
console.log(response.status);
console.log(await response.text());Responses
200
Delete an email template.
{
"data": {
"id": 7,
"deleted": true,
"simulated": false
},
"meta": {}
}| Header | Description |
|---|---|
X-Correlation-ID | Identifier of this request. Give it to support when you report a problem. |
X-RateLimit-Limit | Requests allowed per minute. |
X-RateLimit-Remaining | Requests left in the current minute. |
X-RateLimit-Reset | When the minute ends, as a Unix timestamp in seconds. |
X-API-Mode | The mode of the key that made the request: sandbox or production. |
401
The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account.
{
"error": {
"code": "unauthorized",
"message": "Missing or invalid API key.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}403
The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope).
{
"error": {
"code": "forbidden",
"message": "This account does not have Email Center active. Turn it on in the portal.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"reason": "email_account_required"
}
}
}404
Not found.
{
"error": {
"code": "not_found",
"message": "Not found.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}429
Too many requests. Wait for the time in Retry-After.
{
"error": {
"code": "rate_limited",
"message": "Too many requests. Please try again shortly.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"retry_after": 42
}
}
}| Header | Description |
|---|---|
Retry-After | Seconds to wait before trying again. |
500
An internal error occurred. Give the correlation_id to support.
{
"error": {
"code": "internal_error",
"message": "An internal error occurred. Please give the correlation_id to support.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}503
The API is turned off.
{
"error": {
"code": "disabled",
"message": "The API is currently turned off.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}Errors
| Status | Code | Meaning |
|---|---|---|
| 401 | unauthorized | The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account. |
| 403 | forbidden, insufficient_scope | The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope). |
| 404 | not_found | Not found. |
| 429 | rate_limited | Too many requests. Wait for the time in Retry-After. |
| 500 | internal_error | An internal error occurred. Give the correlation_id to support. |
| 503 | disabled | The API is turned off. |
The error format is explained in Errors.
GETList suppressed addresses
/v1/email/suppressions
https://api.interweb.co.mz/v1/email/suppressionsNeeds email_center:read. Addresses that never receive emails from this account: permanent bounces and complaints enter on their own; you can add others.
Authentication
Needs a valid key in the Authorization: Bearer header. Required permission: email_center:read.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
reason | query | string | no | bounce, complaint or manual. |
email | query | string | no | One address. |
page | query | integer | no | The page number. The first is 1. |
per_page | query | integer | no | Results per page, from 1 to 100. The default is 10. |
X-API-Mode | header | string: sandbox, production | no | Optional. If it does not match the mode of the key, the request is refused with invalid_request and reason mode_mismatch. Use it to make sure a program never runs with the wrong key. |
Examples
curl
curl "https://api.interweb.co.mz/v1/email/suppressions" \
-H "Authorization: Bearer $RLX_API_KEY" \
-H "Accept-Language: en"PHP
<?php
$ch = curl_init('https://api.interweb.co.mz/v1/email/suppressions');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('RLX_API_KEY'),
'Accept-Language: en',
],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo $status, PHP_EOL, $body, PHP_EOL;Python
import os
import requests
headers = {
"Authorization": "Bearer " + os.environ["RLX_API_KEY"],
"Accept-Language": "en",
}
r = requests.get("https://api.interweb.co.mz/v1/email/suppressions", headers=headers, timeout=30)
print(r.status_code)
print(r.text)JavaScript
const response = await fetch("https://api.interweb.co.mz/v1/email/suppressions", {
headers: {
Authorization: `Bearer ${process.env.RLX_API_KEY}`,
"Accept-Language": "en",
},
});
console.log(response.status);
console.log(await response.text());Responses
200
List suppressed addresses.
{
"data": [
{
"email": "[email protected]",
"reason": "manual",
"note": "Asked to stop",
"created_at": "2026-11-12T10:00:00+02:00"
}
],
"meta": {
"page": 1,
"per_page": 10,
"total": 1,
"total_pages": 1
}
}| Header | Description |
|---|---|
X-Correlation-ID | Identifier of this request. Give it to support when you report a problem. |
X-RateLimit-Limit | Requests allowed per minute. |
X-RateLimit-Remaining | Requests left in the current minute. |
X-RateLimit-Reset | When the minute ends, as a Unix timestamp in seconds. |
X-API-Mode | The mode of the key that made the request: sandbox or production. |
401
The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account.
{
"error": {
"code": "unauthorized",
"message": "Missing or invalid API key.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}403
The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope).
{
"error": {
"code": "forbidden",
"message": "This account does not have Email Center active. Turn it on in the portal.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"reason": "email_account_required"
}
}
}422
Some of the data is not valid.
{
"error": {
"code": "validation_failed",
"message": "Some of the data is not valid.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}429
Too many requests. Wait for the time in Retry-After.
{
"error": {
"code": "rate_limited",
"message": "Too many requests. Please try again shortly.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"retry_after": 42
}
}
}| Header | Description |
|---|---|
Retry-After | Seconds to wait before trying again. |
500
An internal error occurred. Give the correlation_id to support.
{
"error": {
"code": "internal_error",
"message": "An internal error occurred. Please give the correlation_id to support.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}503
The API is turned off.
{
"error": {
"code": "disabled",
"message": "The API is currently turned off.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}Errors
| Status | Code | Meaning |
|---|---|---|
| 401 | unauthorized | The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account. |
| 403 | forbidden, insufficient_scope | The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope). |
| 422 | validation_failed | Some of the data is not valid. |
| 429 | rate_limited | Too many requests. Wait for the time in Retry-After. |
| 500 | internal_error | An internal error occurred. Give the correlation_id to support. |
| 503 | disabled | The API is turned off. |
The error format is explained in Errors.
POSTSuppress an address
/v1/email/suppressions
https://api.interweb.co.mz/v1/email/suppressionsNeeds email_center:write. Emails to it are removed before sending and never charged.
Authentication
Needs a valid key in the Authorization: Bearer header. Required permission: email_center:write.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
Idempotency-Key | header | string | no | Any unique value, up to 255 visible characters. Valid for 24 hours per key. Repeating the same request returns the saved answer; a different body, or a first request still in progress, returns 409. |
X-API-Mode | header | string: sandbox, production | no | Optional. If it does not match the mode of the key, the request is refused with invalid_request and reason mode_mismatch. Use it to make sure a program never runs with the wrong key. |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
email | string | yes | |
note | string | no |
Examples
curl
curl -X POST "https://api.interweb.co.mz/v1/email/suppressions" \
-H "Authorization: Bearer $RLX_API_KEY" \
-H "Accept-Language: en" \
-H "Idempotency-Key: 9f1c2d3e-example" \
-H "Content-Type: application/json" \
-d '{"email": "[email protected]", "note": "Asked to stop"}'PHP
<?php
$ch = curl_init('https://api.interweb.co.mz/v1/email/suppressions');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_POSTFIELDS => '{"email": "[email protected]", "note": "Asked to stop"}',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('RLX_API_KEY'),
'Accept-Language: en',
'Idempotency-Key: 9f1c2d3e-example',
'Content-Type: application/json',
],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo $status, PHP_EOL, $body, PHP_EOL;Python
import os
import requests
headers = {
"Authorization": "Bearer " + os.environ["RLX_API_KEY"],
"Accept-Language": "en",
"Idempotency-Key": "9f1c2d3e-example",
}
payload = {"email": "[email protected]", "note": "Asked to stop"}
r = requests.post("https://api.interweb.co.mz/v1/email/suppressions", headers=headers, json=payload, timeout=30)
print(r.status_code)
print(r.text)JavaScript
const response = await fetch("https://api.interweb.co.mz/v1/email/suppressions", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.RLX_API_KEY}`,
"Accept-Language": "en",
"Idempotency-Key": "9f1c2d3e-example",
"Content-Type": "application/json",
},
body: JSON.stringify({"email": "[email protected]", "note": "Asked to stop"}),
});
console.log(response.status);
console.log(await response.text());Responses
201
Suppress an address.
{
"data": {
"email": "[email protected]",
"reason": "manual",
"note": "Asked to stop",
"created_at": "2026-11-12T10:00:00+02:00",
"already_listed": false,
"simulated": false
},
"meta": {}
}| Header | Description |
|---|---|
X-Correlation-ID | Identifier of this request. Give it to support when you report a problem. |
X-RateLimit-Limit | Requests allowed per minute. |
X-RateLimit-Remaining | Requests left in the current minute. |
X-RateLimit-Reset | When the minute ends, as a Unix timestamp in seconds. |
X-API-Mode | The mode of the key that made the request: sandbox or production. |
401
The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account.
{
"error": {
"code": "unauthorized",
"message": "Missing or invalid API key.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}403
The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope).
{
"error": {
"code": "forbidden",
"message": "This account does not have Email Center active. Turn it on in the portal.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"reason": "email_account_required"
}
}
}422
Some of the data is not valid.
{
"error": {
"code": "validation_failed",
"message": "Some of the data is not valid.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}429
Too many requests. Wait for the time in Retry-After.
{
"error": {
"code": "rate_limited",
"message": "Too many requests. Please try again shortly.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"retry_after": 42
}
}
}| Header | Description |
|---|---|
Retry-After | Seconds to wait before trying again. |
500
An internal error occurred. Give the correlation_id to support.
{
"error": {
"code": "internal_error",
"message": "An internal error occurred. Please give the correlation_id to support.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}503
The API is turned off.
{
"error": {
"code": "disabled",
"message": "The API is currently turned off.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}Errors
| Status | Code | Meaning |
|---|---|---|
| 401 | unauthorized | The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account. |
| 403 | forbidden, insufficient_scope | The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope). |
| 422 | validation_failed | Some of the data is not valid. |
| 429 | rate_limited | Too many requests. Wait for the time in Retry-After. |
| 500 | internal_error | An internal error occurred. Give the correlation_id to support. |
| 503 | disabled | The API is turned off. |
The error format is explained in Errors.
DELETERemove a suppressed address
/v1/email/suppressions/{email}
https://api.interweb.co.mz/v1/email/suppressions/{email}Needs email_center:write. The address goes in the path, URL-encoded (ana%40example.org).
Authentication
Needs a valid key in the Authorization: Bearer header. Required permission: email_center:write.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
email | path | string | yes | The address, URL-encoded. |
X-API-Mode | header | string: sandbox, production | no | Optional. If it does not match the mode of the key, the request is refused with invalid_request and reason mode_mismatch. Use it to make sure a program never runs with the wrong key. |
Examples
curl
curl -X DELETE "https://api.interweb.co.mz/v1/email/suppressions/VALUE" \
-H "Authorization: Bearer $RLX_API_KEY" \
-H "Accept-Language: en"PHP
<?php
$ch = curl_init('https://api.interweb.co.mz/v1/email/suppressions/VALUE');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'DELETE',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('RLX_API_KEY'),
'Accept-Language: en',
],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo $status, PHP_EOL, $body, PHP_EOL;Python
import os
import requests
headers = {
"Authorization": "Bearer " + os.environ["RLX_API_KEY"],
"Accept-Language": "en",
}
r = requests.delete("https://api.interweb.co.mz/v1/email/suppressions/VALUE", headers=headers, timeout=30)
print(r.status_code)
print(r.text)JavaScript
const response = await fetch("https://api.interweb.co.mz/v1/email/suppressions/VALUE", {
method: "DELETE",
headers: {
Authorization: `Bearer ${process.env.RLX_API_KEY}`,
"Accept-Language": "en",
},
});
console.log(response.status);
console.log(await response.text());Responses
200
Remove a suppressed address.
{
"data": {
"email": "[email protected]",
"deleted": true,
"simulated": false
},
"meta": {}
}| Header | Description |
|---|---|
X-Correlation-ID | Identifier of this request. Give it to support when you report a problem. |
X-RateLimit-Limit | Requests allowed per minute. |
X-RateLimit-Remaining | Requests left in the current minute. |
X-RateLimit-Reset | When the minute ends, as a Unix timestamp in seconds. |
X-API-Mode | The mode of the key that made the request: sandbox or production. |
401
The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account.
{
"error": {
"code": "unauthorized",
"message": "Missing or invalid API key.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}403
The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope).
{
"error": {
"code": "forbidden",
"message": "This account does not have Email Center active. Turn it on in the portal.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"reason": "email_account_required"
}
}
}404
Not found.
{
"error": {
"code": "not_found",
"message": "Not found.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}429
Too many requests. Wait for the time in Retry-After.
{
"error": {
"code": "rate_limited",
"message": "Too many requests. Please try again shortly.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"retry_after": 42
}
}
}| Header | Description |
|---|---|
Retry-After | Seconds to wait before trying again. |
500
An internal error occurred. Give the correlation_id to support.
{
"error": {
"code": "internal_error",
"message": "An internal error occurred. Please give the correlation_id to support.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}503
The API is turned off.
{
"error": {
"code": "disabled",
"message": "The API is currently turned off.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}Errors
| Status | Code | Meaning |
|---|---|---|
| 401 | unauthorized | The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account. |
| 403 | forbidden, insufficient_scope | The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope). |
| 404 | not_found | Not found. |
| 429 | rate_limited | Too many requests. Wait for the time in Retry-After. |
| 500 | internal_error | An internal error occurred. Give the correlation_id to support. |
| 503 | disabled | The API is turned off. |
The error format is explained in Errors.
GETGet the email webhook
/v1/email/webhook
https://api.interweb.co.mz/v1/email/webhookNeeds email_center:read. The address, the events and the last delivery; never the secret. We POST {"event": "email.delivered", "created_at", "data": {"id", "event_id", "recipient", "detail", "from", "subject", "simulated"}} to your HTTPS address on port 443, one call per event and recipient, only for events after the webhook was saved. Check X-Webhook-Signature: t=<unix time>,v1=<hex>: v1 is HMAC-SHA256 of t + "." + raw body with your secret. Answer 2xx within 5 seconds; otherwise we retry after 1 min, 5 min, 30 min, 2 h and 6 h. This webhook is separate from the SMS one.
Authentication
Needs a valid key in the Authorization: Bearer header. Required permission: email_center:read.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-API-Mode | header | string: sandbox, production | no | Optional. If it does not match the mode of the key, the request is refused with invalid_request and reason mode_mismatch. Use it to make sure a program never runs with the wrong key. |
Examples
curl
curl "https://api.interweb.co.mz/v1/email/webhook" \
-H "Authorization: Bearer $RLX_API_KEY" \
-H "Accept-Language: en"PHP
<?php
$ch = curl_init('https://api.interweb.co.mz/v1/email/webhook');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('RLX_API_KEY'),
'Accept-Language: en',
],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo $status, PHP_EOL, $body, PHP_EOL;Python
import os
import requests
headers = {
"Authorization": "Bearer " + os.environ["RLX_API_KEY"],
"Accept-Language": "en",
}
r = requests.get("https://api.interweb.co.mz/v1/email/webhook", headers=headers, timeout=30)
print(r.status_code)
print(r.text)JavaScript
const response = await fetch("https://api.interweb.co.mz/v1/email/webhook", {
headers: {
Authorization: `Bearer ${process.env.RLX_API_KEY}`,
"Accept-Language": "en",
},
});
console.log(response.status);
console.log(await response.text());Responses
200
Get the email webhook.
{
"data": {
"url": "https://example.com/webhooks/email",
"events": [
"email.delivered",
"email.bounced",
"email.complained"
],
"created_at": "2026-11-12T10:30:00+02:00",
"updated_at": "2026-11-12T10:30:00+02:00",
"last_delivery_at": null,
"last_status_code": null,
"last_error": null
},
"meta": {}
}| Header | Description |
|---|---|
X-Correlation-ID | Identifier of this request. Give it to support when you report a problem. |
X-RateLimit-Limit | Requests allowed per minute. |
X-RateLimit-Remaining | Requests left in the current minute. |
X-RateLimit-Reset | When the minute ends, as a Unix timestamp in seconds. |
X-API-Mode | The mode of the key that made the request: sandbox or production. |
401
The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account.
{
"error": {
"code": "unauthorized",
"message": "Missing or invalid API key.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}403
The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope).
{
"error": {
"code": "forbidden",
"message": "This account does not have Email Center active. Turn it on in the portal.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"reason": "email_account_required"
}
}
}429
Too many requests. Wait for the time in Retry-After.
{
"error": {
"code": "rate_limited",
"message": "Too many requests. Please try again shortly.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"retry_after": 42
}
}
}| Header | Description |
|---|---|
Retry-After | Seconds to wait before trying again. |
500
An internal error occurred. Give the correlation_id to support.
{
"error": {
"code": "internal_error",
"message": "An internal error occurred. Please give the correlation_id to support.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}503
The API is turned off.
{
"error": {
"code": "disabled",
"message": "The API is currently turned off.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}Errors
| Status | Code | Meaning |
|---|---|---|
| 401 | unauthorized | The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account. |
| 403 | forbidden, insufficient_scope | The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope). |
| 429 | rate_limited | Too many requests. Wait for the time in Retry-After. |
| 500 | internal_error | An internal error occurred. Give the correlation_id to support. |
| 503 | disabled | The API is turned off. |
The error format is explained in Errors.
PUTSave the email webhook
/v1/email/webhook
https://api.interweb.co.mz/v1/email/webhookNeeds email_center:write. The secret is shown only when the webhook is created or with rotate_secret: true. We POST {"event": "email.delivered", "created_at", "data": {"id", "event_id", "recipient", "detail", "from", "subject", "simulated"}} to your HTTPS address on port 443, one call per event and recipient, only for events after the webhook was saved. Check X-Webhook-Signature: t=<unix time>,v1=<hex>: v1 is HMAC-SHA256 of t + "." + raw body with your secret. Answer 2xx within 5 seconds; otherwise we retry after 1 min, 5 min, 30 min, 2 h and 6 h. This webhook is separate from the SMS one.
Authentication
Needs a valid key in the Authorization: Bearer header. Required permission: email_center:write.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-API-Mode | header | string: sandbox, production | no | Optional. If it does not match the mode of the key, the request is refused with invalid_request and reason mode_mismatch. Use it to make sure a program never runs with the wrong key. |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
url | string | yes | |
events | array<string: email.sent, email.delivered, email.bounced, email.complained, email.failed> | no | |
rotate_secret | boolean | no |
Examples
curl
curl -X PUT "https://api.interweb.co.mz/v1/email/webhook" \
-H "Authorization: Bearer $RLX_API_KEY" \
-H "Accept-Language: en" \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com/webhooks/email", "events": ["email.delivered", "email.bounced", "email.complained"]}'PHP
<?php
$ch = curl_init('https://api.interweb.co.mz/v1/email/webhook');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'PUT',
CURLOPT_POSTFIELDS => '{"url": "https://example.com/webhooks/email", "events": ["email.delivered", "email.bounced", "email.complained"]}',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('RLX_API_KEY'),
'Accept-Language: en',
'Content-Type: application/json',
],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo $status, PHP_EOL, $body, PHP_EOL;Python
import os
import requests
headers = {
"Authorization": "Bearer " + os.environ["RLX_API_KEY"],
"Accept-Language": "en",
}
payload = {"url": "https://example.com/webhooks/email", "events": ["email.delivered", "email.bounced", "email.complained"]}
r = requests.put("https://api.interweb.co.mz/v1/email/webhook", headers=headers, json=payload, timeout=30)
print(r.status_code)
print(r.text)JavaScript
const response = await fetch("https://api.interweb.co.mz/v1/email/webhook", {
method: "PUT",
headers: {
Authorization: `Bearer ${process.env.RLX_API_KEY}`,
"Accept-Language": "en",
"Content-Type": "application/json",
},
body: JSON.stringify({"url": "https://example.com/webhooks/email", "events": ["email.delivered", "email.bounced", "email.complained"]}),
});
console.log(response.status);
console.log(await response.text());Responses
200
Save the email webhook.
{
"data": {
"url": "https://example.com/webhooks/email",
"events": [
"email.delivered",
"email.bounced",
"email.complained"
],
"created_at": "2026-11-12T10:30:00+02:00",
"updated_at": "2026-11-12T10:30:00+02:00",
"last_delivery_at": null,
"last_status_code": null,
"last_error": null,
"secret": "whsec_8c1f0e2d4b6a7c9e1f3a5b7d9e0c2a4b6d8f0a1c3e5b7d9f",
"simulated": false
},
"meta": {}
}| Header | Description |
|---|---|
X-Correlation-ID | Identifier of this request. Give it to support when you report a problem. |
X-RateLimit-Limit | Requests allowed per minute. |
X-RateLimit-Remaining | Requests left in the current minute. |
X-RateLimit-Reset | When the minute ends, as a Unix timestamp in seconds. |
X-API-Mode | The mode of the key that made the request: sandbox or production. |
401
The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account.
{
"error": {
"code": "unauthorized",
"message": "Missing or invalid API key.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}403
The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope).
{
"error": {
"code": "forbidden",
"message": "This account does not have Email Center active. Turn it on in the portal.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"reason": "email_account_required"
}
}
}422
Some of the data is not valid.
{
"error": {
"code": "validation_failed",
"message": "Some of the data is not valid.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}429
Too many requests. Wait for the time in Retry-After.
{
"error": {
"code": "rate_limited",
"message": "Too many requests. Please try again shortly.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"retry_after": 42
}
}
}| Header | Description |
|---|---|
Retry-After | Seconds to wait before trying again. |
500
An internal error occurred. Give the correlation_id to support.
{
"error": {
"code": "internal_error",
"message": "An internal error occurred. Please give the correlation_id to support.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}503
The API is turned off.
{
"error": {
"code": "disabled",
"message": "The API is currently turned off.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}Errors
| Status | Code | Meaning |
|---|---|---|
| 401 | unauthorized | The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account. |
| 403 | forbidden, insufficient_scope | The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope). |
| 422 | validation_failed | Some of the data is not valid. |
| 429 | rate_limited | Too many requests. Wait for the time in Retry-After. |
| 500 | internal_error | An internal error occurred. Give the correlation_id to support. |
| 503 | disabled | The API is turned off. |
The error format is explained in Errors.
DELETEDelete the email webhook
/v1/email/webhook
https://api.interweb.co.mz/v1/email/webhookNeeds email_center:write. Pending deliveries are cancelled.
Authentication
Needs a valid key in the Authorization: Bearer header. Required permission: email_center:write.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-API-Mode | header | string: sandbox, production | no | Optional. If it does not match the mode of the key, the request is refused with invalid_request and reason mode_mismatch. Use it to make sure a program never runs with the wrong key. |
Examples
curl
curl -X DELETE "https://api.interweb.co.mz/v1/email/webhook" \
-H "Authorization: Bearer $RLX_API_KEY" \
-H "Accept-Language: en"PHP
<?php
$ch = curl_init('https://api.interweb.co.mz/v1/email/webhook');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'DELETE',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('RLX_API_KEY'),
'Accept-Language: en',
],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo $status, PHP_EOL, $body, PHP_EOL;Python
import os
import requests
headers = {
"Authorization": "Bearer " + os.environ["RLX_API_KEY"],
"Accept-Language": "en",
}
r = requests.delete("https://api.interweb.co.mz/v1/email/webhook", headers=headers, timeout=30)
print(r.status_code)
print(r.text)JavaScript
const response = await fetch("https://api.interweb.co.mz/v1/email/webhook", {
method: "DELETE",
headers: {
Authorization: `Bearer ${process.env.RLX_API_KEY}`,
"Accept-Language": "en",
},
});
console.log(response.status);
console.log(await response.text());Responses
200
Delete the email webhook.
{
"data": {
"deleted": true,
"simulated": false
},
"meta": {}
}| Header | Description |
|---|---|
X-Correlation-ID | Identifier of this request. Give it to support when you report a problem. |
X-RateLimit-Limit | Requests allowed per minute. |
X-RateLimit-Remaining | Requests left in the current minute. |
X-RateLimit-Reset | When the minute ends, as a Unix timestamp in seconds. |
X-API-Mode | The mode of the key that made the request: sandbox or production. |
401
The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account.
{
"error": {
"code": "unauthorized",
"message": "Missing or invalid API key.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}403
The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope).
{
"error": {
"code": "forbidden",
"message": "This account does not have Email Center active. Turn it on in the portal.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"reason": "email_account_required"
}
}
}404
Not found.
{
"error": {
"code": "not_found",
"message": "Not found.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}429
Too many requests. Wait for the time in Retry-After.
{
"error": {
"code": "rate_limited",
"message": "Too many requests. Please try again shortly.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"retry_after": 42
}
}
}| Header | Description |
|---|---|
Retry-After | Seconds to wait before trying again. |
500
An internal error occurred. Give the correlation_id to support.
{
"error": {
"code": "internal_error",
"message": "An internal error occurred. Please give the correlation_id to support.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}503
The API is turned off.
{
"error": {
"code": "disabled",
"message": "The API is currently turned off.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}Errors
| Status | Code | Meaning |
|---|---|---|
| 401 | unauthorized | The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account. |
| 403 | forbidden, insufficient_scope | The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope). |
| 404 | not_found | Not found. |
| 429 | rate_limited | Too many requests. Wait for the time in Retry-After. |
| 500 | internal_error | An internal error occurred. Give the correlation_id to support. |
| 503 | disabled | The API is turned off. |
The error format is explained in Errors.
POSTTest the email webhook
/v1/email/webhook/test
https://api.interweb.co.mz/v1/email/webhook/testNeeds email_center:write. Sends a signed webhook.test event to the saved address now and returns what your server answered.
Authentication
Needs a valid key in the Authorization: Bearer header. Required permission: email_center:write.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-API-Mode | header | string: sandbox, production | no | Optional. If it does not match the mode of the key, the request is refused with invalid_request and reason mode_mismatch. Use it to make sure a program never runs with the wrong key. |
Idempotency-Key | header | string | no | A unique identifier for this request, so it can be repeated without duplicating it. |
Examples
curl
curl -X POST "https://api.interweb.co.mz/v1/email/webhook/test" \
-H "Authorization: Bearer $RLX_API_KEY" \
-H "Accept-Language: en" \
-H "Idempotency-Key: 9f1c2d3e-example"PHP
<?php
$ch = curl_init('https://api.interweb.co.mz/v1/email/webhook/test');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('RLX_API_KEY'),
'Accept-Language: en',
'Idempotency-Key: 9f1c2d3e-example',
],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo $status, PHP_EOL, $body, PHP_EOL;Python
import os
import requests
headers = {
"Authorization": "Bearer " + os.environ["RLX_API_KEY"],
"Accept-Language": "en",
"Idempotency-Key": "9f1c2d3e-example",
}
r = requests.post("https://api.interweb.co.mz/v1/email/webhook/test", headers=headers, timeout=30)
print(r.status_code)
print(r.text)JavaScript
const response = await fetch("https://api.interweb.co.mz/v1/email/webhook/test", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.RLX_API_KEY}`,
"Accept-Language": "en",
"Idempotency-Key": "9f1c2d3e-example",
},
});
console.log(response.status);
console.log(await response.text());Responses
200
Test the email webhook.
{
"data": {
"delivered": true,
"status_code": 200,
"error": null
},
"meta": {}
}| Header | Description |
|---|---|
X-Correlation-ID | Identifier of this request. Give it to support when you report a problem. |
X-RateLimit-Limit | Requests allowed per minute. |
X-RateLimit-Remaining | Requests left in the current minute. |
X-RateLimit-Reset | When the minute ends, as a Unix timestamp in seconds. |
X-API-Mode | The mode of the key that made the request: sandbox or production. |
401
The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account.
{
"error": {
"code": "unauthorized",
"message": "Missing or invalid API key.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}403
The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope).
{
"error": {
"code": "forbidden",
"message": "This account does not have Email Center active. Turn it on in the portal.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"reason": "email_account_required"
}
}
}404
Not found.
{
"error": {
"code": "not_found",
"message": "Not found.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}429
Too many requests. Wait for the time in Retry-After.
{
"error": {
"code": "rate_limited",
"message": "Too many requests. Please try again shortly.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"retry_after": 42
}
}
}| Header | Description |
|---|---|
Retry-After | Seconds to wait before trying again. |
500
An internal error occurred. Give the correlation_id to support.
{
"error": {
"code": "internal_error",
"message": "An internal error occurred. Please give the correlation_id to support.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}503
The API is turned off.
{
"error": {
"code": "disabled",
"message": "The API is currently turned off.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}Errors
| Status | Code | Meaning |
|---|---|---|
| 401 | unauthorized | The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account. |
| 403 | forbidden, insufficient_scope | The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope). |
| 404 | not_found | Not found. |
| 429 | rate_limited | Too many requests. Wait for the time in Retry-After. |
| 500 | internal_error | An internal error occurred. Give the correlation_id to support. |
| 503 | disabled | The API is turned off. |
The error format is explained in Errors.
GETList campaigns
/v1/email/campaigns
https://api.interweb.co.mz/v1/email/campaignsNeeds email_center:read. Newest first, without the blocks.
Authentication
Needs a valid key in the Authorization: Bearer header. Required permission: email_center:read.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
status | query | string | no | draft, scheduled, sending, sent, cancelled or automation. |
page | query | integer | no | The page number. The first is 1. |
per_page | query | integer | no | Results per page, from 1 to 100. The default is 10. |
X-API-Mode | header | string: sandbox, production | no | Optional. If it does not match the mode of the key, the request is refused with invalid_request and reason mode_mismatch. Use it to make sure a program never runs with the wrong key. |
Examples
curl
curl "https://api.interweb.co.mz/v1/email/campaigns" \
-H "Authorization: Bearer $RLX_API_KEY" \
-H "Accept-Language: en"PHP
<?php
$ch = curl_init('https://api.interweb.co.mz/v1/email/campaigns');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('RLX_API_KEY'),
'Accept-Language: en',
],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo $status, PHP_EOL, $body, PHP_EOL;Python
import os
import requests
headers = {
"Authorization": "Bearer " + os.environ["RLX_API_KEY"],
"Accept-Language": "en",
}
r = requests.get("https://api.interweb.co.mz/v1/email/campaigns", headers=headers, timeout=30)
print(r.status_code)
print(r.text)JavaScript
const response = await fetch("https://api.interweb.co.mz/v1/email/campaigns", {
headers: {
Authorization: `Bearer ${process.env.RLX_API_KEY}`,
"Accept-Language": "en",
},
});
console.log(response.status);
console.log(await response.text());Responses
200
List campaigns.
{
"data": [
{
"id": 41,
"name": "November news",
"type": "campaign",
"status": "draft",
"subject": "New arrivals for you",
"preheader": "Special prices until the end of the month",
"from": "[email protected]",
"from_name": "Example Ltd",
"reply_to": null,
"recipients": 0,
"credits": 0.0,
"simulated": false,
"scheduled_for": null,
"sent_at": null,
"created_at": "2026-11-12T10:00:00+02:00",
"updated_at": "2026-11-12T10:05:00+02:00",
"blocks": null,
"target": null
}
],
"meta": {
"page": 1,
"per_page": 10,
"total": 1,
"total_pages": 1
}
}| Header | Description |
|---|---|
X-Correlation-ID | Identifier of this request. Give it to support when you report a problem. |
X-RateLimit-Limit | Requests allowed per minute. |
X-RateLimit-Remaining | Requests left in the current minute. |
X-RateLimit-Reset | When the minute ends, as a Unix timestamp in seconds. |
X-API-Mode | The mode of the key that made the request: sandbox or production. |
401
The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account.
{
"error": {
"code": "unauthorized",
"message": "Missing or invalid API key.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}403
The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope).
{
"error": {
"code": "forbidden",
"message": "This account does not have Email Center active. Turn it on in the portal.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"reason": "email_account_required"
}
}
}422
Some of the data is not valid.
{
"error": {
"code": "validation_failed",
"message": "Some of the data is not valid.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}429
Too many requests. Wait for the time in Retry-After.
{
"error": {
"code": "rate_limited",
"message": "Too many requests. Please try again shortly.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"retry_after": 42
}
}
}| Header | Description |
|---|---|
Retry-After | Seconds to wait before trying again. |
500
An internal error occurred. Give the correlation_id to support.
{
"error": {
"code": "internal_error",
"message": "An internal error occurred. Please give the correlation_id to support.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}503
The API is turned off.
{
"error": {
"code": "disabled",
"message": "The API is currently turned off.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}Errors
| Status | Code | Meaning |
|---|---|---|
| 401 | unauthorized | The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account. |
| 403 | forbidden, insufficient_scope | The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope). |
| 422 | validation_failed | Some of the data is not valid. |
| 429 | rate_limited | Too many requests. Wait for the time in Retry-After. |
| 500 | internal_error | An internal error occurred. Give the correlation_id to support. |
| 503 | disabled | The API is turned off. |
The error format is explained in Errors.
POSTCreate a campaign
/v1/email/campaigns
https://api.interweb.co.mz/v1/email/campaignsNeeds email_center:write. Creates a draft. Send blocks, or template for a ready template. Variables: {{first_name}}, {{name}}, {{company}}, {{email}}. With a sandbox key nothing is saved.
Authentication
Needs a valid key in the Authorization: Bearer header. Required permission: email_center:write.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
Idempotency-Key | header | string | no | Any unique value, up to 255 visible characters. Valid for 24 hours per key. Repeating the same request returns the saved answer; a different body, or a first request still in progress, returns 409. |
X-API-Mode | header | string: sandbox, production | no | Optional. If it does not match the mode of the key, the request is refused with invalid_request and reason mode_mismatch. Use it to make sure a program never runs with the wrong key. |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
name | string | no | |
subject | string | no | |
preheader | string | no | Text shown after the subject in the inbox. |
from | string | no | An address at a verified domain. |
from_name | string | no | |
reply_to | string | no | |
blocks | array<object> | no | |
template | string | no | Instead of blocks: a ready template by sector (restauracao, comercio, servicos, educacao, saude, eventos, imobiliario, tecnologia). |
target | object | no | |
target.groups | array<integer> | no | Contact group ids; empty means all contacts. |
target.opened | string, null | no | yes or no: opened any campaign before. |
target.clicked | string, null | no | yes or no. |
target.joined_from | string, null | no | YYYY-MM-DD. |
target.joined_to | string, null | no | YYYY-MM-DD. |
Examples
curl
curl -X POST "https://api.interweb.co.mz/v1/email/campaigns" \
-H "Authorization: Bearer $RLX_API_KEY" \
-H "Accept-Language: en" \
-H "Idempotency-Key: 9f1c2d3e-example" \
-H "Content-Type: application/json" \
-d '{"name": "November news", "template": "comercio", "from": "[email protected]", "from_name": "Example Ltd", "target": {"groups": [3]}}'PHP
<?php
$ch = curl_init('https://api.interweb.co.mz/v1/email/campaigns');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_POSTFIELDS => '{"name": "November news", "template": "comercio", "from": "[email protected]", "from_name": "Example Ltd", "target": {"groups": [3]}}',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('RLX_API_KEY'),
'Accept-Language: en',
'Idempotency-Key: 9f1c2d3e-example',
'Content-Type: application/json',
],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo $status, PHP_EOL, $body, PHP_EOL;Python
import os
import requests
headers = {
"Authorization": "Bearer " + os.environ["RLX_API_KEY"],
"Accept-Language": "en",
"Idempotency-Key": "9f1c2d3e-example",
}
payload = {"name": "November news", "template": "comercio", "from": "[email protected]", "from_name": "Example Ltd", "target": {"groups": [3]}}
r = requests.post("https://api.interweb.co.mz/v1/email/campaigns", headers=headers, json=payload, timeout=30)
print(r.status_code)
print(r.text)JavaScript
const response = await fetch("https://api.interweb.co.mz/v1/email/campaigns", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.RLX_API_KEY}`,
"Accept-Language": "en",
"Idempotency-Key": "9f1c2d3e-example",
"Content-Type": "application/json",
},
body: JSON.stringify({"name": "November news", "template": "comercio", "from": "[email protected]", "from_name": "Example Ltd", "target": {"groups": [3]}}),
});
console.log(response.status);
console.log(await response.text());Responses
201
Create a campaign.
{
"data": {
"id": 41,
"name": "November news",
"type": "campaign",
"status": "draft",
"subject": "New arrivals for you",
"preheader": "Special prices until the end of the month",
"from": "[email protected]",
"from_name": "Example Ltd",
"reply_to": null,
"recipients": 0,
"credits": 0.0,
"simulated": false,
"scheduled_for": null,
"sent_at": null,
"created_at": "2026-11-12T10:00:00+02:00",
"updated_at": "2026-11-12T10:05:00+02:00",
"blocks": [
{
"type": "header",
"title": "New arrivals for you",
"logo": "",
"color": "#af2835"
},
{
"type": "text",
"text": "Hi {{first_name}},\n\nNew products have arrived, with **special prices** until the end of the month."
},
{
"type": "button",
"text": "See what is new",
"url": "https://example.com",
"color": "#af2835"
},
{
"type": "divider"
},
{
"type": "footer",
"text": "You are receiving this email because you subscribed to our news."
}
],
"target": {
"groups": [
3
],
"opened": null,
"clicked": null,
"joined_from": null,
"joined_to": null
}
},
"meta": {}
}| Field | Type | Description |
|---|---|---|
data.target.groups | array<integer> | Contact group ids; empty means all contacts. |
data.target.opened | string, null | yes or no: opened any campaign before. |
data.target.clicked | string, null | yes or no. |
data.target.joined_from | string, null | YYYY-MM-DD. |
data.target.joined_to | string, null | YYYY-MM-DD. |
| Header | Description |
|---|---|
X-Correlation-ID | Identifier of this request. Give it to support when you report a problem. |
X-RateLimit-Limit | Requests allowed per minute. |
X-RateLimit-Remaining | Requests left in the current minute. |
X-RateLimit-Reset | When the minute ends, as a Unix timestamp in seconds. |
X-API-Mode | The mode of the key that made the request: sandbox or production. |
401
The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account.
{
"error": {
"code": "unauthorized",
"message": "Missing or invalid API key.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}403
The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope).
{
"error": {
"code": "forbidden",
"message": "This account does not have Email Center active. Turn it on in the portal.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"reason": "email_account_required"
}
}
}409
The operation cannot be done in the current state. See details.reason.
{
"error": {
"code": "conflict",
"message": "This operation only works on an active domain.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"reason": "domain_not_active"
}
}
}422
Some of the data is not valid.
{
"error": {
"code": "validation_failed",
"message": "Some of the data is not valid.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}429
Too many requests. Wait for the time in Retry-After.
{
"error": {
"code": "rate_limited",
"message": "Too many requests. Please try again shortly.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"retry_after": 42
}
}
}| Header | Description |
|---|---|
Retry-After | Seconds to wait before trying again. |
500
An internal error occurred. Give the correlation_id to support.
{
"error": {
"code": "internal_error",
"message": "An internal error occurred. Please give the correlation_id to support.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}503
The API is turned off.
{
"error": {
"code": "disabled",
"message": "The API is currently turned off.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}Errors
| Status | Code | Meaning |
|---|---|---|
| 401 | unauthorized | The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account. |
| 403 | forbidden, insufficient_scope | The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope). |
| 409 | conflict | The operation cannot be done in the current state. See details.reason. |
| 422 | validation_failed | Some of the data is not valid. |
| 429 | rate_limited | Too many requests. Wait for the time in Retry-After. |
| 500 | internal_error | An internal error occurred. Give the correlation_id to support. |
| 503 | disabled | The API is turned off. |
The error format is explained in Errors.
POSTGenerate a campaign with AI
/v1/email/campaigns/generate
https://api.interweb.co.mz/v1/email/campaigns/generateNeeds email_center:write. Describe what you want to send; the answer has a subject, a preheader and blocks, which you can then send to POST /v1/email/campaigns. Nothing is saved. 503 ai_unavailable if AI is off; counts towards the daily AI limit.
Authentication
Needs a valid key in the Authorization: Bearer header. Required permission: email_center:write.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-API-Mode | header | string: sandbox, production | no | Optional. If it does not match the mode of the key, the request is refused with invalid_request and reason mode_mismatch. Use it to make sure a program never runs with the wrong key. |
Idempotency-Key | header | string | no | A unique identifier for this request, so it can be repeated without duplicating it. |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
description | string | yes | 10 to 1500 characters. |
sector | string | no |
Examples
curl
curl -X POST "https://api.interweb.co.mz/v1/email/campaigns/generate" \
-H "Authorization: Bearer $RLX_API_KEY" \
-H "Accept-Language: en" \
-H "Idempotency-Key: 9f1c2d3e-example" \
-H "Content-Type: application/json" \
-d '{"description": "20% off all plans until Friday, for existing customers.", "sector": "tecnologia"}'PHP
<?php
$ch = curl_init('https://api.interweb.co.mz/v1/email/campaigns/generate');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_POSTFIELDS => '{"description": "20% off all plans until Friday, for existing customers.", "sector": "tecnologia"}',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('RLX_API_KEY'),
'Accept-Language: en',
'Idempotency-Key: 9f1c2d3e-example',
'Content-Type: application/json',
],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo $status, PHP_EOL, $body, PHP_EOL;Python
import os
import requests
headers = {
"Authorization": "Bearer " + os.environ["RLX_API_KEY"],
"Accept-Language": "en",
"Idempotency-Key": "9f1c2d3e-example",
}
payload = {"description": "20% off all plans until Friday, for existing customers.", "sector": "tecnologia"}
r = requests.post("https://api.interweb.co.mz/v1/email/campaigns/generate", headers=headers, json=payload, timeout=30)
print(r.status_code)
print(r.text)JavaScript
const response = await fetch("https://api.interweb.co.mz/v1/email/campaigns/generate", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.RLX_API_KEY}`,
"Accept-Language": "en",
"Idempotency-Key": "9f1c2d3e-example",
"Content-Type": "application/json",
},
body: JSON.stringify({"description": "20% off all plans until Friday, for existing customers.", "sector": "tecnologia"}),
});
console.log(response.status);
console.log(await response.text());Responses
200
Generate a campaign with AI.
{
"data": {
"subject": "Our November offers",
"preheader": "20% off until Friday",
"blocks": [
{
"type": "header",
"title": "New arrivals for you",
"logo": "",
"color": "#af2835"
},
{
"type": "text",
"text": "Hi {{first_name}},\n\nNew products have arrived, with **special prices** until the end of the month."
},
{
"type": "button",
"text": "See what is new",
"url": "https://example.com",
"color": "#af2835"
},
{
"type": "divider"
},
{
"type": "footer",
"text": "You are receiving this email because you subscribed to our news."
}
]
},
"meta": {}
}| Header | Description |
|---|---|
X-Correlation-ID | Identifier of this request. Give it to support when you report a problem. |
X-RateLimit-Limit | Requests allowed per minute. |
X-RateLimit-Remaining | Requests left in the current minute. |
X-RateLimit-Reset | When the minute ends, as a Unix timestamp in seconds. |
X-API-Mode | The mode of the key that made the request: sandbox or production. |
401
The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account.
{
"error": {
"code": "unauthorized",
"message": "Missing or invalid API key.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}403
The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope).
{
"error": {
"code": "forbidden",
"message": "This account does not have Email Center active. Turn it on in the portal.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"reason": "email_account_required"
}
}
}422
Some of the data is not valid.
{
"error": {
"code": "validation_failed",
"message": "Some of the data is not valid.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}429
Too many requests. Wait for the time in Retry-After.
{
"error": {
"code": "rate_limited",
"message": "Too many requests. Please try again shortly.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"retry_after": 42
}
}
}| Header | Description |
|---|---|
Retry-After | Seconds to wait before trying again. |
500
An internal error occurred. Give the correlation_id to support.
{
"error": {
"code": "internal_error",
"message": "An internal error occurred. Please give the correlation_id to support.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}502
The service behind the API did not respond as expected.
{
"error": {
"code": "upstream_error",
"message": "The service did not respond as expected. Please try again later.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}503
The API is turned off.
{
"error": {
"code": "disabled",
"message": "The API is currently turned off.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}Errors
| Status | Code | Meaning |
|---|---|---|
| 401 | unauthorized | The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account. |
| 403 | forbidden, insufficient_scope | The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope). |
| 422 | validation_failed | Some of the data is not valid. |
| 429 | rate_limited | Too many requests. Wait for the time in Retry-After. |
| 500 | internal_error | An internal error occurred. Give the correlation_id to support. |
| 502 | upstream_error | The service behind the API did not respond as expected. |
| 503 | disabled | The API is turned off. |
The error format is explained in Errors.
GETSee a campaign
/v1/email/campaigns/{id}
https://api.interweb.co.mz/v1/email/campaigns/{id}Needs email_center:read. With the blocks and the audience.
Authentication
Needs a valid key in the Authorization: Bearer header. Required permission: email_center:read.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | yes | The campaign id. |
X-API-Mode | header | string: sandbox, production | no | Optional. If it does not match the mode of the key, the request is refused with invalid_request and reason mode_mismatch. Use it to make sure a program never runs with the wrong key. |
Examples
curl
curl "https://api.interweb.co.mz/v1/email/campaigns/00000000-0000-4000-8000-000000000000" \
-H "Authorization: Bearer $RLX_API_KEY" \
-H "Accept-Language: en"PHP
<?php
$ch = curl_init('https://api.interweb.co.mz/v1/email/campaigns/00000000-0000-4000-8000-000000000000');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('RLX_API_KEY'),
'Accept-Language: en',
],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo $status, PHP_EOL, $body, PHP_EOL;Python
import os
import requests
headers = {
"Authorization": "Bearer " + os.environ["RLX_API_KEY"],
"Accept-Language": "en",
}
r = requests.get("https://api.interweb.co.mz/v1/email/campaigns/00000000-0000-4000-8000-000000000000", headers=headers, timeout=30)
print(r.status_code)
print(r.text)JavaScript
const response = await fetch("https://api.interweb.co.mz/v1/email/campaigns/00000000-0000-4000-8000-000000000000", {
headers: {
Authorization: `Bearer ${process.env.RLX_API_KEY}`,
"Accept-Language": "en",
},
});
console.log(response.status);
console.log(await response.text());Responses
200
See a campaign.
{
"data": {
"id": 41,
"name": "November news",
"type": "campaign",
"status": "draft",
"subject": "New arrivals for you",
"preheader": "Special prices until the end of the month",
"from": "[email protected]",
"from_name": "Example Ltd",
"reply_to": null,
"recipients": 0,
"credits": 0.0,
"simulated": false,
"scheduled_for": null,
"sent_at": null,
"created_at": "2026-11-12T10:00:00+02:00",
"updated_at": "2026-11-12T10:05:00+02:00",
"blocks": [
{
"type": "header",
"title": "New arrivals for you",
"logo": "",
"color": "#af2835"
},
{
"type": "text",
"text": "Hi {{first_name}},\n\nNew products have arrived, with **special prices** until the end of the month."
},
{
"type": "button",
"text": "See what is new",
"url": "https://example.com",
"color": "#af2835"
},
{
"type": "divider"
},
{
"type": "footer",
"text": "You are receiving this email because you subscribed to our news."
}
],
"target": {
"groups": [
3
],
"opened": null,
"clicked": null,
"joined_from": null,
"joined_to": null
}
},
"meta": {}
}| Field | Type | Description |
|---|---|---|
data.target.groups | array<integer> | Contact group ids; empty means all contacts. |
data.target.opened | string, null | yes or no: opened any campaign before. |
data.target.clicked | string, null | yes or no. |
data.target.joined_from | string, null | YYYY-MM-DD. |
data.target.joined_to | string, null | YYYY-MM-DD. |
| Header | Description |
|---|---|
X-Correlation-ID | Identifier of this request. Give it to support when you report a problem. |
X-RateLimit-Limit | Requests allowed per minute. |
X-RateLimit-Remaining | Requests left in the current minute. |
X-RateLimit-Reset | When the minute ends, as a Unix timestamp in seconds. |
X-API-Mode | The mode of the key that made the request: sandbox or production. |
401
The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account.
{
"error": {
"code": "unauthorized",
"message": "Missing or invalid API key.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}403
The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope).
{
"error": {
"code": "forbidden",
"message": "This account does not have Email Center active. Turn it on in the portal.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"reason": "email_account_required"
}
}
}404
Not found.
{
"error": {
"code": "not_found",
"message": "Not found.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}429
Too many requests. Wait for the time in Retry-After.
{
"error": {
"code": "rate_limited",
"message": "Too many requests. Please try again shortly.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"retry_after": 42
}
}
}| Header | Description |
|---|---|
Retry-After | Seconds to wait before trying again. |
500
An internal error occurred. Give the correlation_id to support.
{
"error": {
"code": "internal_error",
"message": "An internal error occurred. Please give the correlation_id to support.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}503
The API is turned off.
{
"error": {
"code": "disabled",
"message": "The API is currently turned off.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}Errors
| Status | Code | Meaning |
|---|---|---|
| 401 | unauthorized | The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account. |
| 403 | forbidden, insufficient_scope | The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope). |
| 404 | not_found | Not found. |
| 429 | rate_limited | Too many requests. Wait for the time in Retry-After. |
| 500 | internal_error | An internal error occurred. Give the correlation_id to support. |
| 503 | disabled | The API is turned off. |
The error format is explained in Errors.
PATCHChange a campaign
/v1/email/campaigns/{id}
https://api.interweb.co.mz/v1/email/campaigns/{id}Needs email_center:write. Only drafts and automation emails; only the fields sent change.
Authentication
Needs a valid key in the Authorization: Bearer header. Required permission: email_center:write.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | yes | The campaign id. |
X-API-Mode | header | string: sandbox, production | no | Optional. If it does not match the mode of the key, the request is refused with invalid_request and reason mode_mismatch. Use it to make sure a program never runs with the wrong key. |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
name | string | no | |
subject | string | no | |
preheader | string | no | Text shown after the subject in the inbox. |
from | string | no | An address at a verified domain. |
from_name | string | no | |
reply_to | string | no | |
blocks | array<object> | no | |
template | string | no | Instead of blocks: a ready template by sector (restauracao, comercio, servicos, educacao, saude, eventos, imobiliario, tecnologia). |
target | object | no | |
target.groups | array<integer> | no | Contact group ids; empty means all contacts. |
target.opened | string, null | no | yes or no: opened any campaign before. |
target.clicked | string, null | no | yes or no. |
target.joined_from | string, null | no | YYYY-MM-DD. |
target.joined_to | string, null | no | YYYY-MM-DD. |
Examples
curl
curl -X PATCH "https://api.interweb.co.mz/v1/email/campaigns/00000000-0000-4000-8000-000000000000" \
-H "Authorization: Bearer $RLX_API_KEY" \
-H "Accept-Language: en" \
-H "Content-Type: application/json" \
-d '{"subject": "Last days of our offers"}'PHP
<?php
$ch = curl_init('https://api.interweb.co.mz/v1/email/campaigns/00000000-0000-4000-8000-000000000000');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'PATCH',
CURLOPT_POSTFIELDS => '{"subject": "Last days of our offers"}',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('RLX_API_KEY'),
'Accept-Language: en',
'Content-Type: application/json',
],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo $status, PHP_EOL, $body, PHP_EOL;Python
import os
import requests
headers = {
"Authorization": "Bearer " + os.environ["RLX_API_KEY"],
"Accept-Language": "en",
}
payload = {"subject": "Last days of our offers"}
r = requests.patch("https://api.interweb.co.mz/v1/email/campaigns/00000000-0000-4000-8000-000000000000", headers=headers, json=payload, timeout=30)
print(r.status_code)
print(r.text)JavaScript
const response = await fetch("https://api.interweb.co.mz/v1/email/campaigns/00000000-0000-4000-8000-000000000000", {
method: "PATCH",
headers: {
Authorization: `Bearer ${process.env.RLX_API_KEY}`,
"Accept-Language": "en",
"Content-Type": "application/json",
},
body: JSON.stringify({"subject": "Last days of our offers"}),
});
console.log(response.status);
console.log(await response.text());Responses
200
Change a campaign.
{
"data": {
"id": 41,
"name": "November news",
"type": "campaign",
"status": "draft",
"subject": "New arrivals for you",
"preheader": "Special prices until the end of the month",
"from": "[email protected]",
"from_name": "Example Ltd",
"reply_to": null,
"recipients": 0,
"credits": 0.0,
"simulated": false,
"scheduled_for": null,
"sent_at": null,
"created_at": "2026-11-12T10:00:00+02:00",
"updated_at": "2026-11-12T10:05:00+02:00",
"blocks": [
{
"type": "header",
"title": "New arrivals for you",
"logo": "",
"color": "#af2835"
},
{
"type": "text",
"text": "Hi {{first_name}},\n\nNew products have arrived, with **special prices** until the end of the month."
},
{
"type": "button",
"text": "See what is new",
"url": "https://example.com",
"color": "#af2835"
},
{
"type": "divider"
},
{
"type": "footer",
"text": "You are receiving this email because you subscribed to our news."
}
],
"target": {
"groups": [
3
],
"opened": null,
"clicked": null,
"joined_from": null,
"joined_to": null
}
},
"meta": {}
}| Field | Type | Description |
|---|---|---|
data.target.groups | array<integer> | Contact group ids; empty means all contacts. |
data.target.opened | string, null | yes or no: opened any campaign before. |
data.target.clicked | string, null | yes or no. |
data.target.joined_from | string, null | YYYY-MM-DD. |
data.target.joined_to | string, null | YYYY-MM-DD. |
| Header | Description |
|---|---|
X-Correlation-ID | Identifier of this request. Give it to support when you report a problem. |
X-RateLimit-Limit | Requests allowed per minute. |
X-RateLimit-Remaining | Requests left in the current minute. |
X-RateLimit-Reset | When the minute ends, as a Unix timestamp in seconds. |
X-API-Mode | The mode of the key that made the request: sandbox or production. |
401
The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account.
{
"error": {
"code": "unauthorized",
"message": "Missing or invalid API key.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}403
The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope).
{
"error": {
"code": "forbidden",
"message": "This account does not have Email Center active. Turn it on in the portal.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"reason": "email_account_required"
}
}
}404
Not found.
{
"error": {
"code": "not_found",
"message": "Not found.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}409
The operation cannot be done in the current state. See details.reason.
{
"error": {
"code": "conflict",
"message": "This operation only works on an active domain.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"reason": "domain_not_active"
}
}
}422
Some of the data is not valid.
{
"error": {
"code": "validation_failed",
"message": "Some of the data is not valid.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}429
Too many requests. Wait for the time in Retry-After.
{
"error": {
"code": "rate_limited",
"message": "Too many requests. Please try again shortly.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"retry_after": 42
}
}
}| Header | Description |
|---|---|
Retry-After | Seconds to wait before trying again. |
500
An internal error occurred. Give the correlation_id to support.
{
"error": {
"code": "internal_error",
"message": "An internal error occurred. Please give the correlation_id to support.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}503
The API is turned off.
{
"error": {
"code": "disabled",
"message": "The API is currently turned off.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}Errors
| Status | Code | Meaning |
|---|---|---|
| 401 | unauthorized | The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account. |
| 403 | forbidden, insufficient_scope | The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope). |
| 404 | not_found | Not found. |
| 409 | conflict | The operation cannot be done in the current state. See details.reason. |
| 422 | validation_failed | Some of the data is not valid. |
| 429 | rate_limited | Too many requests. Wait for the time in Retry-After. |
| 500 | internal_error | An internal error occurred. Give the correlation_id to support. |
| 503 | disabled | The API is turned off. |
The error format is explained in Errors.
DELETEDelete a campaign
/v1/email/campaigns/{id}
https://api.interweb.co.mz/v1/email/campaigns/{id}Needs email_center:write. Only drafts and automation emails.
Authentication
Needs a valid key in the Authorization: Bearer header. Required permission: email_center:write.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | yes | The campaign id. |
X-API-Mode | header | string: sandbox, production | no | Optional. If it does not match the mode of the key, the request is refused with invalid_request and reason mode_mismatch. Use it to make sure a program never runs with the wrong key. |
Examples
curl
curl -X DELETE "https://api.interweb.co.mz/v1/email/campaigns/00000000-0000-4000-8000-000000000000" \
-H "Authorization: Bearer $RLX_API_KEY" \
-H "Accept-Language: en"PHP
<?php
$ch = curl_init('https://api.interweb.co.mz/v1/email/campaigns/00000000-0000-4000-8000-000000000000');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'DELETE',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('RLX_API_KEY'),
'Accept-Language: en',
],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo $status, PHP_EOL, $body, PHP_EOL;Python
import os
import requests
headers = {
"Authorization": "Bearer " + os.environ["RLX_API_KEY"],
"Accept-Language": "en",
}
r = requests.delete("https://api.interweb.co.mz/v1/email/campaigns/00000000-0000-4000-8000-000000000000", headers=headers, timeout=30)
print(r.status_code)
print(r.text)JavaScript
const response = await fetch("https://api.interweb.co.mz/v1/email/campaigns/00000000-0000-4000-8000-000000000000", {
method: "DELETE",
headers: {
Authorization: `Bearer ${process.env.RLX_API_KEY}`,
"Accept-Language": "en",
},
});
console.log(response.status);
console.log(await response.text());Responses
200
Delete a campaign.
{
"data": {
"id": 41,
"deleted": true,
"simulated": false
},
"meta": {}
}| Header | Description |
|---|---|
X-Correlation-ID | Identifier of this request. Give it to support when you report a problem. |
X-RateLimit-Limit | Requests allowed per minute. |
X-RateLimit-Remaining | Requests left in the current minute. |
X-RateLimit-Reset | When the minute ends, as a Unix timestamp in seconds. |
X-API-Mode | The mode of the key that made the request: sandbox or production. |
401
The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account.
{
"error": {
"code": "unauthorized",
"message": "Missing or invalid API key.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}403
The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope).
{
"error": {
"code": "forbidden",
"message": "This account does not have Email Center active. Turn it on in the portal.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"reason": "email_account_required"
}
}
}404
Not found.
{
"error": {
"code": "not_found",
"message": "Not found.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}409
The operation cannot be done in the current state. See details.reason.
{
"error": {
"code": "conflict",
"message": "This operation only works on an active domain.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"reason": "domain_not_active"
}
}
}429
Too many requests. Wait for the time in Retry-After.
{
"error": {
"code": "rate_limited",
"message": "Too many requests. Please try again shortly.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"retry_after": 42
}
}
}| Header | Description |
|---|---|
Retry-After | Seconds to wait before trying again. |
500
An internal error occurred. Give the correlation_id to support.
{
"error": {
"code": "internal_error",
"message": "An internal error occurred. Please give the correlation_id to support.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}503
The API is turned off.
{
"error": {
"code": "disabled",
"message": "The API is currently turned off.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}Errors
| Status | Code | Meaning |
|---|---|---|
| 401 | unauthorized | The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account. |
| 403 | forbidden, insufficient_scope | The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope). |
| 404 | not_found | Not found. |
| 409 | conflict | The operation cannot be done in the current state. See details.reason. |
| 429 | rate_limited | Too many requests. Wait for the time in Retry-After. |
| 500 | internal_error | An internal error occurred. Give the correlation_id to support. |
| 503 | disabled | The API is turned off. |
The error format is explained in Errors.
GETCheck a campaign for spam
/v1/email/campaigns/{id}/spam-check
https://api.interweb.co.mz/v1/email/campaigns/{id}/spam-checkNeeds email_center:read. Simple rules (subject in capitals, spam words, little text, only images, shortened links, sender not verified). From blocks_sending_at points the campaign cannot be sent.
Authentication
Needs a valid key in the Authorization: Bearer header. Required permission: email_center:read.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | yes | The campaign id. |
X-API-Mode | header | string: sandbox, production | no | Optional. If it does not match the mode of the key, the request is refused with invalid_request and reason mode_mismatch. Use it to make sure a program never runs with the wrong key. |
Examples
curl
curl "https://api.interweb.co.mz/v1/email/campaigns/00000000-0000-4000-8000-000000000000/spam-check" \
-H "Authorization: Bearer $RLX_API_KEY" \
-H "Accept-Language: en"PHP
<?php
$ch = curl_init('https://api.interweb.co.mz/v1/email/campaigns/00000000-0000-4000-8000-000000000000/spam-check');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('RLX_API_KEY'),
'Accept-Language: en',
],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo $status, PHP_EOL, $body, PHP_EOL;Python
import os
import requests
headers = {
"Authorization": "Bearer " + os.environ["RLX_API_KEY"],
"Accept-Language": "en",
}
r = requests.get("https://api.interweb.co.mz/v1/email/campaigns/00000000-0000-4000-8000-000000000000/spam-check", headers=headers, timeout=30)
print(r.status_code)
print(r.text)JavaScript
const response = await fetch("https://api.interweb.co.mz/v1/email/campaigns/00000000-0000-4000-8000-000000000000/spam-check", {
headers: {
Authorization: `Bearer ${process.env.RLX_API_KEY}`,
"Accept-Language": "en",
},
});
console.log(response.status);
console.log(await response.text());Responses
200
Check a campaign for spam.
{
"data": {
"score": 1,
"max": 10,
"blocks_sending_at": 8,
"warnings": [
{
"code": "preheader_missing"
}
]
},
"meta": {}
}| Header | Description |
|---|---|
X-Correlation-ID | Identifier of this request. Give it to support when you report a problem. |
X-RateLimit-Limit | Requests allowed per minute. |
X-RateLimit-Remaining | Requests left in the current minute. |
X-RateLimit-Reset | When the minute ends, as a Unix timestamp in seconds. |
X-API-Mode | The mode of the key that made the request: sandbox or production. |
401
The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account.
{
"error": {
"code": "unauthorized",
"message": "Missing or invalid API key.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}403
The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope).
{
"error": {
"code": "forbidden",
"message": "This account does not have Email Center active. Turn it on in the portal.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"reason": "email_account_required"
}
}
}404
Not found.
{
"error": {
"code": "not_found",
"message": "Not found.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}429
Too many requests. Wait for the time in Retry-After.
{
"error": {
"code": "rate_limited",
"message": "Too many requests. Please try again shortly.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"retry_after": 42
}
}
}| Header | Description |
|---|---|
Retry-After | Seconds to wait before trying again. |
500
An internal error occurred. Give the correlation_id to support.
{
"error": {
"code": "internal_error",
"message": "An internal error occurred. Please give the correlation_id to support.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}503
The API is turned off.
{
"error": {
"code": "disabled",
"message": "The API is currently turned off.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}Errors
| Status | Code | Meaning |
|---|---|---|
| 401 | unauthorized | The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account. |
| 403 | forbidden, insufficient_scope | The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope). |
| 404 | not_found | Not found. |
| 429 | rate_limited | Too many requests. Wait for the time in Retry-After. |
| 500 | internal_error | An internal error occurred. Give the correlation_id to support. |
| 503 | disabled | The API is turned off. |
The error format is explained in Errors.
POSTSend a campaign now
/v1/email/campaigns/{id}/send
https://api.interweb.co.mz/v1/email/campaigns/{id}/sendNeeds email_center:write. Only subscribed contacts with an email address, not on the suppression list, receive it; each one is one credit (taken now and returned for those that do not go out). Every email carries an unsubscribe link and the List-Unsubscribe header, plus a tracking pixel and signed redirect links for the statistics. A campaign whose spam check score reaches the limit is refused (422 spam_score_too_high). With a sandbox key, or while Email Center is in test mode, nothing is sent or charged and the numbers are simulated (simulated: true).
Authentication
Needs a valid key in the Authorization: Bearer header. Required permission: email_center:write.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | yes | The campaign id. |
Idempotency-Key | header | string | no | Any unique value, up to 255 visible characters. Valid for 24 hours per key. Repeating the same request returns the saved answer; a different body, or a first request still in progress, returns 409. |
X-API-Mode | header | string: sandbox, production | no | Optional. If it does not match the mode of the key, the request is refused with invalid_request and reason mode_mismatch. Use it to make sure a program never runs with the wrong key. |
Examples
curl
curl -X POST "https://api.interweb.co.mz/v1/email/campaigns/00000000-0000-4000-8000-000000000000/send" \
-H "Authorization: Bearer $RLX_API_KEY" \
-H "Accept-Language: en" \
-H "Idempotency-Key: 9f1c2d3e-example"PHP
<?php
$ch = curl_init('https://api.interweb.co.mz/v1/email/campaigns/00000000-0000-4000-8000-000000000000/send');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('RLX_API_KEY'),
'Accept-Language: en',
'Idempotency-Key: 9f1c2d3e-example',
],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo $status, PHP_EOL, $body, PHP_EOL;Python
import os
import requests
headers = {
"Authorization": "Bearer " + os.environ["RLX_API_KEY"],
"Accept-Language": "en",
"Idempotency-Key": "9f1c2d3e-example",
}
r = requests.post("https://api.interweb.co.mz/v1/email/campaigns/00000000-0000-4000-8000-000000000000/send", headers=headers, timeout=30)
print(r.status_code)
print(r.text)JavaScript
const response = await fetch("https://api.interweb.co.mz/v1/email/campaigns/00000000-0000-4000-8000-000000000000/send", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.RLX_API_KEY}`,
"Accept-Language": "en",
"Idempotency-Key": "9f1c2d3e-example",
},
});
console.log(response.status);
console.log(await response.text());Responses
200
Send a campaign now.
{
"data": {
"id": 41,
"name": "November news",
"type": "campaign",
"status": "sending",
"subject": "New arrivals for you",
"preheader": "Special prices until the end of the month",
"from": "[email protected]",
"from_name": "Example Ltd",
"reply_to": null,
"recipients": 1200,
"credits": 1200.0,
"simulated": false,
"scheduled_for": null,
"sent_at": null,
"created_at": "2026-11-12T10:00:00+02:00",
"updated_at": "2026-11-12T10:05:00+02:00",
"blocks": null,
"target": null,
"stats": {
"recipients": 1200,
"sent": 0,
"delivered": 0,
"bounced": 12,
"opened": 0,
"clicked": 0,
"unsubscribed": 4,
"open_rate": 43.77,
"click_rate": 11.03,
"unsubscribe_rate": 0.34,
"bounce_rate": 1.0,
"by_status": {
"enviado": 1200
},
"top_links": [
{
"url": "https://example.com",
"clicks": 131
}
],
"simulated": false
}
},
"meta": {}
}| Field | Type | Description |
|---|---|---|
data.target.groups | array<integer> | Contact group ids; empty means all contacts. |
data.target.opened | string, null | yes or no: opened any campaign before. |
data.target.clicked | string, null | yes or no. |
data.target.joined_from | string, null | YYYY-MM-DD. |
data.target.joined_to | string, null | YYYY-MM-DD. |
| Header | Description |
|---|---|
X-Correlation-ID | Identifier of this request. Give it to support when you report a problem. |
X-RateLimit-Limit | Requests allowed per minute. |
X-RateLimit-Remaining | Requests left in the current minute. |
X-RateLimit-Reset | When the minute ends, as a Unix timestamp in seconds. |
X-API-Mode | The mode of the key that made the request: sandbox or production. |
401
The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account.
{
"error": {
"code": "unauthorized",
"message": "Missing or invalid API key.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}403
The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope).
{
"error": {
"code": "forbidden",
"message": "This account does not have Email Center active. Turn it on in the portal.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"reason": "email_account_required"
}
}
}404
Not found.
{
"error": {
"code": "not_found",
"message": "Not found.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}409
The operation cannot be done in the current state. See details.reason.
{
"error": {
"code": "conflict",
"message": "This operation only works on an active domain.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"reason": "domain_not_active"
}
}
}422
Some of the data is not valid.
{
"error": {
"code": "validation_failed",
"message": "Some of the data is not valid.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}429
Too many requests. Wait for the time in Retry-After.
{
"error": {
"code": "rate_limited",
"message": "Too many requests. Please try again shortly.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"retry_after": 42
}
}
}| Header | Description |
|---|---|
Retry-After | Seconds to wait before trying again. |
500
An internal error occurred. Give the correlation_id to support.
{
"error": {
"code": "internal_error",
"message": "An internal error occurred. Please give the correlation_id to support.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}503
The API is turned off.
{
"error": {
"code": "disabled",
"message": "The API is currently turned off.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}Errors
| Status | Code | Meaning |
|---|---|---|
| 401 | unauthorized | The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account. |
| 403 | forbidden, insufficient_scope | The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope). |
| 404 | not_found | Not found. |
| 409 | conflict | The operation cannot be done in the current state. See details.reason. |
| 422 | validation_failed | Some of the data is not valid. |
| 429 | rate_limited | Too many requests. Wait for the time in Retry-After. |
| 500 | internal_error | An internal error occurred. Give the correlation_id to support. |
| 503 | disabled | The API is turned off. |
The error format is explained in Errors.
POSTSchedule a campaign
/v1/email/campaigns/{id}/schedule
https://api.interweb.co.mz/v1/email/campaigns/{id}/scheduleNeeds email_center:write. send_at in ISO 8601 with the time zone, up to 30 days ahead. Only subscribed contacts with an email address, not on the suppression list, receive it; each one is one credit (taken now and returned for those that do not go out). Every email carries an unsubscribe link and the List-Unsubscribe header, plus a tracking pixel and signed redirect links for the statistics. A campaign whose spam check score reaches the limit is refused (422 spam_score_too_high). With a sandbox key, or while Email Center is in test mode, nothing is sent or charged and the numbers are simulated (simulated: true).
Authentication
Needs a valid key in the Authorization: Bearer header. Required permission: email_center:write.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | yes | The campaign id. |
Idempotency-Key | header | string | no | Any unique value, up to 255 visible characters. Valid for 24 hours per key. Repeating the same request returns the saved answer; a different body, or a first request still in progress, returns 409. |
X-API-Mode | header | string: sandbox, production | no | Optional. If it does not match the mode of the key, the request is refused with invalid_request and reason mode_mismatch. Use it to make sure a program never runs with the wrong key. |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
send_at | string | yes |
Examples
curl
curl -X POST "https://api.interweb.co.mz/v1/email/campaigns/00000000-0000-4000-8000-000000000000/schedule" \
-H "Authorization: Bearer $RLX_API_KEY" \
-H "Accept-Language: en" \
-H "Idempotency-Key: 9f1c2d3e-example" \
-H "Content-Type: application/json" \
-d '{"send_at": "2026-11-20T09:00:00+02:00"}'PHP
<?php
$ch = curl_init('https://api.interweb.co.mz/v1/email/campaigns/00000000-0000-4000-8000-000000000000/schedule');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_POSTFIELDS => '{"send_at": "2026-11-20T09:00:00+02:00"}',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('RLX_API_KEY'),
'Accept-Language: en',
'Idempotency-Key: 9f1c2d3e-example',
'Content-Type: application/json',
],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo $status, PHP_EOL, $body, PHP_EOL;Python
import os
import requests
headers = {
"Authorization": "Bearer " + os.environ["RLX_API_KEY"],
"Accept-Language": "en",
"Idempotency-Key": "9f1c2d3e-example",
}
payload = {"send_at": "2026-11-20T09:00:00+02:00"}
r = requests.post("https://api.interweb.co.mz/v1/email/campaigns/00000000-0000-4000-8000-000000000000/schedule", headers=headers, json=payload, timeout=30)
print(r.status_code)
print(r.text)JavaScript
const response = await fetch("https://api.interweb.co.mz/v1/email/campaigns/00000000-0000-4000-8000-000000000000/schedule", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.RLX_API_KEY}`,
"Accept-Language": "en",
"Idempotency-Key": "9f1c2d3e-example",
"Content-Type": "application/json",
},
body: JSON.stringify({"send_at": "2026-11-20T09:00:00+02:00"}),
});
console.log(response.status);
console.log(await response.text());Responses
200
Schedule a campaign.
{
"data": {
"id": 41,
"name": "November news",
"type": "campaign",
"status": "scheduled",
"subject": "New arrivals for you",
"preheader": "Special prices until the end of the month",
"from": "[email protected]",
"from_name": "Example Ltd",
"reply_to": null,
"recipients": 1200,
"credits": 1200.0,
"simulated": false,
"scheduled_for": "2026-11-20T09:00:00+02:00",
"sent_at": null,
"created_at": "2026-11-12T10:00:00+02:00",
"updated_at": "2026-11-12T10:05:00+02:00",
"blocks": null,
"target": null,
"stats": {
"recipients": 1200,
"sent": 0,
"delivered": 0,
"bounced": 12,
"opened": 0,
"clicked": 0,
"unsubscribed": 4,
"open_rate": 43.77,
"click_rate": 11.03,
"unsubscribe_rate": 0.34,
"bounce_rate": 1.0,
"by_status": {
"enviado": 1200
},
"top_links": [
{
"url": "https://example.com",
"clicks": 131
}
],
"simulated": false
}
},
"meta": {}
}| Field | Type | Description |
|---|---|---|
data.target.groups | array<integer> | Contact group ids; empty means all contacts. |
data.target.opened | string, null | yes or no: opened any campaign before. |
data.target.clicked | string, null | yes or no. |
data.target.joined_from | string, null | YYYY-MM-DD. |
data.target.joined_to | string, null | YYYY-MM-DD. |
| Header | Description |
|---|---|
X-Correlation-ID | Identifier of this request. Give it to support when you report a problem. |
X-RateLimit-Limit | Requests allowed per minute. |
X-RateLimit-Remaining | Requests left in the current minute. |
X-RateLimit-Reset | When the minute ends, as a Unix timestamp in seconds. |
X-API-Mode | The mode of the key that made the request: sandbox or production. |
401
The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account.
{
"error": {
"code": "unauthorized",
"message": "Missing or invalid API key.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}403
The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope).
{
"error": {
"code": "forbidden",
"message": "This account does not have Email Center active. Turn it on in the portal.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"reason": "email_account_required"
}
}
}404
Not found.
{
"error": {
"code": "not_found",
"message": "Not found.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}409
The operation cannot be done in the current state. See details.reason.
{
"error": {
"code": "conflict",
"message": "This operation only works on an active domain.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"reason": "domain_not_active"
}
}
}422
Some of the data is not valid.
{
"error": {
"code": "validation_failed",
"message": "Some of the data is not valid.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}429
Too many requests. Wait for the time in Retry-After.
{
"error": {
"code": "rate_limited",
"message": "Too many requests. Please try again shortly.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"retry_after": 42
}
}
}| Header | Description |
|---|---|
Retry-After | Seconds to wait before trying again. |
500
An internal error occurred. Give the correlation_id to support.
{
"error": {
"code": "internal_error",
"message": "An internal error occurred. Please give the correlation_id to support.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}503
The API is turned off.
{
"error": {
"code": "disabled",
"message": "The API is currently turned off.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}Errors
| Status | Code | Meaning |
|---|---|---|
| 401 | unauthorized | The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account. |
| 403 | forbidden, insufficient_scope | The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope). |
| 404 | not_found | Not found. |
| 409 | conflict | The operation cannot be done in the current state. See details.reason. |
| 422 | validation_failed | Some of the data is not valid. |
| 429 | rate_limited | Too many requests. Wait for the time in Retry-After. |
| 500 | internal_error | An internal error occurred. Give the correlation_id to support. |
| 503 | disabled | The API is turned off. |
The error format is explained in Errors.
POSTCancel a campaign
/v1/email/campaigns/{id}/cancel
https://api.interweb.co.mz/v1/email/campaigns/{id}/cancelNeeds email_center:write. Scheduled or still sending: what has not gone out does not go, and its credits come back (credits_returned).
Authentication
Needs a valid key in the Authorization: Bearer header. Required permission: email_center:write.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | yes | The campaign id. |
Idempotency-Key | header | string | no | Any unique value, up to 255 visible characters. Valid for 24 hours per key. Repeating the same request returns the saved answer; a different body, or a first request still in progress, returns 409. |
X-API-Mode | header | string: sandbox, production | no | Optional. If it does not match the mode of the key, the request is refused with invalid_request and reason mode_mismatch. Use it to make sure a program never runs with the wrong key. |
Examples
curl
curl -X POST "https://api.interweb.co.mz/v1/email/campaigns/00000000-0000-4000-8000-000000000000/cancel" \
-H "Authorization: Bearer $RLX_API_KEY" \
-H "Accept-Language: en" \
-H "Idempotency-Key: 9f1c2d3e-example"PHP
<?php
$ch = curl_init('https://api.interweb.co.mz/v1/email/campaigns/00000000-0000-4000-8000-000000000000/cancel');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('RLX_API_KEY'),
'Accept-Language: en',
'Idempotency-Key: 9f1c2d3e-example',
],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo $status, PHP_EOL, $body, PHP_EOL;Python
import os
import requests
headers = {
"Authorization": "Bearer " + os.environ["RLX_API_KEY"],
"Accept-Language": "en",
"Idempotency-Key": "9f1c2d3e-example",
}
r = requests.post("https://api.interweb.co.mz/v1/email/campaigns/00000000-0000-4000-8000-000000000000/cancel", headers=headers, timeout=30)
print(r.status_code)
print(r.text)JavaScript
const response = await fetch("https://api.interweb.co.mz/v1/email/campaigns/00000000-0000-4000-8000-000000000000/cancel", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.RLX_API_KEY}`,
"Accept-Language": "en",
"Idempotency-Key": "9f1c2d3e-example",
},
});
console.log(response.status);
console.log(await response.text());Responses
200
Cancel a campaign.
{
"data": {
"id": 41,
"name": "November news",
"type": "campaign",
"status": "cancelled",
"subject": "New arrivals for you",
"preheader": "Special prices until the end of the month",
"from": "[email protected]",
"from_name": "Example Ltd",
"reply_to": null,
"recipients": 0,
"credits": 0.0,
"simulated": false,
"scheduled_for": null,
"sent_at": null,
"created_at": "2026-11-12T10:00:00+02:00",
"updated_at": "2026-11-12T10:05:00+02:00",
"blocks": null,
"target": null,
"credits_returned": 1200.0
},
"meta": {}
}| Field | Type | Description |
|---|---|---|
data.target.groups | array<integer> | Contact group ids; empty means all contacts. |
data.target.opened | string, null | yes or no: opened any campaign before. |
data.target.clicked | string, null | yes or no. |
data.target.joined_from | string, null | YYYY-MM-DD. |
data.target.joined_to | string, null | YYYY-MM-DD. |
| Header | Description |
|---|---|
X-Correlation-ID | Identifier of this request. Give it to support when you report a problem. |
X-RateLimit-Limit | Requests allowed per minute. |
X-RateLimit-Remaining | Requests left in the current minute. |
X-RateLimit-Reset | When the minute ends, as a Unix timestamp in seconds. |
X-API-Mode | The mode of the key that made the request: sandbox or production. |
401
The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account.
{
"error": {
"code": "unauthorized",
"message": "Missing or invalid API key.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}403
The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope).
{
"error": {
"code": "forbidden",
"message": "This account does not have Email Center active. Turn it on in the portal.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"reason": "email_account_required"
}
}
}404
Not found.
{
"error": {
"code": "not_found",
"message": "Not found.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}409
The operation cannot be done in the current state. See details.reason.
{
"error": {
"code": "conflict",
"message": "This operation only works on an active domain.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"reason": "domain_not_active"
}
}
}429
Too many requests. Wait for the time in Retry-After.
{
"error": {
"code": "rate_limited",
"message": "Too many requests. Please try again shortly.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"retry_after": 42
}
}
}| Header | Description |
|---|---|
Retry-After | Seconds to wait before trying again. |
500
An internal error occurred. Give the correlation_id to support.
{
"error": {
"code": "internal_error",
"message": "An internal error occurred. Please give the correlation_id to support.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}503
The API is turned off.
{
"error": {
"code": "disabled",
"message": "The API is currently turned off.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}Errors
| Status | Code | Meaning |
|---|---|---|
| 401 | unauthorized | The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account. |
| 403 | forbidden, insufficient_scope | The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope). |
| 404 | not_found | Not found. |
| 409 | conflict | The operation cannot be done in the current state. See details.reason. |
| 429 | rate_limited | Too many requests. Wait for the time in Retry-After. |
| 500 | internal_error | An internal error occurred. Give the correlation_id to support. |
| 503 | disabled | The API is turned off. |
The error format is explained in Errors.
GETSee campaign statistics
/v1/email/campaigns/{id}/stats
https://api.interweb.co.mz/v1/email/campaigns/{id}/statsNeeds email_center:read. Delivered, opens (pixel), clicks (signed links), unsubscribes and bounces; rates over delivered emails. simulated marks example numbers from test mode.
Authentication
Needs a valid key in the Authorization: Bearer header. Required permission: email_center:read.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | yes | The campaign id. |
X-API-Mode | header | string: sandbox, production | no | Optional. If it does not match the mode of the key, the request is refused with invalid_request and reason mode_mismatch. Use it to make sure a program never runs with the wrong key. |
Examples
curl
curl "https://api.interweb.co.mz/v1/email/campaigns/00000000-0000-4000-8000-000000000000/stats" \
-H "Authorization: Bearer $RLX_API_KEY" \
-H "Accept-Language: en"PHP
<?php
$ch = curl_init('https://api.interweb.co.mz/v1/email/campaigns/00000000-0000-4000-8000-000000000000/stats');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('RLX_API_KEY'),
'Accept-Language: en',
],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo $status, PHP_EOL, $body, PHP_EOL;Python
import os
import requests
headers = {
"Authorization": "Bearer " + os.environ["RLX_API_KEY"],
"Accept-Language": "en",
}
r = requests.get("https://api.interweb.co.mz/v1/email/campaigns/00000000-0000-4000-8000-000000000000/stats", headers=headers, timeout=30)
print(r.status_code)
print(r.text)JavaScript
const response = await fetch("https://api.interweb.co.mz/v1/email/campaigns/00000000-0000-4000-8000-000000000000/stats", {
headers: {
Authorization: `Bearer ${process.env.RLX_API_KEY}`,
"Accept-Language": "en",
},
});
console.log(response.status);
console.log(await response.text());Responses
200
See campaign statistics.
{
"data": {
"recipients": 1200,
"sent": 1200,
"delivered": 1188,
"bounced": 12,
"opened": 520,
"clicked": 131,
"unsubscribed": 4,
"open_rate": 43.77,
"click_rate": 11.03,
"unsubscribe_rate": 0.34,
"bounce_rate": 1.0,
"by_status": {
"enviado": 1200
},
"top_links": [
{
"url": "https://example.com",
"clicks": 131
}
],
"simulated": false
},
"meta": {}
}| Header | Description |
|---|---|
X-Correlation-ID | Identifier of this request. Give it to support when you report a problem. |
X-RateLimit-Limit | Requests allowed per minute. |
X-RateLimit-Remaining | Requests left in the current minute. |
X-RateLimit-Reset | When the minute ends, as a Unix timestamp in seconds. |
X-API-Mode | The mode of the key that made the request: sandbox or production. |
401
The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account.
{
"error": {
"code": "unauthorized",
"message": "Missing or invalid API key.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}403
The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope).
{
"error": {
"code": "forbidden",
"message": "This account does not have Email Center active. Turn it on in the portal.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"reason": "email_account_required"
}
}
}404
Not found.
{
"error": {
"code": "not_found",
"message": "Not found.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}429
Too many requests. Wait for the time in Retry-After.
{
"error": {
"code": "rate_limited",
"message": "Too many requests. Please try again shortly.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"retry_after": 42
}
}
}| Header | Description |
|---|---|
Retry-After | Seconds to wait before trying again. |
500
An internal error occurred. Give the correlation_id to support.
{
"error": {
"code": "internal_error",
"message": "An internal error occurred. Please give the correlation_id to support.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}503
The API is turned off.
{
"error": {
"code": "disabled",
"message": "The API is currently turned off.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}Errors
| Status | Code | Meaning |
|---|---|---|
| 401 | unauthorized | The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account. |
| 403 | forbidden, insufficient_scope | The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope). |
| 404 | not_found | Not found. |
| 429 | rate_limited | Too many requests. Wait for the time in Retry-After. |
| 500 | internal_error | An internal error occurred. Give the correlation_id to support. |
| 503 | disabled | The API is turned off. |
The error format is explained in Errors.
GETList campaign recipients
/v1/email/campaigns/{id}/recipients
https://api.interweb.co.mz/v1/email/campaigns/{id}/recipientsNeeds email_center:read. What each contact did: opened, clicked, unsubscribed or bounced.
Authentication
Needs a valid key in the Authorization: Bearer header. Required permission: email_center:read.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | yes | The campaign id. |
page | query | integer | no | The page number. The first is 1. |
per_page | query | integer | no | Results per page, from 1 to 100. The default is 10. |
X-API-Mode | header | string: sandbox, production | no | Optional. If it does not match the mode of the key, the request is refused with invalid_request and reason mode_mismatch. Use it to make sure a program never runs with the wrong key. |
Examples
curl
curl "https://api.interweb.co.mz/v1/email/campaigns/00000000-0000-4000-8000-000000000000/recipients" \
-H "Authorization: Bearer $RLX_API_KEY" \
-H "Accept-Language: en"PHP
<?php
$ch = curl_init('https://api.interweb.co.mz/v1/email/campaigns/00000000-0000-4000-8000-000000000000/recipients');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('RLX_API_KEY'),
'Accept-Language: en',
],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo $status, PHP_EOL, $body, PHP_EOL;Python
import os
import requests
headers = {
"Authorization": "Bearer " + os.environ["RLX_API_KEY"],
"Accept-Language": "en",
}
r = requests.get("https://api.interweb.co.mz/v1/email/campaigns/00000000-0000-4000-8000-000000000000/recipients", headers=headers, timeout=30)
print(r.status_code)
print(r.text)JavaScript
const response = await fetch("https://api.interweb.co.mz/v1/email/campaigns/00000000-0000-4000-8000-000000000000/recipients", {
headers: {
Authorization: `Bearer ${process.env.RLX_API_KEY}`,
"Accept-Language": "en",
},
});
console.log(response.status);
console.log(await response.text());Responses
200
List campaign recipients.
{
"data": [
{
"email": "[email protected]",
"status": "sent",
"simulated": false,
"sent_at": "2026-11-12T10:30:00+02:00",
"opened_at": "2026-11-12T11:02:00+02:00",
"opens": 2,
"clicked_at": null,
"clicks": 0,
"unsubscribed_at": null,
"bounced_at": null
}
],
"meta": {
"page": 1,
"per_page": 10,
"total": 1,
"total_pages": 1
}
}| Header | Description |
|---|---|
X-Correlation-ID | Identifier of this request. Give it to support when you report a problem. |
X-RateLimit-Limit | Requests allowed per minute. |
X-RateLimit-Remaining | Requests left in the current minute. |
X-RateLimit-Reset | When the minute ends, as a Unix timestamp in seconds. |
X-API-Mode | The mode of the key that made the request: sandbox or production. |
401
The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account.
{
"error": {
"code": "unauthorized",
"message": "Missing or invalid API key.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}403
The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope).
{
"error": {
"code": "forbidden",
"message": "This account does not have Email Center active. Turn it on in the portal.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"reason": "email_account_required"
}
}
}404
Not found.
{
"error": {
"code": "not_found",
"message": "Not found.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}422
Some of the data is not valid.
{
"error": {
"code": "validation_failed",
"message": "Some of the data is not valid.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}429
Too many requests. Wait for the time in Retry-After.
{
"error": {
"code": "rate_limited",
"message": "Too many requests. Please try again shortly.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"retry_after": 42
}
}
}| Header | Description |
|---|---|
Retry-After | Seconds to wait before trying again. |
500
An internal error occurred. Give the correlation_id to support.
{
"error": {
"code": "internal_error",
"message": "An internal error occurred. Please give the correlation_id to support.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}503
The API is turned off.
{
"error": {
"code": "disabled",
"message": "The API is currently turned off.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}Errors
| Status | Code | Meaning |
|---|---|---|
| 401 | unauthorized | The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account. |
| 403 | forbidden, insufficient_scope | The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope). |
| 404 | not_found | Not found. |
| 422 | validation_failed | Some of the data is not valid. |
| 429 | rate_limited | Too many requests. Wait for the time in Retry-After. |
| 500 | internal_error | An internal error occurred. Give the correlation_id to support. |
| 503 | disabled | The API is turned off. |
The error format is explained in Errors.
POSTSend a test of a campaign
/v1/email/campaigns/{id}/test
https://api.interweb.co.mz/v1/email/campaigns/{id}/testNeeds email_center:write. One email to one address, with example variables and «[Test]» in the subject; it costs one credit, like any email.
Authentication
Needs a valid key in the Authorization: Bearer header. Required permission: email_center:write.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | yes | The campaign id. |
Idempotency-Key | header | string | no | Any unique value, up to 255 visible characters. Valid for 24 hours per key. Repeating the same request returns the saved answer; a different body, or a first request still in progress, returns 409. |
X-API-Mode | header | string: sandbox, production | no | Optional. If it does not match the mode of the key, the request is refused with invalid_request and reason mode_mismatch. Use it to make sure a program never runs with the wrong key. |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
to | string | yes |
Examples
curl
curl -X POST "https://api.interweb.co.mz/v1/email/campaigns/00000000-0000-4000-8000-000000000000/test" \
-H "Authorization: Bearer $RLX_API_KEY" \
-H "Accept-Language: en" \
-H "Idempotency-Key: 9f1c2d3e-example" \
-H "Content-Type: application/json" \
-d '{"to": "[email protected]"}'PHP
<?php
$ch = curl_init('https://api.interweb.co.mz/v1/email/campaigns/00000000-0000-4000-8000-000000000000/test');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_POSTFIELDS => '{"to": "[email protected]"}',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('RLX_API_KEY'),
'Accept-Language: en',
'Idempotency-Key: 9f1c2d3e-example',
'Content-Type: application/json',
],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo $status, PHP_EOL, $body, PHP_EOL;Python
import os
import requests
headers = {
"Authorization": "Bearer " + os.environ["RLX_API_KEY"],
"Accept-Language": "en",
"Idempotency-Key": "9f1c2d3e-example",
}
payload = {"to": "[email protected]"}
r = requests.post("https://api.interweb.co.mz/v1/email/campaigns/00000000-0000-4000-8000-000000000000/test", headers=headers, json=payload, timeout=30)
print(r.status_code)
print(r.text)JavaScript
const response = await fetch("https://api.interweb.co.mz/v1/email/campaigns/00000000-0000-4000-8000-000000000000/test", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.RLX_API_KEY}`,
"Accept-Language": "en",
"Idempotency-Key": "9f1c2d3e-example",
"Content-Type": "application/json",
},
body: JSON.stringify({"to": "[email protected]"}),
});
console.log(response.status);
console.log(await response.text());Responses
201
Send a test of a campaign.
{
"data": {
"id": "5130",
"status": "sent"
},
"meta": {}
}| Field | Type | Description |
|---|---|---|
data.recipients | integer | Recipients after the suppression list; each one is one credit. |
data.source | string | portal, api or smtp. |
| Header | Description |
|---|---|
X-Correlation-ID | Identifier of this request. Give it to support when you report a problem. |
X-RateLimit-Limit | Requests allowed per minute. |
X-RateLimit-Remaining | Requests left in the current minute. |
X-RateLimit-Reset | When the minute ends, as a Unix timestamp in seconds. |
X-API-Mode | The mode of the key that made the request: sandbox or production. |
401
The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account.
{
"error": {
"code": "unauthorized",
"message": "Missing or invalid API key.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}403
The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope).
{
"error": {
"code": "forbidden",
"message": "This account does not have Email Center active. Turn it on in the portal.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"reason": "email_account_required"
}
}
}404
Not found.
{
"error": {
"code": "not_found",
"message": "Not found.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}422
Some of the data is not valid.
{
"error": {
"code": "validation_failed",
"message": "Some of the data is not valid.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}429
Too many requests. Wait for the time in Retry-After.
{
"error": {
"code": "rate_limited",
"message": "Too many requests. Please try again shortly.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"retry_after": 42
}
}
}| Header | Description |
|---|---|
Retry-After | Seconds to wait before trying again. |
500
An internal error occurred. Give the correlation_id to support.
{
"error": {
"code": "internal_error",
"message": "An internal error occurred. Please give the correlation_id to support.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}503
The API is turned off.
{
"error": {
"code": "disabled",
"message": "The API is currently turned off.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}Errors
| Status | Code | Meaning |
|---|---|---|
| 401 | unauthorized | The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account. |
| 403 | forbidden, insufficient_scope | The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope). |
| 404 | not_found | Not found. |
| 422 | validation_failed | Some of the data is not valid. |
| 429 | rate_limited | Too many requests. Wait for the time in Retry-After. |
| 500 | internal_error | An internal error occurred. Give the correlation_id to support. |
| 503 | disabled | The API is turned off. |
The error format is explained in Errors.
GETList email contacts
/v1/email/contacts
https://api.interweb.co.mz/v1/email/contactsNeeds email_center:read. The SMS contacts that have an email address and the email-only contacts, without repeated addresses, with the subscription status.
Authentication
Needs a valid key in the Authorization: Bearer header. Required permission: email_center:read.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
group | query | string | no | Group id. |
subscription | query | string | no | subscribed, unsubscribed or suppressed. |
opened | query | string | no | yes or no. |
clicked | query | string | no | yes or no. |
joined_from | query | string | no | YYYY-MM-DD. |
joined_to | query | string | no | YYYY-MM-DD. |
q | query | string | no | Search. |
page | query | integer | no | The page number. The first is 1. |
per_page | query | integer | no | Results per page, from 1 to 100. The default is 10. |
X-API-Mode | header | string: sandbox, production | no | Optional. If it does not match the mode of the key, the request is refused with invalid_request and reason mode_mismatch. Use it to make sure a program never runs with the wrong key. |
Examples
curl
curl "https://api.interweb.co.mz/v1/email/contacts" \
-H "Authorization: Bearer $RLX_API_KEY" \
-H "Accept-Language: en"PHP
<?php
$ch = curl_init('https://api.interweb.co.mz/v1/email/contacts');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('RLX_API_KEY'),
'Accept-Language: en',
],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo $status, PHP_EOL, $body, PHP_EOL;Python
import os
import requests
headers = {
"Authorization": "Bearer " + os.environ["RLX_API_KEY"],
"Accept-Language": "en",
}
r = requests.get("https://api.interweb.co.mz/v1/email/contacts", headers=headers, timeout=30)
print(r.status_code)
print(r.text)JavaScript
const response = await fetch("https://api.interweb.co.mz/v1/email/contacts", {
headers: {
Authorization: `Bearer ${process.env.RLX_API_KEY}`,
"Accept-Language": "en",
},
});
console.log(response.status);
console.log(await response.text());Responses
200
List email contacts.
{
"data": [
{
"email": "[email protected]",
"name": "Ana",
"company": "Example Ltd",
"source": "email_contact",
"subscription": "subscribed",
"created_at": "2026-11-12T09:00:00+02:00"
}
],
"meta": {
"page": 1,
"per_page": 10,
"total": 1,
"total_pages": 1
}
}| Header | Description |
|---|---|
X-Correlation-ID | Identifier of this request. Give it to support when you report a problem. |
X-RateLimit-Limit | Requests allowed per minute. |
X-RateLimit-Remaining | Requests left in the current minute. |
X-RateLimit-Reset | When the minute ends, as a Unix timestamp in seconds. |
X-API-Mode | The mode of the key that made the request: sandbox or production. |
401
The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account.
{
"error": {
"code": "unauthorized",
"message": "Missing or invalid API key.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}403
The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope).
{
"error": {
"code": "forbidden",
"message": "This account does not have Email Center active. Turn it on in the portal.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"reason": "email_account_required"
}
}
}422
Some of the data is not valid.
{
"error": {
"code": "validation_failed",
"message": "Some of the data is not valid.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}429
Too many requests. Wait for the time in Retry-After.
{
"error": {
"code": "rate_limited",
"message": "Too many requests. Please try again shortly.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"retry_after": 42
}
}
}| Header | Description |
|---|---|
Retry-After | Seconds to wait before trying again. |
500
An internal error occurred. Give the correlation_id to support.
{
"error": {
"code": "internal_error",
"message": "An internal error occurred. Please give the correlation_id to support.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}503
The API is turned off.
{
"error": {
"code": "disabled",
"message": "The API is currently turned off.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}Errors
| Status | Code | Meaning |
|---|---|---|
| 401 | unauthorized | The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account. |
| 403 | forbidden, insufficient_scope | The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope). |
| 422 | validation_failed | Some of the data is not valid. |
| 429 | rate_limited | Too many requests. Wait for the time in Retry-After. |
| 500 | internal_error | An internal error occurred. Give the correlation_id to support. |
| 503 | disabled | The API is turned off. |
The error format is explained in Errors.
POSTAdd an email contact
/v1/email/contacts
https://api.interweb.co.mz/v1/email/contactsNeeds email_center:write. If the address already belongs to an SMS contact, that contact is used and joins the groups. You confirm that the person agreed to receive your emails.
Authentication
Needs a valid key in the Authorization: Bearer header. Required permission: email_center:write.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
Idempotency-Key | header | string | no | Any unique value, up to 255 visible characters. Valid for 24 hours per key. Repeating the same request returns the saved answer; a different body, or a first request still in progress, returns 409. |
X-API-Mode | header | string: sandbox, production | no | Optional. If it does not match the mode of the key, the request is refused with invalid_request and reason mode_mismatch. Use it to make sure a program never runs with the wrong key. |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
email | string | yes | |
name | string | no | |
company | string | no | |
groups | array<integer> | no | |
subscription | string | no | subscribed (default) or unsubscribed. |
Examples
curl
curl -X POST "https://api.interweb.co.mz/v1/email/contacts" \
-H "Authorization: Bearer $RLX_API_KEY" \
-H "Accept-Language: en" \
-H "Idempotency-Key: 9f1c2d3e-example" \
-H "Content-Type: application/json" \
-d '{"email": "[email protected]", "name": "Ana", "groups": [3]}'PHP
<?php
$ch = curl_init('https://api.interweb.co.mz/v1/email/contacts');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_POSTFIELDS => '{"email": "[email protected]", "name": "Ana", "groups": [3]}',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('RLX_API_KEY'),
'Accept-Language: en',
'Idempotency-Key: 9f1c2d3e-example',
'Content-Type: application/json',
],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo $status, PHP_EOL, $body, PHP_EOL;Python
import os
import requests
headers = {
"Authorization": "Bearer " + os.environ["RLX_API_KEY"],
"Accept-Language": "en",
"Idempotency-Key": "9f1c2d3e-example",
}
payload = {"email": "[email protected]", "name": "Ana", "groups": [3]}
r = requests.post("https://api.interweb.co.mz/v1/email/contacts", headers=headers, json=payload, timeout=30)
print(r.status_code)
print(r.text)JavaScript
const response = await fetch("https://api.interweb.co.mz/v1/email/contacts", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.RLX_API_KEY}`,
"Accept-Language": "en",
"Idempotency-Key": "9f1c2d3e-example",
"Content-Type": "application/json",
},
body: JSON.stringify({"email": "[email protected]", "name": "Ana", "groups": [3]}),
});
console.log(response.status);
console.log(await response.text());Responses
201
Add an email contact.
{
"data": {
"email": "[email protected]",
"name": "Ana",
"company": "Example Ltd",
"source": "email_contact",
"subscription": "subscribed",
"created_at": "2026-11-12T09:00:00+02:00",
"created": true,
"simulated": false
},
"meta": {}
}| Header | Description |
|---|---|
X-Correlation-ID | Identifier of this request. Give it to support when you report a problem. |
X-RateLimit-Limit | Requests allowed per minute. |
X-RateLimit-Remaining | Requests left in the current minute. |
X-RateLimit-Reset | When the minute ends, as a Unix timestamp in seconds. |
X-API-Mode | The mode of the key that made the request: sandbox or production. |
401
The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account.
{
"error": {
"code": "unauthorized",
"message": "Missing or invalid API key.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}403
The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope).
{
"error": {
"code": "forbidden",
"message": "This account does not have Email Center active. Turn it on in the portal.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"reason": "email_account_required"
}
}
}422
Some of the data is not valid.
{
"error": {
"code": "validation_failed",
"message": "Some of the data is not valid.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}429
Too many requests. Wait for the time in Retry-After.
{
"error": {
"code": "rate_limited",
"message": "Too many requests. Please try again shortly.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"retry_after": 42
}
}
}| Header | Description |
|---|---|
Retry-After | Seconds to wait before trying again. |
500
An internal error occurred. Give the correlation_id to support.
{
"error": {
"code": "internal_error",
"message": "An internal error occurred. Please give the correlation_id to support.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}503
The API is turned off.
{
"error": {
"code": "disabled",
"message": "The API is currently turned off.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}Errors
| Status | Code | Meaning |
|---|---|---|
| 401 | unauthorized | The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account. |
| 403 | forbidden, insufficient_scope | The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope). |
| 422 | validation_failed | Some of the data is not valid. |
| 429 | rate_limited | Too many requests. Wait for the time in Retry-After. |
| 500 | internal_error | An internal error occurred. Give the correlation_id to support. |
| 503 | disabled | The API is turned off. |
The error format is explained in Errors.
GETSee an email contact
/v1/email/contacts/{email}
https://api.interweb.co.mz/v1/email/contacts/{email}Needs email_center:read. With the latest campaigns it received and what it did.
Authentication
Needs a valid key in the Authorization: Bearer header. Required permission: email_center:read.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
email | path | string | yes | The address, URL-encoded. |
X-API-Mode | header | string: sandbox, production | no | Optional. If it does not match the mode of the key, the request is refused with invalid_request and reason mode_mismatch. Use it to make sure a program never runs with the wrong key. |
Examples
curl
curl "https://api.interweb.co.mz/v1/email/contacts/VALUE" \
-H "Authorization: Bearer $RLX_API_KEY" \
-H "Accept-Language: en"PHP
<?php
$ch = curl_init('https://api.interweb.co.mz/v1/email/contacts/VALUE');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('RLX_API_KEY'),
'Accept-Language: en',
],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo $status, PHP_EOL, $body, PHP_EOL;Python
import os
import requests
headers = {
"Authorization": "Bearer " + os.environ["RLX_API_KEY"],
"Accept-Language": "en",
}
r = requests.get("https://api.interweb.co.mz/v1/email/contacts/VALUE", headers=headers, timeout=30)
print(r.status_code)
print(r.text)JavaScript
const response = await fetch("https://api.interweb.co.mz/v1/email/contacts/VALUE", {
headers: {
Authorization: `Bearer ${process.env.RLX_API_KEY}`,
"Accept-Language": "en",
},
});
console.log(response.status);
console.log(await response.text());Responses
200
See an email contact.
{
"data": {
"email": "[email protected]",
"name": "Ana",
"company": "Example Ltd",
"source": "email_contact",
"subscription": "subscribed",
"created_at": "2026-11-12T09:00:00+02:00",
"campaigns": [
{
"campaign_id": 41,
"sent_at": "2026-11-12T10:30:00+02:00",
"opened": true,
"clicked": false,
"unsubscribed": false,
"simulated": false
}
]
},
"meta": {}
}| Header | Description |
|---|---|
X-Correlation-ID | Identifier of this request. Give it to support when you report a problem. |
X-RateLimit-Limit | Requests allowed per minute. |
X-RateLimit-Remaining | Requests left in the current minute. |
X-RateLimit-Reset | When the minute ends, as a Unix timestamp in seconds. |
X-API-Mode | The mode of the key that made the request: sandbox or production. |
401
The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account.
{
"error": {
"code": "unauthorized",
"message": "Missing or invalid API key.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}403
The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope).
{
"error": {
"code": "forbidden",
"message": "This account does not have Email Center active. Turn it on in the portal.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"reason": "email_account_required"
}
}
}404
Not found.
{
"error": {
"code": "not_found",
"message": "Not found.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}429
Too many requests. Wait for the time in Retry-After.
{
"error": {
"code": "rate_limited",
"message": "Too many requests. Please try again shortly.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"retry_after": 42
}
}
}| Header | Description |
|---|---|
Retry-After | Seconds to wait before trying again. |
500
An internal error occurred. Give the correlation_id to support.
{
"error": {
"code": "internal_error",
"message": "An internal error occurred. Please give the correlation_id to support.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}503
The API is turned off.
{
"error": {
"code": "disabled",
"message": "The API is currently turned off.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}Errors
| Status | Code | Meaning |
|---|---|---|
| 401 | unauthorized | The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account. |
| 403 | forbidden, insufficient_scope | The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope). |
| 404 | not_found | Not found. |
| 429 | rate_limited | Too many requests. Wait for the time in Retry-After. |
| 500 | internal_error | An internal error occurred. Give the correlation_id to support. |
| 503 | disabled | The API is turned off. |
The error format is explained in Errors.
PUTChange a subscription
/v1/email/contacts/{email}/subscription
https://api.interweb.co.mz/v1/email/contacts/{email}/subscriptionNeeds email_center:write. subscribed or unsubscribed. Contacts who unsubscribed through the link should only be subscribed again with their consent.
Authentication
Needs a valid key in the Authorization: Bearer header. Required permission: email_center:write.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
email | path | string | yes | The address, URL-encoded. |
X-API-Mode | header | string: sandbox, production | no | Optional. If it does not match the mode of the key, the request is refused with invalid_request and reason mode_mismatch. Use it to make sure a program never runs with the wrong key. |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
status | string | yes |
Examples
curl
curl -X PUT "https://api.interweb.co.mz/v1/email/contacts/VALUE/subscription" \
-H "Authorization: Bearer $RLX_API_KEY" \
-H "Accept-Language: en" \
-H "Content-Type: application/json" \
-d '{"status": "unsubscribed"}'PHP
<?php
$ch = curl_init('https://api.interweb.co.mz/v1/email/contacts/VALUE/subscription');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'PUT',
CURLOPT_POSTFIELDS => '{"status": "unsubscribed"}',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('RLX_API_KEY'),
'Accept-Language: en',
'Content-Type: application/json',
],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo $status, PHP_EOL, $body, PHP_EOL;Python
import os
import requests
headers = {
"Authorization": "Bearer " + os.environ["RLX_API_KEY"],
"Accept-Language": "en",
}
payload = {"status": "unsubscribed"}
r = requests.put("https://api.interweb.co.mz/v1/email/contacts/VALUE/subscription", headers=headers, json=payload, timeout=30)
print(r.status_code)
print(r.text)JavaScript
const response = await fetch("https://api.interweb.co.mz/v1/email/contacts/VALUE/subscription", {
method: "PUT",
headers: {
Authorization: `Bearer ${process.env.RLX_API_KEY}`,
"Accept-Language": "en",
"Content-Type": "application/json",
},
body: JSON.stringify({"status": "unsubscribed"}),
});
console.log(response.status);
console.log(await response.text());Responses
200
Change a subscription.
{
"data": {
"email": "[email protected]",
"subscription": "unsubscribed",
"simulated": false
},
"meta": {}
}| Header | Description |
|---|---|
X-Correlation-ID | Identifier of this request. Give it to support when you report a problem. |
X-RateLimit-Limit | Requests allowed per minute. |
X-RateLimit-Remaining | Requests left in the current minute. |
X-RateLimit-Reset | When the minute ends, as a Unix timestamp in seconds. |
X-API-Mode | The mode of the key that made the request: sandbox or production. |
401
The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account.
{
"error": {
"code": "unauthorized",
"message": "Missing or invalid API key.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}403
The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope).
{
"error": {
"code": "forbidden",
"message": "This account does not have Email Center active. Turn it on in the portal.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"reason": "email_account_required"
}
}
}404
Not found.
{
"error": {
"code": "not_found",
"message": "Not found.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}422
Some of the data is not valid.
{
"error": {
"code": "validation_failed",
"message": "Some of the data is not valid.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}429
Too many requests. Wait for the time in Retry-After.
{
"error": {
"code": "rate_limited",
"message": "Too many requests. Please try again shortly.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"retry_after": 42
}
}
}| Header | Description |
|---|---|
Retry-After | Seconds to wait before trying again. |
500
An internal error occurred. Give the correlation_id to support.
{
"error": {
"code": "internal_error",
"message": "An internal error occurred. Please give the correlation_id to support.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}503
The API is turned off.
{
"error": {
"code": "disabled",
"message": "The API is currently turned off.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}Errors
| Status | Code | Meaning |
|---|---|---|
| 401 | unauthorized | The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account. |
| 403 | forbidden, insufficient_scope | The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope). |
| 404 | not_found | Not found. |
| 422 | validation_failed | Some of the data is not valid. |
| 429 | rate_limited | Too many requests. Wait for the time in Retry-After. |
| 500 | internal_error | An internal error occurred. Give the correlation_id to support. |
| 503 | disabled | The API is turned off. |
The error format is explained in Errors.
GETList contact groups
/v1/email/groups
https://api.interweb.co.mz/v1/email/groupsNeeds email_center:read. The same groups as the SMS contacts, with how many have an email address.
Authentication
Needs a valid key in the Authorization: Bearer header. Required permission: email_center:read.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-API-Mode | header | string: sandbox, production | no | Optional. If it does not match the mode of the key, the request is refused with invalid_request and reason mode_mismatch. Use it to make sure a program never runs with the wrong key. |
Examples
curl
curl "https://api.interweb.co.mz/v1/email/groups" \
-H "Authorization: Bearer $RLX_API_KEY" \
-H "Accept-Language: en"PHP
<?php
$ch = curl_init('https://api.interweb.co.mz/v1/email/groups');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('RLX_API_KEY'),
'Accept-Language: en',
],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo $status, PHP_EOL, $body, PHP_EOL;Python
import os
import requests
headers = {
"Authorization": "Bearer " + os.environ["RLX_API_KEY"],
"Accept-Language": "en",
}
r = requests.get("https://api.interweb.co.mz/v1/email/groups", headers=headers, timeout=30)
print(r.status_code)
print(r.text)JavaScript
const response = await fetch("https://api.interweb.co.mz/v1/email/groups", {
headers: {
Authorization: `Bearer ${process.env.RLX_API_KEY}`,
"Accept-Language": "en",
},
});
console.log(response.status);
console.log(await response.text());Responses
200
List contact groups.
{
"data": [
{
"id": 3,
"name": "Customers",
"contacts": 1200
}
],
"meta": {
"total": 1
}
}| Header | Description |
|---|---|
X-Correlation-ID | Identifier of this request. Give it to support when you report a problem. |
X-RateLimit-Limit | Requests allowed per minute. |
X-RateLimit-Remaining | Requests left in the current minute. |
X-RateLimit-Reset | When the minute ends, as a Unix timestamp in seconds. |
X-API-Mode | The mode of the key that made the request: sandbox or production. |
401
The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account.
{
"error": {
"code": "unauthorized",
"message": "Missing or invalid API key.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}403
The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope).
{
"error": {
"code": "forbidden",
"message": "This account does not have Email Center active. Turn it on in the portal.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"reason": "email_account_required"
}
}
}429
Too many requests. Wait for the time in Retry-After.
{
"error": {
"code": "rate_limited",
"message": "Too many requests. Please try again shortly.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {
"retry_after": 42
}
}
}| Header | Description |
|---|---|
Retry-After | Seconds to wait before trying again. |
500
An internal error occurred. Give the correlation_id to support.
{
"error": {
"code": "internal_error",
"message": "An internal error occurred. Please give the correlation_id to support.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}503
The API is turned off.
{
"error": {
"code": "disabled",
"message": "The API is currently turned off.",
"correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
"details": {}
}
}Errors
| Status | Code | Meaning |
|---|---|---|
| 401 | unauthorized | The key is missing, invalid, revoked or expired, or the user who created it no longer has access to the account. |
| 403 | forbidden, insufficient_scope | The account does not have Email Center active (forbidden, details.reason = email_account_required), or the key lacks the permission (insufficient_scope). |
| 429 | rate_limited | Too many requests. Wait for the time in Retry-After. |
| 500 | internal_error | An internal error occurred. Give the correlation_id to support. |
| 503 | disabled | The API is turned off. |
The error format is explained in Errors.
No operation found.