← All posts
Tutorial

Create a WhatsApp Group via API: Confirm the ID and Members

To create a WhatsApp group through UnifyPort, send POST /v1/accounts/{account_id}/groups/create with a required name and an optional members array. For this creation request, WhatsApp initial members are identified by phone numbers. The successful response returns data.id, not a membership report. Save that ID immediately, then read the group and its members before starting dependent automation.

Key takeaways

  • Creating a group, inviting people, and changing existing members are different operations.
  • Initial members uses phone numbers; later member-management requests use a different identifier contract.
  • The public catalogue has no group.created event. Do not wait for one to finish your workflow.
  • A missing response leaves creation uncertain; automatically repeating it can create another group.

Read the creation contract before building the form

The Create group reference defines the following contract. UnifyPort provides an unofficial interface for the connected messaging account, not a WhatsApp Cloud API endpoint. Its action support matrix currently maps group creation to whatsapp, excluding LINE, Telegram, and the separate whatsapp-protocol provider.

ValueMeaningDo not substitute
Path account_idAccount that will create the groupA workspace ID
Body nameRequired group name, up to 100 charactersA unique resource identifier
Body membersOptional initial-member identifiers; phone numbers for WhatsAppA copied array of member LIDs
Response data.idNewly created group IDAn invitation code or operation ID

The creation response contains only the new group ID within data. It does not provide a per-person admission result. Keep the intended initial membership separate from the membership you subsequently observe.

WhatsApp’s official member-management guide describes adding members, inviting them, and reviewing pending requests when approval is enabled. Those are separate user journeys, not interchangeable evidence that someone joined. If people should choose whether to enter an existing group, use the invite-link workflow rather than creating another group.

Prepare one deliberate creation attempt

Before enabling the button, confirm the selected account is authorized and its runtime is running using the account lifecycle reference. Keep the API key on your backend and enforce operator permissions there.

Recommended application safeguards:

  1. Show the selected account, proposed name, and intended participants for confirmation. Add only people who expect to participate.
  2. Save a local creation intent before dispatch. Record the operator and intended inputs in your application, not as extra API fields.
  3. Prevent concurrent submissions for that intent on the backend; disabling the browser button alone is insufficient.
  4. Make one request and preserve its outcome before allowing follow-up actions.

The following illustrative server-side JavaScript constructs the documented request from confirmed inputs. It has not been executed here and deliberately performs no retries:

async function createGroupOnce({ apiKey, accountId, name, phones }) {
  if (!apiKey || !accountId || typeof name !== 'string' || !name.trim()) {
    throw new Error('Missing credential, account, or group name');
  }
  const body = { name };
  if (phones !== undefined) {
    if (!Array.isArray(phones) ||
        phones.some(p => typeof p !== 'string' || !/^[0-9]+$/.test(p))) {
      throw new Error('Use confirmed phone-number strings');
    }
    body.members = phones;
  }
  const response = await fetch(
    `https://api.unifyport.ai/v1/accounts/${encodeURIComponent(accountId)}/groups/create`,
    {
      method: 'POST',
      headers: { 'X-Api-Key': apiKey, 'Content-Type': 'application/json' },
      body: JSON.stringify(body)
    }
  );
  return { httpStatus: response.status, result: await response.json() };
}

Use actual confirmed phone numbers in the documented format. The digit check is a local input guard, not proof that a number belongs to an eligible participant. Validate the documented name limit too. Production code must handle network and non-JSON failures, securely retain request_id when available, and avoid logging credentials or participant phone lists.

Separate the group ID from membership verification

On 200 OK with data.id, persist the returned ID with the selected account and your local creation intent. Then use Get group with that ID as group_id.

To inspect participants, use List conversation members with the group ID as conversation_id and type=group. Follow has_more and next_cursor; a missing person on the first page is not a completed membership check. Preserve returned peer_id and role values without deriving LIDs from phone numbers.

Later management is a separate contract: Manage group members accepts singular member_id, one action per request, and WhatsApp LIDs returned as peer_id by the member list. Do not reuse the creation payload there. If assigning administrators is the next task, follow the admin role-change guide.

ObservationRecommended application stateNext action
Successful response and group ID savedCreated; membership not yet verifiedRead the group and all member pages
Group readable, intended membership not resolvedGroup exists; membership needs reviewInspect identity mappings or review in the native app
Timeout, unreadable response, or missing expected IDCreation outcome unresolvedReconcile before considering a new attempt

These are application states, not additional API response values.

Recover without creating a duplicate group

The standard event catalogue does not include group.created; creation success does not promise that callback. A group.updated event is not a guaranteed receipt for this request either.

If the response is lost, inspect List groups under the same account, following pagination. It includes joined groups even without message activity. Use available details and the native app to investigate; a matching name alone is not proof of identity, and an incomplete or failed read is not proof that creation failed.

The public creation contract documents no idempotency key. A local intent record helps prevent your own duplicate submissions but cannot make the upstream operation exactly-once. Keep dependent invitations and automated messages paused while the outcome remains unresolved. Require operator review before another creation attempt.

FAQ

Can I omit members?

Yes, the API documents members as optional. That is a request-schema property, not a guarantee of every upstream account’s behavior. Verify the actual result.

Does HTTP success prove every requested person joined?

No. The documented result returns a group ID, not per-member outcomes. Read membership separately.

Can I add the description and avatar in the creation request?

They are not documented creation fields. Handle them afterward using the separate group information editing workflow.

Next step and sources

Build against Create group. Test duplicate clicks, lost responses, repeated group names, paginated member lists, and unavailable participants with accounts you control. These are proposed checks, not reported test results.

References checked on 2026-10-24:

UnifyPort API

Turn messaging integration into a stable product pipeline.

Start by sending through one API, then bring every inbound message back into your business system with standard events.