should_send
Should this message go out now? POST /v1/decisions/should_send. $0.003 per answer. Scope decisions:write.
When to call
Section titled “When to call”Call it as the last step before your agent sends a message, after the message is written. It weighs the message, the decisions that led to it and the inbox health numbers you supply. Verdict never sends anything; it only answers.
Inputs
Section titled “Inputs”| Field | Type | Required | Description |
|---|---|---|---|
message |
object | yes | The prepared message. |
message.channel |
enum: “email”, “other” | yes | Channel the message will go out on. |
message.subject |
string | no | Subject line. |
message.body |
string | yes | Plain-text body as it will be sent. At most 8192 bytes of UTF-8. |
decision_ids |
array of string | yes | The decisions behind the message (for example qualify_firm and pick_person), 1 to 10. |
inbox_health |
InboxHealth | yes | Inbox health you measure; Verdict never reads your inbox. |
inbox_health.bounce_rate_7d |
number | no | Share of sends that bounced over the last 7 days. |
inbox_health.spam_complaint_rate_7d |
number | no | Share of sends marked as spam over the last 7 days. |
inbox_health.reply_rate_7d |
number | no | Share of sends replied to over the last 7 days. |
inbox_health.sent_today |
integer | no | Messages sent from this inbox today. |
inbox_health.daily_limit |
integer | no | Your daily send limit for this inbox. |
inbox_health.domain_age_days |
integer | no | Age of the sending domain in days. |
recipient |
object | no | Optional contact history of the recipient. |
recipient.last_contacted_at |
string (date-time) | no | When you last wrote to this recipient. |
recipient.touches_30d |
integer | no | Messages sent to this recipient in 30 days. |
icp_id |
string | yes | The ICP profile to decide against. |
decision_ids are the earlier decisions behind this message (for example the qualify_firm and pick_person ids). inbox_health comes from your sending tool: bounce rate, complaint rate, today’s volume and limit, domain age.
Outputs
Section titled “Outputs”The common envelope plus:
send: probability the message should go out now. Same value asp.answer:sendorhold.hold_reason: why to hold, whenanswerishold.
Hold reasons
Section titled “Hold reasons”hold_reason |
Meaning |
|---|---|
upstream_decision_weak |
A decision behind the message is below its threshold; re-check the firm, person or signal. |
upstream_decision_missing |
A decision id behind the message is unknown; make the decision first. |
inbox_health_degraded |
The sending inbox is unhealthy; pause sending from it. |
daily_volume_limit |
The inbox has hit its daily volume; send tomorrow. |
recently_contacted |
The recipient was contacted too recently; wait. |
message_issue |
Fix the message before sending. |
recipient_opted_out |
The recipient opted out; never send. |
low_confidence |
The overall send probability is below threshold without a single dominant cause. |
Reason codes
Section titled “Reason codes”reason_code |
Meaning |
|---|---|
all_checks_passed |
The upstream decisions, inbox health and message checks all support sending now. |
upstream_decision_below_threshold |
At least one decision behind the message is below its current threshold. |
upstream_decision_missing |
At least one decision id behind the message is unknown to this organization. |
inbox_health_degraded |
The supplied inbox health (bounce, spam-complaint or reply rates) is outside safe bounds. |
daily_volume_limit_reached |
The sending inbox has reached the daily volume the caller supplied. |
recipient_recently_contacted |
The recipient was contacted too recently according to the supplied history. |
message_quality_issue |
The message has a defect such as an unfilled template variable or an empty body. |
recipient_opted_out |
An earlier outcome shows the recipient opted out. |
$0.003 when an answer is returned. Errors bill nothing.
Example
Section titled “Example”curl -X POST 'https://api.askverdict.io/v1/decisions/should_send' \ -H "Authorization: Bearer $VERDICT_API_KEY" \ -H "Idempotency-Key: $(uuidgen)" \ -H 'Content-Type: application/json' \ -d '{ "message": { "channel": "email", "subject": "Trade ops after your raise", "body": "Hi Dana, congratulations on the new fund. We help 10-person advisers automate trade reconciliation. Open to a short call next week?" }, "decision_ids": [ "dec_01JC3Z4Y8R9K2M5N7P1Q3S5T7V" ], "inbox_health": { "bounce_rate_7d": 0.012, "spam_complaint_rate_7d": 0.0005, "sent_today": 38, "daily_limit": 50 }, "recipient": { "touches_30d": 1 }, "icp_id": "icp_01JC3Z4Y8R9K2M5N7P1Q3S5T7V"}'{ "id": "dec_01JC3Z4Y8R9K2M5N7P1Q3S5T7V", "version": "2026-11-01", "question_set_version": "2026-11-01", "model": "jev", "calibration": { "basis": "org", "n_outcomes": 412, "threshold": 0.6 }, "latency_ms": 180, "created_at": "2026-11-07T14:03:00Z", "decision": "should_send", "p": 0.88, "answer": "send", "reason_code": "all_checks_passed", "reason": "Upstream decisions clear their thresholds and inbox health is within bounds.", "evidence": [ { "source": "request", "url": null, "observed_at": "2026-11-07", "pointer": "/inbox_health" } ], "send": 0.88, "hold_reason": null, "cost": { "decision_usd": 0.003, "vendor_usd": 0, "total_usd": 0.003 }, "balance_usd": 18.301}