Paleiskite AI palaikymo agentą per 5 minutes
REST API ir webhook'ai, skirti sprendžiant užklausas, fiksuojant potencialius klientus ir perduodant pokalbį žmonėms — paremti jūsų pačių žinių baze, jums nekuriant orkestracijos.
- Pagrindinis URL
- api.conviro.io/v1
- Autentifikacija
- Bearer token
- Atsakymas
- JSON · p50 ~450ms
$ curl -s api.conviro.io/v1/api/sessions/sess_3f2a/messages \
-H "Authorization: Bearer cvr_live_***" \
-d '{"content":"How do I return an order?"}'
# 201 Created — the AI reply follows via the message.new webhook
{
"messageId": "6d1f0c6e-3b7a-...",
"role": "system",
"content": "Message received. Preparing a response...",
"status": "queued"
}Greitas startas
Jūsų pirmoji sėkminga užklausa
Trys žingsniai. Kopijuojami ir įklijuojami. Tikrą AI atsakymą pamatysite per šešiasdešimt sekundžių — arba visai praleiskite registraciją ir išbandykite jį iš savo terminalo dabar pat.
Išbandykite be API rakto — dabar pat
5 užklausos per minutę vienam IPcurl -X POST https://conviro.io/api/developers/demo \
-H "Content-Type: application/json" \
-d '{"content": "I want to return my last order"}'- 1
Sukurkite API raktą
Eikite į Nustatymai → API raktai ir sukurkite raktą su
Gauti API raktąchat:writeapimtimi. Jis parodomas vieną kartą — saugokite jį savo slaptažodžių tvarkyklėje. - 2
Išsiųskite žinutę
POST į /sessions/:id/messages su Bearer token. Naudokite esamą sesijos id arba pirma sukurkite jį su POST /sessions.
- 3
Apdorokite atsakymą
Gaunate atgal
messageIdir būseną „queued“. DI atsakymas sukuriamas asinchroniškai — prenumeruokite webhook message.new arba nuskaitykite sesiją per GET /sessions/:id.
curl -X POST https://api.conviro.io/v1/api/sessions/SESSION_ID/messages \
-H "Authorization: Bearer cvr_live_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"content": "Can I return an item I bought yesterday?"}'Atsakymas
{
"messageId": "6d1f0c6e-3b7a-4f0e-9a52-8c1e2d4b7a90",
"role": "system",
"content": "Message received. Preparing a response...",
"createdAt": "2026-04-14T10:22:03.412Z",
"status": "queued"
}Playground
Try it right now — no signup
Real HTTP requests to a rate-limited demo endpoint that returns scripted replies — no AI model is called, and the delay is artificial. The authenticated API answers asynchronously (see the quick start below).
Demonstracinis agentas
POST /api/developers/demo
Simuliuota demonstracija — iš anksto parengti atsakymai ir dirbtinė delsa; DI modelis nekviečiamas. Tikroji API atsako asinchroniškai.
Sveiki 👋 Aš esu tiesioginė demonstracinė versija. Išbandykite nustatymą, spustelėkite naudojimo atvejį aukščiau arba įveskite savo.
Ką grąžino API
{
"intent": "greeting",
"confidence": 1,
"model": "scripted-demo",
"message": {
"role": "assistant",
"content": "Sveiki 👋 Aš esu tiesioginė demonstracinė versija. Išbandykite nustatymą, spustelėkite naudojimo atvejį aukščiau arba įveskite savo."
}
}Demonstracinio galinio taško užklausų dažnis ribojamas iki 5 req/min per IP. Tikras API raktas pagal numatytuosius nustatymus gauna 60 užklausų per minutę (konfigūruojama).
Naudojimo atvejai
Ką komandos iš tikrųjų kuria
Spustelėkite bet kurią kortelę, kad paleistumėte ją tiesiogiai bandymų aikštelėje — tikrą API atsakymą pamatysite per sekundę.
Dokumentacija
API paviršius
Galiniai taškai, kuriuos naudosite dažniausiai. Pagrindinis URL: https://api.conviro.io/v1/api
| Metodas | Kelias | Reikalinga apimtis | Aprašymas |
|---|---|---|---|
| POST | /sessions | chat:write | Create a new chat session |
| GET | /sessions | chat:read | List sessions for incremental reconciliation (keyset cursor, metadata only — no transcripts) |
| GET | /sessions/:id/messages | chat:read | Paginated message history for a session (oldest first, keyset cursor) |
| GET | /sessions/:id | chat:read | Get session with last 50 messages |
| POST | /sessions/:id/messages | chat:write | Send a message and get AI response |
| POST | /sessions/:id/identify | chat:write | Identify the visitor in a session from your backend — no frontend change needed |
| POST | /knowledge | kb:write | Add a knowledge base item |
| DELETE | /knowledge/:id | kb:write | Delete a knowledge base item |
| GET | /analytics/summary | analytics:read | Get analytics summary |
| GET | /contacts | contacts:read | List contacts with pagination and filters |
| GET | /contacts/:id | contacts:read | Get single contact with stats |
| POST | /contacts | contacts:write | Create or find contact by email |
| PATCH | /contacts/:id | contacts:write | Update contact fields |
| GET | /lead-forms | chat:read | List active lead forms |
| GET | /appointments/slots | appointments:read | Open booking slots for a chatbot (optionally one local date / service) |
| POST | /appointments | appointments:write | Book an appointment directly (trusted backend — no OTP) |
| GET | /appointments | appointments:read | List appointments (newest first) |
| DELETE | /appointments/:id | appointments:write | Cancel an appointment (also removes the calendar event) |
| GET | /webhooks | webhooks:write | List webhook subscriptions |
| POST | /webhooks | webhooks:write | Subscribe to an event (creates a webhook subscription) |
| DELETE | /webhooks/:id | webhooks:write | Unsubscribe (deletes a webhook subscription) |
| POST | /consent/whatsapp | consent:write | Record a WhatsApp marketing opt-in collected on your checkout or form, with the text shown |
chat:readRead sessions and their messages, and list lead forms.chat:writeCreate sessions, send messages, identify visitors.kb:readRead knowledge base items. Minted, but required by no public operation today.kb:writeCreate and delete knowledge base items, and drive the e-commerce sync endpoints.analytics:readRead the workspace analytics summary.webhooks:writeManage webhook subscriptions. Note this is required to LIST them as well as to change them — there is no webhooks:read scope, so a read-only integration still needs the write scope here.contacts:readRead CRM contacts. Returns PII.contacts:writeCreate and update CRM contacts — the records human agents work from.leads:writeCreate a lead: drop a new inbound record at the top of the funnel. Deliberately narrower than contacts:write, so an automation posting form fills does not also get the power to rewrite existing people. Minted, but required by no public operation today.appointments:readRead open slots and booked appointments.appointments:writeBook and cancel appointments.consent:writeRecord a WhatsApp marketing opt-in. Its own scope rather than riding on leads or contacts: a key that can post form fills should not also be able to assert that a person agreed to campaigns.SDK
Bibliotekos ir klientai
Oficialius SDK pristatome etapais. REST API yra nedidelė, stabili ir lengvai apvelkama — laukti nereikia.
Node.js / TypeScript
Oficialus · netrukus// @conviro/sdk — in private beta. The REST API
// already works great with fetch/axios today.PHP
Oficialus · netrukus// composer require conviro/sdk — in private beta.
// Use the cURL example below in the meantime.Python
Bendruomenė# No official SDK yet — the REST API is small enough
# that plain `requests` or `httpx` works well.Go, Ruby, C#
Naudokite REST API tiesiogiai// No SDK — any HTTP client works. The auth header
// is the only thing you need.Klaidos
Nuspėjamos klaidų formos
Kiekvienas ne 2xx atsakymas naudoja tą patį JSON vokelį. Įtraukite requestId kai kreipiatės į palaikymą.
| Būsena | Pavadinimas | Kada tai įvyksta |
|---|---|---|
| 400 | Bad Request | The request was rejected by the handler. `message` is a single string. |
| 400 | Bad Request (validation) | Body validation failed. Same status and same keys as bad_request, but `message` is an ARRAY of strings, one per failed constraint. Parse it as `string | string[]` or the most common 400 in the API will crash your error handler. Unknown fields also land here: the global pipe runs with forbidNonWhitelisted, so an undeclared field is a 400 rather than being ignored — except on the two contacts endpoints that bind no DTO class, where unknown fields pass through silently. |
| 401 | Unauthorized | Missing or malformed Authorization header, or an invalid, revoked or expired key. Never retry: the credential will not become valid. |
| 403 | Forbidden | The key is valid but lacks the scope, or is restricted to assistants that do not include the one referenced. Scopes are evaluated with OR: holding ANY of the listed scopes is enough. Fix the key, do not retry. |
| 404 | Not Found | No such resource in your workspace. A resource that exists in another tenant is a 404 here, not a 403 — the tenant filter is applied before the lookup, so cross-tenant ids are indistinguishable from absent ones. That is deliberate. |
| 429 | Too Many Requests | Per-key rate limit exceeded. THIS BODY IS DIFFERENT: it carries `retryAfter` and NO `timestamp`, because the guard writes it directly to the response and never reaches the global filter. A `Retry-After: 60` header is set. The separate plan-level limiter produces a 429 with a different message and no `retryAfter`. Retry after the header says, with backoff. |
| 500 | Server Error | Something failed on our side. The message is always this fixed string — internal detail is logged, never returned. Retry with exponential backoff. |
Atsakymo turinys
{
"statusCode": 401,
"error": "Unauthorized",
"message": "API key is missing or invalid.",
"requestId": "req_1H8z...",
"docsUrl": "https://conviro.io/developers#errors"
}Esant 429, atsižvelkite į Retry-After antraštę. Esant 5xx, kartokite su eksponentiniu atidėjimu iki trijų bandymų.
Webhook'ai
Realaus laiko įvykiai, patikrinti
Kiekvieną pristatymą pasirašome HMAC-SHA256. Nepavykę pristatymai kartojami tris kartus su eksponentiniu atidėjimu. Grandinės pertraukiklis 60 sek. izoliuoja nuolat sutrikstančius taškus.
Įvykiai
message.newA message was added to a session, by the visitor or by the assistant.session.startedA new conversation session was created.session.closedA session was closed.session.escalatedA session was escalated to a human.handoff.requestedA visitor asked for a human agent.lead.capturedA lead was captured from a conversation.lead.createdA lead record was created outside a chat — from an ad integration, a lead form, or an e-commerce order.lead_form.submittedA lead form was submitted.csat.submittedA CSAT rating was submitted.csat.receivedThe same rating as csat.ai.failedThe assistant could not produce an answer.ticket.createdA support ticket was opened.ticket.resolvedA support ticket was resolved.contact.createdA CRM contact was created.contact.updatedA CRM contact was updated.contact.mergedTwo CRM contacts were merged.contact.deletedA CRM contact was deleted.appointment.bookedAn appointment was booked. Not listed in the dashboard event picker — subscribe with "*" or by name.appointment.cancelledAn appointment was cancelled. Not listed in the dashboard event picker — subscribe with "*" or by name.lead.hotA lead crossed the hot-lead threshold. Not listed in the dashboard event picker — subscribe with "*" or by name.lead.updatedA lead record was corrected after capture. Not listed in the dashboard event picker — subscribe with "*" or by name.
Naudingoji apkrova
{
"event": "session.closed",
"timestamp": "2026-04-14T10:22:03.412Z",
"data": {
"sessionId": "sess_3f2a...",
"chatbotId": "bot_123"
}
}Patikrinkite parašą
// Node.js (Express) — verify a Conviro webhook
import crypto from 'crypto';
// The RAW body is required. express.json() parses and discards it, and
// JSON.stringify(req.body) does NOT reproduce the signed bytes — key
// order and whitespace both change the digest.
app.post('/conviro/webhook',
express.raw({ type: 'application/json', limit: '1mb' }),
(req, res) => {
if (!verify(req.body, req.header('X-Webhook-Signature'))) {
return res.status(401).end();
}
res.status(200).end(); // acknowledge within 10s
void handle(JSON.parse(req.body.toString('utf8')));
});
const TOLERANCE_SECONDS = 300;
function verify(rawBody, header) {
if (!header) return false;
// Header format: t=<unix_seconds>,v1=<hex_digest>
const parts = new Map(header.split(',').map((p) => {
const i = p.indexOf('=');
return [p.slice(0, i).trim(), p.slice(i + 1).trim()];
}));
const timestamp = parts.get('t');
const signature = parts.get('v1');
if (!timestamp || !signature) return false;
// Replay window: without it, a captured payload is valid forever.
const age = Math.abs(Math.floor(Date.now() / 1000) - Number(timestamp));
if (!Number.isFinite(age) || age > TOLERANCE_SECONDS) return false;
// The digest covers "<timestamp>.<rawBody>" — NOT the body on its own.
const expected = crypto
.createHmac('sha256', process.env.CONVIRO_WEBHOOK_SECRET)
.update(timestamp + '.')
.update(rawBody)
.digest('hex');
const a = Buffer.from(signature, 'utf8');
const b = Buffer.from(expected, 'utf8');
// timingSafeEqual throws on a length mismatch, so check length first.
return a.length === b.length && crypto.timingSafeEqual(a, b);
}Kaip tai veikia
Vienas API iškvietimas, visas konvejeris
Jūs paskelbiate žinutę — mes pasirūpiname klasifikavimu, paieška, generavimu ir nukreipimu. Gaunate vieną atsakymą su viskuo, ko reikia nuspręsti, kas vyks toliau.
Lankytojas
Siunčia žinutę
Klasifikuoti
Ketinimas + patikimumas
Žinios
Gauti iš jūsų žinių bazės
Generuoti
Atsakymas + siūlomi veiksmai
Eskaluoti (galbūt)
Žemas patikimumas → žmogus
- Tipinė delsa
- ~450ms p50
- Užklausų dažnio riba
- 60 užklausų per minutę vienam raktui · konfigūruojama
- Saugu kartoti
- Idempotentiniai pakartojimai · webhook atidėjimas
Pasiruošę, kai tik jūs
Jūsų pirmasis API iškvietimas už 60 sekundžių
Sukurkite API raktą, nukopijuokite greito starto kodo fragmentą, pamatykite tikrą atsakymą. Nemokamas planas apima pakankamai iškvietimų kurti ir testuoti.