Build a connector. Give your agent real data.
A SupportCore connector is a small HTTPS service you host. It lets your support agent look up live data and run the actions you allow — order status, returns, warranty, account changes — all declared by a manifest so SupportCore discovers your capabilities automatically. One contract, any stack, no custom work on our side.
01Quick start
Host the endpoint
Serve a small service at /supportcore/v1 over HTTPS, guarded by a bearer key.
Publish a manifest
Declare your lookups and actions at GET /manifest. Each becomes an agent tool.
Connect it
Paste the base URL + key into Console → Connections. Your agent starts using it.
02Authentication
SupportCore sends a bearer key you issue in the Connections tab. Verify it on every request; reject anything else.
POST https://api.yourapp.com/supportcore/v1/lookup/customer Authorization: Bearer sc_live_9f2c…a71b Content-Type: application/json Idempotency-Key: e0b6…c455 # on actions; safe to retry
HTTPS only. Compare the key in constant time; return 401 on mismatch. Rotate it from
the Connections tab any time — no redeploy. Optionally verify an X-SupportCore-Signature HMAC of the body.
03The manifest — where you define capabilities
The heart of the spec. SupportCore fetches your manifest and turns every entry into a tool the agent can use. To teach the agent a new action — say, a note on an order — add one object here and implement its endpoint. That's it.
{
"connector": "YourApp", "version": "1.0",
"lookups": [
{ "id": "customer", "title": "Customer profile",
"description": "Plan, status and recent activity for an email",
"params": [ { "name": "email", "type": "string", "required": true } ],
"returns": "plan, status, signup_date, last_active" }
],
"actions": [
{ "id": "add_order_note", "title": "Add a note to an order",
"params": [ { "name": "order_id", "type": "string", "required": true, "pattern": "^[0-9]+$" },
{ "name": "note", "type": "string", "required": true } ],
"approval": "optional", "reversible": true },
{ "id": "cancel_subscription", "title": "Cancel a subscription",
"params": [ { "name": "email", "type": "string", "required": true } ],
"approval": "required", "reversible": false }
]
}
| Field | Meaning |
|---|---|
id | Stable name. SupportCore calls /lookup/{id} or /action/{id}. Never rename a live id. |
params[] | Each: name, type, required, optional pattern (regex). SupportCore validates against pattern before calling you. |
approval | required gates the action behind a human click. Default required when omitted. |
reversible | Irreversible actions always get an extra confirm and never auto-run. |
04Lookups · read
Return support-relevant, non-sensitive data. On no match, return 200 with { "found": false } — not a 404.
{ "email": "kees@example.com" }{ "found": true,
"data": { "plan": "Pro", "status": "active",
"open_invoices": 0 } }05Actions · write
The logic and permission checks live in your backend — SupportCore only requests it. Return a short human
message; the agent may quote it. Honour Idempotency-Key so the same key never acts twice.
{ "email": "kees@example.com",
"_meta": { "approved_by": "stephen@urenapp.eu",
"ticket": "89155065-…" } }{ "ok": true,
"message": "Cancelled, effective 1 Aug.",
"reference": "CANCEL-7731" }approval:"required" and
reversible:false. SupportCore never auto-runs these — a human confirms first. On a business-rule
failure, return 200 with { "ok": false, "message": "…" } so the agent can explain it.06Reference data & follow-up questions
The agent is only as good as what it can see. Two kinds of lookups make it genuinely helpful:
Record lookups — “this specific customer / order”
Keyed by an identifier (email, order id). We strongly recommend backing these with a
read-only database account — grant SELECT on just the tables or views support needs
(customers, orders, bookings, invoices) so the agent can see history and status without any write
access or exposure of sensitive fields.
Catalogue lookups — “what do we even offer?”
Expose your options too, not just records. A hotel publishes a room_types lookup
(types, capacity, price); a shop publishes shipping_options. This is what lets the agent
reason and ask the right follow-up instead of guessing.
room_types, sees that pricing depends on dates and room type,
notices the guest gave neither, and replies asking for them — then, once answered, prices it exactly.
You didn't script that conversation; you just published the catalogue and the agent did the reasoning.Rule of thumb: if a human agent would need to look something up or ask a clarifying question to answer, publish a lookup for it. The agent will use it the same way.
07Errors & limits
| Rule | Detail |
|---|---|
| Latency | Respond within 5 seconds — SupportCore times out after that. |
| Errors | HTTP status for transport/auth/server; { ok:false } for business outcomes. Shape: { "error": { "code", "message" } }. |
| Versioning | Pin the major version in the path (/v1/). Add fields freely; never remove one within a version. |
| Rate limit | Return 429 when needed — SupportCore backs off and retries. |
08Security
- ✓Least privilege. Read-only for lookups; writes only through the specific operations your actions implement. Never an admin account.
- ✓Expose only what support needs. No password hashes, full card numbers or unrelated personal data — even behind a valid key.
- ✓Validate server-side. The manifest
patternis a first gate; re-check ownership and entitlements in your handler. - ✓Rotate & log. Rotate the key; log every call with its
ticketandapproved_by.
09Full minimal example
const app = require("express")(); app.use(require("express").json()); const KEY = process.env.SUPPORTCORE_KEY; app.use((req, res, next) => { // 1 · auth const t = (req.headers.authorization || "").replace("Bearer ", ""); if (t !== KEY) return res.status(401).json({ error: { code: "unauthorized" } }); next(); }); app.get("/supportcore/v1/manifest", (_, res) => res.json({ // 2 · manifest connector: "YourApp", version: "1.0", lookups: [{ id: "customer", title: "Customer profile", params: [{ name: "email", type: "string", required: true }] }], actions: [{ id: "add_order_note", title: "Add order note", approval: "optional", params: [{ name: "order_id", type: "string", required: true, pattern: "^[0-9]+$" }, { name: "note", type: "string", required: true }] }] })); app.post("/supportcore/v1/lookup/customer", async (req, res) => { // 3 · lookup const u = await db.user(req.body.email); res.json(u ? { found: true, data: { plan: u.plan, status: u.status } } : { found: false }); }); app.post("/supportcore/v1/action/add_order_note", async (req, res) => { // 4 · action await db.addNote(req.body.order_id, req.body.note); res.json({ ok: true, message: "Note added to order " + req.body.order_id }); }); app.listen(8080);
10Readiness checklist
- ✓HTTPS at a stable
/supportcore/v1base URL. - ✓
GET /manifestlists every lookup and action; eachidhas a handler. - ✓Bearer auth enforced;
401on mismatch; key rotatable. - ✓Lookups return
{ found, data }; actions{ ok, message }; under 5s. - ✓Idempotency on actions; destructive ones
approval:"required". - ✓Read-only, least-privilege data; no sensitive fields exposed.