package main
import (
"context"
"fmt"
"log"
"os"
"github.com/AhaSend/ahasend-go"
"github.com/AhaSend/ahasend-go/api"
"github.com/AhaSend/ahasend-go/models/requests"
"github.com/google/uuid"
)
func main() {
client := api.NewAPIClient(api.WithAPIKey(os.Getenv("AHASEND_API_KEY")))
accountID := uuid.MustParse(os.Getenv("AHASEND_ACCOUNT_ID"))
ctx := context.Background()
// HTML content makes an html campaign template; MJML would make an
// advanced one. The text is made from the HTML when it is left out.
response, _, err := client.CampaignTemplatesAPI.CreateCampaignTemplate(ctx, accountID, requests.CreateCampaignTemplateRequest{
Name: "Monthly newsletter",
Content: &requests.TemplateContentInput{
HTML: ahasend.String(`<p>Hi {{ first_name }},</p><p>Here is our news.</p><p><a href="{{ unsubscribe_url }}">Unsubscribe</a></p>`),
},
})
if err != nil {
log.Fatalf("Error creating campaign template: %v", err)
}
fmt.Printf("Created %s campaign template %s\n", response.Editor, response.ID)
}
import { AhaSendClient } from "@ahasend/sdk";
const client = AhaSendClient.fromEnv();
// The SDK sends a fresh Idempotency-Key automatically and reuses it on its own retries.
const template = await client.campaignTemplates.create({
name: "Monthly newsletter",
content: {
html: '<p>Hello {{ first_name }}.</p><p><a href="{{ unsubscribe_url }}">Unsubscribe</a></p>',
},
});
console.log("Campaign template created.", { id: template.id, editor: template.editor });
curl --request POST \
--url https://api.ahasend.com/v2/accounts/{account_id}/campaign-templates \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"name": "<string>",
"content": {
"mjml": "<string>",
"html": "<string>",
"text": "<string>",
"text_is_custom": true
}
}
'import requests
url = "https://api.ahasend.com/v2/accounts/{account_id}/campaign-templates"
payload = {
"name": "<string>",
"content": {
"mjml": "<string>",
"html": "<string>",
"text": "<string>",
"text_is_custom": True
}
}
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}/campaign-templates",
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([
'name' => '<string>',
'content' => [
'mjml' => '<string>',
'html' => '<string>',
'text' => '<string>',
'text_is_custom' => true
]
]),
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}/campaign-templates")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"<string>\",\n \"content\": {\n \"mjml\": \"<string>\",\n \"html\": \"<string>\",\n \"text\": \"<string>\",\n \"text_is_custom\": true\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.ahasend.com/v2/accounts/{account_id}/campaign-templates")
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 \"name\": \"<string>\",\n \"content\": {\n \"mjml\": \"<string>\",\n \"html\": \"<string>\",\n \"text\": \"<string>\",\n \"text_is_custom\": true\n }\n}"
response = http.request(request)
puts response.read_body{
"object": "campaign_template",
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"created_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z",
"name": "<string>",
"editor": "advanced",
"content": {
"text_is_custom": true,
"mjml": "<string>",
"html": "<string>",
"text": "<string>"
}
}{
"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"
}{
"message": "Error message"
}Create a Campaign Template via the API
Create an AhaSend campaign template from MJML or HTML, or as an empty design for the dashboard’s editor, so that new campaigns can copy its design.
package main
import (
"context"
"fmt"
"log"
"os"
"github.com/AhaSend/ahasend-go"
"github.com/AhaSend/ahasend-go/api"
"github.com/AhaSend/ahasend-go/models/requests"
"github.com/google/uuid"
)
func main() {
client := api.NewAPIClient(api.WithAPIKey(os.Getenv("AHASEND_API_KEY")))
accountID := uuid.MustParse(os.Getenv("AHASEND_ACCOUNT_ID"))
ctx := context.Background()
// HTML content makes an html campaign template; MJML would make an
// advanced one. The text is made from the HTML when it is left out.
response, _, err := client.CampaignTemplatesAPI.CreateCampaignTemplate(ctx, accountID, requests.CreateCampaignTemplateRequest{
Name: "Monthly newsletter",
Content: &requests.TemplateContentInput{
HTML: ahasend.String(`<p>Hi {{ first_name }},</p><p>Here is our news.</p><p><a href="{{ unsubscribe_url }}">Unsubscribe</a></p>`),
},
})
if err != nil {
log.Fatalf("Error creating campaign template: %v", err)
}
fmt.Printf("Created %s campaign template %s\n", response.Editor, response.ID)
}
import { AhaSendClient } from "@ahasend/sdk";
const client = AhaSendClient.fromEnv();
// The SDK sends a fresh Idempotency-Key automatically and reuses it on its own retries.
const template = await client.campaignTemplates.create({
name: "Monthly newsletter",
content: {
html: '<p>Hello {{ first_name }}.</p><p><a href="{{ unsubscribe_url }}">Unsubscribe</a></p>',
},
});
console.log("Campaign template created.", { id: template.id, editor: template.editor });
curl --request POST \
--url https://api.ahasend.com/v2/accounts/{account_id}/campaign-templates \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"name": "<string>",
"content": {
"mjml": "<string>",
"html": "<string>",
"text": "<string>",
"text_is_custom": true
}
}
'import requests
url = "https://api.ahasend.com/v2/accounts/{account_id}/campaign-templates"
payload = {
"name": "<string>",
"content": {
"mjml": "<string>",
"html": "<string>",
"text": "<string>",
"text_is_custom": True
}
}
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}/campaign-templates",
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([
'name' => '<string>',
'content' => [
'mjml' => '<string>',
'html' => '<string>',
'text' => '<string>',
'text_is_custom' => true
]
]),
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}/campaign-templates")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"<string>\",\n \"content\": {\n \"mjml\": \"<string>\",\n \"html\": \"<string>\",\n \"text\": \"<string>\",\n \"text_is_custom\": true\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.ahasend.com/v2/accounts/{account_id}/campaign-templates")
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 \"name\": \"<string>\",\n \"content\": {\n \"mjml\": \"<string>\",\n \"html\": \"<string>\",\n \"text\": \"<string>\",\n \"text_is_custom\": true\n }\n}"
response = http.request(request)
puts response.read_body{
"object": "campaign_template",
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"created_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z",
"name": "<string>",
"editor": "advanced",
"content": {
"text_is_custom": true,
"mjml": "<string>",
"html": "<string>",
"text": "<string>"
}
}{
"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"
}{
"message": "Error message"
}templates:write.
A campaign template has no draft, no versions, no subject and no sender. The request sets the design that a campaign copies when you create it with template_id in Create Campaign. The campaign sets its own subject and sender.
Editor:
content.mjmlcreates anadvancedcampaign template, andcontent.htmlcreates anhtmlcampaign template.- Without
content.mjmlorcontent.html, seteditor. Aneditorthat does not agree with the content is refused. - Without
content, the campaign template gets an empty design, which you can complete in the dashboard’s editor. - You cannot change the editor after you create the campaign template.
- You can change the design of a
simplecampaign template only in the dashboard.
- MJML must pass strict validation. For a validation error, the message gives the line of each problem.
- Images and stylesheets must use full
https://URLs, such ashttps://example.com/logo.png. The API refuses relative paths, such asimages/logo.png, andhttp:,//,data:,cid:and other schemes. A URL that starts with a template variable, such as{{ logo_url }}, is allowed. The API cannot upload files. - The MJML, the HTML and a text written by hand can each be at most 200 KB.
- A campaign can copy the campaign template only when the campaign template has HTML.
Idempotency-Key header. See Idempotency.
Related Guides
- API authentication, Permission scopes, Idempotency.
- Campaigns API overview, Update Campaign Template, API errors, API rate limits.
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
A new campaign template.
Campaign template name. Spaces around it are dropped.
1 - 255Required when content holds neither mjml nor html. content.mjml means advanced and content.html means html; an editor that disagrees with the content is refused.
advanced, simple, html The content, by the rules of TemplateContentInput. A campaign template has no draft, so where those rules name the draft, they mean the campaign template itself.
Show child attributes
Show child attributes
Response
Campaign template created
A design a campaign copies when it is made from it. A campaign template has no draft, no versions, no subject and no sender; the campaign owns its subject and sender.
Object type identifier
campaign_template Campaign template ID
When the campaign template was created
When the campaign template last changed
Campaign template name, as it appears in the dashboard
The editor the template is designed with. It never changes after the template is created.
advanced: designed in MJML, with the dashboard's advanced editor.simple: designed with the dashboard's simple editor. Its HTML is made from the design and can be read but not changed through the API.html: an HTML template, uploaded or written by hand.
advanced, simple, html The content. Null when the campaign template has neither HTML nor text, as for one created without content. A campaign can be made from the campaign template only once it has HTML. List Campaign Templates leaves this field out; every other operation that returns a CampaignTemplate sets it.
Show child attributes
Show child attributes

