Overview
Programmatic access to Relay conversations, contacts, companies, and products.
The Relay API is a REST API for reading and writing conversations, contacts, companies, and products in your workspace. It runs alongside the realtime product, so a message you push through the API appears live in the dashboard for your agents.
Prefer the terminal? The Relay CLI wraps this API for scripting and one-off tasks, and can migrate your data from Crisp in one command.
Authentication
Every request is authenticated with a workspace API key sent as a Bearer token:
curl https://api.superrelay.ai/v1/public/conversations \
-H "Authorization: Bearer rl_live_xxxxxxxxxxxxxxxxxxxxxxxx"Create and manage keys in Settings → API Keys. Keys are scoped to a single workspace and to a set of permissions:
| Scope | Grants |
|---|---|
conversations:read | List and read conversations and their messages |
conversations:write | Create conversations, push messages, update parameters |
contacts:read | List and read contacts |
contacts:write | Create and update contacts |
companies:read | List and read companies (and the deprecated /stores alias); a company's contacts also need contacts:read |
companies:write | Create and update companies (and the deprecated /stores alias) |
products:read | List and read products |
The plaintext key is shown once at creation — store it securely. If a key is lost or leaked, revoke it and create a new one.
products:read and companies:read / companies:write were added with their
resources. Keys created before them don't carry them — create a new key (all
scopes are on by default) or edit the existing key's scopes. Two exceptions:
reading a conversation's product and filtering by productId only need
conversations:read, and keys holding contacts:read / contacts:write keep
working for /companies (and /stores) until the stores sunset.
Products
Every conversation belongs to at most one product — the thing you support: a SaaS product, a website, an app. Products decide which knowledge base and AI context apply, and they are how you filter and report. See Products and routing for how conversations get their product.
In the API:
- Conversations carry a
productobject ({ id, name }), ornullwhen the conversation has not been routed or triaged yet. GET /v1/public/conversations?productId=<id>lists one product's conversations;?productId=nonelists the ones that still need a product.POST /v1/public/conversationstakes an optionalproductId. Omit it to inherit the inbox's product; passnullto leave the conversation unassigned on purpose.GET /v1/public/productsandGET /v1/public/products/{id}list and read products. They are read-only — create, edit, and archive products in Settings → Products.
Companies
A company is the organization a contact belongs to — a customer account, a
company, or a store for e-commerce products. Contacts carry a company object
({ id, name }) and a companyId; PATCH /v1/public/contacts/{id} takes
companyId to link or unlink (null). GET /v1/public/companies/{id}/contacts
lists a company's people.
Companies are also created for you: when a customer's
signed identity carries an
organization claim, Relay resolves it to a company by externalId (creating
one on first sight) and links the contact. Set externalId to your own account
id so both paths meet.
Pagination
List endpoints are cursor-paginated and return a consistent envelope:
{
"data": [],
"has_more": true,
"next_cursor": "eyJ2IjoxLCJ0cyI6..."
}Pass next_cursor back as the cursor query parameter (and limit, 1–200) to
fetch the next page. Cursors are opaque — treat them as a token, don't parse
them.
Errors
Errors return the appropriate HTTP status with a JSON body of the form
{ "error": "message" }. Common cases: 401 (missing/invalid/expired key),
403 (key missing the required scope), 404 (resource not in this workspace),
400 (validation error — for example a productId that is neither a UUID nor
none).
Stores deprecation
stores is the old name of the companies resource. It is now a pure alias:
/v1/public/stores* calls the same handlers as /v1/public/companies*, returns
the same fields and the same ids, and accepts the same scopes. Switching is a
rename.
- Every
/v1/public/stores*route keeps working until 16 February 2027. - Responses carry an RFC 9745
Deprecationheader (a Structured Field Date such as@1786752000— the moment the resource became deprecated), an RFC 8594Sunset: Tue, 16 Feb 2027 00:00:00 GMTheader, and aLink: <…>; rel="deprecation"header pointing here. - On contacts,
storeIdstays as a deprecated alias ofcompanyIdfor the same window. - After the sunset date
/stores*andstoreIdare removed.
Migration: replace /stores with /companies in paths, storeId with
companyId on contacts, and give new API keys the companies:read /
companies:write scopes (existing contacts:* keys keep working until the
sunset).