PUT /contacts/bulk.type and basis sit on the envelope, not on the items. Signing is per-message, so a mixed batch would be technically sendable — this is a deliberate API restriction. One declaration per request means the entitlement and rate-limit decisions happen once, it matches the real use case (a batch is 100 order confirmations), and it removes the failure mode where one transactional item is smuggled into a marketing batch and silently exempted from consent.POST /messages/email/batch/async returning a jobId — mirroring POST /contacts/bulk/async.curl --location '/messages/email/batch' \
--header 'Authorization: Bearer <token>' \
--header 'Idempotency-Key: 0f3e2b1a-7c4d-4e2a-9b11-2f6d8c1a5e30' \
--header 'Content-Type: application/json' \
--data '{
"type": "transactional",
"basis": "contract_performance",
"messages": [
{
"to": {
"contactId": "string",
"clientContactId": "string",
"email": "string",
"name": "string"
},
"cc": [
{
"email": "string",
"name": "string"
}
],
"bcc": [
{
"email": "string",
"name": "string"
}
],
"from": {
"email": "string",
"name": "string"
},
"replyTo": {
"email": "string",
"name": "string"
},
"templateId": 0,
"subject": "string",
"htmlContent": "string",
"textContent": "string",
"language": "string",
"variables": {},
"attachments": [
{
"name": "string",
"content": "string",
"url": "string"
}
],
"headers": {},
"tracking": {
"opens": true,
"clicks": true
},
"tags": [
"string"
],
"metadata": {},
"sendAt": "string",
"createContact": true,
"retainBody": true,
"event": "string",
"permId": "string"
}
]
}'{
"accepted": 0,
"rejected": 0,
"messages": [
{
"index": 0,
"messageId": "string",
"to": "string",
"status": "queued",
"reason": "string",
"error": "string"
}
]
}