Byg på Conecto

Et enkelt REST API til alt, hvad platformen gør: byg bots, der ikke blot svarer, men også kan handle , i jeres database, fakturering og produkt, send billeder, GIF'er, video og kort til chatten og bygge jeres egne integrationer som AI-agenten kalder under samtalen, uanset den underliggende software. Hvis widgetten kan gøre det, kan API'et styre det.

I produktion · Signerede webhooks · 300 anmodninger/min

Det grundlæggende

Sidder I fast? Spørg en AI om dette afsnit:ClaudeChatGPTGrok

Base URL https://conecto.chat/api/v1. Create a credential in Indstillinger → Udviklere , I får et klient-id og et hemmelighed (shown once, stored hashed). Authenticate with HTTP Basic — client ID as username, secret as password — or Authorization: Bearer <client_id>:<secret>. A credential can cover the whole workspace or be scoped to a single widget.

curl https://conecto.chat/api/v1/me/ -u "ck_your_client_id:cs_your_secret"

Bruger I Python? Den officielt SDK (pip install conecto) wraps all of this, and does the parts that are easy to get subtly wrong for you: webhook signature verification, delivery deduplication, idempotent writes, retries, and block validation that fires before a request leaves your process. Everything below still applies — it is the same API underneath.

Hastighedsgrænse 300 anmodninger/min per credential (429 + Retry-After beyond it). Errors are always {"error": {"code", "message"}}. List endpoints paginate with limit og before_id, returning next_before_id. Write endpoints accept an Idempotency-Key header (any UUID): retry the same key and you get the message that was already created, with a 200 instead of a 201, rather than a second copy in front of the visitor.

Ét endepunkt beskriver alle de andre

GET /schema/ returnerer hele overfladen som JSON: hvert endepunkt, hver hændelse, hver bloktype, hver reserveret handling, hver fejlkode og hver numerisk grænse. Den samme kode, der håndhæver grænserne, leverer svaret, så det kan ikke afvige fra den kørende server som en dokumentationsside. Generer klienten derfra, eller kontrollér ved opstart, at den nødvendige funktion er udrullet.

curl https://conecto.chat/api/v1/schema/ -u "ck_...:cs_..." | jq '.limits, .events[].name'

Every response carries X-Conecto-Api-Version. Pin it in your client and log a warning when it changes — that header is how you find out a field moved before your users do.

Rigt indhold: billeder, GIF'er, video og kort

Sidder I fast? Spørg en AI om dette afsnit:ClaudeChatGPTGrok

Any message you send can carry blocks — an ordered list of typed content rendered under the bubble in the widget, and in the agent's inbox exactly as the visitor saw it. Up to 10 per message, and every field is validated and re-projected server-side, so you never hand us markup and we never hand the browser a string.

curl -X POST https://conecto.chat/api/v1/conversations/42/messages/ \
  -u "ck_...:cs_..." -H "Content-Type: application/json" \
  -d '{
    "body": "Here is how to reset it — takes about 20 seconds:",
    "blocks": [
      {"type": "image", "url": "https://cdn.you.com/reset.gif", "alt": "Reset flow"},
      {"type": "buttons", "items": [
        {"label": "That worked"},
        {"label": "Full guide", "url": "https://docs.you.com/reset"}
      ]}
    ]
  }'

Bloktyperne

imageurl, alt, caption, link — animated GIFs are just images
videourl to an .mp4/.webm/.mov, plus poster, autoplay, loop, muted
embedprovider youtube · vimeo · loom · wistia · spotify og det normale delingslink url
audiourl til en .mp3/.wav/.m4a-fil, valgfrit title
fileurl, filename, size — rendered as a download row
cardsitems[] of title · subtitle · text · image · url · price · badge · buttons; layout carousel or list
listrows[] med etiket · værdi · undertitel · billede · URL, til ordreoversigter og leveringstrin
buttonsitems[]: {label, value} replies as the visitor, {label, url} opens a link
text · dividerekstra afsnit og en vandret linje

URLs must be https. A block that can't be built is a 400 naming the block and the reason, never a silent drop — an image that vanishes without explanation costs an afternoon to track down.

Send en GIF uden egen lagerplacering

POST /media/ takes a multipart file (≤10 MB) and hands back a URL you can drop straight into a block. Use the returned url — it is a path, resolved against the widget's own origin, so the same message works in development and in production.

URL=$(curl -s -X POST https://conecto.chat/api/v1/media/ -u "ck_...:cs_..." \
       -F "file=@celebrate.gif" | jq -r .media.url)

curl -X POST https://conecto.chat/api/v1/conversations/42/messages/ \
  -u "ck_...:cs_..." -H "Content-Type: application/json" \
  -d "{\"body\": \"All set!\", \"blocks\": [{\"type\": \"image\", \"url\": \"$URL\"}]}"

Shipping a GIF as a muted, looping video block is usually the better trade: a tenth of the bytes, and the visitor cannot tell the difference.

En kortkarrusel

{"blocks": [{
  "type": "cards",
  "items": [
    {"title": "Trail Runner 2", "subtitle": "Road · Neutral",
     "price": "89.00 USD", "badge": "Back in stock",
     "image": "https://cdn.you.com/tr2.jpg",
     "url": "https://shop.you.com/p/tr2",
     "buttons": [{"label": "Add to cart", "url": "https://shop.you.com/cart/add/tr2"}]}
  ]
}]}

Byg jeres egen integration

Sidder I fast? Spørg en AI om dette afsnit:ClaudeChatGPTGrok

Shopify, Stripe og BigCommerce er integrationer, som vi har skrevet. Dette er den, som I skrive. Beskriv tjenesten med en basis-URL og en liste over handlinger, installer den på en widget, så kalder AI-agenten den under samtalen. Efterfølgende systemer kan ikke skelne den fra en indbygget integration. Det er hele pointen: Hvis butikken, faktureringen eller CRM-systemet kører på en løsning, vi ikke kender, behøver I ikke længere vente på vores understøttelse.

1 · Registrer den

curl -X POST https://conecto.chat/api/v1/integrations/ \
  -u "ck_...:cs_..." -H "Content-Type: application/json" \
  -d '{
    "slug": "acme-store",
    "name": "Acme Store",
    "base_url": "https://api.acme.example/conecto",
    "auth_type": "bearer",
    "credential": "sk_live_...",
    "actions": [
      {"name": "catalog.search_products", "path": "/search",
       "description": "Search the Acme catalog by keyword.",
       "parameters": [{"name": "query", "type": "string", "required": true},
                      {"name": "limit",  "type": "integer"}]},
      {"name": "orders.get_status", "path": "/orders/status", "risk": "verified_read",
       "description": "Look up one of the visitor's orders by number.",
       "parameters": [{"name": "order_number", "type": "string", "required": true}]},
      {"name": "warranty.register", "path": "/warranty", "risk": "write",
       "description": "Register a warranty for a product the visitor owns.",
       "parameters": [{"name": "serial", "type": "string", "required": true}]}
    ]
  }'

The response includes a signing_secret. You need it to verify our calls — it is readable on every later GET too, and {"rotate_signing_secret": true} rolls it.

2 · Installer den på en widget

curl -X POST https://conecto.chat/api/v1/integrations/acme-store/install/ \
  -u "ck_...:cs_..." -H "Content-Type: application/json" \
  -d '{"widget_ids": [7], "actions": ["catalog.search_products", "orders.get_status"]}'

actions is an allowlist — omit it to enable everything you declared, or pass [] to keep the integration installed but idle. Nothing is exposed until you install it, and installing is per widget.

3 · Besvar kaldet

We POST a signed JSON envelope to base_url + path. Verify the signature the same way you verify a webhook — one routine covers both directions:

// POST https://api.acme.example/conecto/search
{
  "action": "catalog.search_products",
  "integration": "acme-store",
  "arguments": { "query": "trail shoes", "limit": 3 },
  "source": "ai_agent",
  "idempotency_key": "8f14e45fceea167a...",
  "workspace": { "id": 12 },
  "widget": { "id": 7, "key": "w_..." },
  "conversation": { "id": 4821 },
  "visitor": { "session": "…", "email": "maya@acme.io",
               "verified": true, "verified_email": "maya@acme.io", "name": "Maya" }
}

// Headers: X-Conecto-Signature: sha256=<HMAC-SHA256(signing_secret, raw body)>
//          X-Conecto-Timestamp, X-Conecto-Action, X-Conecto-Integration,
//          X-Conecto-Idempotency-Key

Svar med én af fem former:

{"ok": true, "result": {...}}                  // success — the agent reads it
{"ok": true, "result": {...}, "blocks": [...]}  // …and attach rich content to the reply
{"ok": true, "not_found": true}                 // nothing matched (a normal outcome)
{"verify_required": true}                       // "I need a verified visitor for this"
{"ok": false, "error": "Already cancelled."}    // a failure the agent may relay

Et almindeligt JSON-objekt uden nogen af disse nøgler behandles som selve resultatet. I kan derfor pege en handling mod et endepunkt, der allerede findes. Grænser: 8 sek. timeout, 128 kB -svar. Alt, I returnerer, når modellen som data i et JSON-envelope, aldrig som instrukser. Nøgler, der ligner hemmeligheder, fjernes på vej ind.

4 · Test før en besøgende gør det

curl -X POST https://conecto.chat/api/v1/integrations/acme-store/actions/catalog.search_products/run/ \
  -u "ck_...:cs_..." -H "Content-Type: application/json" \
  -d '{"arguments": {"query": "trail shoes"}}'

This runs the real call path — signature, credential, timeout, parsing — and shows you the envelope the agent will get. Pass conversation_id to run it in the context of a live chat, which is the only way a verified action can succeed.

Risikoniveauer og den ene regel, der ikke kan slås fra

public_readkatalog, tilgængelighed, dokumentation, ingen identitet påkrævet
verified_readén persons data. Afvises, indtil den besøgendes e-mailadresse er verificeret
public_writeen ændring, der ikke kræver identitet, eksempelvis tilmelding til nyhedsbrev eller indsamling af leads
writeen ændring på én persons konto. Verificeret og aldrig forsøgt igen uden varsel

For de sidste to leveres den verificerede adresse af os, in visitor.verified_email — never taken from the model's arguments. Verification comes from an emailed code, or from your own site attestering af en indlogget bruger. Ingen widgetindstilling kan fritage en handling fra reglen, fordi «hvem tilhører denne ordre?» ikke er et spørgsmål, som en kontakt skal besvare.

Reserverede handlinger: jeres butik, forbundet som en indbygget integration

A few action names mean something to the platform itself. Declare catalog.search_products returning {"products": [{title, url, image, price_from, currency, available}]} and its results become product cards under the AI's replies and fill the widget's Home showcase — the same treatment a Shopify connection gets, from whatever your catalog actually runs on. orders.get_status, orders.get_tracking, orders.list_recent og account.lookup are reserved the same way, and are always verified reads. GET /integrations/{slug}/actions/ returns the full catalog with the shape each one expects.

Brugerdefinerede integrationer indgår i AI-agentabonnementerne og er begrænset til 20 pr. arbejdsområde med 40 handlinger hver. Udgående kald bruger kun HTTPS, opløses og låses til en offentlig IP-adresse før forbindelse, og omdirigeringer afvises. En integrations-URL kan derfor aldrig pege på et privat mål.

Hurtig start: en egen bot i tre trin

Sidder I fast? Spørg en AI om dette afsnit:ClaudeChatGPTGrok

A bot is a webhook and a reply. Subscribe to message.created, answer through the messages endpoint, and the widget renders it live — quick-reply buttons, email capture, the native ticket form, typing indicators. Turn the built-in AI off on the widget and your bot owns the conversation.

1. Abonner med serveren (Indstillinger → Udviklere → Webhooks eller via API):

curl -X POST https://conecto.chat/api/v1/webhooks/ \
  -u "ck_...:cs_..." -H "Content-Type: application/json" \
  -d '{"url": "https://bots.yourapp.com/conecto",
       "events": ["message.created", "conversation.created"]}'

2. Verificer og læs hændelsen. Every delivery is signed: X-Conecto-Signature: sha256=<HMAC-SHA256(secret, raw body)>.

// Node/Express
app.post('/conecto', express.raw({ type: '*/*' }), (req, res) => {
  const sig = 'sha256=' + crypto.createHmac('sha256', WEBHOOK_SECRET)
    .update(req.body).digest('hex')
  if (sig !== req.get('X-Conecto-Signature')) return res.sendStatus(401)

  const { event, data } = JSON.parse(req.body)
  if (event === 'message.created' && data.message.sender === 'visitor') {
    handle(data)                       // your bot logic — reply async, respond 200 fast
  }
  res.sendStatus(200)
})

3. Svar med funktioner.

curl -X POST https://conecto.chat/api/v1/conversations/42/messages/ \
  -u "ck_...:cs_..." -H "Content-Type: application/json" \
  -d '{"body": "I can refund order #1284 right away — confirm?",
       "buttons": ["Yes, refund it", "Talk to a human"]}'

Button taps come back to your webhook as normal visitor messages containing the button text — your bot's state machine lives entirely on your side. Other reply powers: blocks sends images, GIFs, video and cards (see Rigt indhold), {"ask_email": true} renders the email-capture form, {"ticket_form": true} attaches the native open-a-ticket form, products renders tappable product cards, {"internal": true} leaves an agent-only note, /typing/ shows “…is typing”, /handoff/ summons a human, and PATCH closes the conversation when you're done.

Botopskrifter

Sidder I fast? Spørg en AI om dette afsnit:ClaudeChatGPTGrok

Opskrifter, der faktisk bruges i produktion. Hver består af en webhookhandler og nogle API-kald.

1 · Handlingsbotten, ændrer ting i jeres software

Fordi webhooken rammer jeres kan botten gøre alt på jeres server, som backend kan: skrive til databasen, kalde faktureringssystemet eller opdatere en post i regnskabsprogrammet. Sammen med attesteret identitet I ved præcis, hvem der spørger. Derfor kan «bogfør denne kvittering på 250 dollars under Marketing» udføres sikkert:

async function handle({ conversation, visitor, message }) {
  const convo = conversation.id

  // "file 250 under Marketing" — your parsing, your rules
  const cmd = parseAccountingCommand(message.body)
  if (!cmd) return reply(convo, "Tell me e.g. 'file 250 under Marketing'.")

  // Only act for users YOUR backend has vouched for (logged in on your site)
  if (!visitor.verified)
    return reply(convo, "Please sign in first, then ask me again.", ["Log in"])

  await ledger.addEntry({            // <- YOUR accounting system
    account: cmd.account,
    amount:  cmd.amount,
    user:    visitor.verified_email, // identity Conecto guarantees
  })
  await reply(convo,
    `Done — $${cmd.amount} filed under ${cmd.account}. Anything else?`,
    ["Show this month's entries", "Undo that"])
}

Det samme mønster virker til «føj en plads til mit abonnement», «omdøb mit projekt» eller «book en tid torsdag». Botten er et tyndt samtalelag oven på jeres eget API. Vil I hellere bruge den indbyggede AI end at skrive en bot? Registrer de samme endepunkter som en integration og Conectos AI kalder dem under samtalen med samme identitetsverificering, uden en tilstandsmaskine at vedligeholde. Hvis I allerede bruger MCP, virker en ekstern MCP-værktøjsserver også: Dashboard → AI-agenter → Integrationer.

2 · Bot til ordrestatus

if (/where.*order|track/i.test(message.body)) {
  await typing(convo, 'OrderBot', true)
  const order = await shop.lastOrder(visitor.email)     // your store
  await reply(convo, order
    ? `Order #${order.id} is ${order.state} — arriving ${order.eta}.`
    : "I couldn't find an order for this email.",
    order ? [`Track #${order.id}`] : undefined)
}

3 · Bot til at reducere sager

Søg først i hjælpecentret; åbn kun en sag, når intet passer:

const { articles } = await api('GET', '/articles/?q=' + q + '&published=true')
if (articles.length)
  await reply(convo, `This might help: “${articles[0].title}”. Did that solve it?`,
              ["Solved it", "Open a ticket"])
else
  await api('POST', `/conversations/${convo}/messages/`,
            { body: "Let's get this to the team.", ticket_form: true })

4 · Bot til kvalificering af leads

// no email yet? capture it natively, then enrich + route
if (!visitor.email)
  return api('POST', `/conversations/${convo}/messages/`,
             { body: "Happy to help — what's your work email?", ask_email: true })

await api('POST', '/contacts/', { email: visitor.email,
  custom_fields: { lead_source: 'chat', intent: classify(message.body) } })
await api('POST', `/conversations/${convo}/messages/`,
          { body: "Routing you to sales…", internal: true })
await api('POST', `/conversations/${convo}/assign/`, { user_id: SALES_USER_ID })
await api('POST', `/conversations/${convo}/handoff/`)

5 · Proaktive beskeder gennem kunderejsen

Send til en besøgssession uden at vente på en besked, eksempelvis leveringsopdateringer, prøvepåmindelser eller gendannelse af indkøbskurven:

curl -X POST https://conecto.chat/api/v1/widgets/7/visitors/$SESSION/message/ \
  -u "ck_...:cs_..." -H "Content-Type: application/json" \
  -d '{"body": "Your order shipped — want live tracking?",
       "buttons": ["Track my order"]}'

Cart recovery works the same way, with products putting the item itself back in front of them as a tappable card:

-d '{"body": "Still thinking it over? Your cart is saved:",
     "products": [{"title": "Trail Runner 2", "price_from": "89.00",
                   "currency": "USD", "image": "https://cdn.you.com/tr2.jpg",
                   "url": "https://shop.you.com/cart"}]}'

6 · En ukendt butik, forbundet med AI

Ingen webhook og ingen tilstandsmaskine: deklarer den reserverede kataloghandling, peg den mod søgeendepunktet, så anbefaler AI'en varer fra kataloget med rigtige produktkort.

// POST /conecto/search on your server
app.post('/conecto/search', verifyConectoSignature, async (req, res) => {
  const { query, limit = 4 } = req.body.arguments
  const hits = await catalog.search(query, { limit })     // <- YOUR catalog

  res.json({ ok: hits.length > 0, not_found: hits.length === 0,
    products: hits.map(p => ({
      title: p.name, url: p.permalink, image: p.thumbnail,
      price_from: p.price.toFixed(2), currency: p.currency,
      available: p.stock > 0,
    })) })
})

Det er hele integrationen. Kortene, Home-udvalget, reglen «kald igen, før et produkt nævnes» og forbuddet mod, at modellen indsætter rå URL'er, følger automatisk med det reserverede navn.

7 · CSAT-opfølgning

Subscribe to conversation.rated; thank promoters, rescue detractors:

if (event === 'conversation.rated') {
  if (data.rating.score <= 2)
    await api('POST', '/tickets/', { email: data.visitor.email,
      message: `Low CSAT (${data.rating.score}/5): ${data.rating.comment}`,
      priority: 'high' })
  else
    await push(data.widget.id, data.visitor.session,
               "Glad we could help! Here's 10% off your next order: THANKS10")
}

Handle sikkert på jeres egne systemer

Sidder I fast? Spørg en AI om dette afsnit:ClaudeChatGPTGrok

Tre regler gør handlingsbots produktionsklare:

1. Identiteten først. Only mutate data for sessions where visitor.verified is true — your backend vouched for them via /identify/. The vouch is time-boxed and session-scoped; revoke it with /unverify/ on logout.

2. Bekræft destruktive trin. Send handlingen som et spørgsmål med knapper («Refundér ordre #1284?» · Ja / Nej), trykket kommer tilbage som knappens tekst, jeres idempotente handler køres, og transskriptionen dokumenterer samtykket.

3. Overdrag til en person ved usikkerhed. POST /conversations/{id}/handoff/ flags the thread human-needed (your routing rules apply), and {"internal": true} notes give the teammate full context your bot gathered.

Endepunktsreference

Sidder I fast? Spørg en AI om dette afsnit:ClaudeChatGPTGrok

Samtaler og beskeder

GET/conversations/

Newest first. Filters: status (open · pending · closed), widget_id, session; paginate with limit/before_id.

GET/conversations/{id}/

Conversation + visitor-facing transcript (≤500 messages, since_id for increments).

POST/conversations/{id}/messages/

body (≤4000), buttons (≤6 × 60 chars), blocks (≤10 — see Rigt indhold), ask_email, ticket_form (native ticket form), internal (agent-only note), products (≤4 cards rendered as a mini carousel under the bubble: {title, url, price_from, currency, image} — title required, everything else optional). Honors Idempotency-Key. 409 when closed.

POST/conversations/{id}/typing/

{"name": "OrderBot", "on": true} , udløber automatisk efter cirka 8 sek.

POST/conversations/{id}/assign/

{"user_id": 12} (or null to unassign) — teammates come from /members/.

POST/conversations/{id}/handoff/

Markér, at en person er nødvendig; vises i indbakken som en AI-overdragelse, herunder routingregler.

PATCH/conversations/{id}/

{"status": "closed" | "open"}. Closing fires conversation.closed.

POST/widgets/{widget_id}/visitors/{session}/message/

Proactive push: reuses the session's live conversation or opens one; body + buttons + blocks + products. Honors Idempotency-Key.

Integrationer, jeres egen software som fuldgyldig integration

GET/integrations/ · POST

List, or register one: slug, name, base_url (https), optional description/icon_url/homepage_url, auth_type (none · bearer · api_key · basic) + credential, and actions inline. Returns the signing_secret you verify our calls with.

GET/integrations/{slug}/ · PATCH · DELETE

PATCH takes the same fields; actions upserts by name and replace_actions: true makes your list authoritative (deploy-from-source). rotate_signing_secret rolls the secret; active: false switches it off everywhere at once.

GET/integrations/{slug}/actions/ · POST · DELETE /{name}/

Each action: name (dotted, e.g. orders.lookup), path, method, risk, description (what the AI reads), parameters ({name, type, required, description, enum}), ai_enabled. GET also returns the reserved-action catalog.

POST/integrations/{slug}/install/ · /uninstall/

widget_ids (all visible widgets when omitted), actions allowlist, enabled.

POST/integrations/{slug}/actions/{name}/run/

Invoke it now through the real call path. arguments, optional conversation_id for visitor context. Returns {status, result, blocks}.

Medier

POST/media/

Multipart file (≤10 MB) → {media: {url, absolute_url, filename, content_type, size, is_image}}. Put url in an image/video/file block.

Sager

GET/tickets/

Filters: status (open · pending · resolved), email; paginated.

POST/tickets/

email, message, optional name, category_id, priority (low · normal · high · urgent), submission_id (UUID idempotency key). The requester gets the standard acknowledgement email.

GET/tickets/{id}/ · PATCH

Detail with the comment thread; PATCH status, priority, assignee_user_id.

POST/tickets/{id}/reply/

body — emails the requester; internal: true for a private note.

GET/ticket-categories/

Arbejdsområdets kategorier til oprettelse af sager.

Kontakter, synkroniser jeres brugerdatabase

POST/contacts/

Upsert by email (201 created / 200 updated): profile fields + custom_fields (≤30 keys, merged).

GET/contacts/ · GET/PATCH/DELETE /contacts/{id}/

Search with email (exact) or q; standard pagination.

Besøgende, identitet og personalisering

POST/widgets/{widget_id}/visitors/{session}/identify/

email (required), name, data (custom fields), verified + verify_hours (≤72, default 12) — see Identitet. Sessioner kan klargøres på forhånd.

POST/widgets/{widget_id}/visitors/{session}/unverify/

Tilbagekald attesteringen, kald ved logout.

GET/widgets/{widget_id}/visitors/{session}/

Aktuel identitet: e-mail, navn og verificeringsstatus.

Vidensbase

GET/articles/

q full-text search, published=true filter — perfect for bot answer lookups.

POST/articles/ · GET/PATCH/DELETE /articles/{id}/

Synkroniser dokumentation gennem kode. HTML-indhold renses på serveren efter en tilladelsesliste.

Konfiguration og metadata

GET/widgets/{widget_id}/ · PATCH

Læs eller opdater widgetkonfiguration, hilsen, farver, handlingsknapper på Home, hurtige spørgsmål, åbningstider og de samme validerede felter, som dashboardets tilpasningsværktøj redigerer.

GET/members/

Teammedlemmer (user_id, name, role) til tildeling.

GET/stats/

Liveantal: åbne/afventende samtaler, åbne sager, kontakter og publicerede artikler.

GET/me/

Jeres arbejdsområde, loginoplysningens omfang og widgets (id'er + indlejringsnøgler).

GET/schema/

Den maskinlæsbare beskrivelse af alt ovenfor: endepunkter, hændelser, bloktyper, reserverede handlinger, fejlkoder og grænser. Generer klienten fra den.

Identitet: spring ny verificering over for indloggede brugere

Sidder I fast? Spørg en AI om dette afsnit:ClaudeChatGPTGrok

Widgetten gemmer sit session-id i browseren. Læs det på klientsiden, send det til backend med jeres egen sessionscookie, og attestér derefter identiteten fra server til server:

# your backend, right after your own auth check
curl -X POST https://conecto.chat/api/v1/widgets/7/visitors/$CONECTO_SESSION/identify/ \
  -u "ck_...:cs_..." -H "Content-Type: application/json" \
  -d '{"email": "maya@acme.io", "name": "Maya",
       "verified": true, "verify_hours": 24,
       "data": {"plan": "pro", "customer_since": "2024"}}'

While the vouch lasts, Conecto treats the email as verified: the widget knows their name, chats attach to the right CRM contact, and flows that normally demand an email OTP — refund lookups, order changes, sensitive account data through the AI's tools — proceed without one. Your attestation is as strong as our code-by-email, because you actually authenticated them. Only vouch sessions your backend has verified, and call /unverify/ on logout.

Webhooks

Sidder I fast? Spørg en AI om dette afsnit:ClaudeChatGPTGrok

Manage in the dashboard or via GET/POST /webhooks/ og DELETE /webhooks/{id}/ (https only, ≤10 per workspace, optional per-widget scope). Deliveries carry X-Conecto-Event, X-Conecto-Delivery, X-Conecto-Timestamp and the HMAC signature, and time out after 2.5s — respond 200 fast, process async. Events:

conversation.createdførste besøgsbesked i en ny tråd, herunder formularer på Home-fanen
message.createdhver besøgsbesked, udløseren for den egne bot
conversation.closedlukket af en medarbejder eller API'et
conversation.assignedtildelt et teammedlem eller ikke længere tildelt
conversation.handoffmarkeret som krævende en person
conversation.ratedden besøgendes CSAT-vurdering (1–5 + kommentar)
ticket.createdalle kilder: widgetformular, AI, bots, automatiseringer, API
ticket.updatedstatus, prioritet eller tildelt person ændret
contact.createden ny person blev tilføjet i CRM, synkroniser personen med jeres system
visitor.identifieden session blev identificeret gennem API'et med sin attesteringsstatus

Leveringen sker mindst én gang og uden garanteret rækkefølge. Every payload carries an id (also in X-Conecto-Delivery): store it, skip ids you have already handled, and both replays and duplicates stop being your problem. When your bot answers a delivery, pass that same id as the Idempotency-Key and a redelivery can never make it speak twice.

app.post('/conecto', express.raw({ type: '*/*' }), async (req, res) => {
  const sig = 'sha256=' + crypto.createHmac('sha256', WEBHOOK_SECRET)
    .update(req.body).digest('hex')
  if (!crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(req.get('X-Conecto-Signature') || '')))
    return res.sendStatus(401)

  const { id, event, data } = JSON.parse(req.body)
  res.sendStatus(200)                        // ack first, work after
  if (await seen(id)) return                 // at-least-once: dedupe on the delivery id

  if (event === 'message.created' && data.message.sender === 'visitor') {
    await fetch(`https://conecto.chat/api/v1/conversations/${data.conversation.id}/messages/`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json', 'Idempotency-Key': id, ...auth },
      body: JSON.stringify({ body: await answer(data) }),
    })
  }
})

Everything here is designed to sit under an SDK: stable envelopes, slug-addressed integrations, typed errors, cursor pagination, idempotent writes, one signature scheme in both directions, and GET /schema/ to generate from. Building something? Tal med os , vi ønsker, at udviklere bygger på Conecto, og prioriterer deres ønsker.