Send emails programmatically using AhaSend’s powerful API v2 create-message endpoint. This guide covers everything from basic email sending to advanced features like template variables, bulk operations, and scheduled delivery.
API v2 Features: This guide covers the advanced API v2 create-message endpoint, which provides enhanced features like template substitutions, bulk sending, scheduled delivery, and comprehensive webhook support.

Quick Start

Here’s a simple example to send your first email using the API:
curl --request POST \
  --url https://api.ahasend.com/v2/accounts/{account_id}/messages \
  --header 'Authorization: Bearer YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --data '{
    "from": {
      "email": "[email protected]",
      "name": "Your Company"
    },
    "recipients": [
      {
        "email": "[email protected]",
        "name": "John Doe"
      }
    ],
    "subject": "Welcome to our platform!",
    "text_content": "Thanks for signing up. We're excited to have you!"
  }'

Authentication

All API requests require authentication using your API v2 key:
Include your API key in the Authorization header:
Authorization: Bearer YOUR_API_KEY_HERE
Replace {account_id} in the URL with your actual account ID. The API Key must be created within this account.
https://api.ahasend.com/v2/accounts/{account_id}/messages
Need API Keys? If you haven’t created API v2 credentials yet, check out our API Credentials guide for step-by-step instructions.

Basic Examples

{
  "from": {
    "email": "[email protected]",
    "name": "Your Company"
  },
  "recipients": [
    {
      "email": "[email protected]",
      "name": "John Doe"
    }
  ],
  "subject": "Welcome to our platform!",
  "text_content": "Thanks for signing up. We're excited to have you!"
}

Advanced Examples

Multiple Recipients: When you specify multiple recipients in the recipients array, AhaSend sends separate individual emails to each recipient. This is not one email with multiple addresses in the To/CC headers, but rather individual personalized emails where each recipient only sees their own email address and can receive personalized template substitutions.
{
  "from": {
    "email": "[email protected]",
    "name": "Your Newsletter"
  },
  "recipients": [
    {
      "email": "[email protected]",
      "name": "Alice Smith"
    },
    {
      "email": "[email protected]",
      "name": "Bob Johnson"
    },
    {
      "email": "[email protected]",
      "name": "Carol Wilson"
    }
  ],
  "subject": "Monthly Newsletter - {{month}}",
  "html_content": "<h1>{{month}} Newsletter</h1><p>Dear {{name}}, here's what's new this month...</p>",
  "text_content": "{{month}} Newsletter - Dear {{name}}, here's what's new this month...",
  "substitutions": {
    "month": "December",
    "name": "Valued Customer"
  }
}

Response Handling

The API returns a response with information about each message created:

Successful Response (200)

{
  "object": "list",
  "data": [
    {
      "object": "message",
      "id": "3f8e2b1a-7c4d-4e2a-9b1e-2f3a4b5c6d7e",
      "recipient": {
        "email": "[email protected]",
        "name": "John Doe",
        "substitution_data": {
          "first_name": "John",
          "company": "Your Company"
        }
      },
      "status": "queued",
      "error": null,
      "schedule": {
        "first_attempt": "2024-01-15T10:30:00Z",
        "expires": "2024-01-16T10:30:00Z"
      }
    }
  ]
}

Response Fields

  • queued - Message accepted and queued for delivery
  • scheduled - Message scheduled for future delivery
  • failed - Message failed validation or processing
Unique identifier for tracking the message through webhooks and logs
If you include the schedule parameter in your request, the response will include timing information including the scheduled first attempt and expiration.

Error Handling

Handle different HTTP status codes appropriately:
Common causes:
  • Missing required fields (from, recipients, subject)
  • Invalid email addresses
  • Missing text_content or html_content
  • Invalid retention values (outside 1-30 days range)
Example error response:
{
  "error": {
    "type": "validation_error",
    "message": "Either text_content or html_content is required"
  }
}
Common causes:
  • Missing or invalid API key
  • Malformed Authorization header
Solution:
--header 'Authorization: Bearer YOUR_VALID_API_KEY'
Common causes:
  • Sender domain not verified
  • API key doesn’t have permission for the account
  • Account suspended or over limits
Solution: Verify domain in dashboard and check account status
Idempotency key conflict
  • Request with same idempotency key already processed
  • Returns original response for duplicate requests

Validation Requirements

Based on the API documentation, ensure your requests meet these requirements:
  • Either text_content or html_content is required
  • Both can be provided for multipart emails
  • Use proper HTML structure for html_content
  • from.email must be from a domain you own
  • Domain must have valid DNS records configured
  • Domain must be verified in your AhaSend account
  • retention.metadata must be between 1 and 30 days
  • retention.data must be between 0 and 30 days
  • Use 0 for immediate content deletion after processing
  • Schedule times must be in RFC3339 format
  • Example: "2024-12-25T10:30:00Z"
  • Times should be in UTC timezone

Best Practices

Use idempotency keys for safe retries:
--header 'Idempotency-Key: unique-request-id-12345'
Keys expire after 24 hours and ensure duplicate requests return the same response.
AhaSend supports MiniJinja templating language for email content.
  • Use descriptive variable names
  • Provide fallback values in templates
  • Validate variables before sending
  • Escape HTML content in variables
Efficient bulk sending:
  • Send up to 100 requests per second
  • Send up to 100 recipients per request
  • Handle partial failures gracefully
  • Implement retry logic for failed messages
Robust error handling:
  • Implement exponential backoff for retries
  • Log API responses for debugging
  • Handle different status codes appropriately
  • Use webhooks for delivery confirmation