> ## Documentation Index
> Fetch the complete documentation index at: https://ahasend.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> AhaSend stores all message data in the EU. See /facts.
> The API base URL is https://api.ahasend.com. Send the API key in the Authorization: Bearer header. See /api-reference/authentication.
> Use send.ahasend.com for SMTP. Ports 25, 587 and 2525 use STARTTLS. Port 465 is not supported. See /smtp.
> For send-only integrations, create an API Key v2 under Credentials → Add and scope it to messages:send:{your-domain}. See /send-api/credentials and /api-reference/scopes.

# ahasend contacts: Manage Account Contacts

> Create, read, update, delete, and batch-import AhaSend account contacts with the CLI, including status, unsubscribe choices, and custom attributes.

AhaSend CLI contact commands manage account-global contacts by email address or UUID.

> [!NOTE]
>
> These commands need CLI v0.3.0 or later. Check your version with `ahasend --version`, and [upgrade](/docs/cli/installation.md) if it is older.

## Prerequisites

[Authenticate with a full API key](/docs/cli/authentication.md). Contact tasks need these [scopes](/docs/api-reference/scopes.md):

| Scope | Commands |
| - | - |
| `contacts:read` | `contacts list`, `contacts get` |
| `contacts:write` | `contacts create`, `contacts update`, `contacts batch` |
| `contacts:delete` | `contacts delete` |
| `lists:read` | `contacts memberships` |

Attribute keys must already exist in the dashboard. Creating a contact does not add it to a list; add it with [`ahasend lists members add`](/docs/cli/commands/lists#add-and-list-members). The shell examples need Bash.

Commands that take `<id-or-email>` accept a contact ID or a raw email address. Pass the address exactly as written, including `+`, and do not percent-encode it.

## Create, Read and Update

Save these commands in one Bash script. The script creates two test contacts, and its last step deletes them.

```bash theme={null}
set -euo pipefail
ahasend contacts create docs-contact-test@example.com --first-name Pat --last-name Example --status enabled
ahasend contacts list --limit 10
ahasend contacts get docs-contact-test@example.com
ahasend contacts update docs-contact-test@example.com --unsubscribed=true
```

`update` sends only the flags you give, and needs at least one. `--first-name ""`, `--last-name ""` and `--status-reason ""` clear those fields. To remove an attribute, set its value to `null` in `--attributes`, such as `--attributes '{"old_key":null}'`. Status values are `enabled`, `disabled` and `blocked`.

To find contacts, filter the list by email, status, subscription or creation time. Times are RFC 3339, such as `2026-01-15T10:30:00Z`, or relative, such as `7d` for 7 days ago:

```bash theme={null}
ahasend contacts list --status enabled --subscribed=true
ahasend contacts list --from-time 7d --limit 50
```

## Batch Import

Continue the script. `contacts batch` creates or updates up to 1,000 contacts in one request. Save this as `contacts.json`:

```json contacts.json theme={null}
{"data":[{"email":"docs-batch-test@example.com","first_name":"Pat"}]}
```

```bash theme={null}
ahasend contacts batch --file contacts.json
```

* The file is a JSON object whose only field is `data`. The 1,000 limit counts every item, duplicates included.
* Items may hold only contact fields, and no field may be `null`; leave a field out to keep it unchanged. Inside `attributes`, `null` removes that attribute.
* The command prints the result of each item, and exits with code 1 when any item failed.
* With `--idempotency-key`, reuse a key only to retry the same file contents.

## List a Contact's Lists

Continue the script:

```bash theme={null}
ahasend contacts memberships docs-contact-test@example.com
ahasend contacts memberships docs-contact-test@example.com --subscription-status unsubscribed
```

Each membership shows its list and its status: `unconfirmed`, `confirmed`, `unsubscribed` or `complained`.

## Delete the Test Contacts

Finish the script by deleting the contacts it created.

```bash theme={null}
ahasend contacts delete docs-contact-test@example.com --force
ahasend contacts delete docs-batch-test@example.com --force
```

The script stops at the first command that fails, and then deletes nothing. If it stops early, run these two commands to delete the contacts it made; a contact it did not make fails with a not found error.

`contacts delete` asks for confirmation first; see [prompts](/docs/cli/configuration.md#prompts).

> [!WARNING]
>
> Deleting a contact cannot be undone. It cancels the contact's active workflows and erases its unsubscribe, list membership, campaign, open and click history. To stop mail and keep the history, run `ahasend contacts update <id-or-email> --unsubscribed=true` instead.

## Command Flags

These flags come from the CLI's `--help`. All commands also accept the [global flags](/docs/cli/configuration.md#global-flags).

### `contacts batch`

```text theme={null}
ahasend contacts batch --file <path> [flags]
```

| Flag | Description and default |
| - | - |
| `--file string` | JSON file containing `{"data":[...]}` (required) |
| `--idempotency-key string` | Idempotency key for safe retries (generated when omitted) |

### `contacts create`

```text theme={null}
ahasend contacts create <email> [flags]
```

| Flag | Description and default |
| - | - |
| `--attributes string` | Contact attributes as a JSON object |
| `--first-name string` | Contact first name |
| `--idempotency-key string` | Idempotency key for safe retries (generated when omitted) |
| `--last-name string` | Contact last name |
| `--status string` | Contact status: `enabled`, `disabled` or `blocked` |
| `--status-reason string` | Reason for the contact status |
| `--unsubscribed` | Whether the contact is globally unsubscribed |

Attribute values cannot be `null` on `create`.

### `contacts delete`

```text theme={null}
ahasend contacts delete <id-or-email> [flags]
```

| Flag | Description and default |
| - | - |
| `-f`, `--force` | Skip confirmation prompt |

### `contacts get`

```text theme={null}
ahasend contacts get <id-or-email> [flags]
```

No command-specific flags. See [global flags](/docs/cli/configuration.md#global-flags).

### `contacts list`

```text theme={null}
ahasend contacts list [flags]
```

| Flag | Description and default |
| - | - |
| `--after string` | Return the page after this cursor |
| `--before string` | Return the page before this cursor |
| `--email string` | Filter by normalized exact email address |
| `--from-time string` | Filter contacts created after this time (RFC3339 or relative like '24h', '7d') |
| `--limit int32` | Maximum number of items to return (0-100; 0 uses the API default) |
| `--status string` | Filter by status: `enabled`, `disabled` or `blocked` |
| `--subscribed` | Filter by global subscription state |
| `--to-time string` | Filter contacts created before this time (RFC3339 or relative) |

The list is newest first. `--subscribed=false` lists unsubscribed contacts.

### `contacts memberships`

```text theme={null}
ahasend contacts memberships <id-or-email> [flags]
```

| Flag | Description and default |
| - | - |
| `--after string` | Return the page after this cursor |
| `--before string` | Return the page before this cursor |
| `--limit int32` | Maximum number of items to return (0-100; 0 uses the API default) |
| `--subscription-status string` | Filter by membership status: `unconfirmed`, `confirmed`, `unsubscribed` or `complained` |

### `contacts update`

```text theme={null}
ahasend contacts update <id-or-email> [flags]
```

| Flag | Description and default |
| - | - |
| `--attributes string` | Attributes to change as a JSON object (a null value removes that attribute) |
| `--email string` | New email address |
| `--first-name string` | New first name (empty clears it) |
| `--last-name string` | New last name (empty clears it) |
| `--status string` | New status: `enabled`, `disabled` or `blocked` |
| `--status-reason string` | New reason for the status (empty clears it) |
| `--unsubscribed` | Whether the contact is globally unsubscribed (false resubscribes it) |

## Related Guides

* [Contacts API](/docs/api-reference/contacts/overview.md), [Batch upsert contacts](/docs/api-reference/contacts/batch-upsert-contacts.md), [Lists of a contact](/docs/api-reference/lists/get-contact-lists.md).
* [Lists commands](/docs/cli/commands/lists.md), [Campaigns commands](/docs/cli/commands/campaigns.md), [CLI authentication](/docs/cli/authentication.md).
* [CLI configuration and output](/docs/cli/configuration.md), [API authentication](/docs/api-reference/authentication.md), [Permission scopes](/docs/api-reference/scopes.md).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.