REST API and webhooks

Read and open tickets, read chats and contacts from your own systems with the coview REST API, and receive signed webhooks when things happen.

The REST API lets your own systems read and open tickets and read chats and contacts. Webhooks tell them when something happens. Both are on the Growth plan and higher; on other plans the API answers 402. Everything here is set up in Settings › Integrations, which needs the Workspace settings permission.

Create an API key

  1. Open Settings › Integrations and find API keys.
  2. Enter a Key name that says what uses it, such as "Billing system".
  3. Under It may, tick its scopes:
    • tickets.read: read tickets and their messages.
    • tickets.write: open tickets and change their status, priority, type and tags.
    • conversations.read: read chats and their messages.
    • contacts.read: read contacts.
  4. Click Create key and copy it. coview shows it only once.

A key starts with cv_live_. A workspace can have up to 20 active keys. Revoke stops a key at once. Creating and revoking keys, and every change a key makes, are written to the audit log under the key's name.

Make a request

Send the key in the X-Coview-Key header to https://api.coview.work/api/v1:

curl https://api.coview.work/api/v1/tickets?status=open \
  -H "X-Coview-Key: cv_live_…"

Answers are JSON and never cached. Each key makes up to 300 calls a minute; past that the answer is 429 with a Retry-After header.

Endpoints

RequestScopeDoes
GET /ticketstickets.readLists tickets. Filters: status (open, pending, on_hold, solved, closed), priority, type, assignee (a member id, or unassigned), q, before_id. Answers {tickets, counts, next_before_id}.
GET /tickets/:idtickets.readOne ticket with its customer and messages. Pass before_id for older messages.
POST /ticketstickets.writeOpens a ticket: {contact_id | email, subject, body?, priority?, status?, type?, tags?}. The email must belong to a contact coview already knows. body is added as an internal note. Answers {ticket}.
POST /tickets/:idtickets.writeChanges a ticket: {subject?, status?, priority?, type?, tags?, assignee_member_id?}. Answers {ticket}.
GET /conversationsconversations.readLists chats (never tickets). Filters: status (open, snoozed, resolved), q, before_id. Answers {conversations, counts, next_before_id}.
GET /conversations/:idconversations.readOne chat with its customer and messages.
GET /contacts?email=contacts.readThe contact with that email, if any: {contacts}.
GET /contacts/:idcontacts.readOne contact: {contact}.

Lists come newest first, a page at a time. To get the next page, pass the answer's next_before_id as before_id; it is null on the last page. priority is low, normal, high or urgent; type must be one of your ticket types; tags are up to 10, of 1 to 32 characters.

Errors look like {error: {code, message, reason?, violations?}}: 401 for a missing, unknown or revoked key, 403 when the key lacks the scope, 402 off the plans with the API, 404 for an unknown id, and 422 with violations listing each field to fix.

Webhooks

  1. Under Webhooks, enter the Endpoint URL: https only, reachable from the internet.
  2. Keep Send every event, including ones coview adds later, or untick it and choose events.
  3. Click Add endpoint and copy the signing secret (whsec_…). coview shows it only once.

Up to 10 endpoints, each with a test button. Recent deliveries lists what was sent and how it went.

Events: conversation.created, message.created, conversation.assigned, conversation.resolved, ticket.created, ticket.solved, cobrowse.started, cobrowse.ended, contact.created, contact.updated, and ping from a test.

Each delivery is a POST of {id, type, created_at, workspace_id, data} with these headers:

  • X-Coview-Event: the event type.
  • X-Coview-Delivery: the event id, the same on every retry. Use it to skip duplicates.
  • X-Coview-Timestamp: Unix seconds when this try was sent.
  • X-Coview-Signature: sha256= and the hex HMAC-SHA256 of "<timestamp>.<raw body>", keyed with the endpoint's secret.
// Node: check a delivery before you trust it
const crypto = require('node:crypto');
const ts = req.headers['x-coview-timestamp'];
const expected = 'sha256=' + crypto.createHmac('sha256', process.env.COVIEW_WEBHOOK_SECRET)
  .update(ts + '.' + rawBody).digest('hex');
const ok = crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(req.headers['x-coview-signature']))
  && Math.abs(Date.now() / 1000 - Number(ts)) < 300;

Answer with any 2xx status. Anything else, or no answer, is tried again after 1 minute, 5 minutes, 30 minutes, 2 hours and 12 hours; after 6 tries coview gives up on that delivery, and Recent deliveries says so.

Slack

Slack is on every plan. Add Slack's Incoming Webhooks app to your team's channel, paste its address as the Incoming Webhook URL, choose what to post (new chats, new tickets, solved tickets, co-browsing started), and click Connect Slack.

Still stuck?

A person from coview will help — send us a message, or book a demo and we'll walk through it with you.