API/Send Transactional Email API

Send Transactional Email API

Send a template-bound transactional email with per-send variables and delivery tracking.

Trigger an email from your application using a transactional definition created in Growth. Each definition binds a stable slug to an email template and can optionally override that template's subject.

Request

POST /api/v1/email/transactional/send

Send the organization API key with x-api-key or Authorization: Bearer, and send a JSON body.

FieldTypeRequiredDescription
transactionalstringYesDefinition slug or id. slug is accepted as an alias.
emailstringYesRecipient email address.
firstNamestringNoRecipient first name.
lastNamestringNoRecipient last name.
variablesrecord of stringsNoSend-scoped values used by template placeholders.
tagsstring[]NoTags added to the recipient's contact.
curl -X POST https://your-growth-app.convex.site/api/v1/email/transactional/send \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"transactional":"freebie-kit","email":"[email protected]","firstName":"Jane","variables":{"resourceName":"The Essential Launch Guide","resourceDescription":"Your guide is ready to download.","downloadUrl":"https://example.com/kit","expiresAt":"July 31, 2026","organizationName":"Acme"},"tags":["kit"]}'

Variables fill @{key|fallback} placeholders in the template. The ready-made Resource delivery template uses the following values:

VariableRequired for the presetUsed for
downloadUrlYesThe download button destination.
resourceNameNoThe subject, heading, and button label.
resourceDescriptionNoA short explanation above the button.
expiresAtNoHuman-readable link availability, such as July 31, 2026.
organizationNameNoThe team name in the help message.

The top-level firstName field personalizes the greeting. Optional variables use the template's readable fallback when omitted; downloadUrl should always be provided because it powers the CTA. The contact email always remains the destination, while send variables can override names for that render.

Response

A successful request returns 200:

{
  "sent": true,
  "contact": {
    "email": "[email protected]",
    "status": "subscribed"
  }
}

The recipient is upserted as a subscribed contact with source api. Growth records the send and tracks delivery, opens, and clicks.

Unsubscribes Do Not Block This Endpoint

This endpoint sends on the transactional stream. A contact who unsubscribed from your marketing email still receives it — they are paying for the product these emails deliver.

Only a hard bounce or a spam complaint blocks every stream, because in those cases the address is dead or the recipient reported you.

Errors

Refused sends carry a stable code alongside the human-readable message, so your application can tell "the customer did not get what they paid for" from routine noise:

{
  "code": "contact_bounced",
  "message": "The address hard-bounced and is suppressed for every stream. The email was not delivered."
}
StatuscodeMeaning
400—The JSON body is invalid, a required field is missing, or the recipient address is invalid.
401—The API key is missing or invalid.
404—The transactional definition cannot be found in this organization.
409—The definition is archived or its template was deleted.
409contact_bouncedThe address hard-bounced. Nothing was delivered — worth alerting on.
409contact_complainedThe recipient reported a previous email as spam. Nothing was delivered — worth alerting on.
409contact_not_foundThe contact does not belong to this organization.
409provider_not_configuredNo email provider is configured for this organization.

contact_unsubscribed exists in the response contract but is never returned on this endpoint: a marketing unsubscribe no longer blocks transactional email.