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

# API Error Codes and Error Responses

> Reference for AhaSend API v2 HTTP status codes (400, 401, 403, 404, 409, 422, 429, 500, 502, 503), the JSON error format, example messages and fixes for each.

AhaSend API errors use an HTTP status and a JSON message; this reference explains status codes and how your application should handle them.

## Error Response Format

All API errors return a consistent JSON structure with an HTTP status code and a descriptive message:

```json theme={null}
{
  "message": "Error description explaining what went wrong"
}
```

The `message` field is human-readable text, not a stable error code. Use the HTTP status and the operation's contract for program logic.

When [Send Campaign](https://ahasend.com/docs/api-reference/campaigns/send-campaign.md) or [Test Campaign](https://ahasend.com/docs/api-reference/campaigns/test-campaign.md) refuses a campaign with issues, the `400` body also holds `issues`. Each issue has a stable `code` and a `message`. See [Issues](https://ahasend.com/docs/api-reference/campaigns/overview.md#issues).

```json theme={null}
{
  "message": "campaign is not ready to send",
  "issues": [
    {
      "code": "subject_missing",
      "message": "Add a subject before you send the campaign."
    }
  ]
}
```

## HTTP Status Codes

The AhaSend API uses standard HTTP status codes to indicate the success or failure of requests:

### 2xx Success

* **200 OK** - Request succeeded
* **201 Created** - Resource created successfully
* **202 Accepted** - Message accepted for processing; inspect each recipient's status. Send Campaign also answers `202`, with the campaign in `validating`

### 4xx Client Errors

#### 400 Bad Request

Returned when the request is malformed or contains invalid parameters.

> [!WARNING]
>
> Common causes include invalid JSON, missing required fields, or parameters that don't meet validation requirements.

**Example scenarios:**

* Invalid UUID format for `account_id` or resource IDs
* Malformed email addresses
* Invalid time formats (expecting RFC3339)
* Parameters outside allowed ranges (e.g., `limit` not between 1-100)
* Invalid domain names or URLs
* Malformed request body

```json theme={null}
{
  "message": "invalid account_id"
}
```

```json theme={null}
{
  "message": "invalid from_time, provide a valid RFC3339 time string"
}
```

**Template check:** [Create Message](https://ahasend.com/docs/api-reference/messages/create-message.md), [Create Template Message](https://ahasend.com/docs/api-reference/messages/create-template-message.md), [Create Conversation](https://ahasend.com/docs/api-reference/messages/create-conversation.md) and [Test Campaign](https://ahasend.com/docs/api-reference/campaigns/test-campaign.md) check every message with the template engine before they send it. The request is refused with `400`, and nothing of it is sent, when a message's content cannot be rendered with a recipient's values, calls `random`, `randrange`, `lipsum` or `now`, uses `namespace`, passes a work, output, memory or time limit, or has a recipient address the check cannot read. The message is `<email>: the message could not be rendered: <reason>`, or has no `<email>: ` when no recipient had started rendering. Fix the content or the recipient's values before you send the request again.

```json theme={null}
{
  "message": "john@example.com: the message could not be rendered: unknown function: nosuch"
}
```

#### 401 Unauthorized

Authentication failed or is missing.

**Common causes:**

* Missing `Authorization` header
* Invalid API key format (must be `Bearer <api_key>`)
* API key doesn't exist or has been revoked
* Sending is paused on the account of the API key
* API key doesn't belong to the specified account

```json theme={null}
{
  "message": "Missing or malformed bearer token"
}
```

```json theme={null}
{
  "message": "Invalid API key"
}
```

```json theme={null}
{
  "message": "account is paused"
}
```

#### 403 Forbidden

Authentication succeeded, but you don't have permission to access the resource.

> [!TIP]
>
> This typically occurs when your API key doesn't have the required scopes for the operation you're trying to perform.

**Common causes:**

* API key lacks required scopes (e.g., trying to delete domains without `domains:delete:all` or `domains:delete:{domain}` scope)
* Attempting to access resources outside your API key's domain restrictions
* Insufficient permissions for specific operations
* Sending from the domain is paused. You cannot send from the domain or delete it. See [paused domains](https://ahasend.com/docs/domains.md#why-is-sending-paused-on-my-domain).

```json theme={null}
{
  "message": "Insufficient permissions for the required scope"
}
```

```json theme={null}
{
  "message": "api key does not have sufficient permissions to read webhooks"
}
```

```json theme={null}
{
  "message": "Sending from domain 'example.com' is paused. Check your dashboard for the reason."
}
```

#### 404 Not Found

The requested resource doesn't exist or you don't have access to it.

**Common scenarios:**

* Resource ID doesn't exist
* Resource was deleted
* Resource belongs to a different account

```json theme={null}
{
  "message": "account not found"
}
```

```json theme={null}
{
  "message": "domain not found"
}
```

#### 409 Conflict

The request conflicts with the current state of the resource.

**Common causes:**

* **Idempotency conflicts**: Another request with the same idempotency key is already in progress
* **Resource conflicts**: Trying to create a resource that already exists (e.g., duplicate domain)
* **IP allow list conflicts**: Updating your own key would exclude the caller's current IP
* **Campaign status conflicts**: Changing, deleting, testing or sending a campaign that is not a draft, or unscheduling a campaign that is not `validating` or `scheduled` or that has queued mail. See [Changes only to drafts](https://ahasend.com/docs/api-reference/campaigns/overview.md#changes-only-to-drafts)

```json theme={null}
{
  "message": "A request with this idempotency key is already in progress"
}
```

```json theme={null}
{
  "message": "domain already exists"
}
```

#### 422 Unprocessable Entity

The same idempotency key was used with a different method, resolved path, or request body. Use a new key for a new request, or retry the original request unchanged. See [idempotency](https://ahasend.com/docs/api-reference/idempotency.md).

#### 429 Too Many Requests

You've exceeded the API rate limits.

> [!TIP]
>
> When you receive this error, wait the number of seconds in the `Retry-After` header before you retry, and use exponential backoff with jitter if the error repeats. See [API rate limits](https://ahasend.com/docs/api-reference/rate-limits.md).

```json theme={null}
{
  "message": "Too many requests, rate limited."
}
```

**Daily test limit:** [Test Campaign](https://ahasend.com/docs/api-reference/campaigns/test-campaign.md) also answers `429` when the addresses of the test would take the day's total over 50 test emails (UTC). Its message currently reads `daily test send limit reached`. Backoff does not clear this `429`. A test to fewer addresses can still fit the same day; otherwise the limit clears when the UTC day changes. Keep count of the test emails you send each UTC day; a `429` from Test Campaign that stays after backoff is the daily limit. See [Test Campaign](https://ahasend.com/docs/api-reference/campaigns/test-campaign.md) for the rules of the limit.

### 5xx Server Errors

#### 500 Internal Server Error

An unexpected server error occurred on our side (these are rare).

> [!CAUTION]
>
> These errors indicate a problem on our end. If you consistently receive 500 errors, please contact support.

```json theme={null}
{
  "message": "Internal server error"
}
```

```json theme={null}
{
  "message": "internal server error, please try again later"
}
```

#### 502 Bad Gateway

[Test Campaign](https://ahasend.com/docs/api-reference/campaigns/test-campaign.md) answers `502` when the mail server could not take the test. Nothing was sent, and the test does not count toward the daily test limit. Retry the request.

```json theme={null}
{
  "message": "the test could not be sent"
}
```

#### 503 Service Unavailable

The service could not finish the request. Retry it later. When the response has a `Retry-After` header, wait that number of seconds before you retry.

**Template check busy:** [Create Message](https://ahasend.com/docs/api-reference/messages/create-message.md), [Create Template Message](https://ahasend.com/docs/api-reference/messages/create-template-message.md), [Create Conversation](https://ahasend.com/docs/api-reference/messages/create-conversation.md) and [Test Campaign](https://ahasend.com/docs/api-reference/campaigns/test-campaign.md) answer `503` with a `Retry-After` header when the template check could not run right now, because the service was busy or the check failed. Nothing was sent, and nothing is known to be wrong with the message. Send the same request again after the delay. If the request has an `Idempotency-Key`, use the same key: a `503` is not stored under it.

```json theme={null}
{
  "message": "the message could not be checked right now; try again in a moment"
}
```

**Template changing:** the transactional template operations answer `503` with a `Retry-After` header when the template kept changing while the request ran, for example while it was edited in the dashboard. Retry the request after that delay.

```json theme={null}
{
  "message": "template is being changed by another request, try again"
}
```

## Validation Errors

When request validation fails, you'll receive a `400 Bad Request` with a descriptive message:

### Request Body Validation

```json theme={null}
{
  "message": "invalid request body"
}
```

### Field-Specific Validation

The API provides specific validation messages for individual fields:

```json theme={null}
{
  "message": "invalid domain name, please provider a valid fully qualified domain name."
}
```

```json theme={null}
{
  "message": "limit must be between 1 and 100"
}
```

### Security-Related Validation

```json theme={null}
{
  "message": "domain is banned to protect our network from abuse and spammers. if you think this is an error please contact support"
}
```

## Scope and Permission Errors

When your API key doesn't have sufficient permissions:

### Missing Scopes

```json theme={null}
{
  "message": "sender domain not found in api key scopes"
}
```

### Invalid API Key Context

```json theme={null}
{
  "message": "invalid api key context"
}
```

## Best Practices

### Error Handling

* Always check the HTTP status code first
* Show the `message` field to people; do not branch on its text, which can change
* Retry 5xx errors with backoff. When a `503` has a `Retry-After` header, wait that number of seconds first
* Respect rate limits when receiving 429 responses

### Common Fixes

* **400 errors**: Validate your request parameters and JSON structure
* **401 errors**: Check your API key and authentication headers
* **403 errors**: Verify your API key has the required scopes
* **404 errors**: Confirm the resource exists and belongs to your account
* **429 errors**: Implement exponential backoff in your retry logic
* **503 errors**: Wait for the `Retry-After` delay, then send the same request again

> [!NOTE]
>
> Error messages are designed to be descriptive and actionable. They provide specific guidance on what needs to be corrected in your request.

## Related Guides

* [API authentication](https://ahasend.com/docs/api-reference/authentication.md), [Permission scopes](https://ahasend.com/docs/api-reference/scopes.md), [Send-only API keys](https://ahasend.com/docs/send-api/credentials.md).
* [REST sending guide](https://ahasend.com/docs/send-api/send-email.md), [SMTP settings](https://ahasend.com/docs/smtp.md), [CLI quickstart](https://ahasend.com/docs/cli/quickstart.md).
* [Node.js SDK](https://ahasend.com/docs/guides/nodejs-sdk.md), [Go SDK](https://ahasend.com/docs/guides/go-sdk.md), [Idempotency rules](https://ahasend.com/docs/api-reference/idempotency.md).
* [API rate limits](https://ahasend.com/docs/api-reference/rate-limits.md).


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