Skip to content

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

bash
curl "$HELPPUFF_URL/api/v1/admins" \
  -H "Authorization: Bearer $HELPPUFF_API_KEY"
ts
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

json
{
  "me": "key:k7m3p9q2r4s8",
  "owner": "owner@acme.example",
  "admins": [
    {
      "email": "sam@acme.example",
      "name": "Sam",
      "role": "member",
      "createdAt": 1760000000000,
      "lastLoginAt": 1760000000000
    }
  ]
}
ts
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 fieldRequiredDescription
emailyesTheir email address.
namenoUp to 100 characters.
passwordno10+ characters. Without it, the answer has a sign-in link.
rolenoadmin (default: everything) or member (conversations, jobs, contacts, callbacks and live chat; no settings).

Request

bash
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"
}'
ts
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

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

Errors

StatusCodeWhen
409conflictThe 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.

ParameterInRequiredDescription
emailpathyesThe email.
Body fieldRequiredDescription
rolenoadmin or member.
namenoUp to 100 characters: the first name visitors see in live chat.

Request

bash
curl -X PATCH "$HELPPUFF_URL/api/v1/admins/EMAIL" \
  -H "Authorization: Bearer $HELPPUFF_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "role": "admin"
}'
ts
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

json
{
  "email": "sam@acme.example",
  "name": "Sam",
  "role": "admin",
  "createdAt": 1760000000000,
  "lastLoginAt": 1760000000000
}
ts
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.

ParameterInRequiredDescription
emailpathyesThe email.

Request

bash
curl -X DELETE "$HELPPUFF_URL/api/v1/admins/EMAIL" \
  -H "Authorization: Bearer $HELPPUFF_API_KEY"
ts
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

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

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

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

ParameterInRequiredDescription
emailpathyesThe email.

Request

bash
curl -X POST "$HELPPUFF_URL/api/v1/admins/EMAIL/sign-in-link" \
  -H "Authorization: Bearer $HELPPUFF_API_KEY"
ts
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

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

MIT licensed. Runs in your own Cloudflare account.