Skip to content

Send messages into a session

The inbound webhook posts external text into an existing Localix chat session. Use it to deliver a CI result, monitoring event, script output, or external worker report without typing in the composer.

Trust boundary: The endpoint has no authentication, signature, replay protection, or shared secret. The default server bind is loopback; changing HOST can expose the same endpoint more widely.

What you can do

NeedMechanismBoundary
Start a session turnPOST /rpc/webhook/messages with a session id and prompt.The target must be a mutable chat session owned by the resolved user.
Label the callerAdd the optional source string to the request.The caller controls this label; it is provenance, not verified identity.
Deliver while a run is activeThe chat service queues the webhook as an external wake.The success response has an empty messageId until the queued turn runs.
Distinguish external inputThe service persists a hidden user row with wake source external.The UI shows the provenance on the assistant reply, not as a user bubble.
Give the model explicit contextThe route prefixes the prompt with an external-message provenance line.The supplied prompt and source remain model-visible instructions.
Discover the current addressRuntime context includes the resolved webhook URL and current session id.The address is for this running backend instance.

How it works

The route validates the JSON body, wraps the text with one provenance line, and calls the same chat service entry used by the frontend, including its ownership checks, reference expansion and busy-session queue. The provenance line precedes the supplied text, so a prompt such as /usage is model-visible text, not a direct slash-command invocation. Webhook input can still instruct an agent to act; it is not a separate command-dispatch API.

An idle target starts a turn immediately. A busy target enqueues the text with source external; the default queue places it in the machine-wake band alongside loop wakes, behind queued user turns. Both paths keep the triggering user row out of the visible transcript and associate the next visible assistant reply with External provenance.

The backend derives the URL from HOST, PORT, and the canonical webhook path. Wildcard bind addresses are converted to 127.0.0.1 in the address handed to same-machine callers.

OutcomeHTTP statusResponse behavior
Accepted on an idle target200queued is false; messageId identifies the started turn
Accepted on a busy target200queued is true; messageId is an empty string
Invalid JSON fields400The validator rejects the request before chat delivery
Host/origin policy rejection403The API boundary refuses the request before delivery
Chat service rejection409error.code is webhook_send_failed with the service message

Configuration

Request

FieldRequiredConstraintMeaning
sessionIdYesNon-empty stringExisting chat session to receive the turn
promptYes1–65,536 UTF-16 code unitsModel-visible external message
sourceNoAt most 120 UTF-16 code unitsUnverified caller label shown as provenance
x-user-idNoTrimmed when presentSelf-asserted user scope; omission or blank uses the configured default user
Shell
curl --request POST http://127.0.0.1:5051/rpc/webhook/messages \
  --header 'content-type: application/json' \
  --data '{"sessionId":"SESSION_ID","prompt":"Deployment finished. Verify the health check.","source":"ci"}'

Response

JSON
{
  "ok": true,
  "sessionId": "SESSION_ID",
  "messageId": "MESSAGE_ID",
  "queued": false
}
Environment variableDefaultEffect
HOST127.0.0.1Server bind host and input to runtime address resolution
PORT5051Server listen port and runtime webhook URL
LOCALIX_DEFAULT_USER_IDlocal-userUser scope used when x-user-id is absent or blank

Limits

  • The endpoint trusts network reachability and the self-asserted x-user-id header. Allowed Host names include loopback names and the configured concrete bind host. Allowed page origins include the packaged app, explicitly configured LOCALIX_UI_ORIGINS, and the API's same-origin page when it serves the UI. Other page origins are refused before delivery. These checks do not authenticate scripts or local processes.
  • Send the body as application/json. A request with no Origin and a form or plain-text body is refused at the API boundary unless it carries a non-empty x-localix-client header. The webhook still requires valid JSON fields after that boundary check; the header does not make a plain-text body a valid request.
  • Binding the API to a non-loopback interface exposes the webhook with the rest of the API. Wildcard bind addresses do not authorize arbitrary Host names. A proxy must forward an accepted Host. Put an authenticating trusted proxy in front before accepting requests from another machine.
  • There is no webhook-specific idempotency key, signature timestamp, replay cache, delivery receipt, or callback when the resulting agent turn completes.
  • source is inserted into model-visible provenance after trimming. Do not treat it as proof of the sending process, and do not pass an untrusted value when a fixed caller label is available.
  • The 65,536 limit counts UTF-16 code units, not encoded request bytes. Attach or summarize large logs and diffs instead of sending them as one prompt.
  • A successful queued response confirms admission to the session queue, not completion of the turn.
  • This page covers inbound session messages. Outbound lifecycle notifications are a separate mini app surface.

Source of truth