---
title: "Optimize Outbound Messages In A Batch"
method: POST
path: "/api/platform/v1/messages/optimize/batch"
tags: ["assets"]
---

# Optimize Outbound Messages In A Batch

`POST /api/platform/v1/messages/optimize/batch`

## Request

- Base URL: `https://docs.amdahl.ai`
- URL: `https://docs.amdahl.ai/api/platform/v1/messages/optimize/batch`
- Auth: one of:
  - API key in header `X-API-Key`
  - HTTP bearer

Queue many outbound drafts for the optimizer in one request and get a batch_id back at once. Use when a campaign has more drafts than the per-workspace limits on single optimizes allow, or nobody is waiting on each result. Items run later on spare capacity, behind interactive calls, and are never refused as busy. Poll the batch for counts, an estimated finish time and each result. Only items that succeed count as usage.

## Request body

- object
  - `items` object[], required: The drafts, up to 500. Each is the body of one single optimize (message, channel, context, evidence, on_unsupported, include_tries, all optional) plus an optional item_id of your own. Results come back in this order.
    - `item_id` string: Your own id for this draft, returned with its result. Unique within the batch.
    - `context` object: What the message is written FROM, and the quality of the message follows the quality of this. facts are what the sender knows first-hand about the recipient: who they are, why write now, what is offered, the proof that may be cited. rules are what the message must and must not do, including the ask. voice_examples are the sender’s own messages, matched and never copied. keep_cta, max_words, banned_phrases and banned_punctuation are checked exactly. If all you have is the user’s own request, pass it as a fact rather than sending nothing. Blank entries are dropped and any other key is refused.
      - `rules` string[]: Hard constraints on the rewrite, such as "no pricing". They steer the rewrite and are not rewritten or quoted in the message. Up to 20, each up to 500 characters once trimmed.
      - `voice_examples` string[]: Messages the sender wrote themselves. The rewrite matches the sender's voice and does not copy their words. Up to 5, each up to 4000 characters once trimmed.
      - `facts` string[]: What you know first-hand about the recipient or situation that no call recording holds, one fact per entry, such as "Met Priya at the GTM dinner on Sep 24; she said her SDRs rewrite every AI draft". Graded as caller-supplied evidence (tier CALLER, not a customer quote): a claim a fact states is not marked fabricated, a claim that inflates one still is. Up to 10, each up to 1000 characters once trimmed.
      - `keep_cta` boolean: true to keep the draft's closing ask (its last sentence that asks for something) word for word. Checked exactly on every rewrite; the rewrite works on the rest of the message.
      - `max_words` integer: The most words the returned message may have, checked exactly on every rewrite. 10 to 1000.
      - `banned_phrases` string[]: Words or phrases the rewrite leaves out, such as "just" or "reaching out", matched as whole words in any case and checked exactly on every rewrite. Up to 30, each up to 60 characters once trimmed.
      - `banned_punctuation` string[]: Punctuation the rewrite leaves out: any of colon, semicolon, exclamation. Checked exactly on every rewrite; a colon in a time like 2:30pm or in a link does not count.
    - `message` string: Optional, and NOT READ where Amdahl writes from context: nothing is taken out of a draft, not a claim, not a name, not the subject line, and the result carries a draft_ignored note. One exception: a draft sent with no facts in context and no recipient is improved instead, with a draft_improved_no_context note. Put what you know in context.
    - `channel` 'email' | 'linkedin': Where the message will be sent. Send it: with no draft there is nothing to infer it from, and the channel sets the length and format the message is written and judged against. linkedin means a connection note, which carries no sign-off.
    - `on_unsupported` 'flag' | 'remove': What to do with a claim in the draft that nothing in the workspace conversations backs. "flag" (the default) keeps it and lists it in unsupported_claims; "remove" lets the rewrite soften or cut it. Only checked when the workspace has connected conversations.
    - `evidence` 'workspace' | 'off': Optional, default off. workspace grades the draft against what this workspace's customers said in its synced conversations (positioning, grounding, specifics, differentiation), which is slower; off is a fast style pass. Where no conversations can be read the run is graded as off and evidence.reason says why.
    - `include_tries` boolean: Optional, default false. When true, the result also carries `tries`: every version the run scored, the draft first, each with its text, the optimizer's own score and human_tone (1 to 5), the dimensions it aimed at, and which one was returned. It shows how the draft progressed. Those scores come from the judge the rewrites were optimized against, so `lift`, not them, is the before-and-after.
  - `webhook_url` string: Optional. An https URL that gets one signed POST when the batch completes, carrying the batch id and its counts, never a draft or a rewrite.
  - `idempotency_key` string: Optional. Send the same key to retry a submit safely: the same key and body return the first batch and queue nothing new.

## Response `202`

Accepted

- object
  - `data` unknown

## Other responses

- `400`: Invalid input - failed schema validation
- `401`: Authentication required
- `403`: Forbidden - missing scope or role
- `500`: Internal server error

---

[API](https://skmtc.dev/amdahl/apis/amdahl-platform-api.md) · [All operations](https://skmtc.dev/amdahl/apis/amdahl-platform-api/llms.txt) · [OpenAPI document](https://skmtc.dev/amdahl/apis/amdahl-platform-api/revisions/d4eee33e2472?raw)
