Probed API

Read and manage your Probed space from your own systems. Additive changes ship within v1; anything breaking moves to v2.

Paste it into Claude, Cursor or any coding agent.

What you can automate

A key can do what you'd do in the app's settings, from your own code. Each area needs its permission on the key; reading the space, its members, channels and roles needs none.

  • Members and invites: list members, invite people, change their roles, remove them.
  • Roles: create, edit, reorder and delete custom roles.
  • Channels and sections: create public channels, edit, archive and restore them, and organise sections.
  • Messages: read, post, edit, react to and pin messages in public and announcement channels, as the key. See Posting messages.
  • Customers and CRM: customers and their members, tags, notes, canned responses and badges.
  • Bulk customer import: bring in hundreds of customers and their contacts in one request. See Importing customers.
  • Ideas and roadmap: ideas, roadmap items, boards and roadmap settings.
  • Calendar events: events and event templates, at /calendar-events.
  • Soundboard: upload, edit and delete sounds, and set how each emoji plays.
  • Webhooks: get told when something changes. See Webhooks.
  • Moderation: time out, kick and ban members, and read the moderation log.

Quickstart

  1. In Probed, open the space's Settings → API keys and choose Create key. You need the Manage integrations permission and a Premium plan.
  2. Copy the key. It's shown once; Probed keeps only a hash.
  3. Call the API with it:
curl https://api.probed.chat/api/v1/space \
  -H "Authorization: Bearer prbd_sk_…"

You get the space the key belongs to:

{
  "id": "00000000-1111-4222-8333-444444444444",
  "object": "space",
  "name": "Acme",
  "slug": "acme",
  "createdAt": "2026-01-02T03:04:05.000Z"
}

Authentication

Every request sends a space API key as a bearer token: Authorization: Bearer prbd_sk_…. A key belongs to one space, not to the person who made it, and keeps working after they leave until someone revokes it.

  • What a key can do is chosen when it's created. Every key reads the space, its members, public channels, sections, roles and soundboard. Reading messages needs Read messages, each write needs its permission (Invite people, Manage roles, Send messages, Manage customers and so on), and seeing member email addresses needs Manage members.
  • A key acts as itself. Anything it does shows up under the key's name with an API badge, in the moderation log, on invites and on archive notices. Renaming the key in Settings → API keys renames it everywhere, history included. It isn't a member: it doesn't use a seat or appear in member lists.
  • A key can't hand out more than it holds. It can't give anyone a role, a permission or channel access beyond its own, and it can never act on owners or admins, make anyone an admin, edit built-in roles or create private channels. Those answer 403 permission_ceiling. A key can never hold Administrator, Manage billing or Manage space.
  • Rotating issues a new key and keeps the old one working for up to 24 hours so you can switch over.
  • A leaked key can revoke itself with POST /self/revoke. It works on any plan. Once it succeeds, the key is dead, so a retry answers 401.

Conventions

Base URL and versions

All paths below are relative to https://api.probed.chat/api/v1. Within v1, changes are additive only: new endpoints, new fields, new enum values and new error codes can appear at any time, so ignore anything you don't recognise. Removing or changing something moves to v2, with at least 12 months of overlap.

Objects and fields

Responses are JSON with camelCase fields. Every resource object has an id and an object naming its type, and timestamps are ISO 8601 in UTC.

Pagination

Lists take ?limit= (1 to 100, default 25) and ?cursor=, and answer with { "object": "list", "data": [...], "hasMore", "nextCursor" }. Pass nextCursor back unchanged to get the next page; it's null on the last one.

Errors

Errors answer with a status code and { "error": { "type", "code", "message", "param", "docUrl" } }. Branch on code, which is stable; message is for people and may change. Every code is on the errors page.

Rate limits

Each key gets 100 requests a minute on Premium and 300 on Business and above. Data endpoints' responses carry RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset; over the limit you get a 429 with Retry-After in seconds.

Invites and timeouts also have their own limit of 30 an hour per key, which rotating the key doesn't reset. Customer imports don't count toward it.

Posting messages and uploading files have their own limits too: see Posting messages.

Retries and idempotency

POST endpoints accept an Idempotency-Key header: retrying with the same key returns the first response instead of doing the work twice, marked Idempotent-Replayed: true. Send one with every create, so a timeout or a dropped connection can't invite someone twice or make two channels.

A replayed invite answers without its url: the link is a secret and isn't kept. Use the first response, or the invite email.

A key is 1 to 255 printable characters with no spaces (a UUID works), lasts 24 hours and is scoped to the API key. Server errors, 402, 409 and 429 answers aren't stored, so retrying those runs the request again.

Request ids

Every response has a Probed-Request-Id header. Include it when you contact support.

Posting messages

A key posts as itself. Its messages appear under the key's name with an API badge, like everything else it does. It can edit only its own messages. It can delete its own with Send messages, and anyone's with Manage messages, which goes in the moderation log.

Only public and announcement channels. Private channels, customer channels, Community channels and DMs answer 404, for reading and for writing. Reading needs Read messages, and posting needs Send messages.

Announcement channels need the Manage channels permission as well, for posting and for editing, or the key gets 403 announcement_only. Slow mode applies to a key like anyone else, and an archived channel answers 409.

Mentions. mentionUserIds notifies up to 50 members by their userId (as GET /members shows it). mentionEveryone: true needs the Mention everyone permission; without it the post is refused with 403, not sent quietly. Keys can mention everyone in a channel once every 10 minutes.

Files. Upload each file first with POST /uploads (multipart, a file field, up to 8 MB), then send the object it returns in the message's attachments, up to 10 per message. Only files uploaded with the same key work, within about a week.

POST /channels/{id}/messages
{
  "text": "Release 1.4 is out. Notes are in the thread.",
  "attachments": [
    {
      "type": "image",
      "url": "<the url POST /uploads returned>",
      "title": "screenshot.png",
      "mimeType": "image/png"
    }
  ]
}

Limits. On top of the request limit, a key can post 60 messages a minute and mention 200 people a minute, and upload 20 files a minute. Keys can upload 2 GB a day per space in all. Rotating the key doesn't reset these. Over a limit you get 429 with Retry-After.

message.created, message.updated and message.deleted webhooks cover the same channels, for everyone's messages, not only the key's.

Importing customers

Say you have 150 customers in another tool and want each of them in your space, with their own customer channel. Your customers don't need a Probed space of their own. They join yours as customers and, by default, see only their customer channel, not the rest of your space.

One request queues the whole list: up to 500 customers, each with up to 25 contacts. The key needs the Import customers permission, and the space needs a plan with customer profiles (Premium and up).

POST /customers/import
{
  "sendInvites": true,
  "customers": [
    {
      "externalId": "crm_1042",
      "name": "Acme Corp",
      "domain": "acme.com",
      "tags": ["enterprise"],
      "note": "Renews in March.",
      "contacts": [
        { "email": "ada@acme.com", "name": "Ada Lovelace" },
        { "email": "grace@acme.com" }
      ]
    }
  ]
}

Each new customer gets a private customer channel. note becomes its description, and domain is saved with it. Each new contact gets an invite to join your space as that customer. tags are made in the space if they're new, and invited contacts get them when they accept.

Invite emails are off unless you ask. sendInvites defaults to false: the invites exist, and you share them from the app. Set it to true to have Probed email them.

Import customers alone only adds. It creates new customers and invites new contacts. Updating a customer that already exists, adding someone who's already in your space to a customer, and tagging existing members also need Manage customers. Without it, those rows and contacts come back needs_manage_customers.

Give every customer an externalId, your own id for it. A customer with that externalId is updated instead of created (with Manage customers), and contacts already invited aren't invited again, so you can run the same import again safely. Without one, a second run makes a second customer. Two rows in one request can't share an externalId.

The request answers 202 straight away, with the import queued. Only one import can run in a space at a time; another answers 409 import_in_progress.

202 Accepted
{
  "id": "7f3c2a10-5b6d-4e8f-9a01-2b3c4d5e6f70",
  "object": "customer_import",
  "status": "queued",
  "total": 150,
  "processed": 0,
  "counts": { "created": 0, "updated": 0, "skipped": 0, "failed": 0 },
  "sendInvites": true,
  "emailsPending": 0,
  "emailsSent": 0,
  "emailsPausedReason": null,
  "error": null,
  "createdBy": { "type": "api_key", "id": "…", "name": "CRM sync" },
  "createdAt": "2026-10-29T14:03:12.000Z",
  "startedAt": null,
  "finishedAt": null
}

Poll GET /customer-imports/{id} every few seconds until status is completed, failed or cancelled. processed counts the rows done so far. GET /customer-imports lists the space's imports, newest first. Imports are kept for 30 days.

POST /customer-imports/{id}/cancel stops an import at the row in progress and sends no more of its emails. What it already did stays. Once it has finished, cancelling answers 409.

The import comes with a page of row results. Page through them with resultsOffset and resultsLimit (1 to 500, default 100) while resultsHasMore is true.

GET /customer-imports/{id}?resultsOffset=0&resultsLimit=100
{
  "id": "7f3c2a10-5b6d-4e8f-9a01-2b3c4d5e6f70",
  "object": "customer_import",
  "status": "completed",
  "total": 150,
  "processed": 150,
  "counts": { "created": 148, "updated": 2, "skipped": 0, "failed": 0 },
  "emailsPending": 0,
  "emailsSent": 2,
  "emailsPausedReason": null,
  …
  "results": [
    {
      "index": 0,
      "externalId": "crm_1042",
      "customerId": "aaaaaaaa-bbbb-4ccc-8ddd-eeeeeeeeeeee",
      "status": "created",
      "error": null,
      "contacts": [
        { "email": "ada@acme.com", "status": "invited", "inviteId": "…", "emailSent": true, "emailError": null },
        { "email": "grace@acme.com", "status": "added", "inviteId": null, "emailSent": false, "emailError": null }
      ]
    }
  ],
  "resultsHasMore": true
}

A row is created, updated, skipped (its externalId belongs to an archived customer), needs_manage_customers (it matched an existing customer and the key can't update it; counted as skipped) or failed, with error saying why.

Each contact has a status:

invited: a new invite. With sendInvites, emailSent turns true once the email has gone, and emailError says why if it couldn't.

added: a customer already in your space, now added to this customer.

already_member: already on this customer.

already_invited: already has a pending invite to this customer, so nothing new was made.

pending_other_invite: already has a pending invite to your space for something else.

on_other_customer: already belongs to another customer, so they weren't moved.

staff_not_added: an owner, admin or member of your space. Only customers are ever added to a customer.

needs_manage_customers: already in your space, and adding them needs Manage customers.

member_limit_reached: the space is at its plan's member limit, so no invite was made.

invalid: not an email address, or a role address such as postmaster@ or noreply@.

skipped: shown in place of the statuses that say whether someone is in your space, unless the key started the import or holds Manage members. Contact emails are null then too.

A bad address or a full space never fails the whole import.

The plan's member limit still applies. Members and pending invites both count, customers included: 250 on Premium. Contacts past it come back member_limit_reached. Make room or upgrade, then run the same import again.

Invite emails are paced at 500 an hour and 1,000 a day per space, so a big import's emails can keep going out after it completes. emailsPending counts the ones still waiting and emailsSent the ones gone. Imports don't count toward the 30 invites an hour limit.

Emails pause on their own if a recipient marks one as spam, or more than 5% bounce. Every import email in the space then waits, and emailsPausedReason on the import says why. Contact support to look at what happened and resume sending.

Invite links are never returned, here or anywhere in the API: they're secrets. Your customers get them by email, or you send and resend them from the app.

An import stops with failed if its key is revoked or loses Import customers, or the plan loses customer profiles; error says why.

Webhooks follow along: customer.created or customer.updated for each row, invite.created for each invite, member.joined as people accept, and customer.import_completed when it's done, with the counts.

What isn't in the API

Some things stay in the app on purpose.

AI customer briefs. A customer's AI account brief isn't available through the API.

Private and customer channel messages. Keys read and post only in public and announcement channels. Private channels, customer channels, Community channels and DMs are conversations between people.

Votes, follows and favorites. Voting on ideas and roadmap items, following calendar events and favoriting sounds are things people do for themselves. A key can't do them.

Playing soundboard sounds. Sounds play in a member's call, from their app. There's no way to play one from the server.

Webhooks

Webhooks tell your systems when something happens in the space, so an onboarding or offboarding script can react the moment someone joins or leaves instead of polling.

Setting up

Add an endpoint in the app under the space's Settings → Webhooks, or with POST /webhook-endpoints. You need the Manage webhooks permission and a Premium plan. A space can have 10 endpoints.

An endpoint is an https URL, an optional description and the event types it wants. Pick none and it gets every type it's allowed to see. The URL must use port 443 or a port from 1024 up and reach a public address. Redirects aren't followed.

Its signing secret (whsec_…) is shown once, when you create the endpoint. Copy it then. Send test in the app, or POST /webhook-endpoints/{id}/test, sends a webhook.test event to that endpoint only.

The payload

Every delivery is one event, as JSON:

{
  "id": "evt_01JCZ3Q8W4N9R6T2V5X7Y0B1C3",
  "object": "event",
  "type": "member.joined",
  "createdAt": "2026-10-29T14:03:12.000Z",
  "spaceId": "00000000-1111-4222-8333-444444444444",
  "actor": { "type": "member", "userId": "55555555-6666-4777-8888-999999999999" },
  "data": {
    "object": {
      "id": "aaaaaaaa-bbbb-4ccc-8ddd-eeeeeeeeeeee",
      "object": "member",
      "userId": "55555555-6666-4777-8888-999999999999",
      "displayName": "Ada Lovelace",
      "email": null,
      "role": "org_member",
      "nickname": null,
      "avatarUrl": null,
      "joinedAt": "2026-10-29T14:03:12.000Z"
    }
  }
}

data.object is the thing it happened to, in the same shape the API returns it: a member, invite, role, channel, message, customer, idea, roadmap item, calendar event or moderation log entry (see Objects below). So you rarely need a follow-up call.

Some types add fields next to object. member.left has reason: removed, kicked, banned or account_deleted. member.updated has previousRole when the base role changed, and addedRoleId or removedRoleId when a custom role was given or taken away. channel.removed carries only the channel's id, with reason deleted or made_private.

actor is who did it: { "type": "member", "userId" }, { "type": "api_key", "id", "name" }, or null when Probed did it on its own.

New event types and new fields can appear within v1. Ignore anything you don't recognise.

What an endpoint can see

An endpoint gets only what the person or key that created it could read through the API. Invite events need Invite people, moderation.action needs Moderate members, message events need Read messages, customer events need Manage customers, and idea events need Manage roadmap.

Member and invite emails are null unless the endpoint's creator could see emails (Manage members). The field is always there, so your schema holds either way.

Private, customer and Community channels never appear, and neither do their messages. When a public channel is deleted or made private, you get channel.removed and nothing more about it. Member reports never appear either.

An endpoint belongs to the space. It keeps what it can see when its creator leaves or loses a permission. If someone with fewer permissions edits its URL or event types, it narrows to what they hold.

Events

EventWhen
member.joinedSomeone joined the space, by accepting an invite or using a join link. Customers included.
member.updatedA member's base role or custom roles changed.
member.leftSomeone was removed, kicked or banned, or deleted their account. data.reason is removed, kicked, banned or account_deleted; data.object is the member as last known.
invite.createdAn invite was sent. Never carries the link.
invite.acceptedSomeone accepted an invite.
invite.revokedA pending invite was revoked.
role.createdA role was created.
role.updatedA role was renamed, recolored, reordered or given different permissions.
role.deletedA role was deleted.
channel.createdA public or announcement channel was created. Private, customer and Community channels never emit.
channel.updatedA public or announcement channel was renamed, described or moved.
channel.archivedA public or announcement channel was archived.
channel.restoredAn archived channel was restored.
channel.removedA public or announcement channel was deleted or made private. data.object carries only its id; data.reason is deleted or made_private.
moderation.actionA timeout, a timeout lifted, a kick, a ban or an unban. Member reports never emit.
message.createdSomeone (a member, an API key, a webhook or Probed itself) posted a message or a thread reply in a public or announcement text channel.
message.updatedA message was edited, pinned or unpinned. data.change is edited, pinned or unpinned.
message.deletedA message was deleted, by its author or a moderator. data.object is the message as it now reads: empty, with deleted: true.
customer.createdA customer was created.
customer.updatedA customer's name, description or contact email changed.
customer.archivedA customer was archived.
customer.member_addedSomeone was added to a customer. data.object is the customer member. Role changes don't emit.
customer.member_removedSomeone was removed from a customer. data.object is the customer member as last known.
customer.import_completedA bulk customer import finished (status completed) or stopped (failed). data.object is the import with its counts, without row results; invite emails may still be going out (emailsPending).
idea.createdAn idea was posted on the space's ideas board, or created through the API.
idea.updatedAn idea's status or board changed, or it was accepted onto the roadmap (roadmapItemId is then set).
idea.mergedA duplicate idea was merged into another. data.object is the idea it was merged into; data.mergedIdeaId is the one that's gone; data.movedVotes counts the votes that moved.
idea.deletedAn idea was deleted, with its votes. data.object carries only its id. A merge sends idea.merged instead.
roadmap_item.createdA roadmap item was created, directly or by accepting an idea.
roadmap_item.updatedA roadmap item was renamed, described, moved to another board or given a new status.
roadmap_item.deletedA roadmap item was deleted. data.object is the item as last known. Ideas accepted as it are unlinked without an idea.updated; deleting a board sends nothing for the items and ideas filed under it.
calendar_event.createdA calendar event was scheduled.
calendar_event.updatedA calendar event's title, description, place, time, recurrence or linked channel changed.
calendar_event.deletedA calendar event was deleted. data.object is the event as last known. Deleting a calendar event template sends nothing for the events made from it.
webhook.testSent by Send test (POST /webhook-endpoints/{id}/test) to that endpoint only. data.object is {}.

Delivery and retries

Probed sends an HTTPS POST with the JSON body and these headers, which follow Standard Webhooks: webhook-id (the event id), webhook-timestamp (Unix seconds), webhook-signature, and user-agent: Probed-Webhooks/1.

Answer with any 2xx within 10 seconds. Do slow work after you answer, from a queue. Any other status, a redirect or a timeout counts as a failure.

Delivery is at least once and in no set order. The same event can arrive more than once, so dedupe on webhook-id, which stays the same on every attempt. When order matters, compare createdAt or fetch the object.

A failed delivery is tried again after 1 minute, 5 minutes, 30 minutes, 2 hours, 5 hours, 10 hours, 14 hours and 20 hours: 9 attempts over about 2 days. After the last one it's marked failed.

An endpoint that keeps failing for 3 days is turned off, and everyone in the space who can manage webhooks gets an email. Fix it, then turn it back on in Settings → Webhooks, or with PATCH /webhook-endpoints/{id} and "enabled": true.

Each endpoint has a delivery log, in the app or from GET /webhook-endpoints/{id}/deliveries, with the status code, the time and the start of your response. Retry a delivery from the app or with POST /webhook-endpoints/{id}/deliveries/{deliveryId}/retry.

Missed some? GET /events lists the space's events from the last 30 days, with the same bodies webhooks send, so you can catch up.

Verifying signatures

Check the signature before you trust a request. It proves the request came from Probed and wasn't changed on the way.

The signed content is {webhook-id}.{webhook-timestamp}.{body}, with the body exactly as it arrived. Verify before you parse the JSON: parsing and re-encoding changes the bytes. The key is the part of the secret after whsec_, base64-decoded. The signature is the HMAC-SHA256 of the signed content, base64-encoded.

webhook-signature holds one or more v1,<signature> values separated by spaces. After you rotate the secret with POST /webhook-endpoints/{id}/rotate-secret, the old secret keeps signing too for 24 hours, so the header carries both. Accept the request if any one matches, and compare in constant time.

Reject a webhook-timestamp more than 5 minutes away from your clock, so a captured request can't be replayed later.

TypeScript

import { createHmac, timingSafeEqual } from "node:crypto";

// headers: lowercase names, e.g. Object.fromEntries(request.headers).
// body: the raw body as received, e.g. await request.text().
export function verifyWebhook(
  secret: string,
  headers: Record<string, string>,
  body: string
): boolean {
  const id = headers["webhook-id"];
  const timestamp = headers["webhook-timestamp"];
  const signatures = headers["webhook-signature"];
  if (!id || !timestamp || !signatures) return false;

  // Refuse anything more than 5 minutes off, so an old request can't be replayed.
  const now = Math.floor(Date.now() / 1000);
  if (Math.abs(now - Number(timestamp)) > 5 * 60) return false;

  const key = Buffer.from(secret.replace(/^whsec_/, ""), "base64");
  const expected = createHmac("sha256", key)
    .update(`${id}.${timestamp}.${body}`)
    .digest();

  // During a secret rotation the header holds two signatures.
  return signatures.split(" ").some((part) => {
    const [version, sig] = part.split(",");
    if (version !== "v1" || !sig) return false;
    const got = Buffer.from(sig, "base64");
    return got.length === expected.length && timingSafeEqual(got, expected);
  });
}

Python

import base64, hashlib, hmac, time

# headers: lowercase names. body: the raw bytes as received, before parsing.
def verify_webhook(secret: str, headers: dict, body: bytes) -> bool:
    msg_id = headers.get("webhook-id")
    timestamp = headers.get("webhook-timestamp")
    signatures = headers.get("webhook-signature")
    if not msg_id or not timestamp or not signatures:
        return False

    # Refuse anything more than 5 minutes off, so an old request can't be replayed.
    try:
        if abs(time.time() - int(timestamp)) > 5 * 60:
            return False
    except ValueError:
        return False

    key = base64.b64decode(secret.removeprefix("whsec_"))
    signed = f"{msg_id}.{timestamp}.".encode() + body
    expected = base64.b64encode(hmac.new(key, signed, hashlib.sha256).digest()).decode()

    # During a secret rotation the header holds two signatures.
    for part in signatures.split(" "):
        version, _, sig = part.partition(",")
        if version == "v1" and hmac.compare_digest(sig, expected):
            return True
    return False

Go

import (
	"crypto/hmac"
	"crypto/sha256"
	"encoding/base64"
	"net/http"
	"strconv"
	"strings"
	"time"
)

// body is the raw request body, read before any JSON decoding.
func VerifyWebhook(secret string, h http.Header, body []byte) bool {
	id := h.Get("webhook-id")
	timestamp := h.Get("webhook-timestamp")
	signatures := h.Get("webhook-signature")
	if id == "" || timestamp == "" || signatures == "" {
		return false
	}

	// Refuse anything more than 5 minutes off, so an old request can't be replayed.
	ts, err := strconv.ParseInt(timestamp, 10, 64)
	if err != nil {
		return false
	}
	if d := time.Now().Unix() - ts; d > 5*60 || d < -5*60 {
		return false
	}

	key, err := base64.StdEncoding.DecodeString(strings.TrimPrefix(secret, "whsec_"))
	if err != nil {
		return false
	}
	mac := hmac.New(sha256.New, key)
	mac.Write([]byte(id + "." + timestamp + "."))
	mac.Write(body)
	expected := mac.Sum(nil)

	// During a secret rotation the header holds two signatures.
	for _, part := range strings.Split(signatures, " ") {
		version, sig, ok := strings.Cut(part, ",")
		if !ok || version != "v1" {
			continue
		}
		got, err := base64.StdEncoding.DecodeString(sig)
		if err == nil && hmac.Equal(got, expected) {
			return true
		}
	}
	return false
}

Or use one of the official Standard Webhooks libraries, which do the same checks in most languages and take the whsec_ secret as is.

Endpoints

API keys

POST/self/revoke

Revoke the API key making this request

For a key you believe has leaked. Takes effect immediately, works on any plan, and can't be undone.

Returns RevokedApiKey · errors 401, 500

Space

GET/space

Get the space this API key belongs to

Returns Space · errors 401, 402, 404, 429, 500

Members

GET/members

List members

Staff and community members, oldest first. Customers aren't included. Emails are null unless the key holds Manage members.

ParameterTypeDescription
limitquery · string1 to 100. Defaults to 25.
cursorquery · stringnextCursor from the previous page.

Returns MemberList · errors 400, 401, 402, 404, 429, 500

GET/members/{id}

Get a member

ParameterTypeDescription
{id}requiredpath · string

Returns Member · errors 401, 402, 404, 429, 500

PATCH/members/{id}

Change a member's role

Needs Manage roles. A key can't change an owner or make anyone an owner, and the new role can't carry permissions the key doesn't hold.

ParameterTypeDescription
{id}requiredpath · string

Returns Member · errors 400, 401, 402, 403, 404, 409, 429, 500

DELETE/members/{id}

Remove a member from the space

Needs Manage members. A key can't remove an owner. They can rejoin with a new invite.

ParameterTypeDescription
{id}requiredpath · string

Returns DeletedMember · errors 400, 401, 402, 403, 404, 409, 429, 500

POST/members/{id}/roles/{roleId}

Give a member a role

Needs Manage members or Manage roles. A key can give only custom roles that can't do more than the key can, and can't change an owner's or admin's roles. Custom roles need a plan with custom roles. Giving a role someone already holds changes nothing.

ParameterTypeDescription
{id}requiredpath · stringThe member id.
{roleId}requiredpath · string
idempotency-keyheader · stringRetry with the same value and you get the first answer back instead of doing it twice.

Returns RoleAssignment · errors 400, 401, 402, 403, 404, 409, 429, 500

DELETE/members/{id}/roles/{roleId}

Take a role away from a member

Needs Manage members or Manage roles. A key can take away only custom roles that can't do more than the key can, and can't change an owner's or admin's roles.

ParameterTypeDescription
{id}requiredpath · stringThe member id.
{roleId}requiredpath · string

Returns DeletedRoleAssignment · errors 400, 401, 402, 403, 404, 409, 429, 500

Invites

GET/invites

List pending invites

Invites nobody has accepted yet, oldest first, including expired ones. Needs Manage invites. Invite links aren't included.

ParameterTypeDescription
limitquery · string1 to 100. Defaults to 25.
cursorquery · stringnextCursor from the previous page.

Returns InviteList · errors 400, 401, 402, 403, 404, 409, 429, 500

POST/invites

Invite someone by email

Emails them a link that lasts 7 days. Needs Manage invites; the role they join with can't carry permissions the key doesn't hold. A key can send 30 invites an hour.

ParameterTypeDescription
idempotency-keyheader · stringRetry with the same value and you get the first answer back instead of doing it twice.

Returns CreatedInvite · errors 400, 401, 402, 403, 404, 409, 429, 500

DELETE/invites/{id}

Revoke a pending invite

Its link stops working. Needs Manage invites.

ParameterTypeDescription
{id}requiredpath · string

Returns DeletedInvite · errors 400, 401, 402, 403, 404, 409, 429, 500

Roles

GET/roles

List roles

Every role in the space in list order, built-in ones included. Any key can read them.

Returns RoleList · errors 401, 402, 404, 429, 500

POST/roles

Create a role

Needs Manage roles and a plan with custom roles. The role can't carry permissions the key doesn't hold.

ParameterTypeDescription
idempotency-keyheader · stringRetry with the same value and you get the first answer back instead of doing it twice.

Returns Role · errors 400, 401, 402, 403, 404, 409, 429, 500

PATCH/roles/{id}

Edit a role

Needs Manage roles and a plan with custom roles. A key can edit only custom roles that can't do more than the key can, and can't give them more.

ParameterTypeDescription
{id}requiredpath · string

Returns Role · errors 400, 401, 402, 403, 404, 409, 429, 500

DELETE/roles/{id}

Delete a role

Needs Manage roles. Everyone holding it loses it. Built-in roles can't be deleted, and a key can't delete a role that can do more than the key can.

ParameterTypeDescription
{id}requiredpath · string

Returns DeletedRole · errors 400, 401, 402, 403, 404, 409, 429, 500

PUT/roles/order

Reorder roles

Needs Manage roles and a plan with custom roles. A key can only move custom roles that can't do more than the key can, so a reorder that would shift any other role is refused.

Returns RoleList · errors 400, 401, 402, 403, 404, 409, 429, 500

Channels

GET/channels

List channels

The space's public and announcement channels, oldest first. Private channels, customer channels and archived channels aren't included; pass archived=true for archived ones too. Any key can read them.

ParameterTypeDescription
limitquery · string1 to 100. Defaults to 25.
cursorquery · stringnextCursor from the previous page.
archivedquery · "true" | "false"true to include archived channels. Defaults to false.

Returns ChannelList · errors 400, 401, 402, 404, 429, 500

POST/channels

Create a channel

Every member of the space joins it. Needs Manage channels. It counts toward the plan's channel limit. API keys can't create private channels yet.

ParameterTypeDescription
idempotency-keyheader · stringRetry with the same value and you get the first answer back instead of doing it twice.

Returns Channel · errors 400, 401, 402, 403, 404, 409, 429, 500

GET/channels/{id}

Get a channel

A public or announcement channel, archived or not. Private and customer channels answer 404.

ParameterTypeDescription
{id}requiredpath · string

Returns Channel · errors 401, 402, 404, 429, 500

PATCH/channels/{id}

Edit a channel

Rename it, change its description or move it to another section. Needs Manage channels. Archived channels can't be edited; restore them first.

ParameterTypeDescription
{id}requiredpath · string

Returns Channel · errors 400, 401, 402, 403, 404, 409, 429, 500

POST/channels/{id}/archive

Archive a channel

Makes it read-only and frees its place in the plan's channel limit. History is kept, and a note naming the key is posted in it. Needs Manage channels. Archiving an archived channel changes nothing.

ParameterTypeDescription
{id}requiredpath · string
idempotency-keyheader · stringRetry with the same value and you get the first answer back instead of doing it twice.

Returns Channel · errors 400, 401, 402, 403, 404, 409, 429, 500

POST/channels/{id}/restore

Restore an archived channel

Makes it writable again. It has to fit in the plan's channel limit. Needs Manage channels. Restoring an active channel changes nothing.

ParameterTypeDescription
{id}requiredpath · string
idempotency-keyheader · stringRetry with the same value and you get the first answer back instead of doing it twice.

Returns Channel · errors 400, 401, 402, 403, 404, 409, 429, 500

Sections

GET/sections

List sections

The groups channels are listed under in the sidebar, in order. Any key can read them.

Returns SectionList · errors 401, 402, 404, 429, 500

POST/sections

Create a section

Added at the end of the list. Needs Manage sections.

ParameterTypeDescription
idempotency-keyheader · stringRetry with the same value and you get the first answer back instead of doing it twice.

Returns Section · errors 400, 401, 402, 403, 404, 409, 429, 500

PATCH/sections/{id}

Rename a section

Needs Manage sections.

ParameterTypeDescription
{id}requiredpath · string

Returns Section · errors 400, 401, 402, 403, 404, 409, 429, 500

DELETE/sections/{id}

Delete a section

Its channels move to the default section. The default section can't be deleted. Needs Manage sections.

ParameterTypeDescription
{id}requiredpath · string

Returns DeletedSection · errors 400, 401, 402, 403, 404, 409, 429, 500

PUT/sections/order

Reorder sections

Needs Manage sections.

Returns SectionList · errors 400, 401, 402, 403, 404, 409, 429, 500

Moderation

POST/moderation/timeouts

Time a member out

They can't post, react or speak in the space until it ends. Needs Moderate members. A key can't time out an owner or an admin. A key can time out 20 people every 10 minutes.

ParameterTypeDescription
idempotency-keyheader · stringRetry with the same value and you get the first answer back instead of doing it twice.

Returns ModerationLogEntry · errors 400, 401, 402, 403, 404, 409, 429, 500

DELETE/moderation/timeouts/{userId}

End a timeout early

Needs Moderate members.

ParameterTypeDescription
{userId}requiredpath · string

Returns ModerationLogEntry · errors 400, 401, 402, 403, 404, 409, 429, 500

POST/moderation/kicks

Kick a member

Removes them from the space. They can rejoin with a new invite. Needs Kick members. A key can't kick an owner or an admin.

ParameterTypeDescription
idempotency-keyheader · stringRetry with the same value and you get the first answer back instead of doing it twice.

Returns ModerationLogEntry · errors 400, 401, 402, 403, 404, 409, 429, 500

POST/moderation/bans

Ban someone

Removes them from the space and stops them rejoining until they're unbanned. Works for people who aren't members too. Needs Ban members. A key can't ban an owner or an admin.

ParameterTypeDescription
idempotency-keyheader · stringRetry with the same value and you get the first answer back instead of doing it twice.

Returns ModerationLogEntry · errors 400, 401, 402, 403, 404, 409, 429, 500

DELETE/moderation/bans/{userId}

Lift a ban

They can join again with an invite. Needs Ban members.

ParameterTypeDescription
{userId}requiredpath · string

Returns ModerationLogEntry · errors 400, 401, 402, 403, 404, 409, 429, 500

GET/moderation/active

List running timeouts and bans

Newest first. Needs Moderate members.

Returns ActiveModeration · errors 401, 402, 403, 404, 429, 500

GET/moderation/log

Read the moderation log

Every moderation action in the space, newest first. Reports members file aren't included; read those in the app. Needs Moderate members.

ParameterTypeDescription
limitquery · string1 to 100. Defaults to 25.
cursorquery · stringnextCursor from the previous page.

Returns ModerationLog · errors 400, 401, 402, 403, 404, 429, 500

Webhooks

GET/webhook-endpoints

List webhook endpoints

Oldest first. A space has at most 10. Secrets aren't included. Needs Manage webhooks.

Returns WebhookEndpointList · errors 401, 402, 403, 404, 429, 500

POST/webhook-endpoints

Create a webhook endpoint

Probed starts sending it events straight away, signed with the secret in this answer, which is never shown again. It receives what the key could read through the API: member and invite events carry emails only when the key holds Manage members, invite events need Manage invites and moderation events Moderate members. An Idempotency-Key replay answers with the same endpoint and secret: null. A space can have 10. Needs Manage webhooks.

ParameterTypeDescription
idempotency-keyheader · stringRetry with the same value and you get the first answer back instead of doing it twice.

Returns WebhookEndpointWithSecret · errors 400, 401, 402, 403, 404, 409, 429, 500

GET/webhook-endpoints/{id}

Get a webhook endpoint

Needs Manage webhooks.

ParameterTypeDescription
{id}requiredpath · string

Returns WebhookEndpoint · errors 401, 402, 403, 404, 429, 500

PATCH/webhook-endpoints/{id}

Edit a webhook endpoint

Change its URL, description or event types, or turn it off and on. Changing the URL or event types narrows what it receives to what this key could read too, and deliveries from before a URL change can't be retried. Turning back on an endpoint Probed disabled clears the reason. Needs Manage webhooks.

ParameterTypeDescription
{id}requiredpath · string

Returns WebhookEndpoint · errors 400, 401, 402, 403, 404, 409, 429, 500

DELETE/webhook-endpoints/{id}

Delete a webhook endpoint

Nothing more is sent to it, including deliveries waiting to retry. Needs Manage webhooks.

ParameterTypeDescription
{id}requiredpath · string

Returns DeletedWebhookEndpoint · errors 400, 401, 402, 403, 404, 409, 429, 500

POST/webhook-endpoints/{id}/rotate-secret

Rotate a webhook endpoint's signing secret

The new secret is in this answer only. For 24 hours deliveries carry a signature from the old secret too, so you can switch over without missing one. The key needs every permission the endpoint receives with (Manage members, Manage invites, Moderate members). Needs Manage webhooks.

ParameterTypeDescription
{id}requiredpath · string
idempotency-keyheader · stringRetry with the same value and you get the first answer back instead of doing it twice.

Returns WebhookEndpointWithSecret · errors 400, 401, 402, 403, 404, 409, 429, 500

POST/webhook-endpoints/{id}/test

Send a test event

Queues a webhook.test event for this endpoint only, sent within seconds. The endpoint has to be enabled. 5 tests a minute per endpoint, and 30 an hour per key. Needs Manage webhooks.

ParameterTypeDescription
{id}requiredpath · string
idempotency-keyheader · stringRetry with the same value and you get the first answer back instead of doing it twice.

Returns WebhookDelivery · errors 400, 401, 402, 403, 404, 409, 429, 500

GET/webhook-endpoints/{id}/deliveries

List an endpoint's deliveries

Newest first, from the last 30 days. Only event types both the endpoint and the key may receive are listed. Needs Manage webhooks.

ParameterTypeDescription
{id}requiredpath · string
limitquery · string1 to 100. Defaults to 25.
cursorquery · stringnextCursor from the previous page.

Returns WebhookDeliveryList · errors 400, 401, 402, 403, 404, 429, 500

POST/webhook-endpoints/{id}/deliveries/{deliveryId}/retry

Retry a delivery

Sends a finished delivery (succeeded, failed or skipped) again now, with a fresh set of retries. A delivery still pending is already queued, a disabled endpoint has to be enabled first, and deliveries from before the endpoint's URL last changed can't be retried. A key can retry 30 deliveries a minute per endpoint. Needs Manage webhooks.

ParameterTypeDescription
{id}requiredpath · stringThe webhook endpoint id.
{deliveryId}requiredpath · string
idempotency-keyheader · stringRetry with the same value and you get the first answer back instead of doing it twice.

Returns WebhookDelivery · errors 400, 401, 402, 403, 404, 409, 429, 500

Events

GET/events

List events

The space's events from the last 30 days, newest first: what webhooks deliver, for catching up on ones you missed. Any key can read them, except invite events (need Manage invites) and moderation events (need Moderate members). Emails are null unless the key holds Manage members.

ParameterTypeDescription
limitquery · string1 to 100. Defaults to 25.
cursorquery · stringnextCursor from the previous page.
typequery · "member.joined" | "member.updated" | "member.left" | "invite.created" | "invite.accepted" | "invite.revoked" | "role.created" | "role.updated" | "role.deleted" | "channel.created" | "channel.updated" | "channel.archived" | "channel.restored" | "channel.removed" | "moderation.action" | "message.created" | "message.updated" | "message.deleted" | "customer.created" | "customer.updated" | "customer.archived" | "customer.member_added" | "customer.member_removed" | "customer.import_completed" | "idea.created" | "idea.updated" | "idea.merged" | "idea.deleted" | "roadmap_item.created" | "roadmap_item.updated" | "roadmap_item.deleted" | "calendar_event.created" | "calendar_event.updated" | "calendar_event.deleted" | "webhook.test"Only events of this type.

Returns EventList · errors 400, 401, 402, 403, 404, 429, 500

GET/events/{id}

Get an event

An event from the last 30 days, by the id webhooks send as webhook-id. Types the key can't read answer 404.

ParameterTypeDescription
{id}requiredpath · string

Returns Event · errors 401, 402, 404, 429, 500

Messages

GET/channels/{id}/messages

List a channel's messages

Top-level messages (and replies also sent to the channel), oldest first, newest page by default. Needs Read messages. Public and announcement text channels only; private, customer and Community channels, voice channels and DMs answer 404.

ParameterTypeDescription
{id}requiredpath · stringThe channel's id.
limitquery · string1 to 100. Defaults to 25.
beforequery · stringA message id: the page of messages just before it. Without before or after, the newest page.
afterquery · stringA message id: the page of messages just after it.

Returns MessageList · errors 400, 401, 402, 403, 404, 429, 500

POST/channels/{id}/messages

Post a message

Posts as the key's bot, under the key's name. Needs Send messages; announcement channels also need Manage channels, and mentioning everyone needs Mention everyone. Slow mode applies to the bot; archived channels refuse with 409. A key can post 60 messages and mention 200 people a minute, and keys can mention everyone in a channel once every 10 minutes. Attachments are described by what was stored, not by the request. Public and announcement text channels only; private, customer and Community channels, voice channels and DMs answer 404.

ParameterTypeDescription
{id}requiredpath · stringThe channel's id.
idempotency-keyheader · stringRetry with the same value and you get the first answer back instead of doing it twice.

Returns Message · errors 400, 401, 402, 403, 404, 409, 429, 500, 503

GET/channels/{id}/messages/{messageId}

Get a message

Deleted messages answer with deleted: true and no content. Needs Read messages. Public and announcement text channels only; private, customer and Community channels, voice channels and DMs answer 404.

ParameterTypeDescription
{id}requiredpath · stringThe channel's id.
{messageId}requiredpath · string

Returns Message · errors 400, 401, 402, 403, 404, 429, 500

PATCH/channels/{id}/messages/{messageId}

Edit a message

Only messages this key's bot posted (any key of its rotation). Needs Send messages, and Manage channels in an announcement channel.

ParameterTypeDescription
{id}requiredpath · stringThe channel's id.
{messageId}requiredpath · string

Returns Message · errors 400, 401, 402, 403, 404, 409, 429, 500, 503

DELETE/channels/{id}/messages/{messageId}

Delete a message

The key's own messages with Send messages; anyone's with Manage messages, recorded in the moderation log under the key.

ParameterTypeDescription
{id}requiredpath · stringThe channel's id.
{messageId}requiredpath · string

Returns DeletedMessage · errors 400, 401, 402, 403, 404, 409, 429, 500

GET/channels/{id}/messages/{messageId}/replies

List a message's thread replies

Oldest first, newest page by default. Needs Read messages. Public and announcement text channels only; private, customer and Community channels, voice channels and DMs answer 404.

ParameterTypeDescription
{id}requiredpath · stringThe channel's id.
{messageId}requiredpath · string
limitquery · string1 to 100. Defaults to 25.
beforequery · stringA reply's id: the replies just before it. Without it, the newest replies.

Returns MessageList · errors 400, 401, 402, 403, 404, 429, 500

GET/channels/{id}/pins

List a channel's pinned messages

Most recently pinned first, up to 100. Needs Read messages. Public and announcement text channels only; private, customer and Community channels, voice channels and DMs answer 404.

ParameterTypeDescription
{id}requiredpath · stringThe channel's id.

Returns MessageList · errors 400, 401, 402, 403, 404, 429, 500

PUT/channels/{id}/messages/{messageId}/reactions/{type}

React to a message

As the key's bot. Reacting twice with the same type changes nothing. Needs Add reactions and Read messages.

ParameterTypeDescription
{id}requiredpath · stringThe channel's id.
{messageId}requiredpath · string
{type}requiredpath · stringThe reaction, such as an emoji. Up to 64 characters.

Returns Message · errors 400, 401, 402, 403, 404, 409, 429, 500

DELETE/channels/{id}/messages/{messageId}/reactions/{type}

Remove the key's reaction

Only the key's bot's own reaction. Needs Add reactions and Read messages.

ParameterTypeDescription
{id}requiredpath · stringThe channel's id.
{messageId}requiredpath · string
{type}requiredpath · stringThe reaction, such as an emoji. Up to 64 characters.

Returns Message · errors 400, 401, 402, 403, 404, 409, 429, 500

PUT/channels/{id}/messages/{messageId}/pin

Pin a message

Pinning a pinned message changes nothing. Needs Pin messages and Read messages.

ParameterTypeDescription
{id}requiredpath · stringThe channel's id.
{messageId}requiredpath · string

Returns Message · errors 400, 401, 402, 403, 404, 409, 429, 500

DELETE/channels/{id}/messages/{messageId}/pin

Unpin a message

Needs Pin messages and Read messages.

ParameterTypeDescription
{id}requiredpath · stringThe channel's id.
{messageId}requiredpath · string

Returns Message · errors 400, 401, 402, 403, 404, 409, 429, 500

POST/uploads

Upload a file

Multipart, with the file in a file field, up to 8 MB. Returns the attachment to send in a message. Photo location and camera metadata are removed. HTML, SVG, XML, scripts and executables are refused. Keys can upload 2 GB a day per space. Needs Upload files.

ParameterTypeDescription
idempotency-keyheader · stringRetry with the same value and you get the first answer back instead of doing it twice.

Returns Upload · errors 400, 401, 402, 403, 404, 409, 413, 429, 500, 503

Customers

GET/customers

List customers

The space's customers (customer organizations), oldest first. Archived ones aren't included. Needs Manage customers. A customer's private channel, its messages and its AI account brief aren't available through the API.

ParameterTypeDescription
limitquery · string1 to 100. Defaults to 25.
cursorquery · stringnextCursor from the previous page.

Returns CustomerList · errors 400, 401, 402, 403, 404, 409, 429, 500

POST/customers

Create a customer

Also creates the customer's private channel, moderated by the space's owners and admins. Needs Manage customers and a plan with customer profiles.

ParameterTypeDescription
idempotency-keyheader · stringRetry with the same value and you get the first answer back instead of doing it twice.

Returns Customer · errors 400, 401, 402, 403, 404, 409, 429, 500

GET/customers/{id}

Get a customer

404 for an archived customer. Needs Manage customers.

ParameterTypeDescription
{id}requiredpath · string

Returns Customer · errors 400, 401, 402, 403, 404, 409, 429, 500

PATCH/customers/{id}

Update a customer

Send at least one field. Needs Manage customers and a plan with customer profiles.

ParameterTypeDescription
{id}requiredpath · string

Returns Customer · errors 400, 401, 402, 403, 404, 409, 429, 500

DELETE/customers/{id}

Archive a customer

Archives rather than deletes: the customer and its history stay, and it drops out of the list. Needs Manage customers.

ParameterTypeDescription
{id}requiredpath · string

Returns Customer · errors 400, 401, 402, 403, 404, 409, 429, 500

GET/customers/{id}/members

List a customer's members

The people on the customer, oldest first. Needs Manage customers. Emails need Manage members too.

ParameterTypeDescription
{id}requiredpath · string

Returns CustomerMemberList · errors 400, 401, 402, 403, 404, 409, 429, 500

POST/customers/{id}/members

Add someone to a customer

They must already be in the space; to bring in someone new, send a customer invite. Adding someone already on the customer sets their role. Needs Manage customers and a plan with customer profiles.

ParameterTypeDescription
{id}requiredpath · string
idempotency-keyheader · stringRetry with the same value and you get the first answer back instead of doing it twice.

Returns CustomerMember · errors 400, 401, 402, 403, 404, 409, 429, 500

PATCH/customers/{id}/members/{memberId}

Change a customer member's role

Needs Manage customers and a plan with customer profiles.

ParameterTypeDescription
{id}requiredpath · string
{memberId}requiredpath · string

Returns CustomerMember · errors 400, 401, 402, 403, 404, 409, 429, 500

DELETE/customers/{id}/members/{memberId}

Remove someone from a customer

They stay in the space. Needs Manage customers.

ParameterTypeDescription
{id}requiredpath · string
{memberId}requiredpath · string

Returns DeletedCustomerMember · errors 400, 401, 402, 403, 404, 409, 429, 500

POST/customers/{id}/invites

Invite someone to a customer

They join the space as a customer and land on this customer. No email is sent: share url with them. Counts toward the key's invite limit. Needs Manage customers and a plan with customer profiles.

ParameterTypeDescription
{id}requiredpath · string
idempotency-keyheader · stringRetry with the same value and you get the first answer back instead of doing it twice.

Returns CreatedInvite · errors 400, 401, 402, 403, 404, 409, 429, 500

POST/customers/import

Import customers in bulk

Queues up to 500 customers, each with up to 25 contacts, and answers straight away; follow it with GET /customer-imports/{id}. Each row creates a customer with its private channel, and invites its new contacts as customers. Updating the customer with the row's externalId, and adding contacts who are already customers of the space, need Manage customers too. The plan's member limit applies per contact. One import at a time per space. Needs Import customers and a plan with customer profiles.

ParameterTypeDescription
idempotency-keyheader · stringRetry with the same value and you get the first answer back instead of doing it twice.

Returns CustomerImport · errors 400, 401, 402, 403, 404, 409, 429, 500, 503

GET/customer-imports

List customer imports

Newest first, without row results. Needs Import customers.

ParameterTypeDescription
limitquery · string1 to 100. Defaults to 25.
cursorquery · stringnextCursor from the previous page.

Returns CustomerImportList · errors 400, 401, 402, 403, 404, 409, 429, 500

GET/customer-imports/{id}

Get a customer import

Its progress and a page of row results. Imports are kept for 30 days. Needs Import customers.

ParameterTypeDescription
{id}requiredpath · string
resultsOffsetquery · stringThe first row result to return. Defaults to 0.
resultsLimitquery · string1 to 500. Defaults to 100.

Returns CustomerImportDetail · errors 400, 401, 402, 403, 404, 409, 429, 500

POST/customer-imports/{id}/cancel

Cancel a customer import

Stops it at the row in progress and sends no more of its invite emails; what it already did stays. 409 once it has finished. Needs Import customers.

ParameterTypeDescription
{id}requiredpath · string
idempotency-keyheader · stringRetry with the same value and you get the first answer back instead of doing it twice.

Returns CustomerImport · errors 400, 401, 402, 403, 404, 409, 429, 500

Tags and notes

GET/tags

List tags

The space's member tags. Needs Manage customers.

Returns TagList · errors 400, 401, 402, 403, 404, 409, 429, 500

POST/tags

Create a tag

Names are unique in the space. Needs Manage customers and a plan with customer profiles.

ParameterTypeDescription
idempotency-keyheader · stringRetry with the same value and you get the first answer back instead of doing it twice.

Returns Tag · errors 400, 401, 402, 403, 404, 409, 429, 500

DELETE/tags/{id}

Delete a tag

Also takes it off everyone who has it. Needs Manage customers.

ParameterTypeDescription
{id}requiredpath · string

Returns DeletedTag · errors 400, 401, 402, 403, 404, 409, 429, 500

GET/members/{id}/tags

List a member's tags

Customers included. Needs Manage customers.

ParameterTypeDescription
{id}requiredpath · string

Returns TagList · errors 400, 401, 402, 403, 404, 409, 429, 500

PUT/members/{id}/tags/{tagId}

Tag a member

Tagging someone who already has the tag changes nothing. Needs Manage customers and a plan with customer profiles.

ParameterTypeDescription
{id}requiredpath · string
{tagId}requiredpath · string

Returns TagAssignment · errors 400, 401, 402, 403, 404, 409, 429, 500

DELETE/members/{id}/tags/{tagId}

Untag a member

Needs Manage customers.

ParameterTypeDescription
{id}requiredpath · string
{tagId}requiredpath · string

Returns DeletedTagAssignment · errors 400, 401, 402, 403, 404, 409, 429, 500

GET/members/{id}/notes

List notes on a member

Internal notes, oldest first: never shown to the member. Notes written by people and by API keys alike. Needs Manage customers.

ParameterTypeDescription
{id}requiredpath · string

Returns NoteList · errors 400, 401, 402, 403, 404, 409, 429, 500

POST/members/{id}/notes

Add a note on a member

Shown in the app under the key's label. Needs Manage customers and a plan with customer profiles.

ParameterTypeDescription
{id}requiredpath · string
idempotency-keyheader · stringRetry with the same value and you get the first answer back instead of doing it twice.

Returns Note · errors 400, 401, 402, 403, 404, 409, 429, 500

DELETE/members/{id}/notes/{noteId}

Delete a note

Anyone's note on the member, not just the key's own. Needs Manage customers.

ParameterTypeDescription
{id}requiredpath · string
{noteId}requiredpath · string

Returns DeletedNote · errors 400, 401, 402, 403, 404, 409, 429, 500

Canned responses

GET/canned-responses

List canned responses

Saved replies, oldest first. Needs Manage customers.

Returns CannedResponseList · errors 400, 401, 402, 403, 404, 409, 429, 500

POST/canned-responses

Create a canned response

Needs Manage customers and a plan with canned responses. Shortcuts are unique in the space.

ParameterTypeDescription
idempotency-keyheader · stringRetry with the same value and you get the first answer back instead of doing it twice.

Returns CannedResponse · errors 400, 401, 402, 403, 404, 409, 429, 500

PATCH/canned-responses/{id}

Update a canned response

Send at least one field. Needs Manage customers.

ParameterTypeDescription
{id}requiredpath · string

Returns CannedResponse · errors 400, 401, 402, 403, 404, 409, 429, 500

DELETE/canned-responses/{id}

Delete a canned response

Needs Manage customers.

ParameterTypeDescription
{id}requiredpath · string

Returns DeletedCannedResponse · errors 400, 401, 402, 403, 404, 409, 429, 500

Badges

GET/badges

List badges

The space's badges. Any key can read them, as any member can in the app.

Returns BadgeList · errors 400, 401, 402, 403, 404, 409, 429, 500

POST/badges

Create a badge

Needs Manage badges and a plan with custom badges. Names are unique in the space.

ParameterTypeDescription
idempotency-keyheader · stringRetry with the same value and you get the first answer back instead of doing it twice.

Returns Badge · errors 400, 401, 402, 403, 404, 409, 429, 500

PATCH/badges/{id}

Update a badge

Send at least one field. Needs Manage badges.

ParameterTypeDescription
{id}requiredpath · string

Returns Badge · errors 400, 401, 402, 403, 404, 409, 429, 500

DELETE/badges/{id}

Delete a badge

Also takes it off everyone who has it. Needs Manage badges.

ParameterTypeDescription
{id}requiredpath · string

Returns DeletedBadge · errors 400, 401, 402, 403, 404, 409, 429, 500

PUT/members/{id}/badges/{badgeId}

Give a member a badge

Customers included. Giving a badge someone already has changes nothing. Needs Manage badges.

ParameterTypeDescription
{id}requiredpath · string
{badgeId}requiredpath · string

Returns BadgeAssignment · errors 400, 401, 402, 403, 404, 409, 429, 500

DELETE/members/{id}/badges/{badgeId}

Take a badge away from a member

Needs Manage badges.

ParameterTypeDescription
{id}requiredpath · string
{badgeId}requiredpath · string

Returns DeletedBadgeAssignment · errors 400, 401, 402, 403, 404, 409, 429, 500

Ideas

GET/ideas

List ideas

Ideas from the space's ideas board, oldest first. Needs Manage roadmap.

ParameterTypeDescription
limitquery · string1 to 100. Defaults to 25.
cursorquery · stringnextCursor from the previous page.
statusquery · "open" | "planned" | "in_progress" | "completed"Only ideas with this status.
boardIdquery · stringOnly ideas filed under this board.

Returns IdeaList · errors 400, 401, 402, 403, 404, 429, 500

POST/ideas

Create an idea

Posts it on the ideas board under the key's name, open and without votes. Needs Manage roadmap. API keys can't vote.

ParameterTypeDescription
idempotency-keyheader · stringRetry with the same value and you get the first answer back instead of doing it twice.

Returns Idea · errors 400, 401, 402, 403, 404, 409, 429, 500

GET/ideas/{id}

Get an idea

Needs Manage roadmap.

ParameterTypeDescription
{id}requiredpath · string

Returns Idea · errors 401, 402, 403, 404, 429, 500

PATCH/ideas/{id}

Triage an idea

Change its status or board. An accepted idea's roadmap item moves to the new status too (unless it's open). Needs Manage roadmap.

ParameterTypeDescription
{id}requiredpath · string

Returns Idea · errors 400, 401, 402, 403, 404, 409, 429, 500

DELETE/ideas/{id}

Delete an idea

Its votes go with it. Needs Manage roadmap.

ParameterTypeDescription
{id}requiredpath · string

Returns DeletedIdea · errors 400, 401, 402, 403, 404, 409, 429, 500

POST/ideas/{id}/accept

Accept an idea onto the roadmap

Creates a roadmap item from it, attributed to the key, and links the two: from then on their statuses move together. An idea can be accepted once. Needs Manage roadmap.

ParameterTypeDescription
{id}requiredpath · string
idempotency-keyheader · stringRetry with the same value and you get the first answer back instead of doing it twice.

Returns Idea · errors 400, 401, 402, 403, 404, 409, 429, 500

POST/ideas/{id}/merge

Merge a duplicate idea

Moves its votes to targetIdeaId and deletes it. Needs Manage roadmap.

ParameterTypeDescription
{id}requiredpath · string
idempotency-keyheader · stringRetry with the same value and you get the first answer back instead of doing it twice.

Returns IdeaMerge · errors 400, 401, 402, 403, 404, 409, 429, 500

Roadmap

GET/roadmap/items

List roadmap items

Oldest first. Any key can read the roadmap.

ParameterTypeDescription
limitquery · string1 to 100. Defaults to 25.
cursorquery · stringnextCursor from the previous page.

Returns RoadmapItemList · errors 400, 401, 402, 403, 404, 429, 500

POST/roadmap/items

Create a roadmap item

Needs Manage roadmap.

ParameterTypeDescription
idempotency-keyheader · stringRetry with the same value and you get the first answer back instead of doing it twice.

Returns RoadmapItem · errors 400, 401, 402, 403, 404, 409, 429, 500

GET/roadmap/items/{id}

Get a roadmap item

Any key can read the roadmap.

ParameterTypeDescription
{id}requiredpath · string

Returns RoadmapItem · errors 401, 402, 403, 404, 429, 500

PATCH/roadmap/items/{id}

Edit a roadmap item

A new status carries over to the ideas accepted as it. Needs Manage roadmap.

ParameterTypeDescription
{id}requiredpath · string

Returns RoadmapItem · errors 400, 401, 402, 403, 404, 409, 429, 500

DELETE/roadmap/items/{id}

Delete a roadmap item

Its votes go with it. Ideas accepted as it stay, unlinked. Needs Manage roadmap.

ParameterTypeDescription
{id}requiredpath · string

Returns DeletedRoadmapItem · errors 400, 401, 402, 403, 404, 409, 429, 500

GET/roadmap/boards

List roadmap boards

The groups roadmap items and ideas are filed under, in order. Any key can read them.

Returns RoadmapBoardList · errors 401, 402, 403, 404, 429, 500

POST/roadmap/boards

Create a roadmap board

Added at the end. Needs Manage roadmap.

ParameterTypeDescription
idempotency-keyheader · stringRetry with the same value and you get the first answer back instead of doing it twice.

Returns RoadmapBoard · errors 400, 401, 402, 403, 404, 409, 429, 500

PATCH/roadmap/boards/{id}

Edit a roadmap board

Rename it or change its position. Needs Manage roadmap.

ParameterTypeDescription
{id}requiredpath · string

Returns RoadmapBoard · errors 400, 401, 402, 403, 404, 409, 429, 500

DELETE/roadmap/boards/{id}

Delete a roadmap board

Its items and ideas stay, off any board. Needs Manage roadmap.

ParameterTypeDescription
{id}requiredpath · string

Returns DeletedRoadmapBoard · errors 400, 401, 402, 403, 404, 409, 429, 500

GET/roadmap/settings

Get roadmap settings

Any key can read them.

Returns RoadmapSettings · errors 401, 402, 403, 404, 429, 500

PATCH/roadmap/settings

Edit roadmap settings

Needs Manage roadmap. Making the roadmap public needs a plan with the public roadmap.

Returns RoadmapSettings · errors 400, 401, 402, 403, 404, 409, 429, 500

Calendar events

GET/calendar-events

List calendar events

The space's calendar, oldest first by when each was created. Any key can read it. (/events is the webhook event log.)

ParameterTypeDescription
limitquery · string1 to 100. Defaults to 25.
cursorquery · stringnextCursor from the previous page.

Returns CalendarEventList · errors 400, 401, 402, 403, 404, 429, 500

POST/calendar-events

Schedule a calendar event

Needs Manage events. A space holds up to 500. API keys can't follow events.

ParameterTypeDescription
idempotency-keyheader · stringRetry with the same value and you get the first answer back instead of doing it twice.

Returns CalendarEvent · errors 400, 401, 402, 403, 404, 409, 429, 500

GET/calendar-events/{id}

Get a calendar event

Any key can read the calendar.

ParameterTypeDescription
{id}requiredpath · string

Returns CalendarEvent · errors 401, 402, 403, 404, 429, 500

PATCH/calendar-events/{id}

Edit a calendar event

Followers are emailed when its title, place, time or recurrence changes: at most once every 10 minutes per event for changes an API key makes. Needs Manage events.

ParameterTypeDescription
{id}requiredpath · string

Returns CalendarEvent · errors 400, 401, 402, 403, 404, 409, 429, 500

DELETE/calendar-events/{id}

Delete a calendar event

Its followers are told it's cancelled. Needs Manage events.

ParameterTypeDescription
{id}requiredpath · string

Returns DeletedCalendarEvent · errors 400, 401, 402, 403, 404, 409, 429, 500

GET/calendar-event-templates

List calendar event templates

Oldest first. Any key can read them.

Returns CalendarEventTemplateList · errors 401, 402, 403, 404, 429, 500

POST/calendar-event-templates

Create a calendar event template

Needs Manage events. A space holds up to 50.

ParameterTypeDescription
idempotency-keyheader · stringRetry with the same value and you get the first answer back instead of doing it twice.

Returns CalendarEventTemplate · errors 400, 401, 402, 403, 404, 409, 429, 500

PATCH/calendar-event-templates/{id}

Edit a calendar event template

Events already made from it don't change. Needs Manage events.

ParameterTypeDescription
{id}requiredpath · string

Returns CalendarEventTemplate · errors 400, 401, 402, 403, 404, 409, 429, 500

DELETE/calendar-event-templates/{id}

Delete a calendar event template

Events made from it stay, unlinked from it. Needs Manage events.

ParameterTypeDescription
{id}requiredpath · string

Returns DeletedCalendarEventTemplate · errors 400, 401, 402, 403, 404, 409, 429, 500

Soundboard

GET/soundboard/sounds

List sounds

Every sound on the space's soundboard (at most 200), by emoji then age. Any key can read them. Playing a sound isn't possible through the API: sounds play in each member's call client, and there's no server-side trigger.

Returns SoundList · errors 401, 402, 404, 429, 500

POST/soundboard/sounds

Upload a sound

A multipart/form-data upload with file, emoji and label. The audio is up to 1 MB; the request body up to 2 MB. A space holds up to 200 sounds (soundboard_limit_reached). Needs Manage soundboard, and a plan with soundboard uploads. Playing a sound isn't possible through the API: sounds play in each member's call client, and there's no server-side trigger.

ParameterTypeDescription
idempotency-keyheader · stringRetry with the same value and you get the first answer back instead of doing it twice.

Returns Sound · errors 400, 401, 402, 403, 404, 409, 429, 500

PATCH/soundboard/sounds/{id}

Update a sound

Change its emoji, its label or both. The audio can't be replaced; delete the sound and upload a new one. Needs Manage soundboard.

ParameterTypeDescription
{id}requiredpath · string

Returns Sound · errors 400, 401, 402, 403, 404, 409, 429, 500

DELETE/soundboard/sounds/{id}

Delete a sound

Removes it and its audio file. Members who favorited it lose the favorite. Needs Manage soundboard.

ParameterTypeDescription
{id}requiredpath · string

Returns DeletedSound · errors 400, 401, 402, 403, 404, 409, 429, 500

GET/soundboard/emoji-settings

List emoji playback settings

How each emoji with a setting picks between its sounds. An emoji without one plays at random. Any key can read them.

Returns EmojiSettingList · errors 401, 402, 404, 429, 500

PUT/soundboard/emoji-settings

Set an emoji's playback mode

Creates or replaces the setting for one emoji. Needs Manage soundboard.

Returns EmojiSetting · errors 400, 401, 402, 403, 404, 409, 429, 500

Objects

RevokedApiKey

FieldTypeDescription
iduuid
object"api_key"
revokedAtdate-time

Space

FieldTypeDescription
iduuid
object"space"
namestring
slugstring
createdAtdate-time

MemberList

FieldTypeDescription
object"list"
dataMember[]
hasMoreboolean
nextCursorstring or nullPass as cursor to get the next page. Null on the last page.

Member

FieldTypeDescription
iduuidThe membership id.
object"member"
userIduuid
displayNamestring
emailstring or nullNull unless the API key holds the Manage members permission.
role"org_owner" | "org_admin" | "org_member" | "customer"The member's base role. Customers of the space aren't listed, so customer only appears in the answer to a change that made someone one.
nicknamestring or null
avatarUrlstring or null
joinedAtdate-time

UpdateMember

FieldTypeDescription
role"org_admin" | "org_member" | "customer"The base role to give them. The key needs every permission that role carries.

DeletedMember

FieldTypeDescription
iduuid
object"member"
deleted"true"

RoleAssignment

FieldTypeDescription
object"role_assignment"
memberIduuid
roleIduuid
assignedAtdate-time

DeletedRoleAssignment

FieldTypeDescription
object"role_assignment"
memberIduuid
roleIduuid
deleted"true"

InviteList

FieldTypeDescription
object"list"
dataInvite[]
hasMoreboolean
nextCursorstring or nullPass as cursor to get the next page. Null on the last page.

Invite

FieldTypeDescription
iduuid
object"invite"
emailstring
role"org_admin" | "org_member" | "customer"The base role they join with.
roleIduuid or nullA custom role they also get when they join, if any.
expiresAtdate-time
createdAtdate-time

CreatedInvite

FieldTypeDescription

CreateInvite

FieldTypeDescription
emailemail
role"org_admin" | "org_member" | "customer"Defaults to org_member.
roleIduuidA role from the space to give them. A built-in role sets their base role; a custom role is added on top of it.

DeletedInvite

FieldTypeDescription
iduuid
object"invite"
deleted"true"

RoleList

FieldTypeDescription
object"list"
dataRole[]
hasMoreboolean
nextCursorstring or nullPass as cursor to get the next page. Null on the last page.

Role

FieldTypeDescription
iduuid
object"role"
namestring
colorstring
positionintegerWhere it sits in the role list. Lower comes first.
permissionsstring[]What holding the role allows, as permission names such as MANAGE_CHANNELS.
isEveryonebooleanThe @everyone role, which every member holds.
isOwnerbooleanThe built-in Owner role.
tier"org_owner" | "org_admin" | "org_member" | "customer" | "null"The base role this built-in role gives its holders. Null for @everyone and custom roles.
memberCountintegerHow many people hold it, customers included.
createdAtdate-time

CreateRole

FieldTypeDescription
namestring
colorstringDefaults to #99aab5.
permissionsstring[]What holding the role allows, as permission names such as MANAGE_CHANNELS. The key needs every one of them itself.

UpdateRole

FieldTypeDescription
namestringBuilt-in roles can be renamed, except @everyone.
colorstring
permissionsstring[]Replaces the role's permissions. The key needs every one of them itself.

DeletedRole

FieldTypeDescription
iduuid
object"role"
deleted"true"

ReorderRoles

FieldTypeDescription
roleIdsuuid[]Role ids in the order you want them, each once (up to 250). Each takes its place in this list as its position; roles you leave out keep theirs.

ChannelList

FieldTypeDescription
object"list"
dataChannel[]
hasMoreboolean
nextCursorstring or nullPass as cursor to get the next page. Null on the last page.

Channel

FieldTypeDescription
iduuid
object"channel"
namestringShown as #name in the app.
descriptionstring or null
type"public" | "announcement"public: every member can read and post. announcement: every member can read; only admins can post.
kind"text" | "voice"
sectionIduuid or nullThe section it's listed under in the sidebar.
archivedbooleanArchived channels are read-only until they're restored.
archivedAtdate-time or null
createdAtdate-time
createdByanyWho made it: a member, or an API key by its current name. Null when unknown, or the key was deleted.

CreateChannel

FieldTypeDescription
namestring
descriptionstring
type"public" | "announcement"Defaults to public. API keys can't create private channels yet.
kind"text" | "voice"Defaults to text.
sectionIduuidDefaults to the space's default section.

UpdateChannel

FieldTypeDescription
namestring
descriptionstring or nullnull clears it.
sectionIduuid or nullMove it to another section of the space.

SectionList

FieldTypeDescription
object"list"
dataSection[]
hasMoreboolean
nextCursorstring or nullPass as cursor to get the next page. Null on the last page.

Section

FieldTypeDescription
iduuid
object"section"
namestring
positionintegerWhere it sits in the sidebar. Lower comes first.
isDefaultbooleanThe section new channels land in. It can be renamed and moved, not deleted.
createdAtdate-time

SectionName

FieldTypeDescription
namestring

DeletedSection

FieldTypeDescription
iduuid
object"section"
deleted"true"

ReorderSections

FieldTypeDescription
sectionIdsuuid[]Section ids in the order you want them. Each takes its place in this list as its position; sections you leave out keep theirs.

ModerationLogEntry

FieldTypeDescription
iduuid
object"moderation_log_entry"
action"timeout" | "timeout_revoked" | "kick" | "ban" | "unban" | "message_deleted" | "messages_purged" | "slow_mode_enabled" | "slow_mode_disabled" | "reported"What happened. New values may be added.
targetUserIduuid or nullThe person it was done to, by user id.
actoranyWho did it: a person, or an API key by its current name. Null for the system, or when the person's account or the key was deleted.
reasonstring or null
durationSecondsinteger or nullHow long a timeout lasts, or slow mode's interval. Null otherwise.
expiresAtdate-time or nullWhen a timeout ends. Null otherwise.
createdAtdate-time

CreateTimeout

FieldTypeDescription
userIduuidThe member's user id (userId on the member object).
durationSecondsintegerFrom 60 (a minute) to 604800 (a week).
reasonstringShown in the space's moderation log.

ModerationTarget

FieldTypeDescription
userIduuidThe person's user id (userId on the member object).
reasonstringShown in the space's moderation log.

ActiveModeration

FieldTypeDescription
object"moderation_active"
timeoutsActiveTimeout[]
bansActiveBan[]

ActiveTimeout

FieldTypeDescription
iduuidThe timeout's moderation log entry.
object"timeout"
targetUserIduuid
actoranyWho did it: a person, or an API key by its current name. Null for the system, or when the person's account or the key was deleted.
reasonstring or null
expiresAtdate-time
createdAtdate-time

ActiveBan

FieldTypeDescription
iduuid
object"ban"
targetUserIduuid
actoranyWho did it: a person, or an API key by its current name. Null for the system, or when the person's account or the key was deleted.
reasonstring or null
createdAtdate-time

ModerationLog

FieldTypeDescription
object"list"
dataModerationLogEntry[]
hasMoreboolean
nextCursorstring or nullPass as cursor to get the next page. Null on the last page.

WebhookEndpointList

FieldTypeDescription
object"list"
dataWebhookEndpoint[]
hasMoreboolean
nextCursorstring or nullPass as cursor to get the next page. Null on the last page.

WebhookEndpoint

FieldTypeDescription
iduuid
object"webhook_endpoint"
urluri
descriptionstring or null
eventTypes"member.joined" | "member.updated" | "member.left" | "invite.created" | "invite.accepted" | "invite.revoked" | "role.created" | "role.updated" | "role.deleted" | "channel.created" | "channel.updated" | "channel.archived" | "channel.restored" | "channel.removed" | "moderation.action" | "message.created" | "message.updated" | "message.deleted" | "customer.created" | "customer.updated" | "customer.archived" | "customer.member_added" | "customer.member_removed" | "customer.import_completed" | "idea.created" | "idea.updated" | "idea.merged" | "idea.deleted" | "roadmap_item.created" | "roadmap_item.updated" | "roadmap_item.deleted" | "calendar_event.created" | "calendar_event.updated" | "calendar_event.deleted"[]The event types it receives. Empty means every type it may receive: invite events need Manage invites and moderation events Moderate members, held by its creator and by everyone who since changed its URL or event types.
enabledbooleanDisabled endpoints receive nothing.
disabledReasonstring or nullWhy Probed disabled it (deliveries failed for 3 days). Null when it's enabled or was turned off on purpose.
includeEmailsbooleanWhether member and invite events carry email addresses: whether its creator held Manage members, and so did everyone who since changed its URL or event types.
secretPrefixstringThe start of the signing secret, to tell secrets apart. The whole secret is only ever shown once.
createdAtdate-time
updatedAtdate-time
createdByanyWho made it: a member by their current name, or an API key by its current name. Null when unknown, or the account or key was deleted.

WebhookEndpointWithSecret

FieldTypeDescription

CreateWebhookEndpoint

FieldTypeDescription
urlstringAn https URL on a public host, port 443 or 1024 and up. Private, loopback and cloud-metadata addresses are refused.
descriptionstring
eventTypes"member.joined" | "member.updated" | "member.left" | "invite.created" | "invite.accepted" | "invite.revoked" | "role.created" | "role.updated" | "role.deleted" | "channel.created" | "channel.updated" | "channel.archived" | "channel.restored" | "channel.removed" | "moderation.action" | "message.created" | "message.updated" | "message.deleted" | "customer.created" | "customer.updated" | "customer.archived" | "customer.member_added" | "customer.member_removed" | "customer.import_completed" | "idea.created" | "idea.updated" | "idea.merged" | "idea.deleted" | "roadmap_item.created" | "roadmap_item.updated" | "roadmap_item.deleted" | "calendar_event.created" | "calendar_event.updated" | "calendar_event.deleted"[]Event types to receive. Leave it out or send [] for every type you may receive. Invite events need Manage invites and moderation events Moderate members (403 otherwise). webhook.test isn't subscribable; it goes only to the endpoint being tested.

UpdateWebhookEndpoint

FieldTypeDescription
urlstringAn https URL on a public host, port 443 or 1024 and up. Private, loopback and cloud-metadata addresses are refused.
descriptionstring or nullnull clears it.
eventTypes"member.joined" | "member.updated" | "member.left" | "invite.created" | "invite.accepted" | "invite.revoked" | "role.created" | "role.updated" | "role.deleted" | "channel.created" | "channel.updated" | "channel.archived" | "channel.restored" | "channel.removed" | "moderation.action" | "message.created" | "message.updated" | "message.deleted" | "customer.created" | "customer.updated" | "customer.archived" | "customer.member_added" | "customer.member_removed" | "customer.import_completed" | "idea.created" | "idea.updated" | "idea.merged" | "idea.deleted" | "roadmap_item.created" | "roadmap_item.updated" | "roadmap_item.deleted" | "calendar_event.created" | "calendar_event.updated" | "calendar_event.deleted"[]Replaces the list. [] means every type.
enabledbooleanfalse stops deliveries. true turns it back on, clearing an automatic disable.

DeletedWebhookEndpoint

FieldTypeDescription
iduuid
object"webhook_endpoint"
deleted"true"

WebhookDelivery

FieldTypeDescription
iduuid
object"webhook_delivery"
eventIdstring
eventType"member.joined" | "member.updated" | "member.left" | "invite.created" | "invite.accepted" | "invite.revoked" | "role.created" | "role.updated" | "role.deleted" | "channel.created" | "channel.updated" | "channel.archived" | "channel.restored" | "channel.removed" | "moderation.action" | "message.created" | "message.updated" | "message.deleted" | "customer.created" | "customer.updated" | "customer.archived" | "customer.member_added" | "customer.member_removed" | "customer.import_completed" | "idea.created" | "idea.updated" | "idea.merged" | "idea.deleted" | "roadmap_item.created" | "roadmap_item.updated" | "roadmap_item.deleted" | "calendar_event.created" | "calendar_event.updated" | "calendar_event.deleted" | "webhook.test" | "null"
status"pending" | "succeeded" | "failed" | "skipped"pending: queued or waiting to retry. succeeded: your endpoint answered 2xx. failed: every attempt failed. skipped: not sent, because the endpoint was disabled or the space's plan lost the API.
attemptintegerAttempts made so far. Up to 9, over about 2.2 days. A retry starts again from 0.
nextAttemptAtdate-time or nullWhen it's due to be sent next. Null once it's finished.
lastStatusCodeinteger or nullThe HTTP status your endpoint last answered with.
lastErrorstring or nullWhy the last attempt failed, such as timeout or HTTP 500.
lastResponseExcerptstring or nullThe start of your endpoint's last response body (1 KB).
lastDurationMsinteger or null
createdAtdate-time
updatedAtdate-time

WebhookDeliveryList

FieldTypeDescription
object"list"
dataWebhookDelivery[]
hasMoreboolean
nextCursorstring or nullPass as cursor to get the next page. Null on the last page.

EventList

FieldTypeDescription
object"list"
dataEvent[]
hasMoreboolean
nextCursorstring or nullPass as cursor to get the next page. Null on the last page.

Event

FieldTypeDescription
idstringevt_ and a ULID. The same as the webhook-id header on its deliveries: dedupe on it.
object"event"
type"member.joined" | "member.updated" | "member.left" | "invite.created" | "invite.accepted" | "invite.revoked" | "role.created" | "role.updated" | "role.deleted" | "channel.created" | "channel.updated" | "channel.archived" | "channel.restored" | "channel.removed" | "moderation.action" | "message.created" | "message.updated" | "message.deleted" | "customer.created" | "customer.updated" | "customer.archived" | "customer.member_added" | "customer.member_removed" | "customer.import_completed" | "idea.created" | "idea.updated" | "idea.merged" | "idea.deleted" | "roadmap_item.created" | "roadmap_item.updated" | "roadmap_item.deleted" | "calendar_event.created" | "calendar_event.updated" | "calendar_event.deleted" | "webhook.test"What happened. New types may be added.
createdAtdate-time
spaceIduuid
actoranyWho did it: a member, or an API key by its name. Null for the system.
dataobjectobject, plus fields some types add, such as reason on member.left.

MessageList

FieldTypeDescription
object"list"
dataMessage[]Oldest first; pins are most recently pinned first.
hasMoreboolean
nextCursorstring or nullA message id. Pass it as before for the next page back, or as after when you paged with after. Null on the last page.

Message

FieldTypeDescription
idstring
object"message"
channelIduuid
authorMessageAuthor
textstringEmpty once deleted.
attachmentsMessageAttachment[]
parentIdstring or nullThe message this replies to in a thread, or null.
replyCountinteger
reactionsobject[]
pinnedboolean
mentionsstring[]The userIds of the members it mentions.
mentionEveryoneboolean
createdAtdate-time
editedAtdate-time or null
deletedboolean

MessageAuthor

FieldTypeDescription
type"member" | "api_key" | "webhook" | "system"member: a person in the space (id is their userId). api_key: an API key's bot (id is the key's current id; every key of a rotation shares one bot). webhook: an incoming webhook or a mirrored Slack or Teams poster. system: a notice from Probed, such as a channel being archived; id and name are null.
idstring or null
namestring or nullTheir current name. A key's bot shows the key's current name, on old messages too.

MessageAttachment

FieldTypeDescription
typestring
urlstringFiles uploaded to Probed come back as signed links that work for about a week; fetch the message again for a fresh one.
titlestring or null
mimeTypestring or null
sizeinteger or nullBytes.
widthinteger or null
heightinteger or null

CreateMessage

FieldTypeDescription
textstringUp to 5000 characters. Needed unless there's an attachment.
parentIdstringReply in this message's thread (a top-level message).
mentionUserIdsstring[]Members to notify, by userId (up to 50). Each must be a member of the space.
mentionEveryonebooleanNotify everyone in the channel. Needs the Mention everyone permission.
attachmentsMessageAttachmentInput[]Up to 10 files.

MessageAttachmentInput

FieldTypeDescription
typestring
urluriThe url POST /uploads returned for this key.
titlestring or null
mimeTypestring or null
sizeinteger or null
widthinteger or null
heightinteger or null
fileIdstring or nullThe fileId POST /uploads returned, if any.

UpdateMessage

FieldTypeDescription
textstring
attachmentsMessageAttachmentInput[]Replaces the files. Send back the ones to keep as GET returned them.

DeletedMessage

FieldTypeDescription
idstring
object"message"
deleted"true"

Upload

FieldTypeDescription
object"upload"
type"image" | "video" | "file"
urlstringSend it as an attachment's url with this key (any key of its rotation) within about a week.
titlestringThe stored file name.
mimeTypestring
sizeintegerBytes, as stored.
widthinteger or null
heightinteger or null
fileIdstring or nullThe file's id in Probed's file store, when it's kept there. Send it back with the url.

CustomerList

FieldTypeDescription
object"list"
dataCustomer[]
hasMoreboolean
nextCursorstring or nullPass as cursor to get the next page. Null on the last page.

Customer

FieldTypeDescription
iduuid
object"customer"
namestring
slugstring
descriptionstring or null
contactEmailstring or null
externalIdstring or nullYour own id for the customer, from a bulk import. Unique in the space.
lockedbooleanTrue for a customer synced from a space on the free plan. Shown read-only in the app.
archivedboolean
archivedAtdate-time or null
createdAtdate-time
createdByanyWho created it: a member, an API key (by its current label), or null.

CreateCustomer

FieldTypeDescription
namestring
slugstringUnique in the space. Made from the name when you leave it out.
descriptionstring or null
contactEmailemail or null

UpdateCustomer

FieldTypeDescription
namestring
descriptionstring or null
contactEmailemail or null

CustomerMemberList

FieldTypeDescription
object"list"
dataCustomerMember[]
hasMoreboolean
nextCursorstring or nullPass as cursor to get the next page. Null on the last page.

CustomerMember

FieldTypeDescription
iduuidTheir membership id in the space, as on /members.
object"customer_member"
customerIduuid
userIduuid
role"admin" | "member"
displayNamestring
emailstring or nullNull unless the API key holds the Manage members permission.
avatarUrlstring or null
addedAtdate-time
addedByany

AddCustomerMember

FieldTypeDescription
memberIduuidThe membership id of someone already in the space (customers included).
role"admin" | "member"Defaults to member. Adding someone already on the customer sets their role.

UpdateCustomerMember

FieldTypeDescription
role"admin" | "member"

DeletedCustomerMember

FieldTypeDescription
iduuid
object"customer_member"
customerIduuid
deleted"true"

CreateCustomerInvite

FieldTypeDescription
emailemail

TagList

FieldTypeDescription
object"list"
dataTag[]
hasMoreboolean
nextCursorstring or nullPass as cursor to get the next page. Null on the last page.

Tag

FieldTypeDescription
iduuid
object"tag"
namestring
colorstring
createdAtdate-time

CreateTag

FieldTypeDescription
namestring
colorstring

DeletedTag

FieldTypeDescription
iduuid
object"tag"
deleted"true"

TagAssignment

FieldTypeDescription
object"tag_assignment"
memberIduuid
tagIduuid

DeletedTagAssignment

FieldTypeDescription

NoteList

FieldTypeDescription
object"list"
dataNote[]
hasMoreboolean
nextCursorstring or nullPass as cursor to get the next page. Null on the last page.

Note

FieldTypeDescription
iduuid
object"note"
memberIduuid
contentstring
authoranyA member, an API key (by its current label), or null for a key that's since been deleted.
createdAtdate-time

CreateNote

FieldTypeDescription
contentstring

DeletedNote

FieldTypeDescription
iduuid
object"note"
deleted"true"

CannedResponseList

FieldTypeDescription
object"list"
dataCannedResponse[]
hasMoreboolean
nextCursorstring or nullPass as cursor to get the next page. Null on the last page.

CannedResponse

FieldTypeDescription
iduuid
object"canned_response"
shortcutstring
titlestring
contentstring
createdAtdate-time
createdByany

CreateCannedResponse

FieldTypeDescription
shortcutstringUnique in the space.
titlestring
contentstring

UpdateCannedResponse

FieldTypeDescription
shortcutstring
titlestring
contentstring

DeletedCannedResponse

FieldTypeDescription
iduuid
object"canned_response"
deleted"true"

BadgeList

FieldTypeDescription
object"list"
dataBadge[]
hasMoreboolean
nextCursorstring or nullPass as cursor to get the next page. Null on the last page.

Badge

FieldTypeDescription
iduuid
object"badge"
namestring
emojistring
colorstring
descriptionstring or null
createdAtdate-time

CreateBadge

FieldTypeDescription
namestringUnique in the space.
emojistring
colorstring
descriptionstring or null

UpdateBadge

FieldTypeDescription
namestring
emojistring
colorstring
descriptionstring or null

DeletedBadge

FieldTypeDescription
iduuid
object"badge"
deleted"true"

BadgeAssignment

FieldTypeDescription
object"badge_assignment"
memberIduuid
badgeIduuid
assignedAtdate-time

DeletedBadgeAssignment

FieldTypeDescription
object"badge_assignment"
memberIduuid
badgeIduuid
deleted"true"

CustomerImport

FieldTypeDescription
iduuid
object"customer_import"
status"queued" | "running" | "completed" | "failed" | "cancelled"
totalinteger
processedinteger
countsobject
sendInvitesboolean
emailsPendingintegerInvite emails still to go out: at most 500 an hour and 1,000 a day per space are sent.
emailsSentinteger
emailsPausedReasonstring or nullWhy this import's emails stopped: a spam complaint, too many bounces (which pause every import email of the space), or a cancel.
errorstring or null
createdByany
createdAtdate-time
startedAtdate-time or null
finishedAtdate-time or null

CreateCustomerImport

FieldTypeDescription
customersobject[]
sendInvitesbooleanEmail each invite. Defaults to false: the invites exist and you share them from the app. At most 500 import emails an hour and 1,000 a day per space; the rest wait. Role addresses (postmaster@, noreply@ and the like) are refused.

CustomerImportList

FieldTypeDescription
object"list"
dataCustomerImport[]
hasMoreboolean
nextCursorstring or nullPass as cursor to get the next page. Null on the last page.

CustomerImportDetail

FieldTypeDescription

IdeaList

FieldTypeDescription
object"list"
dataIdea[]
hasMoreboolean
nextCursorstring or nullPass as cursor to get the next page. Null on the last page.

Idea

FieldTypeDescription
iduuid
object"idea"
titlestring
bodystring or null
status"open" | "planned" | "in_progress" | "completed"open until it's triaged. Accepting it onto the roadmap moves it to the roadmap item's status, and the two stay in step.
authorNamestring or nullThe name it's shown under on the ideas board. Null when the poster hid their name. An API key's ideas show its name.
voteCountinteger
boardIduuid or null
boardNamestring or null
roadmapItemIduuid or nullThe roadmap item it was accepted as, if it was.
submittedByobject or nullThe API key that created it. Null for ideas people posted: who posted them isn't shown.
createdAtdate-time

CreateIdea

FieldTypeDescription
titlestring
bodystring or null
boardIduuid or nullA roadmap board of the space to file it under.

UpdateIdea

FieldTypeDescription
status"open" | "planned" | "in_progress" | "completed"open until it's triaged. Accepting it onto the roadmap moves it to the roadmap item's status, and the two stay in step.
boardIduuid or nullMove it to another board; null unassigns it.

DeletedIdea

FieldTypeDescription
iduuid
object"idea"
deleted"true"

IdeaMerge

FieldTypeDescription
object"idea_merge"
ideaany
mergedIdeaIduuidThe idea that was merged in, now deleted.
movedVotesintegerVotes that moved over. A voter who had voted for both counts once.

MergeIdea

FieldTypeDescription
targetIdeaIduuidThe idea to keep. The one in the path is deleted.

RoadmapItemList

FieldTypeDescription
object"list"
dataRoadmapItem[]
hasMoreboolean
nextCursorstring or nullPass as cursor to get the next page. Null on the last page.

RoadmapItem

FieldTypeDescription
iduuid
object"roadmap_item"
boardIduuid or null
titlestring
descriptionstring or null
status"planned" | "in_progress" | "completed"
voteCountinteger
createdByanyWho made it: a member, or an API key by its current name. Null when unknown, or the key was deleted.
createdAtdate-time
updatedAtdate-time

CreateRoadmapItem

FieldTypeDescription
titlestring
descriptionstring or null
status"planned" | "in_progress" | "completed"Defaults to planned.
boardIduuid or null

UpdateRoadmapItem

FieldTypeDescription
titlestring
descriptionstring or null
status"planned" | "in_progress" | "completed"Ideas accepted as this item move with it.
boardIduuid or nullnull takes it off its board.

DeletedRoadmapItem

FieldTypeDescription
iduuid
object"roadmap_item"
deleted"true"

RoadmapBoardList

FieldTypeDescription
object"list"
dataRoadmapBoard[]
hasMoreboolean
nextCursorstring or nullPass as cursor to get the next page. Null on the last page.

RoadmapBoard

FieldTypeDescription
iduuid
object"roadmap_board"
namestring
positionintegerLower comes first.
itemCountinteger
createdAtdate-time

CreateRoadmapBoard

FieldTypeDescription
namestring

UpdateRoadmapBoard

FieldTypeDescription
namestring
positioninteger

DeletedRoadmapBoard

FieldTypeDescription
iduuid
object"roadmap_board"
deleted"true"

RoadmapSettings

FieldTypeDescription
object"roadmap_settings"
descriptionstring or null
isPublicbooleanWhether the roadmap and ideas board are on the web.
isIndexablebooleanWhether search engines may list the public roadmap.
primaryColorstring or nullThe public roadmap's accent color. Null for the default.

UpdateRoadmapSettings

FieldTypeDescription
descriptionstring or null
isPublicboolean
isIndexableboolean
primaryColorstring or null#rrggbb, or null for the default.

CalendarEventList

FieldTypeDescription
object"list"
dataCalendarEvent[]
hasMoreboolean
nextCursorstring or nullPass as cursor to get the next page. Null on the last page.

CalendarEvent

FieldTypeDescription
iduuid
object"calendar_event"
titlestring
descriptionstring or null
locationstring or null
startTimedate-time
endTimedate-time
recurrence"none" | "daily" | "weekly" | "biweekly" | "monthly"How it repeats. Defaults to none.
recurrenceUntildate-time or nullThe last day it repeats. Null repeats forever.
linkedChannelIduuid or nullThe channel it happens in. Null when there's none, or it's a channel API keys can't see.
templateIduuid or null
followerCountintegerMembers who get its reminders and change emails.
createdByanyWho made it: a member, or an API key by its current name. Null when unknown, or the key was deleted.
createdAtdate-time
updatedAtdate-time

CreateCalendarEvent

FieldTypeDescription
titlestring
descriptionstring or null
locationstring or null
startTimedate-time
endTimedate-timeOn or after startTime.
recurrence"none" | "daily" | "weekly" | "biweekly" | "monthly"How it repeats. Defaults to none.
recurrenceUntildate-time or nullOn or after startTime.
linkedChannelIduuid or nullA public or announcement channel of the space.
templateIduuid or null

UpdateCalendarEvent

FieldTypeDescription
titlestring
descriptionstring or null
locationstring or null
startTimedate-time
endTimedate-time
recurrence"none" | "daily" | "weekly" | "biweekly" | "monthly"How it repeats. Defaults to none.
recurrenceUntildate-time or null
linkedChannelIduuid or nullA public or announcement channel of the space.

DeletedCalendarEvent

FieldTypeDescription
iduuid
object"calendar_event"
deleted"true"

CalendarEventTemplateList

FieldTypeDescription
object"list"
dataCalendarEventTemplate[]
hasMoreboolean
nextCursorstring or nullPass as cursor to get the next page. Null on the last page.

CalendarEventTemplate

FieldTypeDescription
iduuid
object"calendar_event_template"
namestring
titlestring
descriptionstring or null
locationstring or null
durationMinutesinteger
recurrence"none" | "daily" | "weekly" | "biweekly" | "monthly"How it repeats. Defaults to none.
linkedChannelIduuid or nullNull when there's none, or it's a channel API keys can't see.
createdByanyWho made it: a member, or an API key by its current name. Null when unknown, or the key was deleted.
createdAtdate-time

CreateCalendarEventTemplate

FieldTypeDescription
namestring
titlestring
descriptionstring or null
locationstring or null
durationMinutesinteger5 to 1440. Defaults to 30.
recurrence"none" | "daily" | "weekly" | "biweekly" | "monthly"How it repeats. Defaults to none.
linkedChannelIduuid or nullA public or announcement channel of the space.

UpdateCalendarEventTemplate

FieldTypeDescription
namestring
titlestring
descriptionstring or null
locationstring or null
durationMinutesinteger5 to 1440. Defaults to 30.
recurrence"none" | "daily" | "weekly" | "biweekly" | "monthly"How it repeats. Defaults to none.
linkedChannelIduuid or nullA public or announcement channel of the space.

DeletedCalendarEventTemplate

FieldTypeDescription
iduuid
object"calendar_event_template"
deleted"true"

SoundList

FieldTypeDescription
object"list"
dataSound[]
hasMoreboolean
nextCursorstring or nullPass as cursor to get the next page. Null on the last page.

Sound

FieldTypeDescription
iduuid
object"sound"
emojistringThe emoji that plays it. Several sounds can share one emoji; its playback setting picks between them.
labelstring
audioUrlstringA URL to the audio file. It expires (7 to 8 days after it is issued), so fetch the sound again rather than storing it.
mimeTypestring
sizeBytesinteger
durationMsinteger or null
createdAtdate-time
createdByanyWho uploaded it: a member, or an API key by its current name. Null when unknown, or the key was deleted.

CreateSound

FieldTypeDescription
filebinaryThe audio, up to 1 MB. One of: audio/mpeg, audio/mp3, audio/wav, audio/wave, audio/x-wav, audio/ogg, audio/webm, audio/aac, audio/mp4, audio/x-m4a.
emojistringOne emoji, or a short sequence (up to 16 code points): pictographs and emoji components only.
labelstring1 to 48 characters, trimmed. No control or invisible characters.

UpdateSound

FieldTypeDescription
emojistringOne emoji, or a short sequence (up to 16 code points): pictographs and emoji components only.
labelstring1 to 48 characters, trimmed. No control or invisible characters.

DeletedSound

FieldTypeDescription
iduuid
object"sound"
deleted"true"

EmojiSettingList

FieldTypeDescription
object"list"
dataEmojiSetting[]
hasMoreboolean
nextCursorstring or nullPass as cursor to get the next page. Null on the last page.

EmojiSetting

FieldTypeDescription
object"emoji_setting"
emojistring
playbackMode"random" | "round_robin"How an emoji with several sounds picks one: random, or round_robin (each in turn).
updatedAtdate-time

PutEmojiSetting

FieldTypeDescription
emojistringOne emoji, or a short sequence (up to 16 code points): pictographs and emoji components only.
playbackMode"random" | "round_robin"How an emoji with several sounds picks one: random, or round_robin (each in turn).