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?" }'import os
import uuid
import requests
answer = requests.post(
"https://panlytics.net/api/v1/chat",
headers={
"Authorization": f"Bearer {os.environ['PANLYTICS_KEY']}",
"Idempotency-Key": str(uuid.uuid4()),
},
json={"shopId": 12, "prompt": "Which soft drinks should I order this week, and why?"},
timeout=30,
)
answer.raise_for_status()
started = answer.json()
print(started["runId"])shopIdandpromptare required.promptis at most 4,000 characters.- Add
categoryIdto ask about one category's newest report. Without it the run opens on the shop's newest report of any category. - Add the
threadIdof 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 untilstatusisdone,failedorcancelled;answerholds the assistant's answer.GET /v1/runs/{id}/streamsends 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 answers429 net.rate_limitedwithRetry-After: 15until one closes.
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.
| Limit | What happens past it |
|---|---|
| 30 runs an hour per person | 429 net.rate_limited with limit: 30; wait a few minutes, then ask again |
| The shop's daily AI budget | 429 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.