External Assistant API
What This Does
Section titled “What This Does”The External Assistant API lets another app ask Bombyx for a suggested response.
Good fits:
- Draft a reply to a customer email
- Help a support agent respond inside another helpdesk
- Give a sales inbox a first-pass answer
Bombyx reads the organization’s Brain, assistant settings, and approved training. Then it returns a suggested response.
It does not send the email or message. Your app stays in charge.
External replies run under the explicit external_api assistant workflow. They share the same organization-owned memory, typed outcome, provenance, and reviewed-answer rollout controls as the widget and tester, but connector policy and idempotency stay external-API specific.
Every successful external reply is AI-generated and passes an independent semantic review before Bombyx stores or returns it. External replies do not use deterministic semantic fallbacks or the final-answer cache. If review, evidence validation, or a provider fails, the API returns a typed system_status with no assistant message.
Successful responses use contract version 2026-07-17.2. Bombyx stores an internal v2 reviewed-reply receipt that binds the request fingerprint, tenant, chatbot, conversation, user message, connector, original and current token provenance, exact AgentRun, final text, exact reference set, exact successful tool evidence set, complete review ledger, final review input, evidence fingerprints, reviewer confirmations, and policy versions. Completed retries are returned only after current connector authorization and every bound receipt, run, message, tool, and source invariant is revalidated.
Before You Start
Section titled “Before You Start”Your token needs:
assistant_replyto draft repliesassistant_feedbackto send feedback laterassistant_tool:<tool-key>for each assistant tool the external workflow may call
For example, a connector that may call the lookup_order assistant tool needs both assistant_reply and assistant_tool:lookup_order. The reply capability alone never exposes assistant tools.
External Assistant can use only enabled read-only tools that require no approval and pass the shared strict tool contract. Input and output schemas must be recursively bounded and closed, secret-bearing output fields are forbidden, and approval-required or write-risk tools are rejected before a ToolRun is created. Every accepted output-schema constraint is enforced by the runtime projector, and unsupported constraint keywords are rejected. Successful output is projected once to declared customer-safe fields. Credentials are rejected, and any absolute URI in any string field is rejected unless the field is explicitly linkable and the URL is public HTTP or HTTPS on an allowed host. Tool output remains untrusted data during composition and final review. Reusing an idempotent ToolRun repeats current connector and capability authorization and revalidates its stored output against the current schema.
If the organization has more than one assistant, include chatbot_id.
Step-By-Step
Section titled “Step-By-Step”- Pick a stable thread ID from your system.
- Send the latest message to Bombyx.
- Show the suggested response to a human or your workflow.
- Send feedback when the response is accepted, corrected, or rejected.
Use the same external_thread_id for every turn in the same email or support thread. That keeps the conversation together.
Copyable Request
Section titled “Copyable Request”curl https://bombyxlabs.com/app/api/tool-connectors/v1/assistant/replies \ -H "Authorization: Bearer btx_your_token_here" \ -H "Content-Type: application/json" \ -d '{ "external_thread_id": "email-thread-123", "external_message_id": "email-message-456", "idempotency_key": "reply-email-message-456", "channel": "email", "response_mode": "suggested_reply", "payload": { "subject": "Question about pricing", "from": "[email protected]", "to": "[email protected]", "sent_at": "2026-07-05T15:30:00Z", "text": "Can you send me pricing for the monthly plan?", "history": [ { "role": "customer", "text": "I saw your assistant on the website." } ] }, "metadata": { "source": "supportdesk" } }'Example Response
Section titled “Example Response”{ "ok": true, "reply_id": 381, "conversation_id": 914, "message_id": 1822, "agent_run_id": 771, "external_thread_id": "email-thread-123", "external_message_id": "email-message-456", "suggested_response": { "text": "Thanks for reaching out. Pricing depends on the setup you need, so the best next step is to book a quick discovery call." }, "references": [ { "reference_id": "memory-item:1008:revision:7:chunk:16071", "memory_item_id": 1008, "memory_source_id": 1024, "memory_chunk_ids": [16071], "title": "Monthly plan guidance", "source_uri": "https://example.com/pricing", "source_date": "2026-07-10T18:00:00Z", "revision_date": "2026-07-11T18:45:00Z", "visibility": "organization_internal", "audience": "customer_safe", "authority": { "level": "approved_source", "score": 90, "role": "authoritative" }, "excerpt": "Plan recommendations depend on the customer's setup.", "relevance": { "score": 0.91, "method": "semantic" }, "freshness": { "status": "current", "effective_at": "2026-07-10T18:00:00Z", "expires_at": null }, "limitations": [], "conflicts": [] } ], "source_links": [ { "label": "Monthly plan guidance", "url": "https://example.com/pricing" } ], "source_count": 1, "contract_version": "2026-07-17.2", "memory_recall_trace_id": 1096, "answer_mode": "facts", "answer_intent": "answer_business_question", "generated_by_ai": true, "grounding": { "status": "grounded", "reason": null, "trace_id": 1096, "evidence_as_of": "2026-07-11T18:45:00Z", "corpus_revision": "corpus-2026-07-11-1", "index_revision": "index-2026-07-11-1", "authoritative_reference_count": 1, "supporting_reference_count": 0, "inferences": [], "uncertainties": [], "gaps": [], "idempotent_replay": false, "generated_at": "2026-07-11T19:22:31Z" }, "usage": { "model": "gpt-example", "input_tokens": 1200, "output_tokens": 90, "total_tokens": 1290 }}Save message_id. You need it if you send feedback.
If the reviewed answer cannot be completed safely, the endpoint still returns HTTP 200 for connector compatibility, but it does not create a suggested reply:
{ "ok": false, "outcome": "system_status", "answer": null, "assistant_message": null, "reply_id": 381, "request_status": "failed", "message_id": null, "feedback_token": null, "system_status": { "code": "ai_temporarily_unavailable", "retryable": true, "retry_after_ms": 3000, "trace_id": "771" }}Treat system_status as operational state. Do not display it as assistant speech and do not send feedback for it. Retry the same external message with the same idempotency fields after retry_after_ms.
Bombyx derives retryable and retry_after_ms from one outcome policy. The immediate response, persisted failed-request snapshot, and later request with the same idempotency identity therefore expose the same retry semantics.
Current status codes include ai_temporarily_unavailable, provider_unavailable, assistant_paused, organization_agent_activity_paused, assistant_run_canceled, assistant_safety_limit_reached, assistant_tool_limit_reached, assistant_plan_limit_reached, assistant_runtime_unavailable, assistant_runtime_failed, assistant_answer_incomplete, semantic_review_failed, semantic_review_unavailable, semantic_review_evidence_overflow, deterministic_fallback_rejected, selected_references_invalid, authoritative_evidence_insufficient, evidence_changed, external_tool_approval_unsupported, external_tool_output_unsafe, external_agent_run_binding_invalid, completed_reply_requires_regeneration, and completed_reply_no_longer_available. New status codes may be added, so clients should branch on outcome first and treat unknown codes as non-answer operational state.
When a connector requires authoritative grounding, a successful reply has grounding.status: grounded. If authoritative evidence is insufficient, Bombyx returns outcome: system_status with code authoritative_evidence_insufficient, answer: null, and no assistant message. This prevents a post-review abstention rewrite from becoming customer-visible prose.
Strict replies count only references with trace_verified=true and grounding_eligible=true. Bombyx derives both fields from organization-scoped recall, source, policy, and revision records. Supporting evidence may add detail, but at least one authoritative reference is always required for a grounded reply. Bombyx also runs a fail-closed semantic sufficiency check over the exact evidence items and records that decision in grounding.semantic_sufficiency. The reply abstains when evidence is merely related, does not answer the request as asked, or citation auditing is unavailable or reports unsupported claims.
An insufficient-evidence response makes the stop explicit:
{ "ok": false, "outcome": "system_status", "answer": null, "assistant_message": null, "system_status": { "code": "authoritative_evidence_insufficient", "retryable": false, "retry_after_ms": 0, "trace_id": null }, "request_status": "failed", "message_id": null, "feedback_token": null}Multi-Turn Threads
Section titled “Multi-Turn Threads”Use the same external_thread_id for each turn in the same external conversation.
{ "external_thread_id": "email-thread-123", "external_message_id": "email-message-789", "idempotency_key": "reply-email-message-789", "payload": { "text": "Do you offer annual billing?", "history": [ { "role": "assistant", "text": "Thanks for reaching out. Pricing depends on the setup you need." } ] }}Bombyx reuses the prior external conversation when it sees the same organization, connector, chatbot, and external_thread_id.
The subject, sender, recipient, channel, sent time, latest message, and at most ten recent history items are passed as structured untrusted continuity context. History roles normalize to customer, organization, assistant, agent, or other; arbitrary roles never become system instructions or organization evidence. Only the latest external message is persisted as the user-message body, so supplied history is not repeatedly concatenated into the ledger.
Safe Retries
Section titled “Safe Retries”Use a safe retry key, called idempotency_key, when you retry the same external message.
Also send external_message_id when your system has one.
What happens:
- If the first request completed and the request fingerprint matches, Bombyx revalidates current connector authorization, both receipt copies, exact AgentRun, message hashes, complete expected ToolRun evidence set, source eligibility, and safe links before returning the same reply with
200andgrounding.idempotent_replay: true. - A newly rotated active token for the same connector may perform that replay. The original token remains receipt provenance.
- All legacy v1 reviewed replies and replies with unknown receipt versions are not replayed under weaker rules. They return the typed
completed_reply_requires_regenerationstatus. - If a matching request is still pending, or failed after an assistant message was persisted, Bombyx returns
409. - If a matching request failed before an assistant message was persisted, only a stored retryable transient outcome may reclaim the request. Non-retryable policy, authorization, malformed request, and unsupported approval outcomes return their stored typed result or a stable conflict.
- Concurrent requests using the same retry identity produce one request record. The loser receives the completed replay or a
409while the winner is still in progress. - If a retry reuses a key or external message ID with changed request content, Bombyx returns
409instead of replaying unrelated evidence. - If neither key has been seen, Bombyx creates a new reply.
source_count is the number of returned source_links, not the number of internal references. Links are deduplicated, labels are bounded, and only externally visible HTTP or HTTPS URLs are returned. Local, private, internal-storage, credential-bearing, and unsupported-protocol URLs are withheld. Source access and eligibility are checked again on completed replay.
Disable Strict Grounding
Section titled “Disable Strict Grounding”Operators can safely preview or disable strict grounding for organization-owned connectors:
php artisan tool-connectors:set-grounding-policy ORGANIZATION_ID CONNECTOR_ID --policy=standard --dry-runphp artisan tool-connectors:set-grounding-policy ORGANIZATION_ID CONNECTOR_ID --policy=standardThis changes connector policy only. It preserves source revisions, recall traces, feedback, and audit history.
Send Feedback
Section titled “Send Feedback”Send feedback after a human accepts, rejects, or corrects the suggested response.
curl https://bombyxlabs.com/app/api/tool-connectors/v1/assistant/replies/1822/feedback \ -H "Authorization: Bearer btx_your_token_here" \ -H "Content-Type: application/json" \ -d '{ "outcome": "corrected", "rating": "down", "feedback_kind": "answer_correction", "feedback_issue": "not_factually_correct", "suggested_answer": "Tell the customer that annual billing is available after onboarding.", "note": "The original answer missed annual billing.", "external_feedback_id": "feedback-abc-123" }'Example response:
{ "ok": true, "outcome": "corrected", "rating": "down", "feedback_id": 222, "response_review_id": 88, "proposal_id": 553, "idempotent_replay": false}Use accepted, corrected, or rejected for outcome. For older clients, Bombyx maps rating: up to accepted, a down rating with a useful suggested_answer to corrected, and a down rating without one to rejected. rating: none clears the outcome. When you send both fields, they must agree.
corrected requires suggested_answer. It creates a pending memory proposal and review item, but it does not become authoritative memory automatically. It still follows Bombyx’s normal safety and approval flow.
Use external_feedback_id or idempotency_key for safe feedback retries. The retry identity is scoped to the organization, connector, and assistant message.
Common Mistakes
Section titled “Common Mistakes”- Treating the response as already sent. It is only a suggested response.
- Changing
external_thread_idon each email in the same thread. - Retrying without
idempotency_keyorexternal_message_id. - Using an abstained response as an organization-backed answer.
- Assuming a reference is authoritative without checking
authority.roleand freshness. - Sending feedback for a message that was not created by this external assistant endpoint.