# E-mail and URL Forwarding

https://dev.wisecp.com/es/email-and-url-forwarding

The seven endpoints that send a domain's mail and its visitors somewhere else.

## Overview

These seven endpoints decide **where what arrives** at a domain goes. They are two separate jobs: an e-mail forward moves **the mail**, a URL forward moves **the visitor**.

An e-mail forward opens no mailbox; the mail is passed on as it is. A URL forward points the domain at another address without hosting a site on it.

## Reference

### Listing the E-mail Forwards

get/api/v1/admin/services/{id}/domain/email-forwards

`Services/GetDomainEmailForwards` admin

Returns the records saying where mail to the domain is passed on.

Response fields data[] — 4

identitystringThe record id. When the module gives none it is derived from the prefix and the target, so changing the target changes the id.

prefixstringThe local part of the source address.

sourcestringThe full source address. Worked out from the prefix and the domain.

targetstringWhere the mail is passed on to.

Errors 6

not_found404No such service.

not_domain422The service is not a domain.

no_module422No registrar module is attached.

not_supported422The module does not support this operation.

module_failed500The registry could not complete the operation.

insufficient_scope403The key lacks the required scope.

Request cURL JavaScript PHP (HTTP) PHP (Internal)

```bash
curl 'https://panel.example.com/api/v1/admin/services/520/domain/email-forwards' \
  -H "Authorization: Bearer $API_KEY"
```

```javascript
const res  = await fetch('https://panel.example.com/api/v1/admin/services/520/domain/email-forwards', {
  headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();
```

```php
$ch = curl_init('https://panel.example.com/api/v1/admin/services/520/domain/email-forwards');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
```

```php
// 'source' is a worked-out field; it appears on reads ONLY, never on writes.
$forwards = Api::Services()->GetDomainEmailForwards(['id' => 520])['data'];
```

Response 200

```json
{
  "data": [
    {
      "identity": "3001",
      "prefix": "info",
      "source": "info@example.com",
      "target": "john@example.com"
    }
  ]
}
```

### Adding an E-mail Forward

post/api/v1/admin/services/{id}/domain/email-forwards

`Services/AddDomainEmailForward` admin 201

Passes mail arriving at one of the domain's addresses on to another.

Body 2

prefixstringrequiredThe local part of the source address. The domain is appended for you.

targetstringrequiredWhere to pass the mail on to. Its format is validated.

Response fields data — 2

prefixstringThe source prefix of the forward added.

targetstringThe target it now points to.

Errors 7

not_found404No such service.

not_domain422The service is not a domain.

no_module422No registrar module is attached.

not_supported422The module does not support this operation.

email_fwd_fields_required422One of the required fields was empty.

invalid_email422The target is not a valid e-mail address.

insufficient_scope403The key lacks the required scope.

Request cURL JavaScript PHP (HTTP) PHP (Internal)

```bash
curl -X POST 'https://panel.example.com/api/v1/admin/services/520/domain/email-forwards' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"prefix":"info","target":"john@example.com"}'
```

```javascript
const res = await fetch('https://panel.example.com/api/v1/admin/services/520/domain/email-forwards', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ prefix: 'info', target: 'john@example.com' }),
});

const body = await res.json();
```

```php
$ch = curl_init('https://panel.example.com/api/v1/admin/services/520/domain/email-forwards');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'prefix' => 'info',
        'target' => 'john@example.com',
    ]),
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
```

```php
// The prefix is the local part ONLY: sending a full address produces 'info@example.com@example.com'.
Api::Services()->AddDomainEmailForward([
    'id'     => 520,
    'prefix' => 'info',
    'target' => 'john@example.com',
]);
```

### Updating an E-mail Forward

put/api/v1/admin/services/{id}/domain/email-forwards

`Services/UpdateDomainEmailForward` admin only the target changes

Changes where a forward points. The source prefix cannot be changed.

Body 4

prefixstringrequiredThe source prefix of the record to change.

target_newstringrequiredThe new target address.

targetstringThe current target. It tells apart several records on the same prefix.

identitystringThe record id from the list.

Response fields data — 2

prefixstringThe source prefix of the record changed.

targetstringThe target it now points to. This is the value you sent as `target_new`.

Errors 7

not_found404No such service.

not_domain422The service is not a domain.

no_module422No registrar module is attached.

not_supported422The module does not support this operation.

email_fwd_fields_required422One of the required fields was empty.

invalid_email422The target is not a valid e-mail address.

insufficient_scope403The key lacks the required scope.

Request cURL JavaScript PHP (HTTP) PHP (Internal)

```bash
curl -X PUT 'https://panel.example.com/api/v1/admin/services/520/domain/email-forwards' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"prefix":"info","target":"john@example.com","target_new":"jane@example.com"}'
```

```javascript
const res = await fetch('https://panel.example.com/api/v1/admin/services/520/domain/email-forwards', {
  method: 'PUT',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    prefix: 'info',
    target: 'john@example.com',
    target_new: 'jane@example.com',
  }),
});

const body = await res.json();
```

```php
$ch = curl_init('https://panel.example.com/api/v1/admin/services/520/domain/email-forwards');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'PUT',
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'prefix'     => 'info',
        'target'     => 'john@example.com',
        'target_new' => 'jane@example.com',
    ]),
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
```

```php
// There is no endpoint for changing the prefix: delete the old one and add a new one.
Api::Services()->DeleteDomainEmailForward(['id' => 520, 'prefix' => 'info']);

Api::Services()->AddDomainEmailForward([
    'id'     => 520,
    'prefix' => 'contact',
    'target' => 'jane@example.com',
]);
```

### Deleting an E-mail Forward

delete/api/v1/admin/services/{id}/domain/email-forwards

`Services/DeleteDomainEmailForward` admin

Removes an e-mail forward.

Body 3

prefixstringrequiredThe source prefix of the record to delete.

targetstringThe target. It narrows the match.

identitystringThe record id from the list.

Response fields data — 2

deletedboolWhether the delete succeeded.

prefixstringPrefix of the deleted record.

Errors 6

not_found404No such service.

not_domain422The service is not a domain.

no_module422No registrar module is attached.

not_supported422The module does not support this operation.

email_fwd_fields_required422One of the required fields was empty.

insufficient_scope403The key lacks the required scope.

Request cURL JavaScript PHP (HTTP) PHP (Internal)

```bash
curl -X DELETE 'https://panel.example.com/api/v1/admin/services/520/domain/email-forwards' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"prefix":"info"}'
```

```javascript
const res = await fetch('https://panel.example.com/api/v1/admin/services/520/domain/email-forwards', {
  method: 'DELETE',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ prefix: 'info' }),
});

const body = await res.json();
```

```php
$ch = curl_init('https://panel.example.com/api/v1/admin/services/520/domain/email-forwards');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'DELETE',
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode(['prefix' => 'info']),
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
```

```php
// With several targets on one prefix, sending the prefix alone can delete ALL of them.
Api::Services()->DeleteDomainEmailForward([
    'id'     => 520,
    'prefix' => 'info',
    'target' => 'john@example.com',
]);
```

### Reading the URL Forward

get/api/v1/admin/services/{id}/domain/forwarding

`Services/GetDomainForwarding` admin

Returns whether the domain redirects to another address.

Response fields data — 4

activeboolWhether the forward is running.

methodintThe redirect type. Permanent or temporary; it defaults to permanent.

protocolstringWhich protocol the target is reached over.

domainstringThe address being redirected to.

Errors 6

not_found404No such service.

not_domain422The service is not a domain.

no_module422No registrar module is attached.

not_supported422The module does not support this operation.

module_failed500The registry could not complete the operation.

insufficient_scope403The key lacks the required scope.

Request cURL JavaScript PHP (HTTP) PHP (Internal)

```bash
curl 'https://panel.example.com/api/v1/admin/services/520/domain/forwarding' \
  -H "Authorization: Bearer $API_KEY"
```

```javascript
const res  = await fetch('https://panel.example.com/api/v1/admin/services/520/domain/forwarding', {
  headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();
```

```php
$ch = curl_init('https://panel.example.com/api/v1/admin/services/520/domain/forwarding');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
```

```php
$response = Api::Services()->GetDomainForwarding(['id' => 520]);
```

### Setting the URL Forward

put/api/v1/admin/services/{id}/domain/forwarding

`Services/SetDomainForwarding` admin takes the site away

Sends visitors arriving at the domain to another address.

Body 3

domainstringrequiredThe address to redirect to.

protocolstringWhich protocol to reach the target over. It defaults to the unencrypted one.

methodintThe redirect type. It defaults to permanent, and a permanent redirect is cached by browsers.

Response fields data — 4

activeboolWhether the forward is running.

methodintThe redirect type. Permanent or temporary; it defaults to permanent.

protocolstringWhich protocol the target is reached over.

domainstringThe address being redirected to.

Errors 6

not_found404No such service.

not_domain422The service is not a domain.

no_module422No registrar module is attached.

not_supported422The module does not support this operation.

domain_fwd_url_required422The target address was empty.

insufficient_scope403The key lacks the required scope.

Request cURL JavaScript PHP (HTTP) PHP (Internal)

```bash
curl -X PUT 'https://panel.example.com/api/v1/admin/services/520/domain/forwarding' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"domain":"example.net","protocol":"https","method":301}'
```

```javascript
const res = await fetch('https://panel.example.com/api/v1/admin/services/520/domain/forwarding', {
  method: 'PUT',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    domain: 'example.net',
    protocol: 'https',
    method: 301,
  }),
});

const body = await res.json();
```

```php
$ch = curl_init('https://panel.example.com/api/v1/admin/services/520/domain/forwarding');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'PUT',
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'domain'   => 'example.net',
        'protocol' => 'https',
        'method'   => 301,
    ]),
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
```

```php
// A permanent redirect is cached by browsers, so pick 302 while you are still trying things out.
Api::Services()->SetDomainForwarding([
    'id'       => 520,
    'domain'   => 'example.net',
    'protocol' => 'https',
    'method'   => 302,
]);
```

### Removing the URL Forward

delete/api/v1/admin/services/{id}/domain/forwarding

`Services/CancelDomainForwarding` admin

Removes the redirect and leaves the domain to its own nameservers.

Response fields data — 1

cancelledboolWhether the redirect was removed.

Errors 6

not_found404No such service.

not_domain422The service is not a domain.

no_module422No registrar module is attached.

not_supported422The module does not support this operation.

module_failed500The registry could not complete the operation.

insufficient_scope403The key lacks the required scope.

Request cURL JavaScript PHP (HTTP) PHP (Internal)

```bash
curl -X DELETE 'https://panel.example.com/api/v1/admin/services/520/domain/forwarding' \
  -H "Authorization: Bearer $API_KEY"
```

```javascript
const res = await fetch('https://panel.example.com/api/v1/admin/services/520/domain/forwarding', {
  method: 'DELETE',
  headers: { Authorization: `Bearer ${apiKey}` },
});

const body = await res.json();
```

```php
$ch = curl_init('https://panel.example.com/api/v1/admin/services/520/domain/forwarding');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'DELETE',
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
```

```php
// Removing the redirect leaves the domain to its nameservers; with no DNS record the site will not open.
Api::Services()->CancelDomainForwarding(['id' => 520]);

$records = Api::Services()->GetDnsRecords(['id' => 520])['data'];
```

## Pitfalls

> **The prefix is the local part only**
> 
> Do not send the source address with the domain in it: the endpoint appends the domain to the prefix itself. Send a full address and you get a source with the domain twice, which never matches. The full address you see on a read is a worked-out field and is not used on writes.

> **Sending only the prefix can delete them all**
> 
> Only the prefix is required on the delete. With several targets on one prefix, a request sent without a target or an id can remove **all of them**, because the module does the matching. Send the target too when you mean one record.

> **The prefix cannot be updated**
> 
> The update only changes the target. Changing the source means deleting the record and adding a new one, and mail arriving in between is passed nowhere.

> **A permanent redirect sticks in the browser**
> 
> The default redirect type is permanent and browsers cache it. Point a permanent redirect at the wrong target and fix it later, and users who visited before keep going to the old target for a while. Use the temporary type while trying things out.

> **Removing the forward does not bring a site back**
> 
> With the forward gone the domain falls back to its own nameservers. If there is no record there the domain resolves nowhere, and because a forward was being used no DNS record may ever have been written. Look at the records before removing it.

## Related Articles

- [DNS Management](https://dev.wisecp.com/en/dns-management)
- [Domain Basics](https://dev.wisecp.com/en/domain-basics)
