# Email

Manage the mailboxes of a hosting account through the API: passwords, quotas, forwarders, autoresponders, default address, SPF, DKIM and DMARC.

Updated on 5 November 2026

The API manages the email of the active hosting accounts of your account. Everything runs in the account of the service given in `{id}`. To find the `id`, use [`GET /v1/services`](https://docs.interweb.ao/en/hosting.md).

## What you need

A key with `email:read` to read, and `email:write` to change. With a `sandbox_` key, or while the API is being prepared, changes are simulated: the API checks the request and does not reach the server. See [Sandbox and Production](https://docs.interweb.ao/en/api-rules.md). A service that is not active answers `409`, as in [Hosting](https://docs.interweb.ao/en/hosting.md).

## Mailboxes

- [`GET /v1/services/{id}/email/mailboxes`](https://docs.interweb.ao/en/email.md) lists the mailboxes, with the space used and the quota.
- [`POST /v1/services/{id}/email/mailboxes`](https://docs.interweb.ao/en/email.md) creates a mailbox.
- [`PUT /v1/services/{id}/email/mailboxes/{address}/password`](https://docs.interweb.ao/en/email.md) changes the password.
- [`PUT /v1/services/{id}/email/mailboxes/{address}/quota`](https://docs.interweb.ao/en/email.md) changes the quota.
- [`DELETE /v1/services/{id}/email/mailboxes/{address}`](https://docs.interweb.ao/en/email.md) deletes a mailbox and its messages. It needs the address in `confirm`.

**curl**

```bash
curl -X POST "https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/mailboxes" \
  -H "Authorization: Bearer $RLX_API_KEY" \
  -H "Accept-Language: en" \
  -H "Idempotency-Key: 9f1c2d3e-example" \
  -H "Content-Type: application/json" \
  -d '{"address": "info@example.com", "password": "pP7-kX2mQ9vL4tR8wZ3a", "quota_mb": 1024}'
```

**PHP**

```php
<?php
$ch = curl_init('https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/mailboxes');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_POSTFIELDS => '{"address": "info@example.com", "password": "pP7-kX2mQ9vL4tR8wZ3a", "quota_mb": 1024}',
    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**

```python
import os
import requests

headers = {
    "Authorization": "Bearer " + os.environ["RLX_API_KEY"],
    "Accept-Language": "en",
    "Idempotency-Key": "9f1c2d3e-example",
}
payload = {"address": "info@example.com", "password": "pP7-kX2mQ9vL4tR8wZ3a", "quota_mb": 1024}
r = requests.post("https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/mailboxes", headers=headers, json=payload, timeout=30)
print(r.status_code)
print(r.text)
```

**JavaScript**

```javascript
const response = await fetch("https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/mailboxes", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.RLX_API_KEY}`,
    "Accept-Language": "en",
    "Idempotency-Key": "9f1c2d3e-example",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({"address": "info@example.com", "password": "pP7-kX2mQ9vL4tR8wZ3a", "quota_mb": 1024}),
});
console.log(response.status);
console.log(await response.text());
```


The password has 12 to 128 characters, with at least 3 kinds among lowercase, uppercase, digits and symbols, without the account or mailbox name. System names of the server, such as `_mainaccount`, are not accepted. The API never keeps it or returns it. For that reason, in requests with a password, the `Idempotency-Key` is not kept. The quota goes from 1 MB to the disk space of the plan; unlimited is not accepted.

## Forwarders

[`GET /v1/services/{id}/email/forwarders`](https://docs.interweb.ao/en/email.md), [`POST /v1/services/{id}/email/forwarders`](https://docs.interweb.ao/en/email.md) and [`DELETE /v1/services/{id}/email/forwarders/{address}/{forward_to}`](https://docs.interweb.ao/en/email.md) manage forwarders. Mail only forwards to email addresses, never to programs. The list is for one domain: use `?domain=`, or it uses the main one.

## The domain of the account email

The email used to log in to the account receives the password reset and the login code. Anyone who controls that mail can take over the account. So, on the domain of that email and on the domain of the email of each user of the account, the API does not create, delete or change mailboxes, does not create or delete forwarders and does not change the default address.

These requests answer `409` with the code `account_email_domain`, also in Sandbox. Make these changes in the [Meu Interweb](https://www.meu.interweb.ao/clientarea.php?language=english&currency=2). Reads and autoresponders keep working. The `hosting:login` and `hosting:code` permissions give access to the cPanel account and do not have this protection: give them only to keys that really need them.

## Autoresponders

[`GET /v1/services/{id}/email/autoresponders`](https://docs.interweb.ao/en/email.md) lists, [`GET /v1/services/{id}/email/autoresponders/{address}`](https://docs.interweb.ao/en/email.md) shows one, [`PUT /v1/services/{id}/email/autoresponders/{address}`](https://docs.interweb.ao/en/email.md) creates or replaces and [`DELETE /v1/services/{id}/email/autoresponders/{address}`](https://docs.interweb.ao/en/email.md) deletes.

## Default address

The default address decides what happens to mail for addresses that do not exist. [`GET /v1/services/{id}/email/default-address`](https://docs.interweb.ao/en/email.md) reads and [`PUT /v1/services/{id}/email/default-address`](https://docs.interweb.ao/en/email.md) changes, with `action` set to `fail` (returns it), `forward` (forwards it), `discard` (throws it away) or `main_account` (delivers it to the main account of the hosting service, as on a new account). We recommend `fail`, to receive less spam.

## SPF, DKIM and DMARC

[`GET /v1/services/{id}/email/authentication`](https://docs.interweb.ao/en/email.md) shows the state of the three records of a domain. To change them, use [DNS](https://docs.interweb.ao/en/dns.md).

## Limits

Changes have a limit of 20 per minute, per hosting account, and passwords 10 per minute, on top of the [general limit](https://docs.interweb.ao/en/api-rules.md).

## Not available yet

Email filters and the delivery log are done in the panel.

## Help

To learn more about email, see the [Knowledge Base](https://www.meu.interweb.ao/knowledgebase?language=english&currency=2).


## Operations

15 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.

### List mailboxes

`GET https://api.interweb.ao/v1/services/{id}/email/mailboxes`

Needs `email:read`. `quota_mb` is `null` when the mailbox has no limit of its own. If the service is not active, or is not a supported hosting account, it answers `409` with the reason in `details.reason`.

#### Authentication

Needs a valid key in the `Authorization: Bearer` header. Required permission: `email:read`.

#### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `id` | path | string | yes | The `id` of the hosting service. |
| `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**

```bash
curl "https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/mailboxes" \
  -H "Authorization: Bearer $RLX_API_KEY" \
  -H "Accept-Language: en"
```

**PHP**

```php
<?php
$ch = curl_init('https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/mailboxes');
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**

```python
import os
import requests

headers = {
    "Authorization": "Bearer " + os.environ["RLX_API_KEY"],
    "Accept-Language": "en",
}
r = requests.get("https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/mailboxes", headers=headers, timeout=30)
print(r.status_code)
print(r.text)
```

**JavaScript**

```javascript
const response = await fetch("https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/mailboxes", {
  headers: {
    Authorization: `Bearer ${process.env.RLX_API_KEY}`,
    "Accept-Language": "en",
  },
});
console.log(response.status);
console.log(await response.text());
```


#### Responses

##### `200`

List mailboxes.

```json
{
  "data": [
    {
      "address": "info@example.com",
      "used_mb": 12.5,
      "quota_mb": 1024
    }
  ],
  "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.

```json
{
  "error": {
    "code": "unauthorized",
    "message": "Missing or invalid API key.",
    "correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
    "details": {}
  }
}
```

##### `403`

The account cannot use the API (`forbidden`), the key lacks the permission (`insufficient_scope`), or the IP address is not on the list of the key (`ip_not_allowed`).

```json
{
  "error": {
    "code": "insufficient_scope",
    "message": "This key does not have the required permission.",
    "correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
    "details": {
      "required": "dns:read"
    }
  }
}
```

##### `404`

Not found.

```json
{
  "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`.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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`, `ip_not_allowed` | The account cannot use the API (`forbidden`), the key lacks the permission (`insufficient_scope`), or the IP address is not on the list of the key (`ip_not_allowed`). |
| 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. |
| 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](https://docs.interweb.ao/en/api-rules.md).


### Create a mailbox

`POST https://api.interweb.ao/v1/services/{id}/email/mailboxes`

Needs `email:write`. System names of the server, such as `_mainaccount`, are not accepted. The domain must be of this hosting account. The password is never stored by the API, so `Idempotency-Key` is not kept here. With a `sandbox_` key it only checks the request and changes nothing. On the domain of the account email, or of the email of a user of the account, it answers `409` with the code `account_email_domain`: make the change in the account portal.

#### Authentication

Needs a valid key in the `Authorization: Bearer` header. Required permission: `email:write`.

#### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `id` | path | string | yes | The `id` of the hosting service. |
| `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 |
|---|---|---|---|
| `address` | string | yes | The full email address. |
| `password` | string | yes | 12 to 128 characters, with at least 3 kinds among lowercase, uppercase, digits and symbols, without the account name. It never comes back. |
| `quota_mb` | integer | no | In MB, from 1 to the disk space of the plan. Unlimited is not accepted. |

#### Examples

**curl**

```bash
curl -X POST "https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/mailboxes" \
  -H "Authorization: Bearer $RLX_API_KEY" \
  -H "Accept-Language: en" \
  -H "Idempotency-Key: 9f1c2d3e-example" \
  -H "Content-Type: application/json" \
  -d '{"address": "info@example.com", "password": "pP7-kX2mQ9vL4tR8wZ3a", "quota_mb": 1024}'
```

**PHP**

```php
<?php
$ch = curl_init('https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/mailboxes');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_POSTFIELDS => '{"address": "info@example.com", "password": "pP7-kX2mQ9vL4tR8wZ3a", "quota_mb": 1024}',
    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**

```python
import os
import requests

headers = {
    "Authorization": "Bearer " + os.environ["RLX_API_KEY"],
    "Accept-Language": "en",
    "Idempotency-Key": "9f1c2d3e-example",
}
payload = {"address": "info@example.com", "password": "pP7-kX2mQ9vL4tR8wZ3a", "quota_mb": 1024}
r = requests.post("https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/mailboxes", headers=headers, json=payload, timeout=30)
print(r.status_code)
print(r.text)
```

**JavaScript**

```javascript
const response = await fetch("https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/mailboxes", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.RLX_API_KEY}`,
    "Accept-Language": "en",
    "Idempotency-Key": "9f1c2d3e-example",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({"address": "info@example.com", "password": "pP7-kX2mQ9vL4tR8wZ3a", "quota_mb": 1024}),
});
console.log(response.status);
console.log(await response.text());
```


#### Responses

##### `201`

Create a mailbox.

```json
{
  "data": {
    "address": "info@example.com",
    "quota_mb": 1024,
    "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.

```json
{
  "error": {
    "code": "unauthorized",
    "message": "Missing or invalid API key.",
    "correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
    "details": {}
  }
}
```

##### `403`

The account cannot use the API (`forbidden`), the key lacks the permission (`insufficient_scope`), or the IP address is not on the list of the key (`ip_not_allowed`).

```json
{
  "error": {
    "code": "insufficient_scope",
    "message": "This key does not have the required permission.",
    "correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
    "details": {
      "required": "dns:read"
    }
  }
}
```

##### `404`

Not found.

```json
{
  "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`.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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`, `ip_not_allowed` | The account cannot use the API (`forbidden`), the key lacks the permission (`insufficient_scope`), or the IP address is not on the list of the key (`ip_not_allowed`). |
| 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. |
| 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](https://docs.interweb.ao/en/api-rules.md).


### Delete a mailbox

`DELETE https://api.interweb.ao/v1/services/{id}/email/mailboxes/{address}`

Needs `email:write`. Needs the address in `confirm`. The messages are lost. With a `sandbox_` key it only checks the request and changes nothing. On the domain of the account email, or of the email of a user of the account, it answers `409` with the code `account_email_domain`: make the change in the account portal.

#### Authentication

Needs a valid key in the `Authorization: Bearer` header. Required permission: `email:write`.

#### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `id` | path | string | yes | The `id` of the hosting service. |
| `address` | path | string | yes | The full email address. |
| `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 |
|---|---|---|---|
| `confirm` | string | yes | The exact name of what you are deleting, to confirm. |

#### Examples

**curl**

```bash
curl -X DELETE "https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/mailboxes/VALUE" \
  -H "Authorization: Bearer $RLX_API_KEY" \
  -H "Accept-Language: en" \
  -H "Content-Type: application/json" \
  -d '{"confirm": "info@example.com"}'
```

**PHP**

```php
<?php
$ch = curl_init('https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/mailboxes/VALUE');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => 'DELETE',
    CURLOPT_POSTFIELDS => '{"confirm": "info@example.com"}',
    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**

```python
import os
import requests

headers = {
    "Authorization": "Bearer " + os.environ["RLX_API_KEY"],
    "Accept-Language": "en",
}
payload = {"confirm": "info@example.com"}
r = requests.delete("https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/mailboxes/VALUE", headers=headers, json=payload, timeout=30)
print(r.status_code)
print(r.text)
```

**JavaScript**

```javascript
const response = await fetch("https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/mailboxes/VALUE", {
  method: "DELETE",
  headers: {
    Authorization: `Bearer ${process.env.RLX_API_KEY}`,
    "Accept-Language": "en",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({"confirm": "info@example.com"}),
});
console.log(response.status);
console.log(await response.text());
```


#### Responses

##### `200`

Delete a mailbox.

```json
{
  "data": {
    "address": "info@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.

```json
{
  "error": {
    "code": "unauthorized",
    "message": "Missing or invalid API key.",
    "correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
    "details": {}
  }
}
```

##### `403`

The account cannot use the API (`forbidden`), the key lacks the permission (`insufficient_scope`), or the IP address is not on the list of the key (`ip_not_allowed`).

```json
{
  "error": {
    "code": "insufficient_scope",
    "message": "This key does not have the required permission.",
    "correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
    "details": {
      "required": "dns:read"
    }
  }
}
```

##### `404`

Not found.

```json
{
  "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`.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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`, `ip_not_allowed` | The account cannot use the API (`forbidden`), the key lacks the permission (`insufficient_scope`), or the IP address is not on the list of the key (`ip_not_allowed`). |
| 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. |
| 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](https://docs.interweb.ao/en/api-rules.md).


### Change a mailbox password

`PUT https://api.interweb.ao/v1/services/{id}/email/mailboxes/{address}/password`

Needs `email:write`. System names of the server, such as `_mainaccount`, are not accepted. The password never comes back. Limit: 10 per minute per account. With a `sandbox_` key it only checks the request and changes nothing. On the domain of the account email, or of the email of a user of the account, it answers `409` with the code `account_email_domain`: make the change in the account portal.

#### Authentication

Needs a valid key in the `Authorization: Bearer` header. Required permission: `email:write`.

#### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `id` | path | string | yes | The `id` of the hosting service. |
| `address` | path | string | yes | The full email address. |
| `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 |
|---|---|---|---|
| `password` | string | yes | 12 to 128 characters, with at least 3 kinds among lowercase, uppercase, digits and symbols, without the account name. It never comes back. |

#### Examples

**curl**

```bash
curl -X PUT "https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/mailboxes/VALUE/password" \
  -H "Authorization: Bearer $RLX_API_KEY" \
  -H "Accept-Language: en" \
  -H "Content-Type: application/json" \
  -d '{"password": "pP7-kX2mQ9vL4tR8wZ3a"}'
```

**PHP**

```php
<?php
$ch = curl_init('https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/mailboxes/VALUE/password');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => 'PUT',
    CURLOPT_POSTFIELDS => '{"password": "pP7-kX2mQ9vL4tR8wZ3a"}',
    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**

```python
import os
import requests

headers = {
    "Authorization": "Bearer " + os.environ["RLX_API_KEY"],
    "Accept-Language": "en",
}
payload = {"password": "pP7-kX2mQ9vL4tR8wZ3a"}
r = requests.put("https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/mailboxes/VALUE/password", headers=headers, json=payload, timeout=30)
print(r.status_code)
print(r.text)
```

**JavaScript**

```javascript
const response = await fetch("https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/mailboxes/VALUE/password", {
  method: "PUT",
  headers: {
    Authorization: `Bearer ${process.env.RLX_API_KEY}`,
    "Accept-Language": "en",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({"password": "pP7-kX2mQ9vL4tR8wZ3a"}),
});
console.log(response.status);
console.log(await response.text());
```


#### Responses

##### `200`

Change a mailbox password.

```json
{
  "data": {
    "address": "info@example.com",
    "password_changed": 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.

```json
{
  "error": {
    "code": "unauthorized",
    "message": "Missing or invalid API key.",
    "correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
    "details": {}
  }
}
```

##### `403`

The account cannot use the API (`forbidden`), the key lacks the permission (`insufficient_scope`), or the IP address is not on the list of the key (`ip_not_allowed`).

```json
{
  "error": {
    "code": "insufficient_scope",
    "message": "This key does not have the required permission.",
    "correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
    "details": {
      "required": "dns:read"
    }
  }
}
```

##### `404`

Not found.

```json
{
  "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`.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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`, `ip_not_allowed` | The account cannot use the API (`forbidden`), the key lacks the permission (`insufficient_scope`), or the IP address is not on the list of the key (`ip_not_allowed`). |
| 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. |
| 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](https://docs.interweb.ao/en/api-rules.md).


### Change a mailbox quota

`PUT https://api.interweb.ao/v1/services/{id}/email/mailboxes/{address}/quota`

Needs `email:write`. The quota can never go above the disk space of the plan. With a `sandbox_` key it only checks the request and changes nothing. On the domain of the account email, or of the email of a user of the account, it answers `409` with the code `account_email_domain`: make the change in the account portal.

#### Authentication

Needs a valid key in the `Authorization: Bearer` header. Required permission: `email:write`.

#### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `id` | path | string | yes | The `id` of the hosting service. |
| `address` | path | string | yes | The full email address. |
| `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 |
|---|---|---|---|
| `quota_mb` | integer | yes | In MB, from 1 to the disk space of the plan. Unlimited is not accepted. |

#### Examples

**curl**

```bash
curl -X PUT "https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/mailboxes/VALUE/quota" \
  -H "Authorization: Bearer $RLX_API_KEY" \
  -H "Accept-Language: en" \
  -H "Content-Type: application/json" \
  -d '{"quota_mb": 2048}'
```

**PHP**

```php
<?php
$ch = curl_init('https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/mailboxes/VALUE/quota');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => 'PUT',
    CURLOPT_POSTFIELDS => '{"quota_mb": 2048}',
    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**

```python
import os
import requests

headers = {
    "Authorization": "Bearer " + os.environ["RLX_API_KEY"],
    "Accept-Language": "en",
}
payload = {"quota_mb": 2048}
r = requests.put("https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/mailboxes/VALUE/quota", headers=headers, json=payload, timeout=30)
print(r.status_code)
print(r.text)
```

**JavaScript**

```javascript
const response = await fetch("https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/mailboxes/VALUE/quota", {
  method: "PUT",
  headers: {
    Authorization: `Bearer ${process.env.RLX_API_KEY}`,
    "Accept-Language": "en",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({"quota_mb": 2048}),
});
console.log(response.status);
console.log(await response.text());
```


#### Responses

##### `200`

Change a mailbox quota.

```json
{
  "data": {
    "address": "info@example.com",
    "quota_mb": 2048,
    "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.

```json
{
  "error": {
    "code": "unauthorized",
    "message": "Missing or invalid API key.",
    "correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
    "details": {}
  }
}
```

##### `403`

The account cannot use the API (`forbidden`), the key lacks the permission (`insufficient_scope`), or the IP address is not on the list of the key (`ip_not_allowed`).

```json
{
  "error": {
    "code": "insufficient_scope",
    "message": "This key does not have the required permission.",
    "correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
    "details": {
      "required": "dns:read"
    }
  }
}
```

##### `404`

Not found.

```json
{
  "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`.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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`, `ip_not_allowed` | The account cannot use the API (`forbidden`), the key lacks the permission (`insufficient_scope`), or the IP address is not on the list of the key (`ip_not_allowed`). |
| 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. |
| 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](https://docs.interweb.ao/en/api-rules.md).


### List forwarders

`GET https://api.interweb.ao/v1/services/{id}/email/forwarders`

Needs `email:read`. `forward_to` is `null` if the forwarder goes to a program, set in the panel. If the service is not active, or is not a supported hosting account, it answers `409` with the reason in `details.reason`.

#### Authentication

Needs a valid key in the `Authorization: Bearer` header. Required permission: `email:read`.

#### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `id` | path | string | yes | The `id` of the hosting service. |
| `domain` | query | string | no | A domain of this hosting account. If omitted, the main domain. |
| `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**

```bash
curl "https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/forwarders" \
  -H "Authorization: Bearer $RLX_API_KEY" \
  -H "Accept-Language: en"
```

**PHP**

```php
<?php
$ch = curl_init('https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/forwarders');
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**

```python
import os
import requests

headers = {
    "Authorization": "Bearer " + os.environ["RLX_API_KEY"],
    "Accept-Language": "en",
}
r = requests.get("https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/forwarders", headers=headers, timeout=30)
print(r.status_code)
print(r.text)
```

**JavaScript**

```javascript
const response = await fetch("https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/forwarders", {
  headers: {
    Authorization: `Bearer ${process.env.RLX_API_KEY}`,
    "Accept-Language": "en",
  },
});
console.log(response.status);
console.log(await response.text());
```


#### Responses

##### `200`

List forwarders.

```json
{
  "data": [
    {
      "address": "info@example.com",
      "forward_to": "ana@example.com"
    }
  ],
  "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.

```json
{
  "error": {
    "code": "unauthorized",
    "message": "Missing or invalid API key.",
    "correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
    "details": {}
  }
}
```

##### `403`

The account cannot use the API (`forbidden`), the key lacks the permission (`insufficient_scope`), or the IP address is not on the list of the key (`ip_not_allowed`).

```json
{
  "error": {
    "code": "insufficient_scope",
    "message": "This key does not have the required permission.",
    "correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
    "details": {
      "required": "dns:read"
    }
  }
}
```

##### `404`

Not found.

```json
{
  "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`.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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`, `ip_not_allowed` | The account cannot use the API (`forbidden`), the key lacks the permission (`insufficient_scope`), or the IP address is not on the list of the key (`ip_not_allowed`). |
| 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. |
| 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](https://docs.interweb.ao/en/api-rules.md).


### Create a forwarder

`POST https://api.interweb.ao/v1/services/{id}/email/forwarders`

Needs `email:write`. Only to email addresses, never to programs. With a `sandbox_` key it only checks the request and changes nothing. On the domain of the account email, or of the email of a user of the account, it answers `409` with the code `account_email_domain`: make the change in the account portal.

#### Authentication

Needs a valid key in the `Authorization: Bearer` header. Required permission: `email:write`.

#### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `id` | path | string | yes | The `id` of the hosting service. |
| `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 |
|---|---|---|---|
| `address` | string | yes | The full email address. |
| `forward_to` | string | yes | The address it forwards to. |

#### Examples

**curl**

```bash
curl -X POST "https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/forwarders" \
  -H "Authorization: Bearer $RLX_API_KEY" \
  -H "Accept-Language: en" \
  -H "Idempotency-Key: 9f1c2d3e-example" \
  -H "Content-Type: application/json" \
  -d '{"address": "info@example.com", "forward_to": "ana@example.com"}'
```

**PHP**

```php
<?php
$ch = curl_init('https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/forwarders');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_POSTFIELDS => '{"address": "info@example.com", "forward_to": "ana@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**

```python
import os
import requests

headers = {
    "Authorization": "Bearer " + os.environ["RLX_API_KEY"],
    "Accept-Language": "en",
    "Idempotency-Key": "9f1c2d3e-example",
}
payload = {"address": "info@example.com", "forward_to": "ana@example.com"}
r = requests.post("https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/forwarders", headers=headers, json=payload, timeout=30)
print(r.status_code)
print(r.text)
```

**JavaScript**

```javascript
const response = await fetch("https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/forwarders", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.RLX_API_KEY}`,
    "Accept-Language": "en",
    "Idempotency-Key": "9f1c2d3e-example",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({"address": "info@example.com", "forward_to": "ana@example.com"}),
});
console.log(response.status);
console.log(await response.text());
```


#### Responses

##### `201`

Create a forwarder.

```json
{
  "data": {
    "address": "info@example.com",
    "forward_to": "ana@example.com",
    "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.

```json
{
  "error": {
    "code": "unauthorized",
    "message": "Missing or invalid API key.",
    "correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
    "details": {}
  }
}
```

##### `403`

The account cannot use the API (`forbidden`), the key lacks the permission (`insufficient_scope`), or the IP address is not on the list of the key (`ip_not_allowed`).

```json
{
  "error": {
    "code": "insufficient_scope",
    "message": "This key does not have the required permission.",
    "correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
    "details": {
      "required": "dns:read"
    }
  }
}
```

##### `404`

Not found.

```json
{
  "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`.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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`, `ip_not_allowed` | The account cannot use the API (`forbidden`), the key lacks the permission (`insufficient_scope`), or the IP address is not on the list of the key (`ip_not_allowed`). |
| 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. |
| 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](https://docs.interweb.ao/en/api-rules.md).


### Delete a forwarder

`DELETE https://api.interweb.ao/v1/services/{id}/email/forwarders/{address}/{forward_to}`

Needs `email:write`. Give the two addresses in the path. With a `sandbox_` key it only checks the request and changes nothing. On the domain of the account email, or of the email of a user of the account, it answers `409` with the code `account_email_domain`: make the change in the account portal.

#### Authentication

Needs a valid key in the `Authorization: Bearer` header. Required permission: `email:write`.

#### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `id` | path | string | yes | The `id` of the hosting service. |
| `address` | path | string | yes | The full email address. |
| `forward_to` | path | string | yes | The address it forwards to. |
| `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**

```bash
curl -X DELETE "https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/forwarders/VALUE/VALUE" \
  -H "Authorization: Bearer $RLX_API_KEY" \
  -H "Accept-Language: en"
```

**PHP**

```php
<?php
$ch = curl_init('https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/forwarders/VALUE/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**

```python
import os
import requests

headers = {
    "Authorization": "Bearer " + os.environ["RLX_API_KEY"],
    "Accept-Language": "en",
}
r = requests.delete("https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/forwarders/VALUE/VALUE", headers=headers, timeout=30)
print(r.status_code)
print(r.text)
```

**JavaScript**

```javascript
const response = await fetch("https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/forwarders/VALUE/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 forwarder.

```json
{
  "data": {
    "address": "info@example.com",
    "forward_to": "ana@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.

```json
{
  "error": {
    "code": "unauthorized",
    "message": "Missing or invalid API key.",
    "correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
    "details": {}
  }
}
```

##### `403`

The account cannot use the API (`forbidden`), the key lacks the permission (`insufficient_scope`), or the IP address is not on the list of the key (`ip_not_allowed`).

```json
{
  "error": {
    "code": "insufficient_scope",
    "message": "This key does not have the required permission.",
    "correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
    "details": {
      "required": "dns:read"
    }
  }
}
```

##### `404`

Not found.

```json
{
  "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`.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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`, `ip_not_allowed` | The account cannot use the API (`forbidden`), the key lacks the permission (`insufficient_scope`), or the IP address is not on the list of the key (`ip_not_allowed`). |
| 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. |
| 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](https://docs.interweb.ao/en/api-rules.md).


### List autoresponders

`GET https://api.interweb.ao/v1/services/{id}/email/autoresponders`

Needs `email:read`. The autoresponders of one domain. If the service is not active, or is not a supported hosting account, it answers `409` with the reason in `details.reason`.

#### Authentication

Needs a valid key in the `Authorization: Bearer` header. Required permission: `email:read`.

#### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `id` | path | string | yes | The `id` of the hosting service. |
| `domain` | query | string | no | A domain of this hosting account. If omitted, the main domain. |
| `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**

```bash
curl "https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/autoresponders" \
  -H "Authorization: Bearer $RLX_API_KEY" \
  -H "Accept-Language: en"
```

**PHP**

```php
<?php
$ch = curl_init('https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/autoresponders');
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**

```python
import os
import requests

headers = {
    "Authorization": "Bearer " + os.environ["RLX_API_KEY"],
    "Accept-Language": "en",
}
r = requests.get("https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/autoresponders", headers=headers, timeout=30)
print(r.status_code)
print(r.text)
```

**JavaScript**

```javascript
const response = await fetch("https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/autoresponders", {
  headers: {
    Authorization: `Bearer ${process.env.RLX_API_KEY}`,
    "Accept-Language": "en",
  },
});
console.log(response.status);
console.log(await response.text());
```


#### Responses

##### `200`

List autoresponders.

```json
{
  "data": [
    {
      "address": "info@example.com",
      "subject": "Fora do escritório"
    }
  ],
  "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.

```json
{
  "error": {
    "code": "unauthorized",
    "message": "Missing or invalid API key.",
    "correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
    "details": {}
  }
}
```

##### `403`

The account cannot use the API (`forbidden`), the key lacks the permission (`insufficient_scope`), or the IP address is not on the list of the key (`ip_not_allowed`).

```json
{
  "error": {
    "code": "insufficient_scope",
    "message": "This key does not have the required permission.",
    "correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
    "details": {
      "required": "dns:read"
    }
  }
}
```

##### `404`

Not found.

```json
{
  "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`.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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`, `ip_not_allowed` | The account cannot use the API (`forbidden`), the key lacks the permission (`insufficient_scope`), or the IP address is not on the list of the key (`ip_not_allowed`). |
| 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. |
| 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](https://docs.interweb.ao/en/api-rules.md).


### See an autoresponder

`GET https://api.interweb.ao/v1/services/{id}/email/autoresponders/{address}`

Needs `email:read`. With the text and the dates. If the service is not active, or is not a supported hosting account, it answers `409` with the reason in `details.reason`.

#### Authentication

Needs a valid key in the `Authorization: Bearer` header. Required permission: `email:read`.

#### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `id` | path | string | yes | The `id` of the hosting service. |
| `address` | path | string | yes | The full email address. |
| `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**

```bash
curl "https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/autoresponders/VALUE" \
  -H "Authorization: Bearer $RLX_API_KEY" \
  -H "Accept-Language: en"
```

**PHP**

```php
<?php
$ch = curl_init('https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/autoresponders/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**

```python
import os
import requests

headers = {
    "Authorization": "Bearer " + os.environ["RLX_API_KEY"],
    "Accept-Language": "en",
}
r = requests.get("https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/autoresponders/VALUE", headers=headers, timeout=30)
print(r.status_code)
print(r.text)
```

**JavaScript**

```javascript
const response = await fetch("https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/autoresponders/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 autoresponder.

```json
{
  "data": {
    "address": "info@example.com",
    "from": "Info",
    "subject": "Fora do escritório",
    "body": "Volto na segunda.",
    "html": false,
    "interval_hours": 8,
    "start_at": null,
    "stop_at": 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.

```json
{
  "error": {
    "code": "unauthorized",
    "message": "Missing or invalid API key.",
    "correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
    "details": {}
  }
}
```

##### `403`

The account cannot use the API (`forbidden`), the key lacks the permission (`insufficient_scope`), or the IP address is not on the list of the key (`ip_not_allowed`).

```json
{
  "error": {
    "code": "insufficient_scope",
    "message": "This key does not have the required permission.",
    "correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
    "details": {
      "required": "dns:read"
    }
  }
}
```

##### `404`

Not found.

```json
{
  "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`.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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`, `ip_not_allowed` | The account cannot use the API (`forbidden`), the key lacks the permission (`insufficient_scope`), or the IP address is not on the list of the key (`ip_not_allowed`). |
| 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. |
| 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](https://docs.interweb.ao/en/api-rules.md).


### Save an autoresponder

`PUT https://api.interweb.ao/v1/services/{id}/email/autoresponders/{address}`

Needs `email:write`. Creates or replaces the autoresponder of this address. With a `sandbox_` key it only checks the request and changes nothing.

#### Authentication

Needs a valid key in the `Authorization: Bearer` header. Required permission: `email:write`.

#### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `id` | path | string | yes | The `id` of the hosting service. |
| `address` | path | string | yes | The full email address. |
| `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 | The name of the sender, up to 100 characters. |
| `subject` | string | yes | Up to 200 characters. |
| `body` | string | yes | Up to 20000 characters. |
| `html` | boolean | no | If the text is HTML. |
| `interval_hours` | integer | no | Hours between answers to the same sender, from 0 to 720. If omitted, 8. |
| `start_at` | string | no | Start, in ISO 8601. |
| `stop_at` | string | no | End, in ISO 8601. |

#### Examples

**curl**

```bash
curl -X PUT "https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/autoresponders/VALUE" \
  -H "Authorization: Bearer $RLX_API_KEY" \
  -H "Accept-Language: en" \
  -H "Content-Type: application/json" \
  -d '{"from": "Info", "subject": "Fora do escritório", "body": "Volto na segunda."}'
```

**PHP**

```php
<?php
$ch = curl_init('https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/autoresponders/VALUE');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => 'PUT',
    CURLOPT_POSTFIELDS => '{"from": "Info", "subject": "Fora do escritório", "body": "Volto na segunda."}',
    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**

```python
import os
import requests

headers = {
    "Authorization": "Bearer " + os.environ["RLX_API_KEY"],
    "Accept-Language": "en",
}
payload = {"from": "Info", "subject": "Fora do escritório", "body": "Volto na segunda."}
r = requests.put("https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/autoresponders/VALUE", headers=headers, json=payload, timeout=30)
print(r.status_code)
print(r.text)
```

**JavaScript**

```javascript
const response = await fetch("https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/autoresponders/VALUE", {
  method: "PUT",
  headers: {
    Authorization: `Bearer ${process.env.RLX_API_KEY}`,
    "Accept-Language": "en",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({"from": "Info", "subject": "Fora do escritório", "body": "Volto na segunda."}),
});
console.log(response.status);
console.log(await response.text());
```


#### Responses

##### `200`

Save an autoresponder.

```json
{
  "data": {
    "address": "info@example.com",
    "subject": "Fora do escritório",
    "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.

```json
{
  "error": {
    "code": "unauthorized",
    "message": "Missing or invalid API key.",
    "correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
    "details": {}
  }
}
```

##### `403`

The account cannot use the API (`forbidden`), the key lacks the permission (`insufficient_scope`), or the IP address is not on the list of the key (`ip_not_allowed`).

```json
{
  "error": {
    "code": "insufficient_scope",
    "message": "This key does not have the required permission.",
    "correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
    "details": {
      "required": "dns:read"
    }
  }
}
```

##### `404`

Not found.

```json
{
  "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`.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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`, `ip_not_allowed` | The account cannot use the API (`forbidden`), the key lacks the permission (`insufficient_scope`), or the IP address is not on the list of the key (`ip_not_allowed`). |
| 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. |
| 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](https://docs.interweb.ao/en/api-rules.md).


### Delete an autoresponder

`DELETE https://api.interweb.ao/v1/services/{id}/email/autoresponders/{address}`

Needs `email:write`. The mailbox stays. With a `sandbox_` key it only checks the request and changes nothing.

#### Authentication

Needs a valid key in the `Authorization: Bearer` header. Required permission: `email:write`.

#### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `id` | path | string | yes | The `id` of the hosting service. |
| `address` | path | string | yes | The full email address. |
| `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**

```bash
curl -X DELETE "https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/autoresponders/VALUE" \
  -H "Authorization: Bearer $RLX_API_KEY" \
  -H "Accept-Language: en"
```

**PHP**

```php
<?php
$ch = curl_init('https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/autoresponders/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**

```python
import os
import requests

headers = {
    "Authorization": "Bearer " + os.environ["RLX_API_KEY"],
    "Accept-Language": "en",
}
r = requests.delete("https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/autoresponders/VALUE", headers=headers, timeout=30)
print(r.status_code)
print(r.text)
```

**JavaScript**

```javascript
const response = await fetch("https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/autoresponders/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 an autoresponder.

```json
{
  "data": {
    "address": "info@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.

```json
{
  "error": {
    "code": "unauthorized",
    "message": "Missing or invalid API key.",
    "correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
    "details": {}
  }
}
```

##### `403`

The account cannot use the API (`forbidden`), the key lacks the permission (`insufficient_scope`), or the IP address is not on the list of the key (`ip_not_allowed`).

```json
{
  "error": {
    "code": "insufficient_scope",
    "message": "This key does not have the required permission.",
    "correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
    "details": {
      "required": "dns:read"
    }
  }
}
```

##### `404`

Not found.

```json
{
  "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`.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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`, `ip_not_allowed` | The account cannot use the API (`forbidden`), the key lacks the permission (`insufficient_scope`), or the IP address is not on the list of the key (`ip_not_allowed`). |
| 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. |
| 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](https://docs.interweb.ao/en/api-rules.md).


### See the default address

`GET https://api.interweb.ao/v1/services/{id}/email/default-address`

Needs `email:read`. What happens to mail for addresses that do not exist. `action` is `fail`, `forward`, `discard`, `main_account` or `other`. If the service is not active, or is not a supported hosting account, it answers `409` with the reason in `details.reason`.

#### Authentication

Needs a valid key in the `Authorization: Bearer` header. Required permission: `email:read`.

#### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `id` | path | string | yes | The `id` of the hosting service. |
| `domain` | query | string | no | A domain of this hosting account. If omitted, the main domain. |
| `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**

```bash
curl "https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/default-address" \
  -H "Authorization: Bearer $RLX_API_KEY" \
  -H "Accept-Language: en"
```

**PHP**

```php
<?php
$ch = curl_init('https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/default-address');
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**

```python
import os
import requests

headers = {
    "Authorization": "Bearer " + os.environ["RLX_API_KEY"],
    "Accept-Language": "en",
}
r = requests.get("https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/default-address", headers=headers, timeout=30)
print(r.status_code)
print(r.text)
```

**JavaScript**

```javascript
const response = await fetch("https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/default-address", {
  headers: {
    Authorization: `Bearer ${process.env.RLX_API_KEY}`,
    "Accept-Language": "en",
  },
});
console.log(response.status);
console.log(await response.text());
```


#### Responses

##### `200`

See the default address.

```json
{
  "data": {
    "domain": "example.co.mz",
    "action": "fail",
    "forward_to": null,
    "message": "No such person at this address."
  },
  "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.

```json
{
  "error": {
    "code": "unauthorized",
    "message": "Missing or invalid API key.",
    "correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
    "details": {}
  }
}
```

##### `403`

The account cannot use the API (`forbidden`), the key lacks the permission (`insufficient_scope`), or the IP address is not on the list of the key (`ip_not_allowed`).

```json
{
  "error": {
    "code": "insufficient_scope",
    "message": "This key does not have the required permission.",
    "correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
    "details": {
      "required": "dns:read"
    }
  }
}
```

##### `404`

Not found.

```json
{
  "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`.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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`, `ip_not_allowed` | The account cannot use the API (`forbidden`), the key lacks the permission (`insufficient_scope`), or the IP address is not on the list of the key (`ip_not_allowed`). |
| 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. |
| 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](https://docs.interweb.ao/en/api-rules.md).


### Change the default address

`PUT https://api.interweb.ao/v1/services/{id}/email/default-address`

Needs `email:write`. Accepted actions: `fail`, `forward`, `discard` and `main_account`. With a `sandbox_` key it only checks the request and changes nothing. On the domain of the account email, or of the email of a user of the account, it answers `409` with the code `account_email_domain`: make the change in the account portal.

#### Authentication

Needs a valid key in the `Authorization: Bearer` header. Required permission: `email:write`.

#### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `id` | path | string | yes | The `id` of the hosting service. |
| `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 | A domain of this hosting account. |
| `action` | string | yes | `fail`, `forward`, `discard` or `main_account`. |
| `forward_to` | string | no | Needed with `forward`. |
| `message` | string | no | The message with `fail`, up to 200 characters. |

#### Examples

**curl**

```bash
curl -X PUT "https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/default-address" \
  -H "Authorization: Bearer $RLX_API_KEY" \
  -H "Accept-Language: en" \
  -H "Content-Type: application/json" \
  -d '{"domain": "example.co.mz", "action": "fail", "message": "No such person at this address."}'
```

**PHP**

```php
<?php
$ch = curl_init('https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/default-address');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => 'PUT',
    CURLOPT_POSTFIELDS => '{"domain": "example.co.mz", "action": "fail", "message": "No such person at this address."}',
    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**

```python
import os
import requests

headers = {
    "Authorization": "Bearer " + os.environ["RLX_API_KEY"],
    "Accept-Language": "en",
}
payload = {"domain": "example.co.mz", "action": "fail", "message": "No such person at this address."}
r = requests.put("https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/default-address", headers=headers, json=payload, timeout=30)
print(r.status_code)
print(r.text)
```

**JavaScript**

```javascript
const response = await fetch("https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/default-address", {
  method: "PUT",
  headers: {
    Authorization: `Bearer ${process.env.RLX_API_KEY}`,
    "Accept-Language": "en",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({"domain": "example.co.mz", "action": "fail", "message": "No such person at this address."}),
});
console.log(response.status);
console.log(await response.text());
```


#### Responses

##### `200`

Change the default address.

```json
{
  "data": {
    "domain": "example.co.mz",
    "action": "fail",
    "forward_to": null,
    "message": "No such person at this address.",
    "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.

```json
{
  "error": {
    "code": "unauthorized",
    "message": "Missing or invalid API key.",
    "correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
    "details": {}
  }
}
```

##### `403`

The account cannot use the API (`forbidden`), the key lacks the permission (`insufficient_scope`), or the IP address is not on the list of the key (`ip_not_allowed`).

```json
{
  "error": {
    "code": "insufficient_scope",
    "message": "This key does not have the required permission.",
    "correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
    "details": {
      "required": "dns:read"
    }
  }
}
```

##### `404`

Not found.

```json
{
  "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`.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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`, `ip_not_allowed` | The account cannot use the API (`forbidden`), the key lacks the permission (`insufficient_scope`), or the IP address is not on the list of the key (`ip_not_allowed`). |
| 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. |
| 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](https://docs.interweb.ao/en/api-rules.md).


### See SPF, DKIM and DMARC

`GET https://api.interweb.ao/v1/services/{id}/email/authentication`

Needs `email:read`. The state of the three records of a domain, as published in DNS. If the service is not active, or is not a supported hosting account, it answers `409` with the reason in `details.reason`.

#### Authentication

Needs a valid key in the `Authorization: Bearer` header. Required permission: `email:read`.

#### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `id` | path | string | yes | The `id` of the hosting service. |
| `domain` | query | string | no | A domain of this hosting account. If omitted, the main domain. |
| `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**

```bash
curl "https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/authentication" \
  -H "Authorization: Bearer $RLX_API_KEY" \
  -H "Accept-Language: en"
```

**PHP**

```php
<?php
$ch = curl_init('https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/authentication');
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**

```python
import os
import requests

headers = {
    "Authorization": "Bearer " + os.environ["RLX_API_KEY"],
    "Accept-Language": "en",
}
r = requests.get("https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/authentication", headers=headers, timeout=30)
print(r.status_code)
print(r.text)
```

**JavaScript**

```javascript
const response = await fetch("https://api.interweb.ao/v1/services/00000000-0000-4000-8000-000000000000/email/authentication", {
  headers: {
    Authorization: `Bearer ${process.env.RLX_API_KEY}`,
    "Accept-Language": "en",
  },
});
console.log(response.status);
console.log(await response.text());
```


#### Responses

##### `200`

See SPF, DKIM and DMARC.

```json
{
  "data": {
    "domain": "example.co.mz",
    "spf": {
      "state": "pass"
    },
    "dkim": {
      "state": "valid"
    },
    "dmarc": {
      "state": "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.

```json
{
  "error": {
    "code": "unauthorized",
    "message": "Missing or invalid API key.",
    "correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
    "details": {}
  }
}
```

##### `403`

The account cannot use the API (`forbidden`), the key lacks the permission (`insufficient_scope`), or the IP address is not on the list of the key (`ip_not_allowed`).

```json
{
  "error": {
    "code": "insufficient_scope",
    "message": "This key does not have the required permission.",
    "correlation_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
    "details": {
      "required": "dns:read"
    }
  }
}
```

##### `404`

Not found.

```json
{
  "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`.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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`, `ip_not_allowed` | The account cannot use the API (`forbidden`), the key lacks the permission (`insufficient_scope`), or the IP address is not on the list of the key (`ip_not_allowed`). |
| 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. |
| 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](https://docs.interweb.ao/en/api-rules.md).
