← All posts
Tutorial

Build a WhatsApp Group Join-Request Approval Queue

To automate WhatsApp group join requests, keep WhatsApp’s group approval setting as the source of permission, then mirror pending requests into your backend. UnifyPort gives you the pieces: a group.join_request webhook as a low-latency signal, GET /v1/accounts/{account_id}/groups/join-requests as the reliable list, and POST /v1/accounts/{account_id}/groups/join-requests/update to approve or reject selected requesters.

Key takeaways

  • WhatsApp’s own Help Center says Approve new members is turned off by default, and group admins approve or dismiss people who request to join when it is enabled.
  • Treat group.join_request as a hint, not the full approval database. UnifyPort’s docs explicitly say to poll the List group join requests endpoint for the reliable source.
  • Store the requester’s provider id, the group id, the request method when present, and your moderator decision before calling the update endpoint.
  • If you already read Webhook-First Inbound Integration Checklist, this is the group-moderation version of the same pattern: verify, store, then route.

What WhatsApp controls

WhatsApp group approval is still a WhatsApp group-admin feature. The official Help Center page on approving new members says admins must approve anyone who wants to join when Approve new members is enabled, and that the setting is off by default.

That means the automation should not pretend to replace the admin setting. Your backend should answer a narrower question: when a request exists, who should review it, what evidence should they see, and which exact requester ids should be approved or rejected?

The queue architecture

Use one signed webhook endpoint for group signals, then reconcile with the pending-list endpoint before taking action:

  1. Register a webhook endpoint with subscribed_events including group.join_request, or use ["*"] if you are already collecting all public events. See Webhook event filters for when to choose explicit filters.
  2. When group.join_request arrives, enqueue a reconciliation job keyed by account_id and data.conversation.id.
  3. Poll List group join requests for that group. The returned item id is the value you later pass in member_ids.
  4. Show pending requests to a human moderator, or apply your own internal rules.
  5. Call the update endpoint with action: "approve" or action: "reject".

If you have built the Telegram group join-request approval queue, the operational lesson is the same: the push event wakes your system up; the list endpoint is the state you trust.

Event and request shapes

A WhatsApp join request can arrive as a normalized event like this:

{
  "id": "evt_gjr_5e1c8a3f9b",
  "type": "group.join_request",
  "provider": "whatsapp",
  "account_id": "acc_8c21d0",
  "occurred_at": "2026-06-08T13:10:30Z",
  "data": {
    "conversation": { "id": "120363041234567890@g.us", "type": "group" },
    "requester": { "id": "8613912345678@lid", "type": "user" },
    "request_method": "invite_link",
    "event": { "kind": "group_join_request" }
  }
}

Reconcile before approving:

curl "https://api.unifyport.ai/v1/accounts/acc_8c21d0/groups/join-requests?group_id=120363041234567890%40g.us" \
  -H "X-Api-Key: $UNIFYPORT_API_KEY"

Then approve or reject the returned ids:

curl -X POST "https://api.unifyport.ai/v1/accounts/acc_8c21d0/groups/join-requests/update" \
  -H "X-Api-Key: $UNIFYPORT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "group_id": "120363041234567890@g.us",
    "action": "approve",
    "member_ids": ["8613912345678@lid"]
  }'

A small Node.js worker

const pending = new Map();

app.post('/webhook', verifyUnifyPortSignature, async (req, res) => {
  const event = req.body;
  if (event.type !== 'group.join_request') return res.status(200).end();

  const groupId = event.data.conversation.id;
  const key = `${event.account_id}:${groupId}`;
  pending.set(key, { accountId: event.account_id, groupId });

  res.status(200).end();
});

async function reconcile({ accountId, groupId }) {
  const qs = new URLSearchParams({ group_id: groupId });
  const response = await fetch(
    `https://api.unifyport.ai/v1/accounts/${accountId}/groups/join-requests?${qs}`,
    { headers: { 'X-Api-Key': process.env.UNIFYPORT_API_KEY } }
  );
  const body = await response.json();

  for (const request of body.data.items) {
    await saveForModerator({
      accountId,
      groupId: body.data.group_id,
      memberId: request.id,
      phone: request.phone,
      requestedAt: request.requested_at
    });
  }
}

Use the verified raw-body signature flow from webhook delivery before trusting any event body.

Limitations and trade-offs

This pattern does not grant admin rights to an account that is not already allowed to manage the group. It also does not make push delivery the only source of truth: UnifyPort documents group.join_request as best-effort, so your UI should poll the pending list before showing final state. Finally, keep moderation policy outside the transport layer; UnifyPort moves requests and decisions, while your team decides who belongs in the group.

FAQ

Can I approve WhatsApp group join requests from a webhook alone?

No. Use the webhook to wake the worker, then poll GET /v1/accounts/{account_id}/groups/join-requests and pass the returned item ids to the update endpoint.

Which field becomes member_ids?

Use the id field from the List group join requests response. Do not use a display name or a guessed phone-number format.

Do I need a WhatsApp Business API account?

This tutorial uses UnifyPort’s unofficial interface connected to a WhatsApp account with the needed group permissions. The official WhatsApp group approval setting still controls whether join requests exist.

What should the next step be?

Start with List group join requests, then add Approve / reject join requests after your moderator UI is ready.

Sources checked on 2026-09-02

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.