Chat

Send a message to Marco, the in-product assistant.

POST /api/chat

POST /api/chat is the streaming endpoint used by Marco inside the Macro by Mark app. It is session-aware, plan-aware, and source-aware.

Treat this as the product chat endpoint, not a stable external assistant API. It depends on signed-in session cookies, entitlement resolution, chat budget state, and the current product route.

Authentication and entitlement

The server resolves the caller's plan from the active session. The request body cannot set or upgrade the plan.

Signed-out callers are treated as visitor traffic. Signed-in callers use their server-resolved plan and user id for rate limiting and monthly budget checks.

Request body

messagesarraybodyrequired

UI messages from the chat client. The route keeps only the configured history window for the user's plan and caps text content before it reaches the model.

pathnamestringbody

Current app path, such as /indicators/headline-cpi or /dashboard. Marco uses this for page help, guided tours, locale detection, and navigation context.

clientContextobjectbody

Optional page sidecar context from the client, such as visible chart title, series labels, units, date range, or dashboard route. This context helps Marco explain what is on screen. It is not proof of a latest value.

firstNamestringbody

Optional first name for the greeting. The server strips control characters, non-name characters, and long payloads before the value is used.

{
  "messages": [
    {
      "id": "msg_1",
      "role": "user",
      "parts": [
        {
          "type": "text",
          "text": "What does core PCE measure?"
        }
      ]
    }
  ],
  "pathname": "/indicators/core-pce"
}

Response stream

The endpoint returns an AI SDK UI message stream. Assistant messages can include Marco metadata under metadata.marco.

modestring

The request classification, such as LEARNING_MODE, INDICATOR_MODE, DATA_VALUE_MODE, NEWS_CALENDAR_MODE, FORECASTING_WORKFLOW_MODE, or DASHBOARD_WATCHLIST_MODE.

trustSignalstring

grounded, conceptual, or limited.

sourceRequirementstring

The source class required for the question, such as OBSERVATION_DATA_REQUIRED, NEWS_OR_CALENDAR_REQUIRED, or USER_PRIVATE_CONTEXT_REQUIRED.

sourcesarray

Structured source cards when the server has source context for the answer. Cards can represent product facts, indicator metadata, observations, forecast runs, news items, release events, dashboards, watchlists, saved workspace objects, model references, or page context.

unavailableSourcesarray

Missing source notes with a reason such as not_wired, no_match, permission_denied, stale_source, or ambiguous.

monthlyBudgetobject

Current monthly chat budget state for the caller's plan, including whether more messages are available in the current period.

Source rules

Marco should not state current values, historical values, release dates, news items, forecast results, dashboards, watchlists, or saved workspace facts unless the server supplied a source card for that claim.

For example, a latest CPI answer needs an indicator_observation card. An indicator metadata card can explain what CPI is, but it cannot prove the latest CPI value.

Budget and rate-limit headers

The route keeps per-minute rate limits and monthly chat budgets. Budget headers are included when available.

x-marco-budget-state: ok
x-marco-budget-used-percent: 34
x-marco-budget-reset: 2026-06-01T00:00:00.000Z

Error responses

StatusErrorMeaning
400invalid_jsonRequest body was not valid JSON.
400missing_messagesRequest body did not include messages.
400empty_messagesNo usable user or assistant text remained after normalization.
402monthly_budget_exceededThe caller's monthly Marco budget is exhausted.
429rate_limitedThe caller exceeded the per-minute chat limit.
500chat_failedThe route failed after validation.

Privacy notes

The route does not accept user ids, plan names, backend tokens, or API keys from the browser payload. Private saved-object context is loaded only for signed-in users, only when the request needs that private context, and only through server-side authorization.

Marco may receive limited preference context such as locale, timezone, country, experience level, and focus areas. That context is used for language, formatting, explanation depth, and examples. It is not a source for data claims.