package mainimport ( "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() campaignID := uuid.MustParse("11111111-1111-4111-8111-111111111111") response, _, err := client.CampaignsAPI.TestCampaign(ctx, accountID, campaignID, requests.TestCampaignRequest{ To: []string{"Ann <ann@yourdomain.com>", "bob@yourdomain.com"}, }) if err != nil { log.Fatalf("Error sending test: %v", err) } if response.ResultUnknown { fmt.Println("The test may have gone out; check the inboxes before you send another") return } fmt.Printf("Sent to %v\n", response.SentTo) for _, failure := range response.Failed { fmt.Printf("Refused %s: %s\n", failure.Email, failure.Message) }}
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 campaignId = "00000000-0000-4000-8000-000000000014";
const result = await client.campaigns.test(campaignId, { to: ["reviewer@example.com"] });
console.log("Campaign test sent.", {
sentTo: result.sent_to,
failed: result.failed.length,
resultUnknown: result.result_unknown,
});
{
"message": "campaign is not ready to send",
"issues": [
{
"code": "subject_missing",
"message": "Add a subject before you send the campaign."
}
]
}
{
"message": "Error message"
}
{
"message": "Error message"
}
{
"message": "Error message"
}
{
"message": "campaign is not a draft"
}
{
"message": "idempotency key was already used with a different request payload"
}
{
"message": "Error message"
}
{
"message": "Error message"
}
{
"message": "Error message"
}
{
"message": "the message could not be checked right now; try again in a moment"
}
Campaigns
Send a Campaign Test via the API
Send a test of a draft AhaSend marketing campaign to up to 5 addresses to check it in a real inbox. An account can send 50 test emails per day (UTC).
POST
/
v2
/
accounts
/
{account_id}
/
campaigns
/
{campaign_id}
/
test
AhaSend Go SDK
package mainimport ( "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() campaignID := uuid.MustParse("11111111-1111-4111-8111-111111111111") response, _, err := client.CampaignsAPI.TestCampaign(ctx, accountID, campaignID, requests.TestCampaignRequest{ To: []string{"Ann <ann@yourdomain.com>", "bob@yourdomain.com"}, }) if err != nil { log.Fatalf("Error sending test: %v", err) } if response.ResultUnknown { fmt.Println("The test may have gone out; check the inboxes before you send another") return } fmt.Printf("Sent to %v\n", response.SentTo) for _, failure := range response.Failed { fmt.Printf("Refused %s: %s\n", failure.Email, failure.Message) }}
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 campaignId = "00000000-0000-4000-8000-000000000014";
const result = await client.campaigns.test(campaignId, { to: ["reviewer@example.com"] });
console.log("Campaign test sent.", {
sentTo: result.sent_to,
failed: result.failed.length,
resultUnknown: result.result_unknown,
});
{
"message": "campaign is not ready to send",
"issues": [
{
"code": "subject_missing",
"message": "Add a subject before you send the campaign."
}
]
}
{
"message": "Error message"
}
{
"message": "Error message"
}
{
"message": "Error message"
}
{
"message": "campaign is not a draft"
}
{
"message": "idempotency key was already used with a different request payload"
}
{
"message": "Error message"
}
{
"message": "Error message"
}
{
"message": "Error message"
}
{
"message": "the message could not be checked right now; try again in a moment"
}
The AhaSend API sends a test of a draft campaign. Access requires campaigns:send.Addresses:
to holds 1 to 5 addresses. Addresses that differ only in case count once.
An entry can have a display name, such as Ann <ann@example.com>. The test goes to the address only.
What the test holds:
Each address gets the design with placeholders for the contact’s fields.
The links in the test lead to a contact that does not exist, so a click on the unsubscribe link does not unsubscribe anyone.
When the API refuses the test:
The campaign must be a draft. Any other status answers 409.
A campaign with issues is refused with 400, and the response holds the issues. The issue unsubscribe_link_missing does not stop a test. See Issues.
The domain of the sender must be verified and not paused. If not, the test is refused with 400.
Every test is checked with the template engine before it is sent. Content that the check refuses is answered with 400, and nothing is sent. See API errors.
An account that is blocked until a person acts, for example a sub-account in the parent-suspended status, whose parent account is suspended, cannot send tests: the test is refused with 400. An account that is blocked only until it pays, for example one with no credits left, can still send tests, because tests use no credits.
Daily limit:
Your account can send 50 test emails per day (UTC). Each address of a test counts as one test email. Test sends from the API and from the dashboard count together.
The API refuses the whole test when its addresses would take the day’s total over 50. For example, with 48 test emails used, a test to 5 addresses is refused, and a test to 2 addresses is sent.
The API answers 429 when it refuses a test for the limit. Its message currently reads daily test send limit reached. Backoff does not clear this 429. A test to fewer addresses can still fit in the test emails left for the day, as in the example above. Otherwise, the limit clears when the UTC day changes. To plan for it, keep count of the test emails you send each UTC day. A 429 from Test Campaign that stays after backoff is the daily limit.
An address that the mail server refused still counts, and so does a test with result_unknown. A test that sent nothing does not count: a 502, a 503, or a 400 from the template check.
Response:
sent_to lists the addresses that the mail server accepted, and failed lists the addresses it refused, each with the reason. An address in failed is given as the mail server reported it, so it can differ from the addresses in to.
When result_unknown is true, the mail server took the request, but its answer could not be read. The test may have gone out, and sent_to and failed are empty. Check the inboxes before you send another test.
When the mail server could not take the test, the API answers 502 and nothing was sent. Retry the request.
When the template check could not run right now, the API answers 503 with a Retry-After header, and nothing was sent. Retry the request after that delay.
Idempotency:
This operation accepts an Idempotency-Key header. A 2xx answer is stored, so a retry with the same key replays it and sends nothing again. Unlike other operations, a 4xx answer is not stored. A retry with the same key, for example after the daily limit resets, gets a new answer. A 502 or a 503 is not stored either, so you can retry it with the same key. See Idempotency.
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.
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.
1 to 5 addresses, counted after addresses that differ only in case are dropped. An entry may carry a display name, such as Ann <ann@example.com>; the test goes to the address alone.
Minimum array length: 1
Response
What the test send did. With result_unknown, the test may have gone out.
True when the mail server took the request but its answer could not be read. The test may have gone out; sent_to and failed are empty. Check the inboxes before you send another.
{"docsConfig":{"theme":"mint","$schema":"https://mintlify.com/docs.json","name":"AhaSend","description":"AhaSend is a European transactional email service for developers: send through a REST API, SMTP relay, CLI or the official Node.js and Go SDKs, with data stored in the EU and 1,000 free emails per month.","colors":{"primary":"#066fd1","light":"#F8FAFC","dark":"#0F172A"},"logo":{"light":"https://mintcdn.com/ahasend/F35Ozd-1GsftDpcH/logo.png?fit=max\u0026auto=format\u0026n=F35Ozd-1GsftDpcH\u0026q=85\u0026s=ca1d4c27f7c2811598e65cb25a21323c","dark":"https://mintcdn.com/ahasend/F35Ozd-1GsftDpcH/logo-dark.png?fit=max\u0026auto=format\u0026n=F35Ozd-1GsftDpcH\u0026q=85\u0026s=bb6b9068b30f93fd1ea216e2a7c1d137","href":"https://ahasend.com/"},"favicon":"https://mintcdn.com/ahasend/F35Ozd-1GsftDpcH/favicon.png?fit=max\u0026auto=format\u0026n=F35Ozd-1GsftDpcH\u0026q=85\u0026s=ac855c16b6cb74b8c5965d2e7ef3e324","appearance":{"strict":false},"navbar":{"links":[{"href":"https://dash.ahasend.com","label":"Login"}],"primary":{"type":"button","label":"Get Started","href":"https://dash.ahasend.com/user/register"}},"footer":{"socials":{"x":"https://x.com/aha_send","linkedin":"https://www.linkedin.com/company/ahasend","github":"https://github.com/ahasend"},"links":[{"header":"Resources","items":[{"label":"Pricing","href":"https://ahasend.com/pricing"},{"label":"Support","href":"mailto:support@ahasend.com"},{"label":"Status","href":"https://status.ahasend.com"},{"label":"Security","href":"https://ahasend.com/security"}]},{"header":"Company","items":[{"label":"Blog","href":"https://ahasend.com/blog"},{"label":"Feedback Board","href":"https://ahasend.sleekplan.app/"}]},{"header":"Legal","items":[{"label":"Imprint","href":"https://ahasend.com/imprint"},{"label":"Terms of Service","href":"https://ahasend.com/terms"},{"label":"Privacy Policy","href":"https://ahasend.com/privacy"},{"label":"Data Processing Agreement","href":"https://ahasend.com/dpa"}]}]},"seo":{"metatags":{"canonical":"https://ahasend.com/docs","twitter:site":"@aha_send"},"organization":{"name":"AhaSend","legalName":"AhaSend B.V.","url":"https://ahasend.com","sameAs":["https://x.com/aha_send","https://www.linkedin.com/company/ahasend","https://github.com/ahasend"]}},"integrations":{"telemetry":{"enabled":true},"cookies":{"key":"cookieConsent","value":"true"}},"errors":{"404":{"redirect":true}},"contextual":{"options":["copy","view","chatgpt","claude"],"display":"header"},"thumbnails":{"appearance":"dark","background":"https://mintcdn.com/ahasend/Gpf8BnLpzpIKQ4dU/images/social-background.svg?fit=max\u0026auto=format\u0026n=Gpf8BnLpzpIKQ4dU\u0026q=85\u0026s=df32e1edef517352b8437c75feecbf6e"},"markdown":{"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."]},"styling":{"latex":false},"navigation":{"pages":[]}},"deployment":{"deploymentMetadataValue":{"subdomain":"ahasend","hasAudioNarration":false,"actualSubdomain":"ahasend","customDomains":["ahasend.com"],"gitSource":{"type":"github","owner":"ahasend","repo":"docs","deployBranch":"main","contentDirectory":"","isPrivate":true,"mountPath":"","label":""},"chroma":{"liveDeploymentHistoryId":"6ae676bdbfc5f43dec480549","collectionId":"3ae1f8a4-6f5e-450f-b047-b31a038b1ee5","schemaVersion":"v3","latestBuiltDeploymentHistoryId":"6ae676bdbfc5f43dec480549"},"feedback":{"thumbs":true},"entitlements":{},"buildId":"6ae676bdbfc5f43dec480549","clientVersion":"0.0.4044","searchFilterCounts":[{"language":"default","tag":"API Reference","count":148},{"language":"default","tag":"API reference","count":114},{"language":"default","tag":"Documentation","count":68},{"language":"default","tag":"Guides","count":52},{"language":"default","tag":"Integrations","count":41},{"language":"default","tag":"Webhooks","count":29},{"language":"default","tag":"CLI","count":25},{"language":"default","tag":"Commands","count":15},{"language":"default","tag":"Domain Authentication","count":13},{"language":"default","tag":"Campaigns","count":12}]},"assistantConfig":{},"basePath":"/docs","hasChatPermissions":false,"hasWebMcpPermissions":false,"toggles":[{"name":"kill-isr","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-mintlify-slack","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-integrations-settings","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-pr-grouping","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"custom-prefix","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"analytics-v7","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"user-flows-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"no-publish-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-onboarding","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"llms-txt-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving-live","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"stripTemperatureMiddleware","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"support-platform-pylon-zendesk","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"instant-rollback","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications-server","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-fable","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fixed-ai-action-pricing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automation-resolve-merge-conflict","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"scoped-publishing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"mintql","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"page-level-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-version-history-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-page-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"full-page-search","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workspace-projects","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"assistant-v5","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"byok-sep-25","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fork-pr-previews","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"revalidation-jwt","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"vite-origin","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-updated-9-15","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-sso-scim","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"hobby-abuse-scan","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"dashboard-inbox","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-signup","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"turbopuffer-dual-write","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-enabled","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"approve-review-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"sso-setup-deadline-banner","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false}],"privacy":{"consentBanner":{"enabled":false}},"googleFontsInlined":false},"customCss":[{"filePath":"style.css","content":"#content-container table{display:table}#content-container table thead th{text-align:left}"},{"filePath":"roadmap.css","content":".rm{display:flex;flex-direction:column;gap:2.5rem;margin-top:1.5rem}.rm-head{display:flex;align-items:center;gap:.65rem;margin-bottom:1rem}.rm-badge{display:inline-flex;align-items:center;margin:0;border:0;font-size:.78rem;font-weight:600;letter-spacing:.02em;padding:.28rem .75rem;border-radius:999px;line-height:1}.rm-badge.is-active{background:#fdebd0;color:#854f0b}.rm-badge.is-planned{background:#e6f1fb;color:#0c447c}.rm-badge.is-shipped{background:#e1f5ee;color:#0f6e56}.rm-list{display:flex;flex-direction:column;gap:.65rem}.rm-card{display:flex;gap:.9rem;padding:.9rem 1.05rem;background:#fff;border:1px solid #e5e7eb;border-radius:.7rem;transition:transform .15s ease,box-shadow .15s ease}.rm-card:hover{transform:translateY(-1px);box-shadow:0 4px 14px rgba(0,0,0,.06)}.rm-accent{flex:0 0 3px;border-radius:2px}.rm-card.is-active .rm-accent{background:#ba7517}.rm-card.is-planned .rm-accent{background:#378add}.rm-card.is-shipped .rm-accent{background:#1d9e75}.rm-card.is-sub{margin-left:2rem;position:relative}.rm-card p,.rm-card.is-sub .rm-title{font-size:.9rem}.rm-card.is-sub::after,.rm-card.is-sub::before{content:\"\";position:absolute;left:-1.15rem;pointer-events:none}.rm-card.is-sub::before{top:-.65rem;height:calc(100% + .65rem);border-left:1.5px solid #d1d5db}.rm-card.is-sub::after{top:50%;width:.85rem;border-top:1.5px solid #d1d5db}.rm-card .rm-title{margin:0 0 .2rem;font-size:.97rem;font-weight:600;line-height:1.35;color:#111827}.rm-card p{margin:0;line-height:1.55;color:#4b5563}.rm-date,.rm-tag{display:inline-block}.rm-date{margin-top:.5rem;font-size:.78rem;font-weight:600;color:#0f6e56}.rm-tag{margin-left:.5rem;font-size:.66rem;font-weight:700;letter-spacing:.04em;text-transform:uppercase;padding:.16rem .5rem;border-radius:999px;vertical-align:middle;line-height:1.4;color:#fff;box-shadow:0 1px 2px rgba(0,0,0,.15)}.rm-tag.is-new{background:#6d28d9}.rm-tag.is-product{background:#be123c}.rm-tag.is-improvement{background:#0e7490}.rm-tag.is-early{background:#1d4ed8}.rm-tag.is-bugfix{background:#c2410c}.dark .rm-card{background:rgba(255,255,255,.025);border-color:rgba(255,255,255,.09)}.dark .rm-card p{color:#9ca3af}.dark .rm-badge.is-active{background:rgba(186,117,23,.18);color:#fac074}.dark .rm-badge.is-planned{background:rgba(55,138,221,.18);color:#85b7eb}.dark .rm-badge.is-shipped{background:rgba(29,158,117,.18);color:#5dcaa5}.dark .rm-date{color:#5dcaa5}.dark .rm-card.is-sub::after,.dark .rm-card.is-sub::before{border-color:rgba(255,255,255,.18)}.rm-note{margin-top:2.5rem;font-size:.85rem;color:#6b7280}.dark .rm-note{color:#9ca3af}.dark .rm-card .rm-title{color:#e7e9ee}.rm-jump{margin:-.5rem 0 0;font-size:.88rem}.rm-jump a{color:#2296ff;text-decoration:none;font-weight:500}.rm-jump a:hover{text-decoration:underline}.rm-badge[id]{scroll-margin-top:6rem}"}],"page":{"pagePath":"api-reference/campaigns/test-campaign","slug":"/api-reference/campaigns/test-campaign","pageMetadata":{"title":"Send a Campaign Test via the API","sidebarTitle":"Test Campaign","openapi":"openapi.yaml POST /v2/accounts/{account_id}/campaigns/{campaign_id}/test","description":"Send a test of a draft AhaSend marketing campaign to up to 5 addresses to check it in a real inbox. An account can send 50 test emails per day (UTC).","href":"/api-reference/campaigns/test-campaign"},"description":{"compiledSource":"\"use strict\";\nconst {jsx: _jsx} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n const _components = {\n p: \"p\",\n ..._provideComponents(),\n ...props.components\n };\n return _jsx(_components.p, {\n children: \"Send a test of a draft AhaSend marketing campaign to up to 5 addresses to check it in a real inbox. An account can send 50 test emails per day (UTC).\"\n });\n}\nfunction MDXContent(props = {}) {\n const {wrapper: MDXLayout} = {\n ..._provideComponents(),\n ...props.components\n };\n return MDXLayout ? _jsx(MDXLayout, {\n ...props,\n children: _jsx(_createMdxContent, {\n ...props\n })\n }) : _createMdxContent(props);\n}\nreturn {\n default: MDXContent\n};\n","frontmatter":{},"scope":{}},"pageType":"default","mdx":{"mdxSource":{"compiledSource":"\"use strict\";const{Fragment:_Fragment,jsx:_jsx,jsxs:_jsxs}=arguments[0];const{useMDXComponents:_provideComponents}=arguments[0];function _createMdxContent(props){const _components={a:`a`,code:`code`,li:`li`,p:`p`,strong:`strong`,ul:`ul`,..._provideComponents(),...props.components},{Heading}=_components;if(!Heading)_missingMdxReference(`Heading`,true);return _jsxs(_Fragment,{children:[_jsxs(_components.p,{children:[`The AhaSend API sends a test of a draft campaign. Access requires `,_jsx(_components.code,{children:`campaigns:send`}),`.`]}),`\n`,_jsx(_components.p,{children:_jsx(_components.strong,{children:`Addresses:`})}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[_jsx(_components.code,{children:`to`}),` holds 1 to 5 addresses. Addresses that differ only in case count once.`]}),`\n`,_jsxs(_components.li,{children:[`An entry can have a display name, such as `,_jsx(_components.code,{children:`Ann \u003cann@example.com>`}),`. The test goes to the address only.`]}),`\n`]}),`\n`,_jsx(_components.p,{children:_jsx(_components.strong,{children:`What the test holds:`})}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsx(_components.li,{children:`Each address gets the design with placeholders for the contact’s fields.`}),`\n`,_jsx(_components.li,{children:`The links in the test lead to a contact that does not exist, so a click on the unsubscribe link does not unsubscribe anyone.`}),`\n`]}),`\n`,_jsx(_components.p,{children:_jsx(_components.strong,{children:`When the API refuses the test:`})}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[`The campaign must be a draft. Any other status answers `,_jsx(_components.code,{children:`409`}),`.`]}),`\n`,_jsxs(_components.li,{children:[`A campaign with issues is refused with `,_jsx(_components.code,{children:`400`}),`, and the response holds the issues. The issue `,_jsx(_components.code,{children:`unsubscribe_link_missing`}),` does not stop a test. See `,_jsx(_components.a,{href:`/api-reference/campaigns/overview#issues`,children:`Issues`}),`.`]}),`\n`,_jsxs(_components.li,{children:[`The domain of the sender must be verified and not paused. If not, the test is refused with `,_jsx(_components.code,{children:`400`}),`.`]}),`\n`,_jsxs(_components.li,{children:[`Every test is checked with the template engine before it is sent. Content that the check refuses is answered with `,_jsx(_components.code,{children:`400`}),`, and nothing is sent. See `,_jsx(_components.a,{href:`/api-reference/errors#400-bad-request`,children:`API errors`}),`.`]}),`\n`,_jsxs(_components.li,{children:[`An account that is blocked until a person acts, for example a sub-account in the `,_jsx(_components.code,{children:`parent-suspended`}),` status, whose parent account is suspended, cannot send tests: the test is refused with `,_jsx(_components.code,{children:`400`}),`. An account that is blocked only until it pays, for example one with no credits left, can still send tests, because tests use no credits.`]}),`\n`]}),`\n`,_jsx(_components.p,{children:_jsx(_components.strong,{children:`Daily limit:`})}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsx(_components.li,{children:`Your account can send 50 test emails per day (UTC). Each address of a test counts as one test email. Test sends from the API and from the dashboard count together.`}),`\n`,_jsx(_components.li,{children:`The API refuses the whole test when its addresses would take the day’s total over 50. For example, with 48 test emails used, a test to 5 addresses is refused, and a test to 2 addresses is sent.`}),`\n`,_jsxs(_components.li,{children:[`The API answers `,_jsx(_components.code,{children:`429`}),` when it refuses a test for the limit. Its message currently reads `,_jsx(_components.code,{children:`daily test send limit reached`}),`. Backoff does not clear this `,_jsx(_components.code,{children:`429`}),`. A test to fewer addresses can still fit in the test emails left for the day, as in the example above. Otherwise, the limit clears when the UTC day changes. To plan for it, keep count of the test emails you send each UTC day. A `,_jsx(_components.code,{children:`429`}),` from Test Campaign that stays after backoff is the daily limit.`]}),`\n`,_jsxs(_components.li,{children:[`An address that the mail server refused still counts, and so does a test with `,_jsx(_components.code,{children:`result_unknown`}),`. A test that sent nothing does not count: a `,_jsx(_components.code,{children:`502`}),`, a `,_jsx(_components.code,{children:`503`}),`, or a `,_jsx(_components.code,{children:`400`}),` from the template check.`]}),`\n`]}),`\n`,_jsx(_components.p,{children:_jsx(_components.strong,{children:`Response:`})}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[_jsx(_components.code,{children:`sent_to`}),` lists the addresses that the mail server accepted, and `,_jsx(_components.code,{children:`failed`}),` lists the addresses it refused, each with the reason. An address in `,_jsx(_components.code,{children:`failed`}),` is given as the mail server reported it, so it can differ from the addresses in `,_jsx(_components.code,{children:`to`}),`.`]}),`\n`,_jsxs(_components.li,{children:[`When `,_jsx(_components.code,{children:`result_unknown`}),` is `,_jsx(_components.code,{children:`true`}),`, the mail server took the request, but its answer could not be read. The test may have gone out, and `,_jsx(_components.code,{children:`sent_to`}),` and `,_jsx(_components.code,{children:`failed`}),` are empty. Check the inboxes before you send another test.`]}),`\n`,_jsxs(_components.li,{children:[`When the mail server could not take the test, the API answers `,_jsx(_components.code,{children:`502`}),` and nothing was sent. Retry the request.`]}),`\n`,_jsxs(_components.li,{children:[`When the template check could not run right now, the API answers `,_jsx(_components.code,{children:`503`}),` with a `,_jsx(_components.code,{children:`Retry-After`}),` header, and nothing was sent. Retry the request after that delay.`]}),`\n`]}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`Idempotency:`}),`\nThis operation accepts an `,_jsx(_components.code,{children:`Idempotency-Key`}),` header. A `,_jsx(_components.code,{children:`2xx`}),` answer is stored, so a retry with the same key replays it and sends nothing again. Unlike other operations, a `,_jsx(_components.code,{children:`4xx`}),` answer is not stored. A retry with the same key, for example after the daily limit resets, gets a new answer. A `,_jsx(_components.code,{children:`502`}),` or a `,_jsx(_components.code,{children:`503`}),` is not stored either, so you can retry it with the same key. See `,_jsx(_components.a,{href:`/api-reference/idempotency`,children:`Idempotency`}),`.`]}),`\n`,_jsx(Heading,{level:`2`,id:`related-guides`,children:`Related Guides`}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[_jsx(_components.a,{href:`/api-reference/authentication`,children:`API authentication`}),`, `,_jsx(_components.a,{href:`/api-reference/scopes`,children:`Permission scopes`}),`, `,_jsx(_components.a,{href:`/api-reference/idempotency`,children:`Idempotency`}),`.`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.a,{href:`/api-reference/campaigns/send-campaign`,children:`Send Campaign`}),`, `,_jsx(_components.a,{href:`/api-reference/errors`,children:`API errors`}),`, `,_jsx(_components.a,{href:`/api-reference/rate-limits`,children:`API rate limits`}),`.`]}),`\n`]})]})}function MDXContent(props={}){const{wrapper:MDXLayout}={..._provideComponents(),...props.components};return MDXLayout?_jsx(MDXLayout,{...props,children:_jsx(_createMdxContent,{...props})}):_createMdxContent(props)}return{default:MDXContent};function _missingMdxReference(id,component){throw new Error(`Expected `+(component?`component`:`object`)+\" `\"+id+\"` to be defined: you likely forgot to import, pass, or provide it.\")}","frontmatter":{},"scope":{"config":{},"pageMetadata":{"title":"Send a Campaign Test via the API","sidebarTitle":"Test Campaign","openapi":"openapi.yaml POST /v2/accounts/{account_id}/campaigns/{campaign_id}/test","description":"Send a test of a draft AhaSend marketing campaign to up to 5 addresses to check it in a real inbox. An account can send 50 test emails per day (UTC).","href":"/api-reference/campaigns/test-campaign"}}},"mdxSourceWithNoJs":null},"mdxExtracts":{"tableOfContents":[{"title":"Related Guides","slug":"related-guides","depth":2,"children":[]}],"codeExamples":{}},"jsLinks":["/docs/_mintlify/custom/ahasend/2374706ad872d133/ahasend-utm.js"],"openApiReferenceData":{"operation":{"summary":"Test Campaign","description":"Send a test of a draft AhaSend marketing campaign to up to 5 addresses to check it in a real inbox. An account can send 50 test emails per day (UTC).","operationId":"testCampaign","tags":["Campaigns"],"parameters":["a541d5ff-dfbe-4d64-82ab-59c4271cc6d6","be74d27e-4449-4503-aa03-d86dd26390e4","dd57e0bc-75d0-4fee-8ea2-6589f3d326a1"],"security":["68fd5fc1-be8f-4903-8d85-3e41e3444f4f"],"requestBody":"6c132ce7-f199-4606-8bd3-6d58a9bcb067","responses":{"200":"2ca76c0c-e0ff-4e85-882c-ef691a93f3c5","400":"8dab99e5-00a3-47da-b9e0-10620c164efa","401":"80ffed94-ab1a-49e2-891c-85e65a5a756f","403":"dd9fa907-cf5b-4a11-b8fc-62d06c65a1bc","404":"8c8c7740-4d4a-4727-b4b2-acfc52a8c1b9","409":"a6971505-d77a-4c0f-a0ec-d06a32f88be5","422":"22a80dd0-4183-46e1-9d7a-053cf455bc22","429":"20ef5599-6d8a-478e-a390-e00b9521dc56","500":"31c9060d-39d3-4037-97df-e00fe87d26a4","502":"6aa1500b-7825-4040-ac81-434beb3c3d40","503":"d5e839a6-9504-4f2a-a26b-d6d53038f3ad"},"x-code-samples":[{"lang":"go","label":"AhaSend Go SDK","source":"package main\n\nimport (\n \"context\"\n \"fmt\"\n \"log\"\n \"os\"\n\n \"github.com/AhaSend/ahasend-go/api\"\n \"github.com/AhaSend/ahasend-go/models/requests\"\n \"github.com/google/uuid\"\n)\n\nfunc main() {\n client := api.NewAPIClient(api.WithAPIKey(os.Getenv(\"AHASEND_API_KEY\")))\n accountID := uuid.MustParse(os.Getenv(\"AHASEND_ACCOUNT_ID\"))\n ctx := context.Background()\n\n campaignID := uuid.MustParse(\"11111111-1111-4111-8111-111111111111\")\n\n response, _, err := client.CampaignsAPI.TestCampaign(ctx, accountID, campaignID, requests.TestCampaignRequest{\n To: []string{\"Ann \u003cann@yourdomain.com>\", \"bob@yourdomain.com\"},\n })\n if err != nil {\n log.Fatalf(\"Error sending test: %v\", err)\n }\n if response.ResultUnknown {\n fmt.Println(\"The test may have gone out; check the inboxes before you send another\")\n return\n }\n fmt.Printf(\"Sent to %v\\n\", response.SentTo)\n for _, failure := range response.Failed {\n fmt.Printf(\"Refused %s: %s\\n\", failure.Email, failure.Message)\n }\n}\n"},{"lang":"javascript","label":"Node.js 22+ (AhaSend SDK)","source":"import { AhaSendClient } from \"@ahasend/sdk\";\n\nconst client = AhaSendClient.fromEnv();\n// The SDK sends a fresh Idempotency-Key automatically and reuses it on its own retries.\nconst campaignId = \"00000000-0000-4000-8000-000000000014\";\nconst result = await client.campaigns.test(campaignId, { to: [\"reviewer@example.com\"] });\nconsole.log(\"Campaign test sent.\", {\n sentTo: result.sent_to,\n failed: result.failed.length,\n resultUnknown: result.result_unknown,\n});\n"}],"method":"post","type":"path","servers":["b5fdc511-65a3-4ae3-b4c1-31f6415bb096"],"path":"/v2/accounts/{account_id}/campaigns/{campaign_id}/test","baseUrlOptions":["https://api.ahasend.com"],"title":"Test Campaign","codeSamples":[{"label":"AhaSend Go SDK","lang":"go","source":"package main\n\nimport (\n \"context\"\n \"fmt\"\n \"log\"\n \"os\"\n\n \"github.com/AhaSend/ahasend-go/api\"\n \"github.com/AhaSend/ahasend-go/models/requests\"\n \"github.com/google/uuid\"\n)\n\nfunc main() {\n client := api.NewAPIClient(api.WithAPIKey(os.Getenv(\"AHASEND_API_KEY\")))\n accountID := uuid.MustParse(os.Getenv(\"AHASEND_ACCOUNT_ID\"))\n ctx := context.Background()\n\n campaignID := uuid.MustParse(\"11111111-1111-4111-8111-111111111111\")\n\n response, _, err := client.CampaignsAPI.TestCampaign(ctx, accountID, campaignID, requests.TestCampaignRequest{\n To: []string{\"Ann \u003cann@yourdomain.com>\", \"bob@yourdomain.com\"},\n })\n if err != nil {\n log.Fatalf(\"Error sending test: %v\", err)\n }\n if response.ResultUnknown {\n fmt.Println(\"The test may have gone out; check the inboxes before you send another\")\n return\n }\n fmt.Printf(\"Sent to %v\\n\", response.SentTo)\n for _, failure := range response.Failed {\n fmt.Printf(\"Refused %s: %s\\n\", failure.Email, failure.Message)\n }\n}\n"},{"label":"Node.js 22+ (AhaSend SDK)","lang":"javascript","source":"import { AhaSendClient } from \"@ahasend/sdk\";\n\nconst client = AhaSendClient.fromEnv();\n// The SDK sends a fresh Idempotency-Key automatically and reuses it on its own retries.\nconst campaignId = \"00000000-0000-4000-8000-000000000014\";\nconst result = await client.campaigns.test(campaignId, { to: [\"reviewer@example.com\"] });\nconsole.log(\"Campaign test sent.\", {\n sentTo: result.sent_to,\n failed: result.failed.length,\n resultUnknown: result.result_unknown,\n});\n"}],"requiredOnlyExamples":false,"requestExampleType":"codeSamples","responseExampleType":"generated"},"dependencies":{"parameters":{"a541d5ff-dfbe-4d64-82ab-59c4271cc6d6":{"name":"account_id","in":"path","required":true,"description":"Account ID","schema":{"type":"string","format":"uuid","isRequired":true,"description":"Account ID","uniqueKey":"","typeLabel":"string\u003cuuid>"}},"be74d27e-4449-4503-aa03-d86dd26390e4":{"name":"campaign_id","in":"path","required":true,"description":"Campaign ID","schema":{"type":"string","format":"uuid","isRequired":true,"description":"Campaign ID","uniqueKey":"","typeLabel":"string\u003cuuid>"}},"dd57e0bc-75d0-4fee-8ea2-6589f3d326a1":{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional idempotency key for safe request retries. Must be a unique string for each logical request.\nAn identical request with a completed stored outcome returns the original status and body. An in-progress\nexecution returns 409, a changed method/path/body returns 422, and a released 5xx execution may run again.\nKeys for non-secret responses expire after 24 hours. API-key create responses include a one-time `secret_key`,\nso successful encrypted replay responses for those operations expire after 5 minutes.\n","schema":{"type":"string","maxLength":255,"isRequired":false,"description":"Optional idempotency key for safe request retries. Must be a unique string for each logical request.\nAn identical request with a completed stored outcome returns the original status and body. An in-progress\nexecution returns 409, a changed method/path/body returns 422, and a released 5xx execution may run again.\nKeys for non-secret responses expire after 24 hours. API-key create responses include a one-time `secret_key`,\nso successful encrypted replay responses for those operations expire after 5 minutes.\n","uniqueKey":"","typeLabel":"string"},"example":"user-12345-create-domain-20240101"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["to"],"description":"The addresses to send a test to.","properties":{"to":{"type":"array","minItems":1,"items":{"type":"string","uniqueKey":"to.items.[INDEX]","typeLabel":"string"},"description":"1 to 5 addresses, counted after addresses that differ only in case are dropped. An entry may carry a display name, such as `Ann \u003cann@example.com>`; the test goes to the address alone.","isRequired":true,"uniqueKey":"to","typeLabel":"string[]"}},"uniqueKey":"","typeLabel":"object"},"examples":{"Example":{"title":"Example","value":{"to":["\u003cstring>"]}}},"exampleType":"generated"}},"exampleType":"generated"},"responses":{"2ca76c0c-e0ff-4e85-882c-ef691a93f3c5":{"description":"What the test send did. With `result_unknown`, the test may have gone out.","headers":{"Idempotent-Replayed":{"description":"Indicates that this response is a stored replay of a previous identical request.\nWhen this header is absent, the response is not a stored replay. Ordinary fresh\nresponses do not send `false`; that value is reserved for an in-progress 409.\n","schema":{"type":"string","enum":["true"]}}},"content":{"application/json":{"schema":{"type":"object","required":["object","sent_to","failed","result_unknown"],"description":"What a test send did.","properties":{"object":{"type":"string","enum":["campaign_test"],"description":"Object type identifier","isRequired":true,"uniqueKey":"object","typeLabel":"enum\u003cstring>"},"sent_to":{"type":"array","items":{"type":"string","uniqueKey":"sent_to.items.[INDEX]","typeLabel":"string"},"description":"The addresses the mail server accepted","isRequired":true,"uniqueKey":"sent_to","typeLabel":"string[]"},"failed":{"type":"array","items":{"type":"object","required":["email","message"],"description":"An address the mail server refused.","properties":{"email":{"type":"string","description":"The address as the mail server reported it, which can be one the request did not hold.","isRequired":true,"uniqueKey":"failed.items.[INDEX].email","typeLabel":"string"},"message":{"type":"string","description":"Why the address was refused","isRequired":true,"uniqueKey":"failed.items.[INDEX].message","typeLabel":"string"}},"uniqueKey":"failed.items.[INDEX]","typeLabel":"object"},"description":"The addresses the mail server refused","isRequired":true,"uniqueKey":"failed","typeLabel":"object[]"},"result_unknown":{"type":"boolean","description":"True when the mail server took the request but its answer could not be read. The test may have gone out; `sent_to` and `failed` are empty. Check the inboxes before you send another.","isRequired":true,"uniqueKey":"result_unknown","typeLabel":"boolean"}},"uniqueKey":"","typeLabel":"object"},"examples":{"Example":{"title":"Example","value":{"object":"campaign_test","sent_to":["\u003cstring>"],"failed":[{"email":"\u003cstring>","message":"\u003cstring>"}],"result_unknown":true}}},"exampleType":"generated"}},"exampleType":"generated"},"8dab99e5-00a3-47da-b9e0-10620c164efa":{"description":"Invalid campaign_id, an invalid body or address, no address or more than 5, a campaign with issues (with `issues`), a sender domain that is paused or no longer verified, an account that cannot send, or a test the template check refuses, in which case nothing is sent: content that cannot be rendered with a recipient's values, a call to `random`, `randrange`, `lipsum` or `now`, `namespace`, a work, output, memory or time limit, or an address the check cannot read (`\u003cemail>: the message could not be rendered: \u003creason>`, or without `\u003cemail>: ` when no recipient had started rendering)\n","content":{"application/json":{"schema":{"type":"object","required":["message"],"description":"A refusal. A campaign with issues is refused with `campaign is not ready to send` and the issues that block the request; every other refusal has only `message`.","properties":{"message":{"type":"string","description":"Error message","isRequired":true,"uniqueKey":"message","typeLabel":"string"},"issues":{"type":"array","items":{"type":"object","required":["code","message"],"description":"A reason the campaign cannot be sent yet.","properties":{"code":{"type":"string","enum":["sender_missing","lists_missing","subject_missing","preheader_missing","design_missing","text_broken","text_unchecked","unsubscribe_link_missing"],"description":"- `sender_missing`: the campaign has no complete sender, or its domain was deleted.\n- `lists_missing`: the campaign has no list or segment that still exists.\n- `subject_missing`: the campaign has no subject.\n- `preheader_missing`: the campaign has no preview text.\n- `design_missing`: the campaign has no design, or its design has no HTML.\n- `text_broken`: the subject, the preview text or the design holds template syntax that cannot be rendered, so every message would fail.\n- `text_unchecked`: the subject, the preview text and the design could not be checked right now. Nothing is wrong with them that is known; try again in a moment. Under load it can come and go between reads.\n- `unsubscribe_link_missing`: the HTML does not use `{{ unsubscribe_url }}`, with or without filters.\n","isRequired":true,"uniqueKey":"issues.items.[INDEX].code","typeLabel":"enum\u003cstring>"},"message":{"type":"string","description":"What to do, in the words the dashboard uses.","isRequired":true,"uniqueKey":"issues.items.[INDEX].message","typeLabel":"string"}},"uniqueKey":"issues.items.[INDEX]","typeLabel":"object"},"description":"The issues that block the request, in the order of `CampaignIssue`. For a test, every issue but `unsubscribe_link_missing`.","uniqueKey":"issues","typeLabel":"object[]"}},"example":{"message":"campaign is not ready to send","issues":[{"code":"subject_missing","message":"Add a subject before you send the campaign."}]},"uniqueKey":"","typeLabel":"object"},"examples":{"Example":{"title":"Example","value":{"message":"campaign is not ready to send","issues":[{"code":"subject_missing","message":"Add a subject before you send the campaign."}]}}},"exampleType":"generated"}},"exampleType":"generated"},"80ffed94-ab1a-49e2-891c-85e65a5a756f":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","description":"Human-readable API error. The server currently sends no stable machine\nerror code. In particular, clients must not parse `message` to\ndistinguish IP-allow-list, scope, ownership, plan, self-lockout,\nsuppression-duplicate, or other errors that share an HTTP status.\n","additionalProperties":false,"required":["message"],"properties":{"message":{"type":"string","description":"Error description","isRequired":true,"uniqueKey":"message","typeLabel":"string"}},"example":{"message":"Error message"},"uniqueKey":"","typeLabel":"object"},"examples":{"Example":{"title":"Example","value":{"message":"Error message"}}},"exampleType":"generated"}},"exampleType":"generated"},"dd9fa907-cf5b-4a11-b8fc-62d06c65a1bc":{"description":"Missing `campaigns:send` scope","content":{"application/json":{"schema":{"type":"object","description":"Human-readable API error. The server currently sends no stable machine\nerror code. In particular, clients must not parse `message` to\ndistinguish IP-allow-list, scope, ownership, plan, self-lockout,\nsuppression-duplicate, or other errors that share an HTTP status.\n","additionalProperties":false,"required":["message"],"properties":{"message":{"type":"string","description":"Error description","isRequired":true,"uniqueKey":"message","typeLabel":"string"}},"example":{"message":"Error message"},"uniqueKey":"","typeLabel":"object"},"examples":{"Example":{"title":"Example","value":{"message":"Error message"}}},"exampleType":"generated"}},"exampleType":"generated"},"8c8c7740-4d4a-4727-b4b2-acfc52a8c1b9":{"description":"Campaign not found","content":{"application/json":{"schema":{"type":"object","description":"Human-readable API error. The server currently sends no stable machine\nerror code. In particular, clients must not parse `message` to\ndistinguish IP-allow-list, scope, ownership, plan, self-lockout,\nsuppression-duplicate, or other errors that share an HTTP status.\n","additionalProperties":false,"required":["message"],"properties":{"message":{"type":"string","description":"Error description","isRequired":true,"uniqueKey":"message","typeLabel":"string"}},"example":{"message":"Error message"},"uniqueKey":"","typeLabel":"object"},"examples":{"Example":{"title":"Example","value":{"message":"Error message"}}},"exampleType":"generated"}},"exampleType":"generated"},"a6971505-d77a-4c0f-a0ec-d06a32f88be5":{"description":"Either the campaign's status does not allow the request (for most\nrequests, the campaign is not a draft; for an unschedule, it is not\nvalidating or scheduled, or it has queued mail), or an execution\nwith this idempotency key is still in progress. The in-progress case\nis identified only by `Idempotent-Replayed: false` plus a positive\ninteger `Retry-After`; retry it after that many seconds with the same\nkey. An update that changes the audience can also find a segment it\nnames being rebuilt: `The campaign's audience is being updated. Try\nagain in a minute.` A new status conflict has neither header; a\nstored replay of one has `Idempotent-Replayed: true` (a test send's\nstatus conflict is not stored, so it is never replayed). The audience\nrefusal is stored for the `Idempotency-Key` like a status conflict,\nso retry it with a new key. The message is not a stable\ndiscriminator.\n","headers":{"Idempotent-Replayed":{"description":"`false` with a positive `Retry-After` means an execution is in\nprogress. `true` means a stored status 409 was replayed. Absent\nmeans a fresh status conflict.\n","schema":{"type":"string","enum":["true","false"]}},"Retry-After":{"description":"Positive whole number of seconds after which the in-progress execution\nlease may be retried with the same key and unchanged request.\n","schema":{"type":"integer","minimum":1}}},"content":{"application/json":{"schema":{"type":"object","description":"Human-readable API error. The server currently sends no stable machine\nerror code. In particular, clients must not parse `message` to\ndistinguish IP-allow-list, scope, ownership, plan, self-lockout,\nsuppression-duplicate, or other errors that share an HTTP status.\n","additionalProperties":false,"required":["message"],"properties":{"message":{"type":"string","description":"Error description","isRequired":true,"uniqueKey":"message","typeLabel":"string"}},"example":{"message":"Error message"},"uniqueKey":"","typeLabel":"object"},"example":{"message":"campaign is not a draft"},"examples":{"Example":{"title":"Example","value":{"message":"campaign is not a draft"}}},"exampleType":"examples"}},"exampleType":"examples"},"22a80dd0-4183-46e1-9d7a-053cf455bc22":{"description":"Idempotency key was already used with a different HTTP method, resolved\nrequest path, or request body. This response includes neither\n`Idempotent-Replayed` nor `Retry-After`.\n","content":{"application/json":{"schema":{"type":"object","description":"Human-readable API error. The server currently sends no stable machine\nerror code. In particular, clients must not parse `message` to\ndistinguish IP-allow-list, scope, ownership, plan, self-lockout,\nsuppression-duplicate, or other errors that share an HTTP status.\n","additionalProperties":false,"required":["message"],"properties":{"message":{"type":"string","description":"Error description","isRequired":true,"uniqueKey":"message","typeLabel":"string"}},"example":{"message":"Error message"},"uniqueKey":"","typeLabel":"object"},"example":{"message":"idempotency key was already used with a different request payload"},"examples":{"Example":{"title":"Example","value":{"message":"idempotency key was already used with a different request payload"}}},"exampleType":"examples"}},"exampleType":"examples"},"20ef5599-6d8a-478e-a390-e00b9521dc56":{"description":"Too many requests, or the account's daily limit of 50 test emails is reached (`daily test send limit reached`). Neither is stored, so a retry may use the same `Idempotency-Key`.","content":{"application/json":{"schema":{"type":"object","description":"Human-readable API error. The server currently sends no stable machine\nerror code. In particular, clients must not parse `message` to\ndistinguish IP-allow-list, scope, ownership, plan, self-lockout,\nsuppression-duplicate, or other errors that share an HTTP status.\n","additionalProperties":false,"required":["message"],"properties":{"message":{"type":"string","description":"Error description","isRequired":true,"uniqueKey":"message","typeLabel":"string"}},"example":{"message":"Error message"},"uniqueKey":"","typeLabel":"object"},"examples":{"Example":{"title":"Example","value":{"message":"Error message"}}},"exampleType":"generated"}},"exampleType":"generated"},"31c9060d-39d3-4037-97df-e00fe87d26a4":{"description":"Internal server error","content":{"application/json":{"schema":{"type":"object","description":"Human-readable API error. The server currently sends no stable machine\nerror code. In particular, clients must not parse `message` to\ndistinguish IP-allow-list, scope, ownership, plan, self-lockout,\nsuppression-duplicate, or other errors that share an HTTP status.\n","additionalProperties":false,"required":["message"],"properties":{"message":{"type":"string","description":"Error description","isRequired":true,"uniqueKey":"message","typeLabel":"string"}},"example":{"message":"Error message"},"uniqueKey":"","typeLabel":"object"},"examples":{"Example":{"title":"Example","value":{"message":"Error message"}}},"exampleType":"generated"}},"exampleType":"generated"},"6aa1500b-7825-4040-ac81-434beb3c3d40":{"description":"The mail server could not take the test, and nothing was sent. Retry, with the same `Idempotency-Key` if you sent one.","content":{"application/json":{"schema":{"type":"object","description":"Human-readable API error. The server currently sends no stable machine\nerror code. In particular, clients must not parse `message` to\ndistinguish IP-allow-list, scope, ownership, plan, self-lockout,\nsuppression-duplicate, or other errors that share an HTTP status.\n","additionalProperties":false,"required":["message"],"properties":{"message":{"type":"string","description":"Error description","isRequired":true,"uniqueKey":"message","typeLabel":"string"}},"example":{"message":"Error message"},"uniqueKey":"","typeLabel":"object"},"examples":{"Example":{"title":"Example","value":{"message":"Error message"}}},"exampleType":"generated"}},"exampleType":"generated"},"d5e839a6-9504-4f2a-a26b-d6d53038f3ad":{"description":"Every message is checked with the template engine before it is sent,\nand the check could not run right now: the service was busy, or the\nengine failed. Nothing was sent and nothing is known to be wrong with\nthe message.\nSend it again after `Retry-After` seconds; on an operation that takes\nan `Idempotency-Key`, send it with the same key.\n","headers":{"Retry-After":{"description":"Seconds to wait before retrying","schema":{"type":"integer","minimum":1}}},"content":{"application/json":{"schema":{"type":"object","description":"Human-readable API error. The server currently sends no stable machine\nerror code. In particular, clients must not parse `message` to\ndistinguish IP-allow-list, scope, ownership, plan, self-lockout,\nsuppression-duplicate, or other errors that share an HTTP status.\n","additionalProperties":false,"required":["message"],"properties":{"message":{"type":"string","description":"Error description","isRequired":true,"uniqueKey":"message","typeLabel":"string"}},"example":{"message":"Error message"},"uniqueKey":"","typeLabel":"object"},"example":{"message":"the message could not be checked right now; try again in a moment"},"examples":{"Example":{"title":"Example","value":{"message":"the message could not be checked right now; try again in a moment"}}},"exampleType":"examples"}},"exampleType":"examples"}},"security":{"68fd5fc1-be8f-4903-8d85-3e41e3444f4f":{"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"aha-sk-64-CHARACTER-RANDOM-STRING","description":"API key for authentication. Non-empty Security Requirement values are\nAhaSend API-key roles. Roles listed within one requirement object are\njointly required; separate requirement objects are alternatives.\n","scopes":["campaigns:send"],"schemeName":"BearerAuth"}}},"servers":{"b5fdc511-65a3-4ae3-b4c1-31f6415bb096":{"url":"https://api.ahasend.com","description":"Production server"}},"processedSecurityOptions":[{"schemes":[{"scheme":{"type":"http","scheme":"bearer","bearerFormat":"aha-sk-64-CHARACTER-RANDOM-STRING","description":"API key for authentication. Non-empty Security Requirement values are\nAhaSend API-key roles. Roles listed within one requirement object are\njointly required; separate requirement objects are alternatives.\n","scopes":["campaigns:send"],"schemeName":"BearerAuth"},"schema":{"title":"Bearer Auth","type":"string","isRequired":true,"description":"API key for authentication. Non-empty Security Requirement values are\nAhaSend API-key roles. Roles listed within one requirement object are\njointly required; separate requirement objects are alternatives.\n","format":"bearer","typeLabel":"string\u003cbearer>","deprecated":false},"schemeName":"BearerAuth","name":"Authorization"}],"title":"BearerAuth"}]},"originalFileLocation":"openapi.yaml"},"subdomain":"ahasend","siteName":"AhaSend","title":"Send a Campaign Test via the API - AhaSend","navMaps":{"firstHrefInVersion":{},"firstHrefInLanguage":{}},"lastModified":"2026-10-19T12:46:57.960Z","originalFileLocation":"api-reference/campaigns/test-campaign.mdx"},"headHtml":"\u003cscript data-mint-head>(function(){var d=document.documentElement,p=null;if(!p){try{p=localStorage.getItem(\"isDarkMode\")}catch(e){}if(p==='true')p='dark';else if(p==='false')p='light';if(p!=='light'\u0026\u0026p!=='dark'\u0026\u0026p!=='system')p=\"system\"}var r=p==='system'?(matchMedia(\"(prefers-color-scheme: dark)\").matches?'dark':'light'):p;d.classList.remove(r==='dark'?'light':'dark');d.classList.add(r);d.setAttribute(\"data-theme-preference\",p)})();\u003c/script>\u003cmeta data-mint-head name=\"description\" content=\"Send a test of a draft AhaSend marketing campaign to up to 5 addresses to check it in a real inbox. An account can send 50 test emails per day (UTC).\">\u003cmeta data-mint-head name=\"application-name\" content=\"AhaSend\">\u003cmeta data-mint-head name=\"generator\" content=\"Mintlify\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/docs/mintlify-assets/_mintlify/favicons/ahasend/4BjAcdwrGYDKJCaO/_generated/favicon/android-chrome-192x192.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"apple-touch-icon\" type=\"image/png\" sizes=\"180x180\" href=\"/docs/mintlify-assets/_mintlify/favicons/ahasend/4BjAcdwrGYDKJCaO/_generated/favicon/apple-touch-icon.png\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/docs/mintlify-assets/_mintlify/favicons/ahasend/4BjAcdwrGYDKJCaO/_generated/favicon/favicon-16x16.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/docs/mintlify-assets/_mintlify/favicons/ahasend/4BjAcdwrGYDKJCaO/_generated/favicon/favicon-32x32.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/docs/mintlify-assets/_mintlify/favicons/ahasend/4BjAcdwrGYDKJCaO/_generated/favicon/favicon.ico\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/docs/mintlify-assets/_mintlify/favicons/ahasend/4BjAcdwrGYDKJCaO/_generated/favicon-dark/android-chrome-192x192.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/docs/mintlify-assets/_mintlify/favicons/ahasend/4BjAcdwrGYDKJCaO/_generated/favicon-dark/favicon-16x16.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/docs/mintlify-assets/_mintlify/favicons/ahasend/4BjAcdwrGYDKJCaO/_generated/favicon-dark/favicon-32x32.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/docs/mintlify-assets/_mintlify/favicons/ahasend/4BjAcdwrGYDKJCaO/_generated/favicon-dark/favicon.ico\" media=\"(prefers-color-scheme: dark)\">\u003cmeta data-mint-head property=\"og:title\" content=\"Send a Campaign Test via the API - AhaSend\">\u003cmeta data-mint-head property=\"og:description\" content=\"Send a test of a draft AhaSend marketing campaign to up to 5 addresses to check it in a real inbox. An account can send 50 test emails per day (UTC).\">\u003cmeta data-mint-head property=\"og:site_name\" content=\"AhaSend\">\u003cmeta data-mint-head property=\"og:url\" content=\"https://ahasend.com/docs/api-reference/campaigns/test-campaign\">\u003cmeta data-mint-head property=\"og:type\" content=\"website\">\u003cmeta data-mint-head property=\"og:image\" content=\"https://ahasend.mintlify.app/_mintlify/api/og/v2?division=Campaigns\u0026amp;title=Send+a+Campaign+Test+via+the+API\u0026amp;description=Send+a+test+of+a+draft+AhaSend+marketing+campaign+to+up+to+5+addresses+to+check+it+in+a+real+inbox.+An+account+can+send+50+test+emails+per+day+%28UTC%29.\u0026amp;theme=fec911c84bb9f722051c4af3\u0026amp;signature=42abb1238d06849e77b6f3cdd0496120b6eaee8bbe644a79747722d5c322b74e\">\u003cmeta data-mint-head property=\"og:image:width\" content=\"1200\">\u003cmeta data-mint-head property=\"og:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"twitter:card\" content=\"summary_large_image\">\u003cmeta data-mint-head name=\"twitter:title\" content=\"Send a Campaign Test via the API - AhaSend\">\u003cmeta data-mint-head name=\"twitter:description\" content=\"Send a test of a draft AhaSend marketing campaign to up to 5 addresses to check it in a real inbox. An account can send 50 test emails per day (UTC).\">\u003cmeta data-mint-head name=\"twitter:image\" content=\"https://ahasend.mintlify.app/_mintlify/api/og/v2?division=Campaigns\u0026amp;title=Send+a+Campaign+Test+via+the+API\u0026amp;description=Send+a+test+of+a+draft+AhaSend+marketing+campaign+to+up+to+5+addresses+to+check+it+in+a+real+inbox.+An+account+can+send+50+test+emails+per+day+%28UTC%29.\u0026amp;theme=fec911c84bb9f722051c4af3\u0026amp;signature=42abb1238d06849e77b6f3cdd0496120b6eaee8bbe644a79747722d5c322b74e\">\u003cmeta data-mint-head name=\"twitter:image:width\" content=\"1200\">\u003cmeta data-mint-head name=\"twitter:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"msapplication-config\" content=\"/docs/mintlify-assets/_mintlify/favicons/ahasend/4BjAcdwrGYDKJCaO/_generated/favicon/browserconfig.xml\">\u003cmeta data-mint-head name=\"apple-mobile-web-app-title\" content=\"AhaSend\">\u003cmeta data-mint-head name=\"msapplication-TileColor\" content=\"#066fd1\">\u003clink data-mint-head rel=\"canonical\" href=\"https://ahasend.com/docs/api-reference/campaigns/test-campaign\">\u003clink data-mint-head rel=\"alternate\" type=\"application/xml\" href=\"/docs/sitemap.xml\">\u003clink data-mint-head rel=\"alternate\" type=\"text/markdown\" href=\"/docs/api-reference/campaigns/test-campaign.md\">\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@graph\":[{\"@type\":\"Organization\",\"@id\":\"https://ahasend.com/#organization\",\"name\":\"AhaSend\",\"legalName\":\"AhaSend B.V.\",\"url\":\"https://ahasend.com\",\"logo\":{\"@type\":\"ImageObject\",\"url\":\"https://mintcdn.com/ahasend/F35Ozd-1GsftDpcH/logo.png?fit=max\u0026auto=format\u0026n=F35Ozd-1GsftDpcH\u0026q=85\u0026s=ca1d4c27f7c2811598e65cb25a21323c\"},\"sameAs\":[\"https://x.com/aha_send\",\"https://www.linkedin.com/company/ahasend\",\"https://github.com/ahasend\"]},{\"@type\":\"WebSite\",\"@id\":\"https://ahasend.com/docs#website\",\"name\":\"AhaSend\",\"url\":\"https://ahasend.com/docs\",\"publisher\":{\"@id\":\"https://ahasend.com/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https://ahasend.com/docs/api-reference/campaigns/test-campaign#webpage\",\"url\":\"https://ahasend.com/docs/api-reference/campaigns/test-campaign\",\"name\":\"Send a Campaign Test via the API\",\"description\":\"Send a test of a draft AhaSend marketing campaign to up to 5 addresses to check it in a real inbox. An account can send 50 test emails per day (UTC).\",\"dateModified\":\"2026-10-19T12:46:57.960Z\",\"isPartOf\":{\"@id\":\"https://ahasend.com/docs#website\"},\"breadcrumb\":{\"@id\":\"https://ahasend.com/docs/api-reference/campaigns/test-campaign#breadcrumb\"}},{\"@type\":\"BreadcrumbList\",\"@id\":\"https://ahasend.com/docs/api-reference/campaigns/test-campaign#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"API reference\",\"item\":\"https://ahasend.com/docs/api-reference/messages/create-message\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Campaigns\",\"item\":\"https://ahasend.com/docs/api-reference/campaigns/overview\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Send a Campaign Test via the API\",\"item\":\"https://ahasend.com/docs/api-reference/campaigns/test-campaign\"}]},{\"@type\":[\"TechArticle\",\"APIReference\"],\"@id\":\"https://ahasend.com/docs/api-reference/campaigns/test-campaign#apireference\",\"headline\":\"Send a Campaign Test via the API\",\"name\":\"Send a Campaign Test via the API\",\"description\":\"Send a test of a draft AhaSend marketing campaign to up to 5 addresses to check it in a real inbox. An account can send 50 test emails per day (UTC).\",\"url\":\"https://ahasend.com/docs/api-reference/campaigns/test-campaign\",\"mainEntityOfPage\":{\"@id\":\"https://ahasend.com/docs/api-reference/campaigns/test-campaign#webpage\"},\"dateModified\":\"2026-10-19T12:46:57.960Z\",\"publisher\":{\"@id\":\"https://ahasend.com/#organization\"},\"isPartOf\":{\"@id\":\"https://ahasend.com/docs#website\"}}]}\u003c/script>\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@type\":\"WebSite\",\"name\":\"AhaSend\",\"creator\":{\"@type\":\"Organization\",\"name\":\"Mintlify\",\"url\":\"https://mintlify.com\"}}\u003c/script>","siteName":"AhaSend","nav":{"global":null,"tabs":[{"tab":"Documentation","icon":"book-open","pages":[{"title":"Documentation","href":""}]},{"tab":"API Reference","icon":"code","groups":[{"group":"Overview","pages":[{"title":"Email API Reference (v2)","sidebarTitle":"Introduction","icon":"book","href":"/api-reference"},{"title":"API Authentication with Bearer API Keys","sidebarTitle":"Authentication","icon":"key","href":"/api-reference/authentication"},{"title":"API Key Scopes and Permissions","sidebarTitle":"Scopes","icon":"lock","href":"/api-reference/scopes"},{"title":"API Rate Limits and 429 Handling","sidebarTitle":"Rate Limits","icon":"gauge-high","href":"/api-reference/rate-limits"},{"title":"Idempotency Keys for Safe API Retries","icon":"repeat","sidebarTitle":"Idempotency","href":"/api-reference/idempotency"},{"title":"API Error Codes and Error Responses","icon":"triangle-exclamation","sidebarTitle":"Errors","href":"/api-reference/errors"}]},{"group":"API reference","pages":[{"group":"Messages","icon":"envelope","pages":[{"title":"Send an Email via the API","sidebarTitle":"Create Message","openapi":"openapi.yaml POST /v2/accounts/{account_id}/messages","href":"/api-reference/messages/create-message"},{"title":"Send a Transactional Template via the API","sidebarTitle":"Create Template Message","openapi":"openapi.yaml POST /v2/accounts/{account_id}/messages/template","href":"/api-reference/messages/create-template-message"},{"title":"Send Email with CC and BCC via the API","sidebarTitle":"Create Conversation","openapi":"openapi.yaml POST /v2/accounts/{account_id}/messages/conversation","href":"/api-reference/messages/create-conversation"},{"title":"Get a Message by ID via the API","sidebarTitle":"Get Message","openapi":"openapi.yaml GET /v2/accounts/{account_id}/messages/{message_id}","href":"/api-reference/messages/get-message"},{"title":"List and Search Sent Emails via the API","sidebarTitle":"List Messages","openapi":"openapi.yaml GET /v2/accounts/{account_id}/messages","href":"/api-reference/messages/get-messages"},{"title":"Cancel a Scheduled Email via the API","sidebarTitle":"Cancel Message","openapi":"openapi.yaml DELETE /v2/accounts/{account_id}/messages/{message_id}/cancel","href":"/api-reference/messages/cancel-message"}]},{"group":"Transactional Templates","icon":"file-lines","pages":[{"title":"Create a Transactional Template via the API","sidebarTitle":"Create Template","openapi":"openapi.yaml POST /v2/accounts/{account_id}/templates","href":"/api-reference/templates/create-template"},{"title":"Get a Transactional Template via the API","sidebarTitle":"Get Template","openapi":"openapi.yaml GET /v2/accounts/{account_id}/templates/{template_id}","href":"/api-reference/templates/get-template"},{"title":"Get a Published Transactional Template via the API","sidebarTitle":"Get Published Template","openapi":"openapi.yaml GET /v2/accounts/{account_id}/templates/{template_id}/published","href":"/api-reference/templates/get-published-template"},{"title":"List Transactional Templates via the API","sidebarTitle":"List Templates","openapi":"openapi.yaml GET /v2/accounts/{account_id}/templates","href":"/api-reference/templates/get-templates"},{"title":"Update a Transactional Template via the API","sidebarTitle":"Update Template","openapi":"openapi.yaml PUT /v2/accounts/{account_id}/templates/{template_id}","href":"/api-reference/templates/update-template"},{"title":"Publish a Template Draft via the API","sidebarTitle":"Publish Template","openapi":"openapi.yaml POST /v2/accounts/{account_id}/templates/{template_id}/publish","href":"/api-reference/templates/publish-template"},{"title":"Discard a Template Draft via the API","sidebarTitle":"Discard Template Draft","openapi":"openapi.yaml DELETE /v2/accounts/{account_id}/templates/{template_id}/draft","href":"/api-reference/templates/discard-template-draft"},{"title":"List Template Versions via the API","sidebarTitle":"List Template Versions","openapi":"openapi.yaml GET /v2/accounts/{account_id}/templates/{template_id}/versions","href":"/api-reference/templates/get-template-versions"},{"title":"Get a Template Version via the API","sidebarTitle":"Get Template Version","openapi":"openapi.yaml GET /v2/accounts/{account_id}/templates/{template_id}/versions/{version_id}","href":"/api-reference/templates/get-template-version"},{"title":"Restore a Template Version via the API","sidebarTitle":"Restore Template Version","openapi":"openapi.yaml POST /v2/accounts/{account_id}/templates/{template_id}/versions/{version_id}/restore","href":"/api-reference/templates/restore-template-version"},{"title":"Delete a Transactional Template via the API","sidebarTitle":"Delete Template","openapi":"openapi.yaml DELETE /v2/accounts/{account_id}/templates/{template_id}","href":"/api-reference/templates/delete-template"}]},{"group":"Campaigns","icon":"bullhorn","pages":[{"title":"Campaigns API Overview","sidebarTitle":"Introduction","icon":"bullhorn","href":"/api-reference/campaigns/overview"},{"title":"Create a Campaign via the API","sidebarTitle":"Create Campaign","openapi":"openapi.yaml POST /v2/accounts/{account_id}/campaigns","href":"/api-reference/campaigns/create-campaign"},{"title":"Get a Campaign via the API","sidebarTitle":"Get Campaign","openapi":"openapi.yaml GET /v2/accounts/{account_id}/campaigns/{campaign_id}","href":"/api-reference/campaigns/get-campaign"},{"title":"List Campaigns via the API","sidebarTitle":"List Campaigns","openapi":"openapi.yaml GET /v2/accounts/{account_id}/campaigns","href":"/api-reference/campaigns/get-campaigns"},{"title":"Update a Campaign via the API","sidebarTitle":"Update Campaign","openapi":"openapi.yaml PUT /v2/accounts/{account_id}/campaigns/{campaign_id}","href":"/api-reference/campaigns/update-campaign"},{"title":"Duplicate a Campaign via the API","sidebarTitle":"Duplicate Campaign","openapi":"openapi.yaml POST /v2/accounts/{account_id}/campaigns/{campaign_id}/duplicate","description":"Make a new draft from an AhaSend marketing campaign in any status, with a copy of its design, its subject, preview text and sender, and the same audience.","href":"/api-reference/campaigns/duplicate-campaign"},{"title":"Send a Campaign Test via the API","sidebarTitle":"Test Campaign","openapi":"openapi.yaml POST /v2/accounts/{account_id}/campaigns/{campaign_id}/test","href":"/api-reference/campaigns/test-campaign"},{"title":"Send or Schedule a Campaign via the API","sidebarTitle":"Send Campaign","openapi":"openapi.yaml POST /v2/accounts/{account_id}/campaigns/{campaign_id}/send","description":"Send a draft AhaSend marketing campaign to its lists and segments now, or schedule it for a later time. The campaign must be a draft with no issues to send.","href":"/api-reference/campaigns/send-campaign"},{"title":"Unschedule a Campaign via the API","sidebarTitle":"Unschedule Campaign","openapi":"openapi.yaml POST /v2/accounts/{account_id}/campaigns/{campaign_id}/unschedule","href":"/api-reference/campaigns/unschedule-campaign"},{"title":"Get Campaign Stats via the API","sidebarTitle":"Get Campaign Stats","openapi":"openapi.yaml GET /v2/accounts/{account_id}/campaigns/{campaign_id}/stats","href":"/api-reference/campaigns/get-campaign-stats"},{"title":"List Campaign Recipients via the API","sidebarTitle":"List Campaign Recipients","openapi":"openapi.yaml GET /v2/accounts/{account_id}/campaigns/{campaign_id}/recipients","href":"/api-reference/campaigns/get-campaign-recipients"},{"title":"Delete a Campaign via the API","sidebarTitle":"Delete Campaign","openapi":"openapi.yaml DELETE /v2/accounts/{account_id}/campaigns/{campaign_id}","href":"/api-reference/campaigns/delete-campaign"}]},{"group":"Campaign Templates","icon":"palette","pages":[{"title":"Create a Campaign Template via the API","sidebarTitle":"Create Template","openapi":"openapi.yaml POST /v2/accounts/{account_id}/campaign-templates","href":"/api-reference/campaign-templates/create-campaign-template"},{"title":"Get a Campaign Template via the API","sidebarTitle":"Get Template","openapi":"openapi.yaml GET /v2/accounts/{account_id}/campaign-templates/{template_id}","href":"/api-reference/campaign-templates/get-campaign-template"},{"title":"List Campaign Templates via the API","sidebarTitle":"List Templates","openapi":"openapi.yaml GET /v2/accounts/{account_id}/campaign-templates","href":"/api-reference/campaign-templates/get-campaign-templates"},{"title":"Update a Campaign Template via the API","sidebarTitle":"Update Template","openapi":"openapi.yaml PUT /v2/accounts/{account_id}/campaign-templates/{template_id}","href":"/api-reference/campaign-templates/update-campaign-template"},{"title":"Delete a Campaign Template via the API","sidebarTitle":"Delete Template","openapi":"openapi.yaml DELETE /v2/accounts/{account_id}/campaign-templates/{template_id}","href":"/api-reference/campaign-templates/delete-campaign-template"}]},{"group":"Contacts","icon":"address-book","pages":[{"title":"Contacts API Overview","sidebarTitle":"Introduction","icon":"address-book","href":"/api-reference/contacts/overview"},{"title":"Create a Contact via the API","sidebarTitle":"Create Contact","openapi":"openapi.yaml POST /v2/accounts/{account_id}/contacts","href":"/api-reference/contacts/create-contact"},{"title":"Get a Contact via the API","sidebarTitle":"Get Contact","openapi":"openapi.yaml GET /v2/accounts/{account_id}/contacts/{id_or_email}","href":"/api-reference/contacts/get-contact"},{"title":"List Contacts via the API","sidebarTitle":"List Contacts","openapi":"openapi.yaml GET /v2/accounts/{account_id}/contacts","href":"/api-reference/contacts/get-contacts"},{"title":"Update a Contact via the API","sidebarTitle":"Update Contact","openapi":"openapi.yaml PUT /v2/accounts/{account_id}/contacts/{id_or_email}","href":"/api-reference/contacts/update-contact"},{"title":"Delete a Contact via the API","sidebarTitle":"Delete Contact","openapi":"openapi.yaml DELETE /v2/accounts/{account_id}/contacts/{id_or_email}","href":"/api-reference/contacts/delete-contact"},{"title":"Create or Update Contacts in a Batch via the API","sidebarTitle":"Batch Upsert Contacts","openapi":"openapi.yaml POST /v2/accounts/{account_id}/contacts/batch","href":"/api-reference/contacts/batch-upsert-contacts"}]},{"group":"Lists","icon":"list-ul","pages":[{"title":"Lists API Overview","sidebarTitle":"Introduction","icon":"list-ul","href":"/api-reference/lists/overview"},{"title":"Create a List via the API","sidebarTitle":"Create List","openapi":"openapi.yaml POST /v2/accounts/{account_id}/lists","href":"/api-reference/lists/create-list"},{"title":"Get a List via the API","sidebarTitle":"Get List","openapi":"openapi.yaml GET /v2/accounts/{account_id}/lists/{list_id}","href":"/api-reference/lists/get-list"},{"title":"List Contact Lists via the API","sidebarTitle":"List Lists","openapi":"openapi.yaml GET /v2/accounts/{account_id}/lists","href":"/api-reference/lists/get-lists"},{"title":"Update a List via the API","sidebarTitle":"Update List","openapi":"openapi.yaml PUT /v2/accounts/{account_id}/lists/{list_id}","href":"/api-reference/lists/update-list"},{"title":"Delete a List via the API","sidebarTitle":"Delete List","openapi":"openapi.yaml DELETE /v2/accounts/{account_id}/lists/{list_id}","href":"/api-reference/lists/delete-list"},{"title":"List the Contacts on a List via the API","sidebarTitle":"List Contacts on a List","openapi":"openapi.yaml GET /v2/accounts/{account_id}/lists/{list_id}/contacts","href":"/api-reference/lists/get-list-contacts"},{"title":"Add or Update a List Contact via the API","sidebarTitle":"Add or Update List Contact","openapi":"openapi.yaml PUT /v2/accounts/{account_id}/lists/{list_id}/contacts/{id_or_email}","href":"/api-reference/lists/upsert-list-contact"},{"title":"Add Contacts to a List in a Batch via the API","sidebarTitle":"Batch Add List Contacts","openapi":"openapi.yaml POST /v2/accounts/{account_id}/lists/{list_id}/contacts/batch","href":"/api-reference/lists/batch-add-list-contacts"},{"title":"Remove a Contact from a List via the API","sidebarTitle":"Remove List Contact","openapi":"openapi.yaml DELETE /v2/accounts/{account_id}/lists/{list_id}/contacts/{id_or_email}","href":"/api-reference/lists/delete-list-contact"},{"title":"List a Contact's Lists via the API","sidebarTitle":"List Contact's Lists","openapi":"openapi.yaml GET /v2/accounts/{account_id}/contacts/{id_or_email}/lists","href":"/api-reference/lists/get-contact-lists"}]},{"group":"Segments","icon":"filter","pages":[{"title":"Segments API Overview","sidebarTitle":"Introduction","icon":"filter","href":"/api-reference/segments/overview"},{"title":"Preview a Segment via the API","sidebarTitle":"Preview Segment","openapi":"openapi.yaml POST /v2/accounts/{account_id}/segments/preview","href":"/api-reference/segments/preview-segment"},{"title":"Create a Segment via the API","sidebarTitle":"Create Segment","openapi":"openapi.yaml POST /v2/accounts/{account_id}/segments","href":"/api-reference/segments/create-segment"},{"title":"Get a Segment via the API","sidebarTitle":"Get Segment","openapi":"openapi.yaml GET /v2/accounts/{account_id}/segments/{segment_id}","href":"/api-reference/segments/get-segment"},{"title":"List Segments via the API","sidebarTitle":"List Segments","openapi":"openapi.yaml GET /v2/accounts/{account_id}/segments","href":"/api-reference/segments/get-segments"},{"title":"Update a Segment via the API","sidebarTitle":"Update Segment","openapi":"openapi.yaml PUT /v2/accounts/{account_id}/segments/{segment_id}","href":"/api-reference/segments/update-segment"},{"title":"Delete a Segment via the API","sidebarTitle":"Delete Segment","openapi":"openapi.yaml DELETE /v2/accounts/{account_id}/segments/{segment_id}","href":"/api-reference/segments/delete-segment"},{"title":"List the Contacts in a Segment via the API","sidebarTitle":"List Segment Contacts","openapi":"openapi.yaml GET /v2/accounts/{account_id}/segments/{segment_id}/contacts","href":"/api-reference/segments/get-segment-contacts"},{"title":"List a Contact's Segments via the API","sidebarTitle":"List Contact's Segments","openapi":"openapi.yaml GET /v2/accounts/{account_id}/contacts/{id_or_email}/segments","href":"/api-reference/segments/get-contact-segments"}]},{"group":"Suppressions","icon":"ban","pages":[{"title":"Add an Address to the Suppression List via the API","sidebarTitle":"Create Suppression","openapi":"openapi.yaml POST /v2/accounts/{account_id}/suppressions","href":"/api-reference/suppressions/create-suppression"},{"title":"List Suppressed Addresses via the API","sidebarTitle":"List Suppressions","openapi":"openapi.yaml GET /v2/accounts/{account_id}/suppressions","href":"/api-reference/suppressions/get-suppressions"},{"title":"Remove a Suppression via the API","sidebarTitle":"Delete Suppression","openapi":"openapi.yaml DELETE /v2/accounts/{account_id}/suppressions","href":"/api-reference/suppressions/delete-suppression"},{"title":"Delete All Suppressions via the API","sidebarTitle":"Delete All Suppressions","openapi":"openapi.yaml DELETE /v2/accounts/{account_id}/suppressions/all","href":"/api-reference/suppressions/wipe-suppressions"}]},{"group":"SMTP Credentials","icon":"user-shield","pages":[{"title":"Create SMTP Credentials via the API","sidebarTitle":"Create SMTP Credential","openapi":"openapi.yaml POST /v2/accounts/{account_id}/smtp-credentials","href":"/api-reference/smtp-credentials/create-smtp-credential"},{"title":"Get an SMTP Credential via the API","sidebarTitle":"Get SMTP Credential","openapi":"openapi.yaml GET /v2/accounts/{account_id}/smtp-credentials/{smtp_credential_id}","href":"/api-reference/smtp-credentials/get-smtp-credential"},{"title":"List SMTP Credentials via the API","sidebarTitle":"List SMTP Credentials","openapi":"openapi.yaml GET /v2/accounts/{account_id}/smtp-credentials","href":"/api-reference/smtp-credentials/get-smtp-credentials"},{"title":"Delete an SMTP Credential via the API","sidebarTitle":"Delete SMTP Credential","openapi":"openapi.yaml DELETE /v2/accounts/{account_id}/smtp-credentials/{smtp_credential_id}","href":"/api-reference/smtp-credentials/delete-smtp-credential"}]},{"group":"Webhooks","icon":"webhook","pages":[{"title":"Create a Webhook via the API","sidebarTitle":"Create Webhook","openapi":"openapi.yaml POST /v2/accounts/{account_id}/webhooks","href":"/api-reference/webhooks/create-webhook"},{"title":"Get a Webhook via the API","sidebarTitle":"Get Webhook","openapi":"openapi.yaml GET /v2/accounts/{account_id}/webhooks/{webhook_id}","href":"/api-reference/webhooks/get-webhook"},{"title":"List Webhooks via the API","sidebarTitle":"List Webhooks","openapi":"openapi.yaml GET /v2/accounts/{account_id}/webhooks","href":"/api-reference/webhooks/get-webhooks"},{"title":"Update a Webhook via the API","sidebarTitle":"Update Webhook","openapi":"openapi.yaml PUT /v2/accounts/{account_id}/webhooks/{webhook_id}","href":"/api-reference/webhooks/update-webhook"},{"title":"Delete a Webhook via the API","sidebarTitle":"Delete Webhook","openapi":"openapi.yaml DELETE /v2/accounts/{account_id}/webhooks/{webhook_id}","href":"/api-reference/webhooks/delete-webhook"}]},{"group":"Routes","icon":"route","pages":[{"title":"Create an Inbound Email Route via the API","sidebarTitle":"Create Route","openapi":"openapi.yaml POST /v2/accounts/{account_id}/routes","href":"/api-reference/routes/create-route"},{"title":"Get an Inbound Email Route via the API","sidebarTitle":"Get Route","openapi":"openapi.yaml GET /v2/accounts/{account_id}/routes/{route_id}","href":"/api-reference/routes/get-route"},{"title":"List Inbound Email Routes via the API","sidebarTitle":"List Routes","openapi":"openapi.yaml GET /v2/accounts/{account_id}/routes","href":"/api-reference/routes/get-routes"},{"title":"Update an Inbound Email Route via the API","sidebarTitle":"Update Route","openapi":"openapi.yaml PUT /v2/accounts/{account_id}/routes/{route_id}","href":"/api-reference/routes/update-route"},{"title":"Delete an Inbound Email Route via the API","sidebarTitle":"Delete Route","openapi":"openapi.yaml DELETE /v2/accounts/{account_id}/routes/{route_id}","href":"/api-reference/routes/delete-route"}]},{"group":"Domains","icon":"globe","pages":[{"title":"Add a Sending Domain via the API","sidebarTitle":"Create Domain","openapi":"openapi.yaml POST /v2/accounts/{account_id}/domains","href":"/api-reference/domains/create-domain"},{"title":"Get a Domain and Its DNS Records via the API","sidebarTitle":"Get Domain","openapi":"openapi.yaml GET /v2/accounts/{account_id}/domains/{domain}","href":"/api-reference/domains/get-domain"},{"title":"List Sending Domains via the API","sidebarTitle":"List Domains","openapi":"openapi.yaml GET /v2/accounts/{account_id}/domains","href":"/api-reference/domains/get-domains"},{"title":"Update a Sending Domain via the API","sidebarTitle":"Update Domain","openapi":"openapi.yaml PUT /v2/accounts/{account_id}/domains/{domain}","href":"/api-reference/domains/update-domain"},{"title":"Check Domain DNS Records via the API","sidebarTitle":"Check Domain DNS","openapi":"openapi.yaml POST /v2/accounts/{account_id}/domains/{domain}/check-dns","href":"/api-reference/domains/check-dns"},{"title":"Delete a Sending Domain via the API","sidebarTitle":"Delete Domain","openapi":"openapi.yaml DELETE /v2/accounts/{account_id}/domains/{domain}","href":"/api-reference/domains/delete-domain"}]},{"group":"Accounts","icon":"building","pages":[{"title":"Get Account Details via the API","sidebarTitle":"Get Account","openapi":"openapi.yaml GET /v2/accounts/{account_id}","href":"/api-reference/accounts/get-account"},{"title":"Update Account Settings via the API","sidebarTitle":"Update Account","openapi":"openapi.yaml PUT /v2/accounts/{account_id}","href":"/api-reference/accounts/update-account"},{"title":"List Account Members via the API","sidebarTitle":"List Account Members","openapi":"openapi.yaml GET /v2/accounts/{account_id}/members","href":"/api-reference/accounts/get-account-members"},{"title":"Add an Account Member via the API","sidebarTitle":"Add Account Member","openapi":"openapi.yaml POST /v2/accounts/{account_id}/members","href":"/api-reference/accounts/create-account-member"},{"title":"Remove an Account Member via the API","sidebarTitle":"Remove Account Member","openapi":"openapi.yaml DELETE /v2/accounts/{account_id}/members/{user_id}","href":"/api-reference/accounts/delete-account-member"}]},{"group":"Sub-Accounts","icon":"sitemap","pages":[{"title":"Sub-Accounts API Overview","sidebarTitle":"Introduction","icon":"sitemap","href":"/api-reference/sub-accounts/overview"},{"title":"Create a Sub-Account via the API","sidebarTitle":"Create Sub-Account","openapi":"openapi.yaml POST /v2/accounts/{account_id}/sub-accounts","href":"/api-reference/sub-accounts/create-sub-account"},{"title":"List Sub-Accounts via the API","sidebarTitle":"List Sub-Accounts","openapi":"openapi.yaml GET /v2/accounts/{account_id}/sub-accounts","href":"/api-reference/sub-accounts/get-sub-accounts"},{"title":"Get a Sub-Account via the API","sidebarTitle":"Get Sub-Account","openapi":"openapi.yaml GET /v2/accounts/{account_id}/sub-accounts/{sub_account_id}","href":"/api-reference/sub-accounts/get-sub-account"},{"title":"Update a Sub-Account via the API","sidebarTitle":"Update Sub-Account","openapi":"openapi.yaml PUT /v2/accounts/{account_id}/sub-accounts/{sub_account_id}","href":"/api-reference/sub-accounts/update-sub-account"},{"title":"Pause a Sub-Account via the API","sidebarTitle":"Pause Sub-Account","openapi":"openapi.yaml POST /v2/accounts/{account_id}/sub-accounts/{sub_account_id}/suspend","href":"/api-reference/sub-accounts/suspend-sub-account"},{"title":"Resume a Sub-Account via the API","sidebarTitle":"Resume Sub-Account","openapi":"openapi.yaml POST /v2/accounts/{account_id}/sub-accounts/{sub_account_id}/unsuspend","href":"/api-reference/sub-accounts/unsuspend-sub-account"},{"title":"Unpause a Sub-Account Domain via the API","sidebarTitle":"Unpause Sub-Account Domain","openapi":"openapi.yaml POST /v2/accounts/{account_id}/sub-accounts/{sub_account_id}/domains/{domain}/unpause","href":"/api-reference/sub-accounts/unpause-sub-account-domain"},{"title":"Delete a Sub-Account via the API","sidebarTitle":"Delete Sub-Account","openapi":"openapi.yaml DELETE /v2/accounts/{account_id}/sub-accounts/{sub_account_id}","href":"/api-reference/sub-accounts/delete-sub-account"},{"title":"Get Sub-Account Usage via the API","sidebarTitle":"Sub-Account Usage","openapi":"openapi.yaml GET /v2/accounts/{account_id}/sub-accounts/usage","href":"/api-reference/sub-accounts/get-sub-accounts-usage"}]},{"group":"Sub-Account API Keys","icon":"key","pages":[{"title":"Create a Sub-Account API Key via the API","sidebarTitle":"Create API Key","openapi":"openapi.yaml POST /v2/accounts/{account_id}/sub-accounts/{sub_account_id}/api-keys","href":"/api-reference/sub-accounts/create-sub-account-api-key"},{"title":"Get a Sub-Account API Key via the API","sidebarTitle":"Get API Key","openapi":"openapi.yaml GET /v2/accounts/{account_id}/sub-accounts/{sub_account_id}/api-keys/{key_id}","href":"/api-reference/sub-accounts/get-sub-account-api-key"},{"title":"List Sub-Account API Keys via the API","sidebarTitle":"List API Keys","openapi":"openapi.yaml GET /v2/accounts/{account_id}/sub-accounts/{sub_account_id}/api-keys","href":"/api-reference/sub-accounts/get-sub-account-api-keys"},{"title":"Update a Sub-Account API Key via the API","sidebarTitle":"Update API Key","openapi":"openapi.yaml PUT /v2/accounts/{account_id}/sub-accounts/{sub_account_id}/api-keys/{key_id}","href":"/api-reference/sub-accounts/update-sub-account-api-key"},{"title":"Delete a Sub-Account API Key via the API","sidebarTitle":"Delete API Key","openapi":"openapi.yaml DELETE /v2/accounts/{account_id}/sub-accounts/{sub_account_id}/api-keys/{key_id}","href":"/api-reference/sub-accounts/delete-sub-account-api-key"}]},{"group":"Reports","icon":"chart-line","pages":[{"title":"Get Email Deliverability Statistics via the API","sidebarTitle":"Deliverability Report","openapi":"openapi.yaml GET /v2/accounts/{account_id}/statistics/transactional/deliverability","href":"/api-reference/reports/get-deliverability-report"},{"title":"Get Email Bounce Statistics via the API","sidebarTitle":"Bounce Report","openapi":"openapi.yaml GET /v2/accounts/{account_id}/statistics/transactional/bounce","href":"/api-reference/reports/get-bounce-report"},{"title":"Get Email Delivery Time Statistics via the API","sidebarTitle":"Delivery Time Report","openapi":"openapi.yaml GET /v2/accounts/{account_id}/statistics/transactional/delivery-time","href":"/api-reference/reports/get-delivery-time-report"}]},{"group":"API Keys","icon":"key","pages":[{"title":"Create an API Key via the API","sidebarTitle":"Create API Key","openapi":"openapi.yaml POST /v2/accounts/{account_id}/api-keys","href":"/api-reference/api-keys/create-api-key"},{"title":"Get an API Key via the API","sidebarTitle":"Get API Key","openapi":"openapi.yaml GET /v2/accounts/{account_id}/api-keys/{key_id}","href":"/api-reference/api-keys/get-api-key"},{"title":"List API Keys via the API","sidebarTitle":"List API Keys","openapi":"openapi.yaml GET /v2/accounts/{account_id}/api-keys","href":"/api-reference/api-keys/get-api-keys"},{"title":"Update an API Key via the API","sidebarTitle":"Update API Key","openapi":"openapi.yaml PUT /v2/accounts/{account_id}/api-keys/{key_id}","href":"/api-reference/api-keys/update-api-key"},{"title":"Delete an API Key via the API","sidebarTitle":"Delete API Key","openapi":"openapi.yaml DELETE /v2/accounts/{account_id}/api-keys/{key_id}","href":"/api-reference/api-keys/delete-api-key"}]},{"group":"Utility endpoints","icon":"bolt","pages":[{"title":"Test Your API Key with the Ping Endpoint","sidebarTitle":"Ping","openapi":"openapi.yaml GET /v2/ping","href":"/api-reference/utility/ping"}]}]},{"group":"Webhooks","pages":[{"title":"Webhook Events and Payload Reference","sidebarTitle":"Introduction","icon":"webhook","href":"/api-reference/webhooks/index"},{"title":"Verify Webhook and Route Signatures (HMAC)","sidebarTitle":"Security","icon":"shield-check","href":"/api-reference/webhooks/security"},{"title":"Webhook and Route Retry Policy","sidebarTitle":"Retry Policy","icon":"repeat","href":"/api-reference/webhooks/retry-policy"},{"group":"Message Events","icon":"envelope","pages":[{"title":"message.reception Webhook Event","sidebarTitle":"Reception","openapi":"webhooks.yaml webhook message.reception","href":"/api-reference/webhooks/message-reception"},{"title":"message.delivered Webhook Event","sidebarTitle":"Delivered","openapi":"webhooks.yaml webhook message.delivered","href":"/api-reference/webhooks/message-delivered"},{"title":"message.transient_error (Deferred) Webhook Event","sidebarTitle":"Deferred","openapi":"webhooks.yaml webhook message.transient_error","href":"/api-reference/webhooks/message-transient_error"},{"title":"message.failed Webhook Event","sidebarTitle":"Failed","openapi":"webhooks.yaml webhook message.failed","href":"/api-reference/webhooks/message-failed"},{"title":"message.bounced Webhook Event","sidebarTitle":"Bounced","openapi":"webhooks.yaml webhook message.bounced","href":"/api-reference/webhooks/message-bounced"},{"title":"message.suppressed Webhook Event","sidebarTitle":"Suppressed","openapi":"webhooks.yaml webhook message.suppressed","href":"/api-reference/webhooks/message-suppressed"},{"title":"message.opened Webhook Event","sidebarTitle":"Opened","openapi":"webhooks.yaml webhook message.opened","href":"/api-reference/webhooks/message-opened"},{"title":"message.clicked Webhook Event","sidebarTitle":"Clicked","openapi":"webhooks.yaml webhook message.clicked","href":"/api-reference/webhooks/message-clicked"},{"title":"message.unsubscribed Webhook Event","sidebarTitle":"Unsubscribed","openapi":"webhooks.yaml webhook message.unsubscribed","href":"/api-reference/webhooks/message-unsubscribed"},{"title":"message.complained Webhook Event","sidebarTitle":"Complained","openapi":"webhooks.yaml webhook message.complained","href":"/api-reference/webhooks/message-complained"}]},{"group":"Suppression Events","icon":"ban","pages":[{"title":"suppression.created Webhook Event","sidebarTitle":"Suppression Created","openapi":"webhooks.yaml webhook suppression.created","href":"/api-reference/webhooks/suppression-created"},{"title":"suppression.deleted Webhook Event","sidebarTitle":"Suppression Deleted","openapi":"webhooks.yaml webhook suppression.deleted","href":"/api-reference/webhooks/suppression-deleted"}]},{"group":"Domain Events","icon":"globe","pages":[{"title":"domain.dns_error Webhook Event","sidebarTitle":"DNS Error","openapi":"webhooks.yaml webhook domain.dns_error","href":"/api-reference/webhooks/domain-dns_error"}]},{"group":"Contact Events","icon":"address-book","pages":[{"title":"contact.created Webhook Event","sidebarTitle":"Contact Created","openapi":"webhooks.yaml webhook contact.created","href":"/api-reference/webhooks/contact-created"},{"title":"contact.updated Webhook Event","sidebarTitle":"Contact Updated","openapi":"webhooks.yaml webhook contact.updated","href":"/api-reference/webhooks/contact-updated"},{"title":"contact.deleted Webhook Event","sidebarTitle":"Contact Deleted","openapi":"webhooks.yaml webhook contact.deleted","href":"/api-reference/webhooks/contact-deleted"},{"title":"contact.added_to_list Webhook Event","sidebarTitle":"Contact Added to List","openapi":"webhooks.yaml webhook contact.added_to_list","href":"/api-reference/webhooks/contact-added_to_list"},{"title":"contact.removed_from_list Webhook Event","sidebarTitle":"Contact Removed from List","openapi":"webhooks.yaml webhook contact.removed_from_list","href":"/api-reference/webhooks/contact-removed_from_list"},{"title":"contact.subscribed Webhook Event","sidebarTitle":"Contact Subscribed","openapi":"webhooks.yaml webhook contact.subscribed","href":"/api-reference/webhooks/contact-subscribed"},{"title":"contact.unsubscribed Webhook Event","sidebarTitle":"Contact Unsubscribed","openapi":"webhooks.yaml webhook contact.unsubscribed","href":"/api-reference/webhooks/contact-unsubscribed"},{"title":"contact.complained Webhook Event","sidebarTitle":"Contact Complained","openapi":"webhooks.yaml webhook contact.complained","href":"/api-reference/webhooks/contact-complained"}]}]},{"group":"Message Routing","pages":[{"title":"Inbound Email Routing API Overview","sidebarTitle":"Introduction","icon":"route","href":"/api-reference/routes/index"},{"title":"message.routing Inbound Email Webhook Event","sidebarTitle":"Message Routing","openapi":"webhooks.yaml webhook message.routing","href":"/api-reference/routes/route-message"}]},{"group":"API v1 (legacy)","pages":[{"title":"API v1 vs v2: Differences and Migration","sidebarTitle":"v1 vs v2","icon":"code-compare","href":"/api-reference/v1/v1-vs-v2"},{"title":"Send Email with API v1 (Legacy)","sidebarTitle":"Send Email (Legacy)","icon":"paper-plane","openapi":"openapi-v1.yaml POST /v1/email/send","href":"/api-reference/v1/index"}]}]},{"tab":"CLI","icon":"square-terminal","pages":[{"title":"CLI","href":"/cli"}]},{"tab":"Guides","icon":"plug","pages":[{"title":"Guides","href":"/guides"}]},{"tab":"Changelog","icon":"clock-rotate-left","pages":[{"title":"Changelog","href":"/changelog"}]},{"tab":"Roadmap","icon":"map","pages":[{"title":"Roadmap","href":"/roadmap"}]}]},"basePath":"","title":"Send a Campaign Test via the API - AhaSend","buildId":"dpl_6cCEiK8XNNvaLBBkWzcBhdE9QfLC","deploymentId":"dpl_6cCEiK8XNNvaLBBkWzcBhdE9QfLC","dynamics":["c2aa737661","2b790eda92","b0f84f53ff","a9bb46feb3"],"chunks":["OpenApiReferenceProvider-CLz2_Z5D.js","utils-7A5jZhOT.js","cloneDeep-izs3Hzxb.js","_Uint8Array-BVIqJ90l.js","isObjectLike-C8vmzPEN.js","isArray-Dcu1dQ5t.js","utils-BVWmkKuv.js","toString-BX-iyh8G.js","isSymbol-CSH9U2Gm.js","addUniqueKeysToSchema-4SOfrh0F.js","snippetPresets-CMc8KicP.js","style-to-object-BY3JEAdk.js","v4-DIgz8zy6.js","ApiExamples-Ba9tX7z3.js","isEqual-BfaiBbcl.js","usePlaygroundInputsStore-Be8krXvv.js","shallow-CBC3K1uB.js","getApiPlaygroundDisplay-4tKcUAYo.js","CodeSnippet-C1Xa06ft.js","CodeSnippets-vqiz27A_.js","Page-DeQN5MDd.js","getPastedJson-NUwRfM32.js","icon-DkIVqWh9.js","MethodPill-qmhT7_wz.js","DuplicateIcon-_gWp1vhn.js","createIcon-NA1p_TVA.js","DynamicMarkdown-Bas9A7wq.js","SectionHeading-a1cS-24U.js","axios-vUo_bRtp.js","Markdown-D3ZTwq_a.js","clsx-BcghKhHb.js","lib-DuNMoZ05.js","lib-B8HbPgcC.js","html-void-elements-mCSPHezU.js","dist-B66mVNPp.js","katex-YMM-FMeD.js","marked.esm-CZWythHk.js","AssistantPageLink-DmooSyTN.js"]}