Email settings and transactional templates (order confirmation, shipping notification, password reset, …). Templates support Handlebars with safe-by-default escaping. Use these endpoints to customize per-store branding and edit individual templates.
Every operation below is on the public API surface: the 8 /v1/email/* operations take Authorization: Bearer brainerce_* and are what external integrators call (settings, templates CRUD, and preview).
The merchant dashboard uses its own internal email routes (signed-in session: AI template editing, domains, logs, versions, AI memory). They are not part of the public contract and are not listed here.
Get email settings for store
Returns the email sender settings of the store.
Admin API key (server-to-server). Issue via the dashboard at Settings → API keys. Plain-text key is shown once — store in a secret manager. Format: Authorization: Bearer brainerce_xxxxxxxxx.
In: header
curl -X GET "https://api.brainerce.com/api/v1/email/settings"{
"id": "clx1a2b3c4d5e6f7g8h9",
"accountId": "clx1a2b3c4d5e6f7g8h9",
"storeId": "clx1a2b3c4d5e6f7g8h9",
"emailsEnabled": true,
"defaultFromName": "Acme Store",
"defaultFromLocalPart": "info",
"defaultReplyTo": "[email protected]",
"eventSettings": {},
"hourlyRateLimit": 100,
"customDomainId": "clx1a2b3c4d5e6f7g8h9",
"dailyCampaignSendLimit": 5,
"clickTrackingEnabled": true,
"footerAddress": "12 Herzl St, Tel Aviv, Israel",
"deliveryProviderOverride": "AWS_SES",
"sesTenantName": "store-clx1a2b3",
"marketingSendingPaused": true,
"marketingPauseReason": "High complaint rate",
"marketingPausedAt": "2019-08-24T14:15:22Z",
"createdAt": "2019-08-24T14:15:22Z",
"updatedAt": "2019-08-24T14:15:22Z",
"customDomain": {
"id": "clx1a2b3c4d5e6f7g8h9",
"storeId": "clx1a2b3c4d5e6f7g8h9",
"domain": "mail.mystore.com",
"status": "VERIFIED",
"dnsRecords": [
{
"type": "CNAME",
"name": "string",
"value": "string",
"status": "verified"
}
],
"provider": "AWS_SES",
"providerIdentityId": "clx1a2b3c4d5e6f7g8h9",
"providerRegion": "eu-west-1",
"mailFromDomain": "bounce.mail.example.com",
"dkimStatus": "SUCCESS",
"mailFromStatus": "SUCCESS",
"resendDomainId": "clx1a2b3c4d5e6f7g8h9",
"verifiedAt": "2019-08-24T14:15:22Z",
"lastCheckedAt": "2019-08-24T14:15:22Z",
"createdAt": "2019-08-24T14:15:22Z",
"updatedAt": "2019-08-24T14:15:22Z"
},
"hasOwnerEmail": true
}{
"statusCode": 401,
"code": "UNAUTHORIZED",
"message": "Invalid or expired credential",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/v1/email/settings"
}{
"statusCode": 403,
"code": "INSUFFICIENT_SCOPE",
"message": "API key does not have the required scope: products:write",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/v1/email/settings"
}{
"statusCode": 429,
"code": "RATE_LIMITED",
"message": "Too many requests",
"details": {
"retryAfterSeconds": 12
},
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/v1/store"
}Update email settings for store
Supports Idempotency-Key header for safe retries.
Admin API key (server-to-server). Issue via the dashboard at Settings → API keys. Plain-text key is shown once — store in a secret manager. Format: Authorization: Bearer brainerce_xxxxxxxxx.
In: header
Header Parameters
Client-supplied key (a UUID v4 is the recommended form, max 255 characters) that makes this mutation safe to retry.
- Replay window: 24 hours. The first response for a key is cached; a retry inside the window with the same request body returns the original status and body without re-running the handler.
- Reusing a key with a different body returns
409 Conflictwithcode: "IDEMPOTENCY_KEY_REUSED". The request fingerprint (method + path + body hash) is compared against the stored one; a mismatch is refused rather than served the old response. - Keys are scoped to the calling credential and store — two API keys may safely use the same key value.
- Error responses are cached too, so a retry of a request that failed validation returns the same 400 immediately.
- Sending this header on a
GETreturns400withcode: "IDEMPOTENCY_KEY_NOT_SUPPORTED"— GETs are already idempotent. - Support is per-route and this parameter is the authoritative signal: a key sent to a route that does not declare it is accepted and silently ignored.
length <= 255Whether emails are enabled for this store
trueTrack link clicks in marketing campaigns. Off by default, because enabling it starts recording which recipients clicked, so the store owner must opt in rather than inherit it. Opens are never tracked.
falseDefault from name for emails
The part of the From address before the @, used when the store sends from its own verified domain (for example info gives [email protected]). Lowercase letters, digits, ., - and _, up to 64 characters, starting and ending with a letter or digit. Send null or an empty string to go back to the default, notifications. It is a send-only address: replies go to the Reply-To address.
length <= 64Reply-to email address
emailPer-event settings keyed by event type, for example ORDER_CONFIRMATION. Each value sets enabled and optionally sendToCustomer and sendToOwner.
Hourly rate limit for emails
1001 <= value <= 1000Custom domain ID to use for sending
Physical postal address shown in the footer of marketing mail. Required before any marketing-class message can be sent. CAN-SPAM mandates a visible business address, and the send is refused without one.
length <= 255curl -X PUT "https://api.brainerce.com/api/v1/email/settings" \ -H "Idempotency-Key: string" \ -H "Content-Type: application/json" \ -d '{}'{
"id": "clx1a2b3c4d5e6f7g8h9",
"accountId": "clx1a2b3c4d5e6f7g8h9",
"storeId": "clx1a2b3c4d5e6f7g8h9",
"emailsEnabled": true,
"defaultFromName": "Acme Store",
"defaultFromLocalPart": "info",
"defaultReplyTo": "[email protected]",
"eventSettings": {},
"hourlyRateLimit": 100,
"customDomainId": "clx1a2b3c4d5e6f7g8h9",
"dailyCampaignSendLimit": 5,
"clickTrackingEnabled": true,
"footerAddress": "12 Herzl St, Tel Aviv, Israel",
"deliveryProviderOverride": "AWS_SES",
"sesTenantName": "store-clx1a2b3",
"marketingSendingPaused": true,
"marketingPauseReason": "High complaint rate",
"marketingPausedAt": "2019-08-24T14:15:22Z",
"createdAt": "2019-08-24T14:15:22Z",
"updatedAt": "2019-08-24T14:15:22Z",
"customDomain": {
"id": "clx1a2b3c4d5e6f7g8h9",
"storeId": "clx1a2b3c4d5e6f7g8h9",
"domain": "mail.mystore.com",
"status": "VERIFIED",
"dnsRecords": [
{
"type": "CNAME",
"name": "string",
"value": "string",
"status": "verified"
}
],
"provider": "AWS_SES",
"providerIdentityId": "clx1a2b3c4d5e6f7g8h9",
"providerRegion": "eu-west-1",
"mailFromDomain": "bounce.mail.example.com",
"dkimStatus": "SUCCESS",
"mailFromStatus": "SUCCESS",
"resendDomainId": "clx1a2b3c4d5e6f7g8h9",
"verifiedAt": "2019-08-24T14:15:22Z",
"lastCheckedAt": "2019-08-24T14:15:22Z",
"createdAt": "2019-08-24T14:15:22Z",
"updatedAt": "2019-08-24T14:15:22Z"
},
"hasOwnerEmail": true
}{
"statusCode": 400,
"code": "VALIDATION_FAILED",
"message": "name should not be empty, price must be a positive number",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/v1/email/settings"
}{
"statusCode": 401,
"code": "UNAUTHORIZED",
"message": "Invalid or expired credential",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/v1/email/settings"
}{
"statusCode": 403,
"code": "INSUFFICIENT_SCOPE",
"message": "API key does not have the required scope: products:write",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/v1/email/settings"
}{
"statusCode": 429,
"code": "RATE_LIMITED",
"message": "Too many requests",
"details": {
"retryAfterSeconds": 12
},
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/v1/store"
}Get all email templates for store
Returns the email templates of the store.
Admin API key (server-to-server). Issue via the dashboard at Settings → API keys. Plain-text key is shown once — store in a secret manager. Format: Authorization: Bearer brainerce_xxxxxxxxx.
In: header
curl -X GET "https://api.brainerce.com/api/v1/email/templates"{
"templates": [
{
"id": "clx1a2b3c4d5e6f7g8h9",
"accountId": "clx1a2b3c4d5e6f7g8h9",
"storeId": "clx1a2b3c4d5e6f7g8h9",
"name": "Order Confirmation",
"eventType": "ORDER_CONFIRMATION",
"language": "en",
"subject": "Order {{orderNumber}} Confirmed",
"htmlContent": "<h1>Thanks for your order {{customerName}}</h1>",
"textContent": "Thanks for your order {{customerName}}",
"variables": {},
"isDefault": true,
"isActive": true,
"createdAt": "2019-08-24T14:15:22Z",
"updatedAt": "2019-08-24T14:15:22Z"
}
],
"language": "en",
"supportedLanguages": [
"string"
]
}{
"statusCode": 401,
"code": "UNAUTHORIZED",
"message": "Invalid or expired credential",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/v1/email/templates"
}{
"statusCode": 403,
"code": "INSUFFICIENT_SCOPE",
"message": "API key does not have the required scope: products:write",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/v1/email/templates"
}{
"statusCode": 429,
"code": "RATE_LIMITED",
"message": "Too many requests",
"details": {
"retryAfterSeconds": 12
},
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/v1/store"
}Get email template by ID
Returns one email template of this store.
Admin API key (server-to-server). Issue via the dashboard at Settings → API keys. Plain-text key is shown once — store in a secret manager. Format: Authorization: Bearer brainerce_xxxxxxxxx.
In: header
Path Parameters
Template ID
curl -X GET "https://api.brainerce.com/api/v1/email/templates/string"{
"id": "clx1a2b3c4d5e6f7g8h9",
"accountId": "clx1a2b3c4d5e6f7g8h9",
"storeId": "clx1a2b3c4d5e6f7g8h9",
"name": "Order Confirmation",
"eventType": "ORDER_CONFIRMATION",
"language": "en",
"subject": "Order {{orderNumber}} Confirmed",
"htmlContent": "<h1>Thanks for your order {{customerName}}</h1>",
"textContent": "Thanks for your order {{customerName}}",
"variables": {},
"isDefault": true,
"isActive": true,
"createdAt": "2019-08-24T14:15:22Z",
"updatedAt": "2019-08-24T14:15:22Z"
}{
"statusCode": 401,
"code": "UNAUTHORIZED",
"message": "Invalid or expired credential",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/v1/email/templates/{templateId}"
}{
"statusCode": 403,
"code": "INSUFFICIENT_SCOPE",
"message": "API key does not have the required scope: products:write",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/v1/email/templates/{templateId}"
}{
"statusCode": 404,
"code": "RESOURCE_NOT_FOUND",
"message": "Resource not found",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/v1/email/templates/{templateId}"
}{
"statusCode": 429,
"code": "RATE_LIMITED",
"message": "Too many requests",
"details": {
"retryAfterSeconds": 12
},
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/v1/store"
}Create a new email template
Supports Idempotency-Key header for safe retries.
Admin API key (server-to-server). Issue via the dashboard at Settings → API keys. Plain-text key is shown once — store in a secret manager. Format: Authorization: Bearer brainerce_xxxxxxxxx.
In: header
Header Parameters
Client-supplied key (a UUID v4 is the recommended form, max 255 characters) that makes this mutation safe to retry.
- Replay window: 24 hours. The first response for a key is cached; a retry inside the window with the same request body returns the original status and body without re-running the handler.
- Reusing a key with a different body returns
409 Conflictwithcode: "IDEMPOTENCY_KEY_REUSED". The request fingerprint (method + path + body hash) is compared against the stored one; a mismatch is refused rather than served the old response. - Keys are scoped to the calling credential and store — two API keys may safely use the same key value.
- Error responses are cached too, so a retry of a request that failed validation returns the same 400 immediately.
- Sending this header on a
GETreturns400withcode: "IDEMPOTENCY_KEY_NOT_SUPPORTED"— GETs are already idempotent. - Support is per-route and this parameter is the authoritative signal: a key sent to a route that does not declare it is accepted and silently ignored.
length <= 255Template display name
Event type this template is for
"ORDER_CONFIRMATION" | "ORDER_SHIPPED" | "ORDER_CANCELLED" | "ORDER_COMPLETED" | "ORDER_REFUNDED" | "ORDER_NOTE" | "NEW_ORDER_ADMIN" | "NEW_CUSTOMER" | "LOW_STOCK_ALERT" | "CART_ABANDONED" | "EMAIL_VERIFICATION" | "TEAM_INVITATION" | "ORDERS_LINKED" | "STORE_INVITATION" | "STORE_ROLE_CHANGED" | "STORE_DELETED" | "EXPORT_COMPLETE" | "SCHEDULED_BACKUP_SUCCESS" | "SCHEDULED_BACKUP_FAILED" | "CAMPAIGN_SCHEDULE_FAILED" | "PASSWORD_RESET" | "INQUIRY_NEW_ADMIN" | "INQUIRY_REPLY_CUSTOMER" | "INQUIRY_CONFIRMATION_CUSTOMER" | "MARKETING_CAMPAIGN"Locale this template is for (must be in store.supportedLanguages)
Email subject line (supports Handlebars)
HTML content of the email (supports Handlebars)
Plain text content of the email
Variable schema for this template. Keys are variable names, values are type labels such as string.
Whether this template is active
truecurl -X POST "https://api.brainerce.com/api/v1/email/templates" \ -H "Idempotency-Key: string" \ -H "Content-Type: application/json" \ -d '{ "name": "Order Confirmation", "eventType": "ORDER_CONFIRMATION", "language": "en", "subject": "Order #{{orderNumber}} Confirmed", "htmlContent": "<h1>Thank you for your order!</h1>" }'{
"id": "clx1a2b3c4d5e6f7g8h9",
"accountId": "clx1a2b3c4d5e6f7g8h9",
"storeId": "clx1a2b3c4d5e6f7g8h9",
"name": "Order Confirmation",
"eventType": "ORDER_CONFIRMATION",
"language": "en",
"subject": "Order {{orderNumber}} Confirmed",
"htmlContent": "<h1>Thanks for your order {{customerName}}</h1>",
"textContent": "Thanks for your order {{customerName}}",
"variables": {},
"isDefault": true,
"isActive": true,
"createdAt": "2019-08-24T14:15:22Z",
"updatedAt": "2019-08-24T14:15:22Z"
}{
"statusCode": 400,
"code": "VALIDATION_FAILED",
"message": "name should not be empty, price must be a positive number",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/v1/email/templates"
}{
"statusCode": 401,
"code": "UNAUTHORIZED",
"message": "Invalid or expired credential",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/v1/email/templates"
}{
"statusCode": 403,
"code": "INSUFFICIENT_SCOPE",
"message": "API key does not have the required scope: products:write",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/v1/email/templates"
}{
"statusCode": 429,
"code": "RATE_LIMITED",
"message": "Too many requests",
"details": {
"retryAfterSeconds": 12
},
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/v1/store"
}Update an email template
Supports Idempotency-Key header for safe retries.
Admin API key (server-to-server). Issue via the dashboard at Settings → API keys. Plain-text key is shown once — store in a secret manager. Format: Authorization: Bearer brainerce_xxxxxxxxx.
In: header
Path Parameters
Template ID
Header Parameters
Client-supplied key (a UUID v4 is the recommended form, max 255 characters) that makes this mutation safe to retry.
- Replay window: 24 hours. The first response for a key is cached; a retry inside the window with the same request body returns the original status and body without re-running the handler.
- Reusing a key with a different body returns
409 Conflictwithcode: "IDEMPOTENCY_KEY_REUSED". The request fingerprint (method + path + body hash) is compared against the stored one; a mismatch is refused rather than served the old response. - Keys are scoped to the calling credential and store — two API keys may safely use the same key value.
- Error responses are cached too, so a retry of a request that failed validation returns the same 400 immediately.
- Sending this header on a
GETreturns400withcode: "IDEMPOTENCY_KEY_NOT_SUPPORTED"— GETs are already idempotent. - Support is per-route and this parameter is the authoritative signal: a key sent to a route that does not declare it is accepted and silently ignored.
length <= 255Template display name
Email subject line (supports Handlebars)
HTML content of the email (supports Handlebars)
Plain text content of the email
Variable schema for this template. Keys are variable names, values are type labels such as string.
Whether this template is active
curl -X PUT "https://api.brainerce.com/api/v1/email/templates/string" \ -H "Idempotency-Key: string" \ -H "Content-Type: application/json" \ -d '{}'{
"id": "clx1a2b3c4d5e6f7g8h9",
"accountId": "clx1a2b3c4d5e6f7g8h9",
"storeId": "clx1a2b3c4d5e6f7g8h9",
"name": "Order Confirmation",
"eventType": "ORDER_CONFIRMATION",
"language": "en",
"subject": "Order {{orderNumber}} Confirmed",
"htmlContent": "<h1>Thanks for your order {{customerName}}</h1>",
"textContent": "Thanks for your order {{customerName}}",
"variables": {},
"isDefault": true,
"isActive": true,
"createdAt": "2019-08-24T14:15:22Z",
"updatedAt": "2019-08-24T14:15:22Z"
}{
"statusCode": 400,
"code": "VALIDATION_FAILED",
"message": "name should not be empty, price must be a positive number",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/v1/email/templates/{templateId}"
}{
"statusCode": 401,
"code": "UNAUTHORIZED",
"message": "Invalid or expired credential",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/v1/email/templates/{templateId}"
}{
"statusCode": 403,
"code": "INSUFFICIENT_SCOPE",
"message": "API key does not have the required scope: products:write",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/v1/email/templates/{templateId}"
}{
"statusCode": 404,
"code": "RESOURCE_NOT_FOUND",
"message": "Resource not found",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/v1/email/templates/{templateId}"
}{
"statusCode": 429,
"code": "RATE_LIMITED",
"message": "Too many requests",
"details": {
"retryAfterSeconds": 12
},
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/v1/store"
}Delete an email template
Supports Idempotency-Key header for safe retries.
Admin API key (server-to-server). Issue via the dashboard at Settings → API keys. Plain-text key is shown once — store in a secret manager. Format: Authorization: Bearer brainerce_xxxxxxxxx.
In: header
Path Parameters
Template ID
Header Parameters
Client-supplied key (a UUID v4 is the recommended form, max 255 characters) that makes this mutation safe to retry.
- Replay window: 24 hours. The first response for a key is cached; a retry inside the window with the same request body returns the original status and body without re-running the handler.
- Reusing a key with a different body returns
409 Conflictwithcode: "IDEMPOTENCY_KEY_REUSED". The request fingerprint (method + path + body hash) is compared against the stored one; a mismatch is refused rather than served the old response. - Keys are scoped to the calling credential and store — two API keys may safely use the same key value.
- Error responses are cached too, so a retry of a request that failed validation returns the same 400 immediately.
- Sending this header on a
GETreturns400withcode: "IDEMPOTENCY_KEY_NOT_SUPPORTED"— GETs are already idempotent. - Support is per-route and this parameter is the authoritative signal: a key sent to a route that does not declare it is accepted and silently ignored.
length <= 255curl -X DELETE "https://api.brainerce.com/api/v1/email/templates/string" \ -H "Idempotency-Key: string"{
"statusCode": 401,
"code": "UNAUTHORIZED",
"message": "Invalid or expired credential",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/v1/email/templates/{templateId}"
}{
"statusCode": 403,
"code": "INSUFFICIENT_SCOPE",
"message": "API key does not have the required scope: products:write",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/v1/email/templates/{templateId}"
}{
"statusCode": 404,
"code": "RESOURCE_NOT_FOUND",
"message": "Resource not found",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/v1/email/templates/{templateId}"
}{
"statusCode": 429,
"code": "RATE_LIMITED",
"message": "Too many requests",
"details": {
"retryAfterSeconds": 12
},
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/v1/store"
}Preview an email template with sample data
Supports Idempotency-Key header for safe retries.
Admin API key (server-to-server). Issue via the dashboard at Settings → API keys. Plain-text key is shown once — store in a secret manager. Format: Authorization: Bearer brainerce_xxxxxxxxx.
In: header
Path Parameters
Template ID
Header Parameters
Client-supplied key (a UUID v4 is the recommended form, max 255 characters) that makes this mutation safe to retry.
- Replay window: 24 hours. The first response for a key is cached; a retry inside the window with the same request body returns the original status and body without re-running the handler.
- Reusing a key with a different body returns
409 Conflictwithcode: "IDEMPOTENCY_KEY_REUSED". The request fingerprint (method + path + body hash) is compared against the stored one; a mismatch is refused rather than served the old response. - Keys are scoped to the calling credential and store — two API keys may safely use the same key value.
- Error responses are cached too, so a retry of a request that failed validation returns the same 400 immediately.
- Sending this header on a
GETreturns400withcode: "IDEMPOTENCY_KEY_NOT_SUPPORTED"— GETs are already idempotent. - Support is per-route and this parameter is the authoritative signal: a key sent to a route that does not declare it is accepted and silently ignored.
length <= 255Free-form sample values for the template placeholders. They are merged over the built-in sample data before rendering. Max 100 KB serialized.
curl -X POST "https://api.brainerce.com/api/v1/email/templates/string/preview" \ -H "Idempotency-Key: string" \ -H "Content-Type: application/json" \ -d '{}'{
"subject": "Your order ORD-1042 is confirmed",
"html": "<h1>Thanks for your order Dana</h1>",
"text": "Thanks for your order Dana"
}{
"statusCode": 400,
"code": "VALIDATION_FAILED",
"message": "name should not be empty, price must be a positive number",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/v1/email/templates/{templateId}/preview"
}{
"statusCode": 401,
"code": "UNAUTHORIZED",
"message": "Invalid or expired credential",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/v1/email/templates/{templateId}/preview"
}{
"statusCode": 403,
"code": "INSUFFICIENT_SCOPE",
"message": "API key does not have the required scope: products:write",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/v1/email/templates/{templateId}/preview"
}{
"statusCode": 404,
"code": "RESOURCE_NOT_FOUND",
"message": "Resource not found",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/v1/email/templates/{templateId}/preview"
}{
"statusCode": 429,
"code": "RATE_LIMITED",
"message": "Too many requests",
"details": {
"retryAfterSeconds": 12
},
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/v1/store"
}