package main
import (
"context"
"fmt"
"log"
"github.com/AhaSend/ahasend-go"
"github.com/AhaSend/ahasend-go/api"
"github.com/AhaSend/ahasend-go/models/common"
"github.com/AhaSend/ahasend-go/models/requests"
"github.com/google/uuid"
)
func main() {
// Create API client with authentication
client := api.NewAPIClient(
api.WithAPIKey("aha-sk-your-64-character-key"),
)
accountID := uuid.New()
// Create context for the API call
ctx := context.Background()
// A conversational message sets the To/CC/BCC headers directly, so
// recipients can see each other (BCC excluded). The combined
// To + CC + BCC count must not exceed 50. Unlike Create Message,
// this endpoint does not support template substitutions.
response, httpResp, err := client.MessagesAPI.CreateConversationMessage(
ctx,
accountID,
requests.CreateConversationMessageRequest{
From: common.SenderAddress{
Email: "info@example.com",
Name: ahasend.String("Example Corp."),
},
To: []common.SenderAddress{
{Email: "john@example.com", Name: ahasend.String("John Smith")},
{Email: "jane@example.com", Name: ahasend.String("Jane Doe")},
},
CC: []common.SenderAddress{
{Email: "hr@example.com", Name: ahasend.String("Example Corp HR")},
},
BCC: []common.SenderAddress{
{Email: "archive@example.com"},
},
Subject: "Welcome to Example Corp",
HtmlContent: ahasend.String("<h1>Dear John and Jane, welcome to Example Corp!</h1>"),
TextContent: ahasend.String("Dear John and Jane, welcome to Example Corp!"),
Sandbox: ahasend.Bool(true),
},
)
if err != nil {
log.Fatalf("Error sending conversational message: %v", err)
}
// Check response
if httpResp.StatusCode == 202 {
fmt.Printf("✅ Send successful! Status: %d\n", httpResp.StatusCode)
if response != nil && len(response.Data) > 0 && response.Data[0].ID != nil {
fmt.Printf("Message ID: %s\n", *response.Data[0].ID)
}
} else {
fmt.Printf("❌ Unexpected status code: %d\n", httpResp.StatusCode)
}
}import { AhaSendClient } from "@ahasend/sdk";
const client = AhaSendClient.fromEnv();
const result = await client.messages.sendConversation(
{
from: { email: "sender@example.com", name: "Example" },
to: [{ email: "recipient@example.net" }],
subject: "Hello from AhaSend",
html_content: "<p>Hello!</p>",
sandbox: true,
},
{ idempotencyKey: "sdk-sample-send-conversation" },
);
console.log("Sandbox conversation accepted.", { count: result.data.length });
curl --request POST \
--url https://api.ahasend.com/v2/accounts/{account_id}/messages/conversation \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"from": {
"email": "noreply@example.com",
"name": "Example Corp"
},
"to": [
{
"email": "user@example.com",
"name": "John Doe"
},
{
"email": "someone@example.com",
"name": "Jane Doe"
}
],
"cc": [
{
"email": "hr@example.com",
"name": "Example Corp HR"
}
],
"bcc": [
{
"email": "bcc@example.com",
"name": "BCC Recipient"
}
],
"subject": "Welcome to Example Corp",
"html_content": "<h1>Dear John and Jane, welcome to Example Corp!</h1>",
"text_content": "Dear John and Jane, welcome to Example Corp!"
}
'import requests
url = "https://api.ahasend.com/v2/accounts/{account_id}/messages/conversation"
payload = {
"from": {
"email": "noreply@example.com",
"name": "Example Corp"
},
"to": [
{
"email": "user@example.com",
"name": "John Doe"
},
{
"email": "someone@example.com",
"name": "Jane Doe"
}
],
"cc": [
{
"email": "hr@example.com",
"name": "Example Corp HR"
}
],
"bcc": [
{
"email": "bcc@example.com",
"name": "BCC Recipient"
}
],
"subject": "Welcome to Example Corp",
"html_content": "<h1>Dear John and Jane, welcome to Example Corp!</h1>",
"text_content": "Dear John and Jane, welcome to Example Corp!"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.ahasend.com/v2/accounts/{account_id}/messages/conversation",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'from' => [
'email' => 'noreply@example.com',
'name' => 'Example Corp'
],
'to' => [
[
'email' => 'user@example.com',
'name' => 'John Doe'
],
[
'email' => 'someone@example.com',
'name' => 'Jane Doe'
]
],
'cc' => [
[
'email' => 'hr@example.com',
'name' => 'Example Corp HR'
]
],
'bcc' => [
[
'email' => 'bcc@example.com',
'name' => 'BCC Recipient'
]
],
'subject' => 'Welcome to Example Corp',
'html_content' => '<h1>Dear John and Jane, welcome to Example Corp!</h1>',
'text_content' => 'Dear John and Jane, welcome to Example Corp!'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}HttpResponse<String> response = Unirest.post("https://api.ahasend.com/v2/accounts/{account_id}/messages/conversation")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"from\": {\n \"email\": \"noreply@example.com\",\n \"name\": \"Example Corp\"\n },\n \"to\": [\n {\n \"email\": \"user@example.com\",\n \"name\": \"John Doe\"\n },\n {\n \"email\": \"someone@example.com\",\n \"name\": \"Jane Doe\"\n }\n ],\n \"cc\": [\n {\n \"email\": \"hr@example.com\",\n \"name\": \"Example Corp HR\"\n }\n ],\n \"bcc\": [\n {\n \"email\": \"bcc@example.com\",\n \"name\": \"BCC Recipient\"\n }\n ],\n \"subject\": \"Welcome to Example Corp\",\n \"html_content\": \"<h1>Dear John and Jane, welcome to Example Corp!</h1>\",\n \"text_content\": \"Dear John and Jane, welcome to Example Corp!\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.ahasend.com/v2/accounts/{account_id}/messages/conversation")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"from\": {\n \"email\": \"noreply@example.com\",\n \"name\": \"Example Corp\"\n },\n \"to\": [\n {\n \"email\": \"user@example.com\",\n \"name\": \"John Doe\"\n },\n {\n \"email\": \"someone@example.com\",\n \"name\": \"Jane Doe\"\n }\n ],\n \"cc\": [\n {\n \"email\": \"hr@example.com\",\n \"name\": \"Example Corp HR\"\n }\n ],\n \"bcc\": [\n {\n \"email\": \"bcc@example.com\",\n \"name\": \"BCC Recipient\"\n }\n ],\n \"subject\": \"Welcome to Example Corp\",\n \"html_content\": \"<h1>Dear John and Jane, welcome to Example Corp!</h1>\",\n \"text_content\": \"Dear John and Jane, welcome to Example Corp!\"\n}"
response = http.request(request)
puts response.read_body{
"object": "list",
"data": [
{
"object": "message",
"id": "<uuid@example.com>",
"recipient": {
"email": "user@example.com",
"name": "John Doe",
"substitutions": {
"first_name": "John",
"order_id": "12345"
}
},
"status": "queued",
"error": "<string>",
"schedule": {
"first_attempt": "2023-11-07T05:31:56Z",
"expires": "2023-11-07T05:31:56Z"
}
}
]
}{
"message": "Error message"
}{
"message": "Error message"
}{
"message": "Error message"
}{
"message": "A request with this idempotency key is already in progress"
}{
"message": "idempotency key was already used with a different request payload"
}{
"message": "Error message"
}Create Conversational Message
Creates and sends a conversational message (with support for CC and BCC) to one or more recipients. This API does not support template substitutions, use Create Message instead if you need substitutions.
Validation Requirements:
- Either
text_contentorhtml_contentis required from.emailmust be from a domain you own with valid DNS recordsretention.metadatamust be between 1 and 30 daysretention.datamust be between 0 and 30 days- If the
reply_toparameter is provided, do not includereply-toin headers - If the
ccparameter is provided, do not includeccin headers message-idheader will be ignored and automatically generated- Schedule times must be in RFC3339 format
schedule.first_attemptmust be in the future and within 7 days of the requestschedule.expiresmust be in the future and within 8 days of the request
Authorization uses the domain in from.email: either
messages:send:all or the matching domain-specific send role is
sufficient.
package main
import (
"context"
"fmt"
"log"
"github.com/AhaSend/ahasend-go"
"github.com/AhaSend/ahasend-go/api"
"github.com/AhaSend/ahasend-go/models/common"
"github.com/AhaSend/ahasend-go/models/requests"
"github.com/google/uuid"
)
func main() {
// Create API client with authentication
client := api.NewAPIClient(
api.WithAPIKey("aha-sk-your-64-character-key"),
)
accountID := uuid.New()
// Create context for the API call
ctx := context.Background()
// A conversational message sets the To/CC/BCC headers directly, so
// recipients can see each other (BCC excluded). The combined
// To + CC + BCC count must not exceed 50. Unlike Create Message,
// this endpoint does not support template substitutions.
response, httpResp, err := client.MessagesAPI.CreateConversationMessage(
ctx,
accountID,
requests.CreateConversationMessageRequest{
From: common.SenderAddress{
Email: "info@example.com",
Name: ahasend.String("Example Corp."),
},
To: []common.SenderAddress{
{Email: "john@example.com", Name: ahasend.String("John Smith")},
{Email: "jane@example.com", Name: ahasend.String("Jane Doe")},
},
CC: []common.SenderAddress{
{Email: "hr@example.com", Name: ahasend.String("Example Corp HR")},
},
BCC: []common.SenderAddress{
{Email: "archive@example.com"},
},
Subject: "Welcome to Example Corp",
HtmlContent: ahasend.String("<h1>Dear John and Jane, welcome to Example Corp!</h1>"),
TextContent: ahasend.String("Dear John and Jane, welcome to Example Corp!"),
Sandbox: ahasend.Bool(true),
},
)
if err != nil {
log.Fatalf("Error sending conversational message: %v", err)
}
// Check response
if httpResp.StatusCode == 202 {
fmt.Printf("✅ Send successful! Status: %d\n", httpResp.StatusCode)
if response != nil && len(response.Data) > 0 && response.Data[0].ID != nil {
fmt.Printf("Message ID: %s\n", *response.Data[0].ID)
}
} else {
fmt.Printf("❌ Unexpected status code: %d\n", httpResp.StatusCode)
}
}import { AhaSendClient } from "@ahasend/sdk";
const client = AhaSendClient.fromEnv();
const result = await client.messages.sendConversation(
{
from: { email: "sender@example.com", name: "Example" },
to: [{ email: "recipient@example.net" }],
subject: "Hello from AhaSend",
html_content: "<p>Hello!</p>",
sandbox: true,
},
{ idempotencyKey: "sdk-sample-send-conversation" },
);
console.log("Sandbox conversation accepted.", { count: result.data.length });
curl --request POST \
--url https://api.ahasend.com/v2/accounts/{account_id}/messages/conversation \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"from": {
"email": "noreply@example.com",
"name": "Example Corp"
},
"to": [
{
"email": "user@example.com",
"name": "John Doe"
},
{
"email": "someone@example.com",
"name": "Jane Doe"
}
],
"cc": [
{
"email": "hr@example.com",
"name": "Example Corp HR"
}
],
"bcc": [
{
"email": "bcc@example.com",
"name": "BCC Recipient"
}
],
"subject": "Welcome to Example Corp",
"html_content": "<h1>Dear John and Jane, welcome to Example Corp!</h1>",
"text_content": "Dear John and Jane, welcome to Example Corp!"
}
'import requests
url = "https://api.ahasend.com/v2/accounts/{account_id}/messages/conversation"
payload = {
"from": {
"email": "noreply@example.com",
"name": "Example Corp"
},
"to": [
{
"email": "user@example.com",
"name": "John Doe"
},
{
"email": "someone@example.com",
"name": "Jane Doe"
}
],
"cc": [
{
"email": "hr@example.com",
"name": "Example Corp HR"
}
],
"bcc": [
{
"email": "bcc@example.com",
"name": "BCC Recipient"
}
],
"subject": "Welcome to Example Corp",
"html_content": "<h1>Dear John and Jane, welcome to Example Corp!</h1>",
"text_content": "Dear John and Jane, welcome to Example Corp!"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.ahasend.com/v2/accounts/{account_id}/messages/conversation",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'from' => [
'email' => 'noreply@example.com',
'name' => 'Example Corp'
],
'to' => [
[
'email' => 'user@example.com',
'name' => 'John Doe'
],
[
'email' => 'someone@example.com',
'name' => 'Jane Doe'
]
],
'cc' => [
[
'email' => 'hr@example.com',
'name' => 'Example Corp HR'
]
],
'bcc' => [
[
'email' => 'bcc@example.com',
'name' => 'BCC Recipient'
]
],
'subject' => 'Welcome to Example Corp',
'html_content' => '<h1>Dear John and Jane, welcome to Example Corp!</h1>',
'text_content' => 'Dear John and Jane, welcome to Example Corp!'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}HttpResponse<String> response = Unirest.post("https://api.ahasend.com/v2/accounts/{account_id}/messages/conversation")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"from\": {\n \"email\": \"noreply@example.com\",\n \"name\": \"Example Corp\"\n },\n \"to\": [\n {\n \"email\": \"user@example.com\",\n \"name\": \"John Doe\"\n },\n {\n \"email\": \"someone@example.com\",\n \"name\": \"Jane Doe\"\n }\n ],\n \"cc\": [\n {\n \"email\": \"hr@example.com\",\n \"name\": \"Example Corp HR\"\n }\n ],\n \"bcc\": [\n {\n \"email\": \"bcc@example.com\",\n \"name\": \"BCC Recipient\"\n }\n ],\n \"subject\": \"Welcome to Example Corp\",\n \"html_content\": \"<h1>Dear John and Jane, welcome to Example Corp!</h1>\",\n \"text_content\": \"Dear John and Jane, welcome to Example Corp!\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.ahasend.com/v2/accounts/{account_id}/messages/conversation")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"from\": {\n \"email\": \"noreply@example.com\",\n \"name\": \"Example Corp\"\n },\n \"to\": [\n {\n \"email\": \"user@example.com\",\n \"name\": \"John Doe\"\n },\n {\n \"email\": \"someone@example.com\",\n \"name\": \"Jane Doe\"\n }\n ],\n \"cc\": [\n {\n \"email\": \"hr@example.com\",\n \"name\": \"Example Corp HR\"\n }\n ],\n \"bcc\": [\n {\n \"email\": \"bcc@example.com\",\n \"name\": \"BCC Recipient\"\n }\n ],\n \"subject\": \"Welcome to Example Corp\",\n \"html_content\": \"<h1>Dear John and Jane, welcome to Example Corp!</h1>\",\n \"text_content\": \"Dear John and Jane, welcome to Example Corp!\"\n}"
response = http.request(request)
puts response.read_body{
"object": "list",
"data": [
{
"object": "message",
"id": "<uuid@example.com>",
"recipient": {
"email": "user@example.com",
"name": "John Doe",
"substitutions": {
"first_name": "John",
"order_id": "12345"
}
},
"status": "queued",
"error": "<string>",
"schedule": {
"first_attempt": "2023-11-07T05:31:56Z",
"expires": "2023-11-07T05:31:56Z"
}
}
]
}{
"message": "Error message"
}{
"message": "Error message"
}{
"message": "Error message"
}{
"message": "A request with this idempotency key is already in progress"
}{
"message": "idempotency key was already used with a different request payload"
}{
"message": "Error message"
}Authorizations
API key for authentication. Non-empty Security Requirement values are AhaSend API-key roles. Roles listed within one requirement object are jointly required; separate requirement objects are alternatives.
Headers
Optional idempotency key for safe request retries. Must be a unique string for each logical request.
An identical request with a completed stored outcome returns the original status and body. An in-progress
execution returns 409, a changed method/path/body returns 422, and a released 5xx execution may run again.
Keys for non-secret responses expire after 24 hours. API-key create responses include a one-time secret_key,
so successful encrypted replay responses for those operations expire after 5 minutes.
255Path Parameters
Account ID
Body
Show child attributes
Show child attributes
{
"email": "noreply@example.com",
"name": "Example Corp"
}
This parameter can set the To header to multiple addresses. The combined to, cc, and bcc recipient count must not exceed 50.
1 - 50 elementsShow child attributes
Show child attributes
Email subject line
This parameter can set the CC header to multiple addresses. Do not include cc in the headers array. The combined to, cc, and bcc recipient count must not exceed 50.
1 - 50 elementsShow child attributes
Show child attributes
This parameter can set the To header to multiple addresses. The combined to, cc, and bcc recipient count must not exceed 50.
1 - 50 elementsShow child attributes
Show child attributes
If provided, the reply-to header in headers array must not be provided
Show child attributes
Show child attributes
{
"email": "noreply@example.com",
"name": "Example Corp"
}
Plain text content. Required if html_content is empty
HTML content. Required if text_content is empty
AMP HTML content
File attachments. For inline images, set the attachment's content_id to a value wrapped in angle brackets (e.g. <image1@example.com>) and reference it from html_content with cid: (e.g. <img src="cid:image1@example.com">).
Show child attributes
Show child attributes
Custom email headers. cc and reply-to headers cannot be provided if reply_to or cc parameters are provided, message-id will be ignored and automatically generated
Show child attributes
Show child attributes
Tags for categorizing messages
If true, the message will be sent to the sandbox environment
The result of the sandbox send
deliver, bounce, defer, fail, suppress Tracking settings for the message, overrides default account settings
Show child attributes
Show child attributes
{ "open": true, "click": true }
Retention settings for the message, overrides default account settings
Show child attributes
Show child attributes
{ "metadata": 1, "data": 0 }
Schedule for message delivery
Show child attributes
Show child attributes

