← All posts
Tutorial

Move WhatsApp Chats Between Labels: A Safe API Handoff

To move a WhatsApp chat from one workflow label to another through UnifyPort, use two membership operations: add the destination label, verify the result, then remove the source label. There is no documented atomic move operation. Keep unrelated labels intact, and leave an uncertain handoff visible rather than deleting the label itself or treating a timeout as proof that nothing changed.

Key takeaways

  • action: "remove" removes a label from selected conversations; deleting a label is a different operation.
  • Labels can coexist. They do not enforce one owner or one workflow stage.
  • Adding before removing favors continued visibility, but temporarily leaves both labels present.
  • Keep authoritative assignment and transition progress in your application, not inferred solely from labels.

Define the handoff, not a replacement label set

WhatsApp’s label help page describes organizing chats with labels and applying multiple labels to a chat. It also notes a gradual transition from labels to lists. That interface terminology does not rename UnifyPort’s documented label_id field or establish that every app list has an API equivalent.

Consider this hypothetical workflow: a chat has “Waiting” and “VIP”; an agent wants to move it to “In progress.” The intended change is to add “In progress” and remove “Waiting,” leaving “VIP” untouched. It is not “replace every label with In progress.”

The June API update introduced the label operations. For a handoff, distinguish their targets:

IntentionOperationTarget
Create or rename a categoryCreate or update labelLabel definition
Add the destinationMembership action: "add"Selected conversations under that label
Remove the sourceMembership action: "remove"Selected conversations under that label
Retire a categoryDelete labelLabel itself, not one chat’s membership

Never substitute label deletion for removing one conversation from a workflow stage. A label may organize other chats too.

Prepare the two operations

Use the label catalogue under the selected messaging account to resolve source and destination IDs. Follow its pagination; names are display text, not stable identity keys. If a destination must be created, use Create or update label and retain the returned data.id.

Resolve the chat’s conversation_id under the same account. Do not use a label name, contact display name, or message ID as a conversation ID. Check the action support matrix: these label operations currently support whatsapp, not LINE, Telegram, Zalo, or the separate whatsapp-protocol provider.

The membership reference defines POST /v1/accounts/{account_id}/conversations/labels with label_id, action, and a nonempty conversation_ids array.

This server-side JavaScript helper performs one operation, deliberately not the whole handoff. Supply real IDs selected by your backend and a securely stored API key. This is illustrative code, not a tested production client.

async function changeLabelMembership({
  apiKey, accountId, labelId, conversationIds, action
}) {
  const validId = value => typeof value === 'string' && value.trim() !== '';
  if (!validId(accountId) || !validId(labelId) ||
      !Array.isArray(conversationIds) || conversationIds.length === 0 ||
      !conversationIds.every(validId) || !['add', 'remove'].includes(action)) {
    throw new Error('Select an account, label, conversations, and action');
  }
  const response = await fetch(
    `https://api.unifyport.ai/v1/accounts/${encodeURIComponent(accountId)}/conversations/labels`,
    {
      method: 'POST',
      headers: { 'X-Api-Key': apiKey, 'Content-Type': 'application/json' },
      body: JSON.stringify({
        label_id: labelId,
        action,
        conversation_ids: [...new Set(conversationIds)]
      })
    }
  );
  const result = await response.json();
  return { httpStatus: response.status, result };
}

For the first call, use the destination ID and add. For the later call, use the source ID and remove, with the same selected chat. Reject identical source and destination IDs locally. Inspect the HTTP status and returned data; a fulfilled fetch promise is not necessarily success. The documented success body identifies the affected label_id, action, and conversation_ids.

Put an observation gate between add and remove

The following is an application design recommendation, not a transaction guarantee from UnifyPort:

  1. Save the intended account, conversation, source, and destination locally. Confirm the operator may change that workflow assignment.
  2. Add the destination. Record the response and request_id, without logging the API key.
  3. Query the destination view with List conversations using its explicit label_id. Confirm the selected chat appears before removing the source.
  4. Remove only the source membership. Preserve independent labels such as VIP.
  5. Reconcile both views and show unfinished work if the observations do not match the intended state.

Do not validate the destination using an unfiltered list. On WhatsApp, omitting label_id selects starred conversations in the documented contract. The missing-chats and label-filter guide explains that boundary and pagination. A chat missing from the first page is not evidence of absence; a failed read is not an empty result. Live paginated reads are not a documented immutable snapshot.

Observed membershipInterpretation for this handoffRecommended action
Source onlyDestination not yet observedKeep the source; investigate the add
Both source and destinationIntermediate state, or another editor’s changeConfirm current intent before removing the source
Destination onlyDesired membership pattern observedRecord completion if the local assignment still agrees
Neither, or incomplete readsUnresolved statePreserve local work and investigate; do not guess completion

Recover without replaying stale intentions

Serialize your application’s changes for a conversation and reject obsolete queued work before dispatch. If another agent has changed the assignment, do not blindly finish an older handoff. Local serialization cannot lock every linked client, so reconcile external changes rather than claiming exclusive control.

If the add times out, retain the source and inspect the destination before deciding what to do next. If removal is uncertain, inspect both views before repeating it. Do not automatically “roll back” by removing the destination: another operator may now rely on it.

The public reference does not promise atomicity across these calls, batch all-or-nothing behavior, a version precondition, or a dedicated label-change webhook. For bulk work, keep progress per conversation rather than treating the entire batch as one completed assignment. set_label_members_failed is documented for server-side or upstream failure; unsupported_by_provider is a capability boundary, not a reason for endless retries.

FAQ

Does adding a label remove the old one?

No. The API exposes explicit add and remove actions. Treat each label membership independently.

Can labels enforce exactly one support owner?

Not through this contract. Store ownership and permissions in your application; use labels as a provider-side projection of that decision.

Will conversation.updated confirm the handoff?

Do not assume so. Its documented settings include mute, archive, pin, and read state, not a guaranteed label-membership receipt.

Is this an official WhatsApp Cloud API operation?

No. These are UnifyPort unofficial interface endpoints for a connected account. WhatsApp’s app help explains the user-facing concept, not this API contract.

Next step and sources

Start with Add / remove label on conversations. In a controlled account, test a successful handoff, destination-add failure, removal timeout, competing edits, pagination, and preservation of an unrelated label before enabling bulk transitions. These are proposed acceptance checks, not reported results.

References checked on 2026-10-14:

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.