Create or upsert a contact by email. Permission: `subscribers`.

`skipDoubleOptIn` defaults to `false`. Pass `true` from a trusted backend to create the contact as `SUBSCRIBED` even when organization double opt-in is on. This does not write confirmation evidence and does not resubscribe `UNSUBSCRIBED` unless `resubscribe` is also true.

## Body Parameters

| Name | Type | Description |
| ---- | ---- | ----------- |
| `email` | string | **Required.** Contact email. Upserts if it already exists. |
| `name` | string or null | Display name. |
| `phone` | string or null | Phone number. |
| `tags` | string[] | Tag names to attach. Created if missing. |
| `fields` | `Record<string, string \| null>` | Custom field values. |
| `replaceTags` | boolean | When `true`, replace existing tags with `tags`. Default `false`. |
| `resubscribe` | boolean | Re-subscribe an `UNSUBSCRIBED` contact. Default `true` on create. |
| `triggerWorkflows` | boolean | Fire subscribe / tag workflows. |
| `skipDoubleOptIn` | boolean | Create as `SUBSCRIBED` even when org double opt-in is on. Default `false`. |
| `ipAddress` | string | Client IP stored as signup evidence. |
| `country` | string | ISO 3166-1 alpha-2 country code. |

## Response Fields

| Field | Type | Description |
| ----- | ---- | ----------- |
| `id` | string | Subscriber id. |
| `email` | string | Email address. |
| `name` | string or null | Display name. |
| `phone` | string or null | Phone number. |
| `status` | string | `PENDING_CONFIRMATION`, `SUBSCRIBED`, `UNSUBSCRIBED`, `BOUNCED`, `BANNED`, `COMPLAINED`, or `TRANSACTIONAL`. |
| `tags` | `{ id, name }[]` | Current audience tags. |
| `fields` | object | Custom fields. |
| `warnings` | string[] | Present when some tags or fields could not be applied. |

## Errors

| Status | `name` | When |
| ------ | ------ | ---- |
| 401 | `missing_api_key` | Missing or invalid bearer token |
| 403 | `missing_permission` | Token lacks the `subscribers` permission |
| 422 | `validation_error` | Invalid email or payload |

## Related

- [Get Subscriber](/docs/api-reference/v2/subscribers-get)
- [List Subscribers](/docs/api-reference/v2/subscribers-list)
- [SDK: lumail.subscribers.create](/docs/sdk/v2/subscribers-create)


## API Reference
**Method:** POST
**Endpoint:** /api/v2/subscribers

### SDK
```ts
import { Lumail } from "lumail";

const lumail = new Lumail({ apiKey: process.env.LUMAIL_API_KEY });
const { data, error } = await lumail.subscribers.create({
  email: "user@example.com",
  name: "Ada",
  tags: ["newsletter"],
});
if (error) {
  throw error;
}
console.log(data.id);
```

### cURL
```bash
curl -X POST https://lumail.io/api/v2/subscribers \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"email":"user@example.com","name":"Ada","tags":["newsletter"]}'
```

### JavaScript
```javascript
const response = await fetch("https://lumail.io/api/v2/subscribers", {
  method: "POST",
  headers: {
    Authorization: "Bearer YOUR_API_TOKEN",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    email: "user@example.com",
    name: "Ada",
    tags: ["newsletter"],
  }),
});
const data = await response.json();
```

### Success Response
```json
{
  "id": "sub_abc123",
  "email": "user@example.com",
  "name": "Ada",
  "status": "SUBSCRIBED"
}
```

### Error Response
```json
{
  "name": "validation_error",
  "message": "Invalid email",
  "statusCode": 422
}
```
