Bygg på Conecto

Ett tydligt REST API för allt plattformen gör: bygg botar som inte bara svarar utan även kan agera , i er databas, fakturering och produkt, skicka bilder, GIF-filer, video och kort till chatten och bygga egna integrationer som AI-agenten anropar under konversationen, oavsett underliggande programvara. Om widgeten kan göra det kan API:t styra det.

I produktion · Signerade webhooks · 300 förfrågningar/min

Grunderna

Har ni fastnat? Fråga en AI om det här avsnittet:ClaudeChatGPTGrok

Base URL https://conecto.chat/api/v1. Create a credential in Inställningar → Utvecklare , ni får ett klient-ID och ett hemlighet (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"

Använder ni Python? Den officiellt 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.

Hastighetsgräns 300 förfrågningar/min per credential (429 + Retry-After beyond it). Errors are always {"error": {"code", "message"}}. List endpoints paginate with limit och 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.

En ändpunkt beskriver alla andra

GET /schema/ returnerar hela ytan som JSON: varje ändpunkt, händelse, blocktyp, reserverad åtgärd, felkod och numerisk gräns. Samma kod som upprätthåller gränserna levererar svaret, så det kan inte avvika från den körande servern som en dokumentationssida kan. Generera klienten därifrån eller kontrollera vid start att funktionen ni behöver är driftsatt.

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.

Rikt innehåll: bilder, GIF-filer, video och kort

Har ni fastnat? Fråga en AI om det här avsnittet: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"}
      ]}
    ]
  }'

Blocktyperna

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 och den vanliga delningslänken url
audiourl till en .mp3/.wav/.m4a-fil, valfritt 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 etikett · värde · underrubrik · bild · URL, för beställningsöversikter och leveranssteg
buttonsitems[]: {label, value} replies as the visitor, {label, url} opens a link
text · dividerextra stycken och en horisontell 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.

Skicka en GIF utan egen lagringsplats

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 kortkarusell

{"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"}]}
  ]
}]}

Bygg en egen integration

Har ni fastnat? Fråga en AI om det här avsnittet:ClaudeChatGPTGrok

Shopify, Stripe och BigCommerce är integrationer som vi har skrivit. Det här är den som ni skriva. Beskriv tjänsten med en bas-URL och en lista över åtgärder, installera den på en widget, så anropar AI-agenten den under konversationen. Efterföljande system kan inte skilja den från en inbyggd integration. Det är hela poängen: om butiken, faktureringen eller CRM-systemet körs på en lösning vi inte känner till behöver ni inte längre vänta på vårt stöd.

1 · Registrera 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 · Installera 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 · Besvara anropet

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

Svara med en av 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

Ett vanligt JSON-objekt utan någon av dessa nycklar behandlas som själva resultatet. Ni kan därför peka en åtgärd på en ändpunkt som redan finns. Gränser: 8 sek. timeout, 128 kB -svar. Allt ni returnerar når modellen som data i ett JSON-envelope, aldrig som instruktioner. Nycklar som ser ut som hemligheter tas bort på vägen in.

4 · Testa innan en besökare 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.

Risknivåer och den enda regel som inte kan stängas av

public_readkatalog, tillgänglighet, dokumentation, ingen identitet krävs
verified_readen persons data. Nekas tills besökarens e-postadress är verifierad
public_writeen ändring som inte kräver identitet, exempelvis nyhetsbrevsregistrering eller insamling av leads
writeen ändring på en persons konto. Verifierad och aldrig tyst återförsökt

För de två sista tillhandahålls den verifierade adressen av oss, in visitor.verified_email — never taken from the model's arguments. Verification comes from an emailed code, or from your own site attestering av en inloggad användare. Ingen widgetinställning kan undanta en åtgärd från regeln, eftersom «vems beställning är det?» inte är en fråga som en omkopplare ska besvara.

Reserverade åtgärder: er butik, ansluten som en inbyggd 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 och 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.

Anpassade integrationer ingår i AI-agentabonnemangen och är begränsade till 20 per arbetsyta med 40 åtgärder vardera. Utgående anrop använder endast HTTPS, löses och låses till en offentlig IP-adress före anslutning, och omdirigeringar nekas. En integrations-URL kan därför aldrig peka på ett privat mål.

Snabbstart: en egen bot i tre steg

Har ni fastnat? Fråga en AI om det här avsnittet: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. Prenumerera med servern (Inställningar → Utvecklare → 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. Verifiera och 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. Svara 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 Rikt innehåll), {"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.

Botrecept

Har ni fastnat? Fråga en AI om det här avsnittet:ClaudeChatGPTGrok

Recept som faktiskt används i produktion. Varje består av en webhookhanterare och några API-anrop.

1 · Åtgärdsboten, ändrar saker i er programvara

Eftersom webhooken träffar er kan boten göra allt på er server som backend kan: skriva till databasen, anropa faktureringssystemet eller uppdatera en post i bokföringsprogrammet. Tillsammans med attesterad identitet ni vet exakt vem som frågar. Därför kan «bokför det här kvittot på 250 dollar under Marknadsföring» utföras säkert:

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"])
}

Samma mönster fungerar för «lägg till en plats i mitt abonnemang», «byt namn på mitt projekt» eller «boka en tid på torsdag». Boten är ett tunt konversationslager ovanpå ert eget API. Vill ni hellre använda den inbyggda AI:n än skriva en bot? Registrera samma ändpunkter som en integration och Conectos AI anropar dem under konversationen med samma identitetsverifiering, utan en tillståndsmaskin att underhålla. Om ni redan använder MCP fungerar även en fjärransluten MCP-verktygsserver: Dashboard → AI-agenter → Integrationer.

2 · Bot för beställningsstatus

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 för att undvika ärenden

Sök först i hjälpcentret; öppna bara ett ärende när inget passar:

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 för leadkvalificering

// 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 · Proaktiva meddelanden under kundresan

Skicka till en besökarsession utan att vänta på ett meddelande, till exempel leveransuppdateringar, provpåminnelser eller återställning av varukorg:

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 okänd butik, ansluten till AI

Ingen webhook och ingen tillståndsmaskin: deklarera den reserverade katalogåtgärden, peka den på er sökändpunkt, så rekommenderar AI:n artiklar ur katalogen med riktiga 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 är hela integrationen. Korten, Home-urvalet, regeln «anropa igen innan en produkt nämns» och förbudet mot att modellen klistrar in råa URL:er följer automatiskt med det reserverade namnet.

7 · CSAT-uppföljning

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")
}

Agera säkert på era egna system

Har ni fastnat? Fråga en AI om det här avsnittet:ClaudeChatGPTGrok

Tre regler gör åtgärdsbotar produktionsklara:

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äfta destruktiva steg. Skicka åtgärden som en fråga med knappar («Återbetala beställning #1284?» · Ja / Nej), trycket kommer tillbaka som knappens text, er idempotenta hanterare körs och transkriptionen dokumenterar samtycket.

3. Överlämna till en person vid osäkerhet. 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.

Ändpunktsreferens

Har ni fastnat? Fråga en AI om det här avsnittet:ClaudeChatGPTGrok

Samtal och meddelanden

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 Rikt innehåll), 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} , upphör automatiskt efter cirka 8 sek.

POST/conversations/{id}/assign/

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

POST/conversations/{id}/handoff/

Markera att en person behövs; visas i inkorgen som en AI-överlämning, inklusive dirigeringsregler.

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, er egen programvara som fullvärdig 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}.

Media

POST/media/

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

Ärenden

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/

Arbetsytans kategorier för att skapa ärenden.

Kontakter, synkronisera användardatabasen

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ökare, identitet och personalisering

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

email (required), name, data (custom fields), verified + verify_hours (≤72, default 12) — see Identitet. Sessioner kan förberedas i förväg.

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

Återkalla attesteringen, anropa vid utloggning.

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

Aktuell identitet: e-post, namn och verifieringsstatus.

Kunskapsbas

GET/articles/

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

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

Synkronisera dokumentation via kod. HTML-innehåll rensas på servern enligt en tillåtelselista.

Konfiguration och metadata

GET/widgets/{widget_id}/ · PATCH

Läs eller uppdatera widgetkonfiguration, hälsning, färger, åtgärdsknappar på Home, snabbfrågor, öppettider och samma validerade fält som dashboardens anpassningsverktyg redigerar.

GET/members/

Teammedlemmar (user_id, name, role) för tilldelning.

GET/stats/

Liveantal: öppna/väntande konversationer, öppna ärenden, kontakter och publicerade artiklar.

GET/me/

Er arbetsyta, inloggningsuppgiftens omfattning och widgetar (ID:n + inbäddningsnycklar).

GET/schema/

Den maskinläsbara beskrivningen av allt ovan: ändpunkter, händelser, blocktyper, reserverade åtgärder, felkoder och gränser. Generera klienten från den.

Identitet: hoppa över ny verifiering för inloggade användare

Har ni fastnat? Fråga en AI om det här avsnittet:ClaudeChatGPTGrok

Widgeten lagrar sitt sessions-ID i webbläsaren. Läs det på klientsidan, skicka det till backend med er egen sessionscookie och attestera sedan identiteten server till 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

Har ni fastnat? Fråga en AI om det här avsnittet:ClaudeChatGPTGrok

Manage in the dashboard or via GET/POST /webhooks/ och 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örsta besökarmeddelandet i en ny tråd, inklusive formulär på fliken Home
message.createdvarje besökarmeddelande, utlösaren för den egna boten
conversation.closedstängd av en handläggare eller API:t
conversation.assignedtilldelad en teammedlem eller inte längre tilldelad
conversation.handoffmarkerad som i behov av en person
conversation.ratedbesökarens CSAT-betyg (1–5 + kommentar)
ticket.createdalla källor: widgetformulär, AI, botar, automatiseringar, API
ticket.updatedstatus, prioritet eller tilldelad person ändrad
contact.createden ny person lades till i CRM, synkronisera personen med ert system
visitor.identifieden session identifierades via API:t, med sitt attesteringstillstånd

Leveransen sker minst en gång och utan garanterad ordning. 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? Prata med oss , vi vill att utvecklare ska bygga på Conecto och prioriterar deras önskemål.