Skip to content

API Reference Team

github-actions[bot] edited this page Oct 8, 2026 · 3 revisions

Team API

Who can sign in to the dashboard. Part of the API reference: setup, shared types and errors are there.

List dashboard accounts

GET /admins · scope team:read

Each account's role: admin (everything) or member (conversations, jobs, contacts, callbacks and live chat only).

Request

curl "$HELPPUFF_URL/api/v1/admins" \
  -H "Authorization: Bearer $HELPPUFF_API_KEY"
const response = await fetch(`${process.env.HELPPUFF_URL}/api/v1/admins`, {
  headers: {
    Authorization: `Bearer ${process.env.HELPPUFF_API_KEY}`,
  },
});
if (!response.ok) throw new Error(((await response.json()) as ApiError).error.message);
const data = (await response.json()) as ListDashboardAccountsResponse;

Response 200

{
  "me": "key:k7m3p9q2r4s8",
  "owner": "owner@acme.example",
  "admins": [
    {
      "email": "sam@acme.example",
      "name": "Sam",
      "role": "member",
      "createdAt": 1760000000000,
      "lastLoginAt": 1760000000000
    }
  ]
}
type ListDashboardAccountsResponse = {
  me: string;
  owner: string;
  admins: Array<{
    email: string;
    name: string;
    role: string;
    createdAt: number;
    lastLoginAt: number;
  }>;
};

Add a dashboard account

POST /admins · scope team:write

With a password (10+ characters) they can sign in at once; without one, the answer has a one-time sign-in link (7 days) to send them. team:write can give dashboard access: treat it like full access.

Body field Required Description
email yes Their email address.
name no Up to 100 characters.
password no 10+ characters. Without it, the answer has a sign-in link.
role no admin (default: everything) or member (conversations, jobs, contacts, callbacks and live chat; no settings).

Request

curl -X POST "$HELPPUFF_URL/api/v1/admins" \
  -H "Authorization: Bearer $HELPPUFF_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "email": "sam@acme.example",
  "name": "Sam",
  "role": "member"
}'
type AddDashboardAccountRequest = {
  /** Their email address. */
  email: string;
  /** Up to 100 characters. */
  name?: string;
  /** 10+ characters. Without it, the answer has a sign-in link. */
  password?: string;
  /**
   * `admin` (default: everything) or `member` (conversations, jobs, contacts,
   * callbacks and live chat; no settings).
   */
  role?: string;
};

const response = await fetch(`${process.env.HELPPUFF_URL}/api/v1/admins`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.HELPPUFF_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    email: 'sam@acme.example',
    name: 'Sam',
    role: 'member'
  } satisfies AddDashboardAccountRequest),
});
if (!response.ok) throw new Error(((await response.json()) as ApiError).error.message);
const data = (await response.json()) as AddDashboardAccountResponse;

Response 201

{
  "email": "sam@acme.example",
  "name": "Sam",
  "role": "member",
  "createdAt": 1760000000000,
  "signInLink": "https://helppuff.example.workers.dev/admin/#/signin/9xQ…",
  "signInLinkExpiresAt": 1760604800000
}
type AddDashboardAccountResponse = {
  email: string;
  name: string;
  role: string;
  createdAt: number;
  signInLink: string;
  signInLinkExpiresAt: number;
};

Errors

Status Code When
409 conflict The email can already sign in.

Change a role or name

PATCH /admins/:email · scope team:write

role: admin or member. The owner always has full access.

Parameter In Required Description
email path yes The email.
Body field Required Description
role no admin or member.
name no Up to 100 characters: the first name visitors see in live chat.

Request

curl -X PATCH "$HELPPUFF_URL/api/v1/admins/EMAIL" \
  -H "Authorization: Bearer $HELPPUFF_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "role": "admin"
}'
type ChangeRoleNameRequest = {
  /** `admin` or `member`. */
  role?: string;
  /** Up to 100 characters: the first name visitors see in live chat. */
  name?: string;
};

const email = 'sam@acme.example';
const response = await fetch(`${process.env.HELPPUFF_URL}/api/v1/admins/${email}`, {
  method: 'PATCH',
  headers: {
    Authorization: `Bearer ${process.env.HELPPUFF_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    role: 'admin'
  } satisfies ChangeRoleNameRequest),
});
if (!response.ok) throw new Error(((await response.json()) as ApiError).error.message);
const data = (await response.json()) as ChangeRoleNameResponse;

Response 200

{
  "email": "sam@acme.example",
  "name": "Sam",
  "role": "admin",
  "createdAt": 1760000000000,
  "lastLoginAt": 1760000000000
}
type ChangeRoleNameResponse = {
  email: string;
  name: string | null;
  role: string;
  createdAt: number;
  lastLoginAt: number | null;
};

Remove a dashboard account

DELETE /admins/:email · scope team:write

They are signed out at their next request. The owner (set in the Worker's config) cannot be removed here.

Parameter In Required Description
email path yes The email.

Request

curl -X DELETE "$HELPPUFF_URL/api/v1/admins/EMAIL" \
  -H "Authorization: Bearer $HELPPUFF_API_KEY"
const email = 'sam@acme.example';
const response = await fetch(`${process.env.HELPPUFF_URL}/api/v1/admins/${email}`, {
  method: 'DELETE',
  headers: {
    Authorization: `Bearer ${process.env.HELPPUFF_API_KEY}`,
  },
});
if (!response.ok) throw new Error(((await response.json()) as ApiError).error.message);
const data = (await response.json()) as RemoveDashboardAccountResponse;

Response 200

{
  "email": "sam@acme.example",
  "deleted": true
}
type RemoveDashboardAccountResponse = {
  email: string;
  deleted: boolean;
};

Make a one-time sign-in link

POST /admins/:email/sign-in-link · scope team:write

Valid 15 minutes, once. The way back in after a lost password.

Parameter In Required Description
email path yes The email.

Request

curl -X POST "$HELPPUFF_URL/api/v1/admins/EMAIL/sign-in-link" \
  -H "Authorization: Bearer $HELPPUFF_API_KEY"
const email = 'sam@acme.example';
const response = await fetch(`${process.env.HELPPUFF_URL}/api/v1/admins/${email}/sign-in-link`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.HELPPUFF_API_KEY}`,
  },
});
if (!response.ok) throw new Error(((await response.json()) as ApiError).error.message);
const data = (await response.json()) as MakeOneTimeSignInLinkResponse;

Response 201

{
  "email": "sam@acme.example",
  "url": "https://helppuff.example.workers.dev/admin/#/signin/7bR…",
  "expiresAt": 1760000900000
}
type MakeOneTimeSignInLinkResponse = {
  email: string;
  url: string;
  expiresAt: number;
};

Clone this wiki locally