Guides

Chat with Panlytics

Ask Panlytics a question through the API, follow the answer as it is written, and leave anything it proposes for a person to approve.

What chat is

Chat is the same assistant people use in the app. It reads the shop's figures, its products and what Panlytics has learned about the shop, and answers in plain words: why a product is on the order list, what sold less than usual last week, which supplier is slowest.

Through the API, a question starts a run. The run works in the background, and you either poll it until it has its answer or follow it as it is written.

You need a key whose maker's role holds Ask the agents, at the shop you ask about. A key may ask; approving what the assistant proposes stays with a person in the app.

Ask a question

curl -X POST https://panlytics.net/api/v1/chat \
  -H "Authorization: Bearer $PANLYTICS_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{ "shopId": 12, "prompt": "Which soft drinks should I order this week, and why?" }'
  • shopId and prompt are required. prompt is at most 4,000 characters.
  • Add categoryId to ask about one category's newest report. Without it the run opens on the shop's newest report of any category.
  • Add the threadId of an earlier answer to continue that conversation.

The answer is 201 with runId, threadId and status: "queued". Then:

  • GET /v1/runs/{id} answers with the run as it stands. Poll it every few seconds until status is done, failed or cancelled; answer holds the assistant's answer.
  • GET /v1/runs/{id}/stream sends the answer as it is written, as server-sent events (a response that stays open and sends one line per piece). If the connection drops, reconnect with ?from= set to the last offset you saw. A key may hold three streams open at once; a fourth answers 429 net.rate_limited with Retry-After: 15 until one closes.
Poll until it ends
import time

while True:
    run = requests.get(
        f"https://panlytics.net/api/v1/runs/{started['runId']}",
        headers={"Authorization": f"Bearer {os.environ['PANLYTICS_KEY']}"},
        timeout=30,
    ).json()
    if run["status"] in ("done", "failed", "cancelled", "awaiting_approval"):
        break
    time.sleep(3)
print(run["status"], run["answer"])

Proposals wait for a person

When the assistant wants to change something, such as keeping a product at a new level, it does not do it. It writes a proposal, the run's status becomes awaiting_approval, and the proposal is listed in the run's waitingForPerson. It waits in the app for a person to approve or reject it.

What it costs

Every run spends the shop's daily AI budget, the same budget the app's chat uses: 2 euros a day per shop unless the CEO or a Manager changes it in the organisation's AI settings. The day turns at midnight UTC.

LimitWhat happens past it
30 runs an hour per person429 net.rate_limited with limit: 30; wait a few minutes, then ask again
The shop's daily AI budget429 api.ai_budget, with Retry-After set to the seconds until midnight UTC

Both are checked before the run starts, so a refused question costs nothing.

When the key ends

A run outlives the call that started it. When its key stops being live (revoked, past its end, developer mode switched off, its maker removed, or its maker's role no longer holding the key ability), the run is stopped at its next step with the code api.key_ended, and an open stream closes on its next ping, within 15 seconds. Make a new key and ask again.