sayintel
Docs

Errors and QA codes.

Two vocabularies an agent can act on without reading prose. Transport errors tell you the call went wrong. QA codes tell you a draft is not ready to send, and what would fix it.

Error shape

{
  "ok": false,
  "tool": "create_campaign",
  "kind": "write",
  "data": null,
  "error": { "code": "invalid_input", "message": "conference_url must be an http(s) URL" }
}

Error codes

codeHTTPWhat it means
unauthenticated401Missing or invalid API key.
forbidden_scope403Key lacks the required scope (read, write or send).
invalid_request400Arguments failed schema validation.
not_found404No such resource, or not owned by this account.
rate_limited429Too many calls. Back off and retry.
tool_error500The capability failed while running.

QA hard-fail codes

A draft that trips any of these is held back from approval. Read them from get_draft_qa, or fetch this same list at runtime from GET /api/public/v1/qa-codes. Drafts scoring below 8 never bulk-approve.

vague_openerrewrite_opener

Opener references an unnamed event. Use a named anchor or switch to Pattern B (role + industry).

fake_insight_openerrewrite_opener

Opener invents an insight. Anchor on an extracted signal or drop to Pattern B.

presumed_painrewrite_opener

Remove presumed pain. State only what the research verified.

speculation_v2rewrite_opener

Strip speculative verbs (must be, probably, I imagine).

missing_specificityrewrite_opener

Add a concrete anchor: amount, product, partner, metric or talk title.

persona_mismatch_pitchrepersona

Pitch line does not match the detected persona. Re-pick from persona_pitch_map.

self_cancelling_openerrewrite_opener

Opener contradicts itself. Keep one claim.

ai_tell_openerrewrite_opener

Remove AI-tell phrasing; open plain and human.

appointment_phrase_presentrewrite_cta

Replace appointment-speak CTA with a specific shared-context ask.

banned_cta_v12rewrite_cta

Replace the 'worth ___' CTA family with a concrete ask.

url_in_messagestrip_url

Remove the URL from M1.

slots_identicalrewrite_followups

M2/M3 duplicate M1. Reframe without recycling the M1 anchor.

recipient_self_referencerewrite_opener

Message references the recipient's own company as the signal. Use a different anchor.

banned_phrase_universalrewrite_body

Remove the banned phrase or unverified market-category noun.

banned_phrase_extrarewrite_body

Remove the campaign-banned phrase.

trademark_symbol_presentsanitize

Strip ™/® symbols.

emoji_presentsanitize

Strip emoji.

m1_cta_locked_missingrestore_locked_phrase

Locked CTA phrase missing from M1; reinsert verbatim.

m1_pitch_locked_missingrestore_locked_phrase

Locked pitch phrase missing from M1; reinsert verbatim.

exact_pct_requiredrestore_locked_phrase

Required percentage figure missing or altered.

booth_cta_missingrewrite_cta

Add the configured booth CTA.

unresolved_placeholderresolve_placeholder

Mail-merge placeholder leaked; resolve {first_name}/{company} before send.

mid_sentence_truncationredraft

Draft was cut off by a token cap. Redraft with a higher cap.

incomplete_sentence_fragmentredraft

Fragment sentence; redraft the affected slot.

generic_filler_openerrewrite_opener

Filler opener; anchor on the talk topic or a real signal.

m1_over_hard_ceilingshorten

M1 exceeds the hard word ceiling; cut to target length.

session_anchor_available_but_unusedanchor_on_session

A session title exists — anchor the opener on it.

talk_topic_anchor_unusedanchor_on_session

Opener ignores the talk title. Reference the actual session topic.

wrong_event_yearfix_year

Wrong event year referenced; use the campaign's target year.

stale_talk_topicanchor_on_session

Talk topic is stale; use the current session.

presumed_attendancerewrite_cta

Do not assert the recipient is attending; frame the CTA conditionally.

fabricated_personalizationredraft

Invented tenure/career claim with no signal. Redraft with Pattern B.

proof_point_distortedrestore_proof_point

Proof point altered; restore verbatim from campaign config.

all_lowercase_bodyrestore_casing

Body was fully lowercased; restore proper-noun casing.

unverified_speaker_claimrewrite_opener

Claim about the speaker is unverified; drop it or swap to a verified anchor.

industry_inappropriaterewrite_body

Industry framing does not fit; use industry_challenge_map for this industry.

The usual repair loop is get_draft_qa(only_failing: true) then request_rewrite with the failing code as the reason, then re-read the QA state.