MisarMisar Docs
MisarMailMisarBlogMisarReachMisarPostMisarDevMisarCoderMisarSEOMisar PlatformMisar SSO
API Reference

Sales Agent API

Configure the AI sales agent, read its decision audit trail and active conversations, and process a conversation — api.misar.io/reach/api/sales-agent.

The sales agent is MisarReach's AI assistant for follow-up. It reads a conversation, decides what should happen next, and drafts the reply. Every decision is written to an audit trail before anything is sent.

Base URL: https://api.misar.io/reach/api · Auth: Authorization: Bearer mrk_…

Pro plan and above

Enabling the agent and processing a conversation both require a Pro-or-higher MisarReach plan. Reading configuration, actions, and conversations does not.

Scopes

Api-Key mrk_… and a bare mrk_… header value are accepted alongside Bearer. A key with the * scope satisfies every requirement below.

EndpointScope
GET /api/sales-agent/configsales_agent:read
PATCH /api/sales-agent/configsales_agent:write
GET /api/sales-agent/actionssales_agent:read
GET /api/sales-agent/conversationssales_agent:read
POST /api/sales-agent/processsales_agent:write

Get configuration

GET/api/sales-agent/config

Returns the caller's agent configuration. Takes no parameters.

Response fields

okboolean

Always true on success.

config.user_idstring

Owner of the configuration.

config.enabledboolean

Whether the agent runs at all. Defaults to false.

config.auto_sendboolean

Whether approved replies are sent without review. Defaults to false.

config.cal_linkstring | null

Booking link the agent offers when it decides to ask for a meeting.

config.offer_pricenumber

Offer price in the smallest currency unit (paise). Defaults to 0.

config.offer_descriptionstring | null

What the agent is selling. Up to 1000 characters.

config.max_replies_per_daynumber

Daily cap on auto-sent replies. Defaults to 20.

config.confidence_thresholdnumber

Decisions below this confidence are flagged for a human. Defaults to 0.65.

config.updated_atstring

ISO-8601 last-modified time. Absent on the synthesised default.

Request
curl https://api.misar.io/reach/api/sales-agent/config \
  -H "Authorization: Bearer mrk_your_key_here"
200 — Configured
{
  "ok": true,
  "config": {
    "user_id": "3f1a2b4c-5d6e-4f70-8a91-b2c3d4e5f607",
    "enabled": true,
    "auto_send": false,
    "cal_link": "https://cal.com/jane/30min",
    "offer_price": 1000000,
    "offer_description": "Annual growth retainer",
    "max_replies_per_day": 20,
    "confidence_threshold": 0.65,
    "updated_at": "2026-08-01T10:22:07.114Z"
  }
}

No row yet? You still get a config

If the agent has never been configured, the response is a synthesised default with enabled: false and no updated_at. It is not a 404.

Status codes

CodeMeaning
200Configuration returned
401Not authenticated
403Missing sales_agent:read
500{ "error": "Failed to load config" }

Update configuration

PATCH/api/sales-agent/config

Partial update — send only the fields you want to change. Unknown keys are ignored. An empty body is valid and simply touches updated_at.

Request body

enabledbooleanbody

Turn the agent on or off. Setting this to true triggers the Pro plan check.

auto_sendbooleanbody

Whether approved replies send without review.

cal_linkstring | nullbody

Must be a valid URL, at most 500 characters. null clears it.

offer_pricenumberbody

Non-negative integer in the smallest currency unit.

offer_descriptionstring | nullbody

Up to 1000 characters. null clears it.

max_replies_per_daynumberbody

Integer between 1 and 500.

confidence_thresholdnumberbody

Between 0 and 1.

Response fields

okboolean

true when the update was written. The updated configuration is not echoed back — re-read it with GET if you need it.

Request
curl -X PATCH https://api.misar.io/reach/api/sales-agent/config \
  -H "Authorization: Bearer mrk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "enabled": true,
    "confidence_threshold": 0.75,
    "max_replies_per_day": 30,
    "cal_link": "https://cal.com/jane/30min"
  }'
200 — Updated
{ "ok": true }
403 — Plan gate
{
  "success": false,
  "error": "The AI Sales Agent is available on Pro and above. Upgrade to enable it.",
  "feature": "ai_sales_agent",
  "upgrade": true,
  "upgrade_url": "/settings?tab=billing"
}

Status codes

CodeMeaning
200Updated
400Validation failed, or the body was not valid JSON. The message names the offending field.
401Not authenticated
403Missing sales_agent:write, or the plan gate rejected enabled: true
500{ "error": "Failed to update config" }

The plan gate only guards enabling

It runs solely when the body sets enabled to true. A lower-tier account can still change other fields, and can always disable the agent.

List today's actions

GET/api/sales-agent/actions

The agent's decision audit trail for today only, newest first, capped at 20 rows. There are no query parameters and no pagination.

Response fields

okboolean

Always true.

actions[].idstring

Action id.

actions[].actionstring

One of reply, ask_for_meeting, send_offer, close_deal, human_handoff.

actions[].reasonstring | null

Why the agent chose this action.

actions[].confidencenumber

Between 0 and 1.

actions[].flagged_humanboolean

Whether the decision was routed to a human.

actions[].auto_sentboolean

Whether the reply was sent without review. Only auto-sent actions count against the daily cap.

actions[].conversation_idstring

The conversation the decision applies to.

actions[].created_atstring

ISO-8601 decision time.

statsobject

total (rows returned), deals (how many were close_deal), flagged (how many were flagged for a human).

Request
curl https://api.misar.io/reach/api/sales-agent/actions \
  -H "Authorization: Bearer mrk_your_key_here"
200 — OK
{
  "ok": true,
  "actions": [
    {
      "id": "7b2c1a9d-4e5f-4061-9a72-c3d4e5f60718",
      "action": "ask_for_meeting",
      "reason": "Lead asked about availability twice",
      "confidence": 0.82,
      "flagged_human": false,
      "auto_sent": false,
      "conversation_id": "1a2b3c4d-5e6f-4071-8a92-b3c4d5e6f708",
      "created_at": "2026-08-04T09:14:02.771Z"
    }
  ],
  "stats": { "total": 1, "deals": 0, "flagged": 0 }
}

Today is the server's day, and the window is fixed

The cutoff is local midnight on the server, and the cap is a hard 20 rows. There is no date filter and no way to page further back — this is a live dashboard feed, not a history API. A read failure also returns 200, with an empty actions array and zeroed stats.

Status codes

CodeMeaning
200Returned
401Not authenticated
403Missing sales_agent:read

List active conversations

GET/api/sales-agent/conversations

Active conversations for the caller, ordered by most recent message.

Query parameters

limitnumberquerydefault: 25

Rows to return. Capped at 50. Pass a positive integer.

Response fields

okboolean

Always true.

conversations[].idstring

Conversation id. Pass this to POST /api/sales-agent/process.

conversations[].lead_namestring | null

Lead's display name.

conversations[].lead_emailstring | null

Lead's email address.

conversations[].channelstring

email, whatsapp, sms, linkedin, instagram, facebook, twitter, or telegram.

conversations[].last_messagestring | null

Most recent message body.

conversations[].last_message_atstring | null

ISO-8601 timestamp of the most recent message.

Request
curl "https://api.misar.io/reach/api/sales-agent/conversations?limit=25" \
  -H "Authorization: Bearer mrk_your_key_here"
200 — OK
{
  "ok": true,
  "conversations": [
    {
      "id": "1a2b3c4d-5e6f-4071-8a92-b3c4d5e6f708",
      "lead_name": "Sam Rivera",
      "lead_email": "sam@example.com",
      "channel": "email",
      "last_message": "Could we do Thursday instead?",
      "last_message_at": "2026-08-04T08:41:19.220Z"
    }
  ]
}

Status codes

CodeMeaning
200Returned
401Not authenticated
403Missing sales_agent:read
500{ "error": "Failed to load conversations" }

Process a conversation

POST/api/sales-agent/process

Runs the agent over one conversation: decide the next action, then draft the reply unless the decision was flagged for a human. The decision is written to the audit trail either way.

Request body

conversationIdstringbodyrequired

UUID of the conversation to process. Exactly one conversation per call.

Response fields

okboolean

Always true on success.

decision.actionstring

One of reply, ask_for_meeting, send_offer, close_deal, human_handoff.

decision.reasonstring

Why the agent chose it.

decision.confidencenumber

Between 0 and 1.

replystring | null

The drafted reply, or null when flaggedHuman is true.

flaggedHumanboolean

true when the action was human_handoff or the confidence fell below the configured threshold.

todayCountnumber

Auto-sent replies today, including this run.

dailyLimitnumber

The configured max_replies_per_day.

Request
curl -X POST https://api.misar.io/reach/api/sales-agent/process \
  -H "Authorization: Bearer mrk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{ "conversationId": "1a2b3c4d-5e6f-4071-8a92-b3c4d5e6f708" }'
200 — Reply drafted
{
  "ok": true,
  "decision": {
    "action": "ask_for_meeting",
    "reason": "Lead asked about availability twice",
    "confidence": 0.82
  },
  "reply": "Thursday works — here is my calendar: https://cal.com/jane/30min",
  "flaggedHuman": false,
  "todayCount": 4,
  "dailyLimit": 20
}
200 — Flagged for a human
{
  "ok": true,
  "decision": {
    "action": "human_handoff",
    "reason": "Pricing objection outside configured offer",
    "confidence": 0.41
  },
  "reply": null,
  "flaggedHuman": true,
  "todayCount": 4,
  "dailyLimit": 20
}
429 — Daily cap
{ "error": "Daily reply limit reached", "limitReached": true }

This endpoint never sends anything

The manual path always records auto_sent: false and returns the draft for you to send. Auto-sending happens only on the agent's own scheduled path, and only when auto_send is enabled. There is no queue mode — one conversationId per call.

Status codes

CodeMeaning
200Processed
400conversationId missing or not a UUID, or the body was not valid JSON
401Not authenticated
403Missing sales_agent:write; the agent is disabled (Sales agent is not enabled); or the plan gate rejected the call
404{ "error": "Conversation not found" } — also returned when the conversation belongs to another user
429{ "error": "Daily reply limit reached", "limitReached": true }
500{ "error": "Failed to load messages" }

Decision pipeline

Ownership and configuration

The conversation must belong to the caller and the agent must be enabled, otherwise the call stops at 404 or 403.

Daily cap

Auto-sent replies from today are counted. At or above max_replies_per_day, the call returns 429.

Decide

The last 20 messages are read in order and the agent picks an action with a confidence score.

Flag or draft

human_handoff, or any confidence below confidence_threshold, flags the decision and skips drafting. Otherwise the reply is generated.

Audit

The decision is written to the audit trail — visible immediately via GET /api/sales-agent/actions.

Rate limits

These endpoints carry no request rate limit. The only throttle is the per-day auto-send cap, and because manual process calls never auto-send, they do not consume it.

See Errors and Conversations.