# Atomic webhook and alias endpoint

> Create a webhook and email alias in a single API call with automatic linking

Source: https://emailconnect.eu/help/webhook-alias-atomic-endpoint/

The atomic webhook/alias endpoint lets you create a webhook and email alias in a single API call. Both resources are created together in a transaction — if either fails, neither is created. This is the recommended way to set up email forwarding programmatically.

## Endpoint

```
POST https://app.emailconnect.eu/api/webhooks/alias
X-API-KEY: YOUR_API_KEY
Content-Type: application/json
```

## Request body

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `domainId` | string | Yes | ID of the domain to create the alias under |
| `webhookUrl` | string | Yes | URL to receive webhook payloads (must be a valid URI) |
| `webhookName` | string | Yes | Display name for the webhook (1–100 characters) |
| `webhookDescription` | string | No | Optional description (max 500 characters) |
| `aliasType` | string | Yes | `"catchall"` or `"specific"` |
| `localPart` | string | Conditional | Required when `aliasType` is `"specific"`. The part before the `@` (1–64 characters) |
| `syncWithDomain` | boolean | No | Sync catch-all webhook with domain default. Default: `true` |
| `firstOrCreate` | boolean | No | Smart create/update — reuse existing alias if found. Default: `false` |
| `updateWebhookData` | boolean | No | Update webhook name/URL if alias already exists. Default: `true` |
| `generateSecret` | boolean | No | Generate webhook signing secret (all plans). Default: `false` |
| `webhookSecret` | string | No | Provide your own signing secret (all plans) |

## Basic example

### Node.js

```javascript
const response = await fetch('https://app.emailconnect.eu/api/webhooks/alias', {
  method: 'POST',
  headers: {
    'X-API-KEY': 'YOUR_API_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    domainId: 'dom_abc123',
    webhookUrl: 'https://your-app.com/webhook/emails',
    webhookName: 'My email webhook',
    aliasType: 'specific',
    localPart: 'support'
  })
});

const result = await response.json();
// result.alias.email → "support@yourdomain.com"
// result.webhook.id → "wh_xyz789"
```

### Python

```python
import requests

response = requests.post(
    'https://app.emailconnect.eu/api/webhooks/alias',
    headers={
        'X-API-KEY': 'YOUR_API_KEY',
        'Content-Type': 'application/json'
    },
    json={
        'domainId': 'dom_abc123',
        'webhookUrl': 'https://your-app.com/webhook/emails',
        'webhookName': 'My email webhook',
        'aliasType': 'specific',
        'localPart': 'support'
    }
)

result = response.json()
```

### cURL

```bash
curl -X POST https://app.emailconnect.eu/api/webhooks/alias \
  -H "X-API-KEY: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "domainId": "dom_abc123",
    "webhookUrl": "https://your-app.com/webhook/emails",
    "webhookName": "My email webhook",
    "aliasType": "specific",
    "localPart": "support"
  }'
```

## Response

```json
{
  "success": true,
  "webhook": {
    "id": "wh_xyz789",
    "name": "My email webhook",
    "url": "https://your-app.com/webhook/emails",
    "verified": false,
    "hasSecret": false,
    "verificationToken": "abc12",
    "createdAt": "2026-02-03T12:00:00.000Z"
  },
  "alias": {
    "id": "al_def456",
    "email": "support@yourdomain.com",
    "active": true,
    "createdAt": "2026-02-03T12:00:00.000Z"
  },
  "action": "created",
  "message": "Webhook and alias created successfully"
}
```

## Response fields

| Field | Description |
|-------|-------------|
| `action` | One of `"created"`, `"updated"`, `"webhook_added"`, or `"cross_domain_update"` |
| `webhook.verified` | Whether the webhook URL has been verified |
| `webhook.verificationToken` | Present only if webhook is not yet verified — use to complete verification |
| `webhook.hasSecret` | Whether webhook signing is enabled |
| `webhookSecret` | Present only once when `generateSecret` is `true` — save it immediately |

## Smart create/update with firstOrCreate

When `firstOrCreate` is `true`, the endpoint checks if a matching alias already exists — even across domains. This prevents duplicate aliases and simplifies integration setup.

**Behavior by scenario:**

| Scenario | Result | `action` value |
|----------|--------|----------------|
| No existing alias | Creates new webhook + alias | `"created"` |
| Alias exists in same domain | Updates webhook details | `"updated"` |
| Alias exists in different domain | Moves alias to target domain | `"cross_domain_update"` |
| Alias exists without webhook | Creates and links new webhook | `"webhook_added"` |

### Example with firstOrCreate

```bash
curl -X POST https://app.emailconnect.eu/api/webhooks/alias \
  -H "X-API-KEY: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "domainId": "dom_abc123",
    "webhookUrl": "https://your-app.com/webhook/emails",
    "webhookName": "Updated webhook",
    "aliasType": "specific",
    "localPart": "support",
    "firstOrCreate": true
  }'
```

## Catch-all aliases

Set `aliasType` to `"catchall"` to create a catch-all alias that receives all unmatched emails for a domain.

```json
{
  "domainId": "dom_abc123",
  "webhookUrl": "https://your-app.com/webhook/emails",
  "webhookName": "Catch-all webhook",
  "aliasType": "catchall",
  "syncWithDomain": true
}
```

When `syncWithDomain` is `true` (the default), the domain's default webhook is also updated to point to this URL.

## Webhook signing

Add webhook signing (Standard Webhooks) to verify webhook authenticity. Available on every plan, Free included.

```json
{
  "domainId": "dom_abc123",
  "webhookUrl": "https://your-app.com/webhook/emails",
  "webhookName": "Signed webhook",
  "aliasType": "specific",
  "localPart": "secure",
  "generateSecret": true
}
```

The response will include a `webhookSecret` field. Save it immediately — it will not be shown again. See [Webhook signing](https://emailconnect.eu/help/webhook-signing/) for verification details.

## Error responses

| Status | Reason |
|--------|--------|
| 400 | Invalid request body or missing required fields |
| 402 | Plan limit exceeded (webhook or alias count) or a paid-plan feature was requested |
| 404 | Domain not found or access denied |
| 409 | Alias already exists (when `firstOrCreate` is `false`) |

## Related

- [API keys and integrations](https://emailconnect.eu/help/api-keys-integrations/) — managing API keys
- [Webhook signing](https://emailconnect.eu/help/webhook-signing/) — verifying webhook signatures
- [Webhook configuration](https://emailconnect.eu/help/webhook-configuration/) — general webhook setup
