package main
import (
"context"
"fmt"
"log"
"os"
"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()
templateID := uuid.MustParse("11111111-1111-4111-8111-111111111111")
versionID := uuid.MustParse("22222222-2222-4222-8222-222222222222")
// The version goes into the draft; Publish then publishes it, so sends use
// it again.
response, _, err := client.TemplatesAPI.RestoreTemplateVersion(ctx, accountID, templateID, versionID, requests.RestoreTemplateVersionRequest{
Publish: true,
})
if err != nil {
log.Fatalf("Error restoring template version: %v", err)
}
fmt.Printf("Restored template %s, has draft: %t\n", response.Name, response.HasDraft)
}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 templateId = "00000000-0000-4000-8000-000000000009";
const versionId = "00000000-0000-4000-8000-000000000012";
const template = await client.templates.restoreVersion(templateId, versionId, { publish: true });
console.log("Template version restored.", { id: template.id, hasDraft: template.has_draft });
curl --request POST \
--url https://api.ahasend.com/v2/accounts/{account_id}/templates/{template_id}/versions/{version_id}/restore \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"publish": false
}
'import requests
url = "https://api.ahasend.com/v2/accounts/{account_id}/templates/{template_id}/versions/{version_id}/restore"
payload = { "publish": False }
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}/templates/{template_id}/versions/{version_id}/restore",
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([
'publish' => false
]),
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}/templates/{template_id}/versions/{version_id}/restore")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"publish\": false\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.ahasend.com/v2/accounts/{account_id}/templates/{template_id}/versions/{version_id}/restore")
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 \"publish\": false\n}"
response = http.request(request)
puts response.read_body{
"object": "template",
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"created_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z",
"name": "<string>",
"subject": "<string>",
"preheader": "<string>",
"variables": [
{
"name": "<string>",
"required": true
}
],
"from": {
"email": "noreply@example.com",
"name": "Example Corp"
},
"reply_to": {
"email": "noreply@example.com",
"name": "Example Corp"
},
"editor": "advanced",
"has_draft": true,
"content": {
"text_is_custom": true,
"mjml": "<string>",
"html": "<string>",
"text": "<string>"
}
}{
"message": "Error message"
}{
"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"
}{
"message": "template is being changed by another request, try again"
}Restore a Template Version via the API
Copy a published version of an AhaSend transactional template into its draft, and optionally publish it in the same request so that sends use it.
package main
import (
"context"
"fmt"
"log"
"os"
"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()
templateID := uuid.MustParse("11111111-1111-4111-8111-111111111111")
versionID := uuid.MustParse("22222222-2222-4222-8222-222222222222")
// The version goes into the draft; Publish then publishes it, so sends use
// it again.
response, _, err := client.TemplatesAPI.RestoreTemplateVersion(ctx, accountID, templateID, versionID, requests.RestoreTemplateVersionRequest{
Publish: true,
})
if err != nil {
log.Fatalf("Error restoring template version: %v", err)
}
fmt.Printf("Restored template %s, has draft: %t\n", response.Name, response.HasDraft)
}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 templateId = "00000000-0000-4000-8000-000000000009";
const versionId = "00000000-0000-4000-8000-000000000012";
const template = await client.templates.restoreVersion(templateId, versionId, { publish: true });
console.log("Template version restored.", { id: template.id, hasDraft: template.has_draft });
curl --request POST \
--url https://api.ahasend.com/v2/accounts/{account_id}/templates/{template_id}/versions/{version_id}/restore \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"publish": false
}
'import requests
url = "https://api.ahasend.com/v2/accounts/{account_id}/templates/{template_id}/versions/{version_id}/restore"
payload = { "publish": False }
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}/templates/{template_id}/versions/{version_id}/restore",
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([
'publish' => false
]),
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}/templates/{template_id}/versions/{version_id}/restore")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"publish\": false\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.ahasend.com/v2/accounts/{account_id}/templates/{template_id}/versions/{version_id}/restore")
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 \"publish\": false\n}"
response = http.request(request)
puts response.read_body{
"object": "template",
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"created_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z",
"name": "<string>",
"subject": "<string>",
"preheader": "<string>",
"variables": [
{
"name": "<string>",
"required": true
}
],
"from": {
"email": "noreply@example.com",
"name": "Example Corp"
},
"reply_to": {
"email": "noreply@example.com",
"name": "Example Corp"
},
"editor": "advanced",
"has_draft": true,
"content": {
"text_is_custom": true,
"mjml": "<string>",
"html": "<string>",
"text": "<string>"
}
}{
"message": "Error message"
}{
"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"
}{
"message": "template is being changed by another request, try again"
}templates:write.
The API and the dashboard edit the same draft, so the restore replaces the whole draft, including changes made in the dashboard. The template’s name does not change.
With publish: true, the API then publishes the draft, as Publish Template does. If the version cannot be published, the API refuses the request and the draft stays as it was. If the publish step fails after the restore, the draft keeps the restored version.
If the template changes in the dashboard or through another request while this request runs, the API tries again. If that continues, the API answers 503 with a Retry-After header. Retry the request after that delay.
This operation accepts an Idempotency-Key header. A 503 stores no response, so a retry with the same key runs the request again. See Idempotency.
Related Guides
- API authentication, Permission scopes, Idempotency.
- List Template Versions, 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
Template ID
Version ID
Body
Optional. An empty body restores without publishing.
Publish the draft once the version is restored into it.
Response
Version restored. The Template object is the published copy; has_draft says whether a draft is left.
Object type identifier
template Pass as template_id to Create Template Message to send this template
When the template was created
When the template's name or published content last changed
Template name, as it appears in the dashboard
The published subject, set on the template page. Empty until one is published, and overridden by a send that names its own subject.
The published preview text, injected into the delivered HTML when it is set
Every variable the design uses. A send of this template takes the
values only from each recipient's substitutions. Every recipient
must give a value for each required variable; if one does not, the
request is rejected and no message is sent.
Show child attributes
Show child attributes
The default sender, used by a send that names no from. Null when the template has none, and then every send must name one.
Show child attributes
Show child attributes
{
"email": "noreply@example.com",
"name": "Example Corp"
}
The default reply-to address, used by a send that sets no reply-to, also one that names its own from. Null when the template has none. It has the shape of a send request's reply_to; its name is always empty.
Show child attributes
Show child attributes
{
"email": "noreply@example.com",
"name": "Example Corp"
}
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 Whether the template has a draft, changes saved in the dashboard or through the API that are not published yet. Get Template Draft returns it.
The published content. Null when the published copy has no body, as for a template that was never published. List Templates leaves this field out; every other operation that returns a Template sets it.
Show child attributes
Show child attributes

