---
title: "Create a WhatsApp group (asynchronous)"
method: POST
path: "/v2/groups"
tags: ["WhatsApp Groups"]
---

# Create a WhatsApp group (asynchronous)

`POST /v2/groups`

## Request

- Base URL: `https://api.spurnow.com`
- URL: `https://api.spurnow.com/v2/groups`
- Auth: HTTP bearer

Starts group creation at Meta and returns the pending conversation in the `creating` state. The group is finalized asynchronously by the group_lifecycle_update webhook (or the polling reconciler), so poll `GET /v2/groups/{id}` until `lifecycleStatus` is `active` before inviting anyone or reading `inviteLink`. Note the shape changes: this response carries `lifecycleStatus` at the top level, while the GET nests it as `group.lifecycleStatus`. Reusing the path from this response makes a poll read nothing and time out on a group that is already active.

Send an `idempotencyKey` to make the call repeat-safe: the first request creates the group, and any later request carrying the same key returns that same group instead of creating a second one. Without a key, two requests produce two groups, since WhatsApp itself offers no idempotency.

A repeat returns the group exactly as it already is, so the `subject` and `description` sent with the repeat are ignored, not applied. Use `POST /v2/groups/{id}/settings` to change either after creation.

## Request body

- CreateGroupBody
  - `channelId` number, required: WhatsApp channel to create the group on.
  - `subject` string, required: Group subject (trimmed, 1-128 characters).
  - `description` string: Optional group description (trimmed, up to 2048 characters).
  - `idempotencyKey` string: Your own key identifying what this group is for, unique per workspace. Repeating a request with the same key returns the group created the first time instead of creating a second one, which makes retries and duplicate form submissions safe. Use something stable and specific, such as `partner:acme@example.com`.

## Response `201`

The new group. When the `idempotencyKey` was already used, the group that key created, unchanged.

- GroupConversationDto
  - `id` number, required
  - `metaGroupId` string, nullable, required
  - `channelId` number, required
  - `requestId` string, nullable, required
  - `subject` string, nullable, required
  - `description` string, nullable, required
  - `notes` string, nullable, required: Internal group-level notes used as AI context. Never sent to WhatsApp.
  - `inviteLink` string, nullable, required
  - `profilePictureUrl` string, nullable, required: S3 URL of the group icon Meta accepted. Rendered by the UI; Meta stores its own copy for delivery to WhatsApp. Null if never set or if a subsequent update was rejected by Meta.
  - `lifecycleStatus` 'creating' | 'active' | 'suspended' | 'deleted', required
  - `conversationStatus` 'OPEN' | 'CLOSED', required
  - `assignedAgentId` number, nullable, required
  - `assignedTeamId` number, nullable, required
  - `lastMessageAt` string, date-time, nullable, required
  - `agentLastSeenAt` string, date-time, nullable, required
  - `createdAt` string, date-time, required
  - `updatedAt` string, date-time, required

## Other responses

- `400`: Validation failure or a mapped Meta error (e.g. number not eligible).
- `403`: The workspace has reached its live-group cap (early access: 1 by default, raisable per workspace by Spur support; exempt workspaces are not subject to the cap at all). The body carries `code: "GROUP_LIMIT_REACHED"` and the effective `limit` so the dashboard can offer the "contact support" path instead of a generic error.
- `404`: WhatsApp channel not found in this workspace.

---

[API](https://skmtc.dev/spurnow/apis/spur-apis.md) - [All operations](https://skmtc.dev/spurnow/apis/spur-apis/llms.txt) - [OpenAPI document](https://skmtc.dev/spurnow/apis/spur-apis/revisions/27ca7bf002cb?raw)
