Ir al contenido
WhatsMarketingDeveloper Hub

Contactos

Las personas con las que habla tu organización: datos, etapa del ciclo de vida, etiquetas, identidades por canal, consentimiento y notas. Un contacto puede tener varias identidades (su WhatsApp, su Instagram, su correo) y todas apuntan a la misma ficha.

Listar contactos

GET/contacts

Contactos de la organización, paginados y con filtros: pestaña (tab), etapa, propietario (ownerId, o none para los que no tienen), origen, canal, etiqueta, búsqueda libre (q) o actividad reciente (days). Además de data y meta trae tabs (cuántos hay en cada pestaña) y summary (las cifras de cabecera del panel).

Permisos: contacts:read

Parámetros

NombreDóndeTipoValores
pageconsultanumberpor defecto: 1 · 1 – …
pageSizeconsultanumberpor defecto: 20 · 1 – 100
tabconsultastringall · leads · in_progress · customers · inactive · no_consent
lifecycleStageIdconsultauuid
ownerIdconsultastring^(none|[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$
sourceconsultastringOTHER · MANUAL · IMPORT · WHATSAPP_INBOUND · CAMPAIGN · WEBSITE_FORM · REFERRAL
channelTypeconsultastringWHATSAPP · INSTAGRAM · MESSENGER · FACEBOOK · TELEGRAM · TIKTOK · WEBCHAT · EMAIL · SMS · WECHAT · VOICE
tagconsultastring0–60 caracteres
qconsultastring0–120 caracteres
searchconsultastring0–120 caracteres
daysconsultanumber7 · 30 · 90
idsconsultauuid[]≤ 500
curl
curl "https://micuenta.whatsmarketing.es/api/v1/contacts?page=1&pageSize=20" \
  -H "Authorization: Bearer $WM_API_KEY"
Node.js
const res = await fetch('https://micuenta.whatsmarketing.es/api/v1/contacts?page=1&pageSize=20', {
  headers: {
    Authorization: `Bearer ${process.env.WM_API_KEY}`,
  },
});
const data = await res.json();
Python
import os, requests

r = requests.get(
    "https://micuenta.whatsmarketing.es/api/v1/contacts?page=1&pageSize=20",
    headers={"Authorization": f"Bearer {os.environ['WM_API_KEY']}"},
    timeout=30,
)
r.raise_for_status()
data = r.json()
PHP
<?php
$ch = curl_init('https://micuenta.whatsmarketing.es/api/v1/contacts?page=1&pageSize=20');
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => [
    'Authorization: Bearer ' . getenv('WM_API_KEY'),
  ],
]);
$data = json_decode(curl_exec($ch), true);
Respuesta 200
{
  "data": [
    {
      "id": "0b1c2d3e-5f6a-4b7c-8d9e-0f1a2b3c4d5e",
      "fullName": "Laura Pérez",
      "primaryPhone": "+34612345678",
      "primaryEmail": "laura@ejemplo.com",
      "company": "Clínica Sol",
      "country": "ES",
      "source": "WEBSITE_FORM",
      "lifecycleStageId": "9c2a1f00-2b3c-4d5e-8f90-1a2b3c4d5e6f",
      "lifecycleStage": {
        "id": "9c2a1f00-2b3c-4d5e-8f90-1a2b3c4d5e6f",
        "name": "Lead nuevo",
        "order": 1
      },
      "ownerId": null,
      "owner": null,
      "optedOut": false,
      "consent": {
        "given": true,
        "at": "2026-10-14T10:20:00.000Z",
        "how": "WEBSITE_FORM"
      },
      "tags": [
        "web"
      ],
      "identities": [
        {
          "id": "6d7e8f90-1a2b-4c3d-9e4f-5a6b7c8d9e0f",
          "channelType": "WHATSAPP",
          "externalId": "34612345678"
        }
      ],
      "lastConversation": null,
      "createdAt": "2026-10-14T10:20:05.000Z",
      "updatedAt": "2026-10-14T10:20:05.000Z"
    }
  ],
  "meta": {
    "page": 1,
    "pageSize": 20,
    "total": 1,
    "totalPages": 1
  },
  "tabs": {
    "all": 1,
    "leads": 1,
    "in_progress": 0,
    "customers": 0,
    "inactive": 0,
    "no_consent": 0
  },
  "summary": {
    "days": 30,
    "total": 1,
    "newInPeriod": 1,
    "withConsent": 1,
    "withoutConsent": 0,
    "consentPct": 100,
    "leadsNew": 1,
    "leadsInProgress": 0,
    "customers": 0,
    "customersNewInPeriod": 0,
    "tags": [
      "web"
    ]
  }
}

Crear un contacto

POST/contacts

Crea la ficha. El teléfono va en formato internacional con prefijo (+34…). Si ya existe un contacto con ese teléfono, responde 409 CONTACT_PHONE_EXISTS con el contactId del existente. consent registra cuándo y cómo dio consentimiento para recibir mensajes; note deja una primera nota interna.

Permisos: contacts:write

Cuerpo de la petición CreateContact

NombreTipoValores
fullNamestring0–160 caracteres
primaryPhonestring0–32 caracteres
primaryEmailemail
companystring0–160 caracteres
countrystring0–2 caracteres
sourcestringOTHER · MANUAL · IMPORT · WHATSAPP_INBOUND · CAMPAIGN · WEBSITE_FORM · REFERRAL
lifecycleStageIduuid
ownerIduuid
optedOutboolean
consentConsent
tagsstring[]≤ 50
notestring0–4000 caracteres

Errores frecuentes

  • 409 CONTACT_PHONE_EXISTS Ya hay un contacto con ese teléfono; la respuesta trae contactId y fullName.
curl
curl -X POST "https://micuenta.whatsmarketing.es/api/v1/contacts" \
  -H "Authorization: Bearer $WM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "fullName": "Laura Pérez",
  "primaryPhone": "+34612345678",
  "primaryEmail": "laura@ejemplo.com",
  "company": "Clínica Sol",
  "country": "ES",
  "source": "WEBSITE_FORM",
  "tags": [
    "web"
  ],
  "consent": {
    "given": true,
    "at": "2026-10-14T10:20:00.000Z",
    "how": "WEBSITE_FORM"
  }
}'
Node.js
const res = await fetch('https://micuenta.whatsmarketing.es/api/v1/contacts', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.WM_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "fullName": "Laura Pérez",
    "primaryPhone": "+34612345678",
    "primaryEmail": "laura@ejemplo.com",
    "company": "Clínica Sol",
    "country": "ES",
    "source": "WEBSITE_FORM",
    "tags": [
      "web"
    ],
    "consent": {
      "given": true,
      "at": "2026-10-14T10:20:00.000Z",
      "how": "WEBSITE_FORM"
    }
  }),
});
const data = await res.json();
Python
import os, requests

r = requests.post(
    "https://micuenta.whatsmarketing.es/api/v1/contacts",
    headers={"Authorization": f"Bearer {os.environ['WM_API_KEY']}"},
    json={
        "fullName": "Laura Pérez",
        "primaryPhone": "+34612345678",
        "primaryEmail": "laura@ejemplo.com",
        "company": "Clínica Sol",
        "country": "ES",
        "source": "WEBSITE_FORM",
        "tags": [
            "web"
        ],
        "consent": {
            "given": True,
            "at": "2026-10-14T10:20:00.000Z",
            "how": "WEBSITE_FORM"
        }
    },
    timeout=30,
)
r.raise_for_status()
data = r.json()
PHP
<?php
$ch = curl_init('https://micuenta.whatsmarketing.es/api/v1/contacts');
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_CUSTOMREQUEST => 'POST',
  CURLOPT_HTTPHEADER => [
    'Authorization: Bearer ' . getenv('WM_API_KEY'),
    'Content-Type: application/json',
  ],
  CURLOPT_POSTFIELDS => json_encode([
    'fullName' => 'Laura Pérez',
    'primaryPhone' => '+34612345678',
    'primaryEmail' => 'laura@ejemplo.com',
    'company' => 'Clínica Sol',
    'country' => 'ES',
    'source' => 'WEBSITE_FORM',
    'tags' => [
      'web'
    ],
    'consent' => [
      'given' => true,
      'at' => '2026-10-14T10:20:00.000Z',
      'how' => 'WEBSITE_FORM'
    ]
  ]),
]);
$data = json_decode(curl_exec($ch), true);
Respuesta 201
{
  "id": "0b1c2d3e-5f6a-4b7c-8d9e-0f1a2b3c4d5e",
  "organizationId": "f0e1d2c3-b4a5-4968-8776-655443322110",
  "fullName": "Laura Pérez",
  "primaryPhone": "+34612345678",
  "primaryEmail": "laura@ejemplo.com",
  "company": "Clínica Sol",
  "country": "ES",
  "source": "WEBSITE_FORM",
  "lifecycleStageId": null,
  "lifecycleStage": null,
  "ownerId": null,
  "owner": null,
  "optedOut": false,
  "consent": {
    "given": true,
    "at": "2026-10-14T10:20:00.000Z",
    "how": "WEBSITE_FORM"
  },
  "tags": [
    "web"
  ],
  "identities": [
    {
      "id": "6d7e8f90-1a2b-4c3d-9e4f-5a6b7c8d9e0f",
      "channelType": "WHATSAPP",
      "externalId": "34612345678"
    }
  ],
  "createdAt": "2026-10-14T10:20:05.000Z",
  "updatedAt": "2026-10-14T10:20:05.000Z"
}

Actualizar contactos en lote

POST/contacts/bulk

Hasta 500 contactos por llamada: cambiar de etapa, añadir etiquetas (hasta 20) o reasignar el propietario (ownerId: null lo quita). Al menos una de las tres. skipped son los ids que no pertenecen a tu organización.

Permisos: contacts:write

Cuerpo de la petición BulkContacts

NombreTipoValores
ids obligatoriouuid[]≤ 500
lifecycleStageIduuid
addTagsstring[]≤ 20
ownerIduuid
curl
curl -X POST "https://micuenta.whatsmarketing.es/api/v1/contacts/bulk" \
  -H "Authorization: Bearer $WM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "ids": [
    "0b1c2d3e-5f6a-4b7c-8d9e-0f1a2b3c4d5e",
    "4e5f6a7b-8c9d-4e0f-9a1b-2c3d4e5f6a7b"
  ],
  "addTags": [
    "evento-madrid"
  ],
  "lifecycleStageId": "9c2a1f00-2b3c-4d5e-8f90-1a2b3c4d5e6f"
}'
Node.js
const res = await fetch('https://micuenta.whatsmarketing.es/api/v1/contacts/bulk', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.WM_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "ids": [
      "0b1c2d3e-5f6a-4b7c-8d9e-0f1a2b3c4d5e",
      "4e5f6a7b-8c9d-4e0f-9a1b-2c3d4e5f6a7b"
    ],
    "addTags": [
      "evento-madrid"
    ],
    "lifecycleStageId": "9c2a1f00-2b3c-4d5e-8f90-1a2b3c4d5e6f"
  }),
});
const data = await res.json();
Python
import os, requests

r = requests.post(
    "https://micuenta.whatsmarketing.es/api/v1/contacts/bulk",
    headers={"Authorization": f"Bearer {os.environ['WM_API_KEY']}"},
    json={
        "ids": [
            "0b1c2d3e-5f6a-4b7c-8d9e-0f1a2b3c4d5e",
            "4e5f6a7b-8c9d-4e0f-9a1b-2c3d4e5f6a7b"
        ],
        "addTags": [
            "evento-madrid"
        ],
        "lifecycleStageId": "9c2a1f00-2b3c-4d5e-8f90-1a2b3c4d5e6f"
    },
    timeout=30,
)
r.raise_for_status()
data = r.json()
PHP
<?php
$ch = curl_init('https://micuenta.whatsmarketing.es/api/v1/contacts/bulk');
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_CUSTOMREQUEST => 'POST',
  CURLOPT_HTTPHEADER => [
    'Authorization: Bearer ' . getenv('WM_API_KEY'),
    'Content-Type: application/json',
  ],
  CURLOPT_POSTFIELDS => json_encode([
    'ids' => [
      '0b1c2d3e-5f6a-4b7c-8d9e-0f1a2b3c4d5e',
      '4e5f6a7b-8c9d-4e0f-9a1b-2c3d4e5f6a7b'
    ],
    'addTags' => [
      'evento-madrid'
    ],
    'lifecycleStageId' => '9c2a1f00-2b3c-4d5e-8f90-1a2b3c4d5e6f'
  ]),
]);
$data = json_decode(curl_exec($ch), true);
Respuesta 201
{
  "updated": 2,
  "skipped": 0
}

Ver un contacto

GET/contacts/{id}

La ficha completa: identidades por canal, consentimiento, etiquetas, propietario, etapa y oportunidades abiertas.

Permisos: contacts:read

Parámetros

NombreDóndeTipoValores
id obligatoriorutastring
curl
curl "https://micuenta.whatsmarketing.es/api/v1/contacts/{id}" \
  -H "Authorization: Bearer $WM_API_KEY"
Node.js
const res = await fetch('https://micuenta.whatsmarketing.es/api/v1/contacts/{id}', {
  headers: {
    Authorization: `Bearer ${process.env.WM_API_KEY}`,
  },
});
const data = await res.json();
Python
import os, requests

r = requests.get(
    "https://micuenta.whatsmarketing.es/api/v1/contacts/{id}",
    headers={"Authorization": f"Bearer {os.environ['WM_API_KEY']}"},
    timeout=30,
)
r.raise_for_status()
data = r.json()
PHP
<?php
$ch = curl_init('https://micuenta.whatsmarketing.es/api/v1/contacts/{id}');
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => [
    'Authorization: Bearer ' . getenv('WM_API_KEY'),
  ],
]);
$data = json_decode(curl_exec($ch), true);
Respuesta 200
{
  "id": "0b1c2d3e-5f6a-4b7c-8d9e-0f1a2b3c4d5e",
  "organizationId": "f0e1d2c3-b4a5-4968-8776-655443322110",
  "fullName": "Laura Pérez",
  "primaryPhone": "+34612345678",
  "primaryEmail": "laura@ejemplo.com",
  "company": "Clínica Sol",
  "country": "ES",
  "source": "WEBSITE_FORM",
  "lifecycleStageId": null,
  "lifecycleStage": null,
  "ownerId": null,
  "owner": null,
  "optedOut": false,
  "consent": {
    "given": true,
    "at": "2026-10-14T10:20:00.000Z",
    "how": "WEBSITE_FORM"
  },
  "tags": [
    "web"
  ],
  "identities": [
    {
      "id": "6d7e8f90-1a2b-4c3d-9e4f-5a6b7c8d9e0f",
      "channelType": "WHATSAPP",
      "externalId": "34612345678"
    }
  ],
  "createdAt": "2026-10-14T10:20:05.000Z",
  "updatedAt": "2026-10-14T10:20:05.000Z"
}

Editar un contacto

PATCH/contacts/{id}

Todos los campos son opcionales; solo cambia lo que mandas. Cambiar el teléfono a uno que ya tiene otro contacto responde 409 CONTACT_PHONE_EXISTS. Responde con la ficha actualizada.

Permisos: contacts:write

Parámetros

NombreDóndeTipoValores
id obligatoriorutastring

Cuerpo de la petición UpdateContact

NombreTipoValores
fullNamestring0–160 caracteres
primaryPhonestring0–32 caracteres
primaryEmailemail
companystring0–160 caracteres
countrystring0–2 caracteres
sourcestringOTHER · MANUAL · IMPORT · WHATSAPP_INBOUND · CAMPAIGN · WEBSITE_FORM · REFERRAL
lifecycleStageIduuid
ownerIduuid
optedOutboolean
consentConsent
tagsstring[]≤ 50
curl
curl -X PATCH "https://micuenta.whatsmarketing.es/api/v1/contacts/{id}" \
  -H "Authorization: Bearer $WM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "company": "Clínica Sol Fuengirola",
  "tags": [
    "web",
    "cliente"
  ],
  "lifecycleStageId": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d"
}'
Node.js
const res = await fetch('https://micuenta.whatsmarketing.es/api/v1/contacts/{id}', {
  method: 'PATCH',
  headers: {
    Authorization: `Bearer ${process.env.WM_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "company": "Clínica Sol Fuengirola",
    "tags": [
      "web",
      "cliente"
    ],
    "lifecycleStageId": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d"
  }),
});
const data = await res.json();
Python
import os, requests

r = requests.patch(
    "https://micuenta.whatsmarketing.es/api/v1/contacts/{id}",
    headers={"Authorization": f"Bearer {os.environ['WM_API_KEY']}"},
    json={
        "company": "Clínica Sol Fuengirola",
        "tags": [
            "web",
            "cliente"
        ],
        "lifecycleStageId": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d"
    },
    timeout=30,
)
r.raise_for_status()
data = r.json()
PHP
<?php
$ch = curl_init('https://micuenta.whatsmarketing.es/api/v1/contacts/{id}');
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_CUSTOMREQUEST => 'PATCH',
  CURLOPT_HTTPHEADER => [
    'Authorization: Bearer ' . getenv('WM_API_KEY'),
    'Content-Type: application/json',
  ],
  CURLOPT_POSTFIELDS => json_encode([
    'company' => 'Clínica Sol Fuengirola',
    'tags' => [
      'web',
      'cliente'
    ],
    'lifecycleStageId' => 'a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d'
  ]),
]);
$data = json_decode(curl_exec($ch), true);
Respuesta 200
{
  "id": "0b1c2d3e-5f6a-4b7c-8d9e-0f1a2b3c4d5e",
  "organizationId": "f0e1d2c3-b4a5-4968-8776-655443322110",
  "fullName": "Laura Pérez",
  "primaryPhone": "+34612345678",
  "primaryEmail": "laura@ejemplo.com",
  "company": "Clínica Sol",
  "country": "ES",
  "source": "WEBSITE_FORM",
  "lifecycleStageId": null,
  "lifecycleStage": null,
  "ownerId": null,
  "owner": null,
  "optedOut": false,
  "consent": {
    "given": true,
    "at": "2026-10-14T10:20:00.000Z",
    "how": "WEBSITE_FORM"
  },
  "tags": [
    "web"
  ],
  "identities": [
    {
      "id": "6d7e8f90-1a2b-4c3d-9e4f-5a6b7c8d9e0f",
      "channelType": "WHATSAPP",
      "externalId": "34612345678"
    }
  ],
  "createdAt": "2026-10-14T10:20:05.000Z",
  "updatedAt": "2026-10-14T10:20:05.000Z"
}

Eliminar un contacto

DELETE/contacts/{id}

Solo si el contacto no tiene conversaciones, campañas ni ventas; si las tiene, responde 409 CONTACT_HAS_HISTORY y conviene retirarle el consentimiento (optedOut: true) en lugar de borrarlo. Las notas e identidades se eliminan con él.

Permisos: contacts:write

Parámetros

NombreDóndeTipoValores
id obligatoriorutastring

Errores frecuentes

  • 409 CONTACT_HAS_HISTORY El contacto tiene historial: no se elimina para que los informes sigan cuadrando.
curl
curl -X DELETE "https://micuenta.whatsmarketing.es/api/v1/contacts/{id}" \
  -H "Authorization: Bearer $WM_API_KEY"
Node.js
const res = await fetch('https://micuenta.whatsmarketing.es/api/v1/contacts/{id}', {
  method: 'DELETE',
  headers: {
    Authorization: `Bearer ${process.env.WM_API_KEY}`,
  },
});
const data = await res.json();
Python
import os, requests

r = requests.delete(
    "https://micuenta.whatsmarketing.es/api/v1/contacts/{id}",
    headers={"Authorization": f"Bearer {os.environ['WM_API_KEY']}"},
    timeout=30,
)
r.raise_for_status()
data = r.json()
PHP
<?php
$ch = curl_init('https://micuenta.whatsmarketing.es/api/v1/contacts/{id}');
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_CUSTOMREQUEST => 'DELETE',
  CURLOPT_HTTPHEADER => [
    'Authorization: Bearer ' . getenv('WM_API_KEY'),
  ],
]);
$data = json_decode(curl_exec($ch), true);
Respuesta 200
{
  "deleted": true
}

Línea de tiempo de un contacto

GET/contacts/{id}/timeline

Conversaciones, campañas recibidas, notas, cambios de etapa, consentimiento y alta, en orden cronológico inverso. type filtra por conversations, campaigns o notes; cada entrada lleva su type.

Permisos: contacts:read

Parámetros

NombreDóndeTipoValores
id obligatoriorutastring
pageconsultanumberpor defecto: 1 · 1 – …
pageSizeconsultanumberpor defecto: 20 · 1 – 100
typeconsultastringall · conversations · campaigns · notes
curl
curl "https://micuenta.whatsmarketing.es/api/v1/contacts/{id}/timeline?page=1&pageSize=20" \
  -H "Authorization: Bearer $WM_API_KEY"
Node.js
const res = await fetch('https://micuenta.whatsmarketing.es/api/v1/contacts/{id}/timeline?page=1&pageSize=20', {
  headers: {
    Authorization: `Bearer ${process.env.WM_API_KEY}`,
  },
});
const data = await res.json();
Python
import os, requests

r = requests.get(
    "https://micuenta.whatsmarketing.es/api/v1/contacts/{id}/timeline?page=1&pageSize=20",
    headers={"Authorization": f"Bearer {os.environ['WM_API_KEY']}"},
    timeout=30,
)
r.raise_for_status()
data = r.json()
PHP
<?php
$ch = curl_init('https://micuenta.whatsmarketing.es/api/v1/contacts/{id}/timeline?page=1&pageSize=20');
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => [
    'Authorization: Bearer ' . getenv('WM_API_KEY'),
  ],
]);
$data = json_decode(curl_exec($ch), true);
Respuesta 200
{
  "data": [
    {
      "id": "7c8d9e0f-1a2b-4c3d-8e4f-5a6b7c8d9e0f",
      "type": "campaign",
      "at": "2026-10-10T08:00:00.000Z",
      "campaign": {
        "id": "3a4b5c6d-7e8f-4a9b-8c0d-1e2f3a4b5c6d",
        "name": "Octubre: promo"
      },
      "status": "DELIVERED",
      "sentAt": "2026-10-10T08:00:02.000Z",
      "deliveredAt": "2026-10-10T08:00:05.000Z",
      "readAt": null,
      "failedAt": null,
      "errorMessage": null
    },
    {
      "id": "8d9e0f1a-2b3c-4d4e-9f5a-6b7c8d9e0f1a",
      "type": "note",
      "at": "2026-10-09T17:12:00.000Z",
      "author": "Ana Gómez",
      "body": "Pidió presupuesto por teléfono"
    },
    {
      "id": "9e0f1a2b-3c4d-4e5f-8a6b-7c8d9e0f1a2b",
      "type": "stage",
      "at": "2026-10-09T17:00:00.000Z",
      "by": "Ana Gómez",
      "from": "Lead nuevo",
      "to": "En proceso",
      "bulk": false
    },
    {
      "id": "0b1c2d3e-5f6a-4b7c-8d9e-0f1a2b3c4d5e",
      "type": "created",
      "at": "2026-10-01T09:00:00.000Z",
      "source": "WEBSITE_FORM"
    }
  ],
  "meta": {
    "page": 1,
    "pageSize": 20,
    "total": 4,
    "totalPages": 1
  }
}

Añadir una identidad de canal

POST/contacts/{id}/identities

Vincula otro canal a la misma ficha: channelType es el tipo de canal (WHATSAPP, INSTAGRAM, MESSENGER, EMAIL…) y externalId el identificador del contacto en ese canal (teléfono sin + para WhatsApp, usuario para Instagram, correo para email). Si esa identidad ya pertenece a otro contacto, responde 409.

Permisos: contacts:write

Parámetros

NombreDóndeTipoValores
id obligatoriorutastring

Cuerpo de la petición AddIdentity

NombreTipoValores
channelType obligatoriostringWHATSAPP · INSTAGRAM · MESSENGER · FACEBOOK · TELEGRAM · TIKTOK · WEBCHAT · EMAIL · SMS · WECHAT · VOICE
externalId obligatoriostring
curl
curl -X POST "https://micuenta.whatsmarketing.es/api/v1/contacts/{id}/identities" \
  -H "Authorization: Bearer $WM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "channelType": "INSTAGRAM",
  "externalId": "laura.perez"
}'
Node.js
const res = await fetch('https://micuenta.whatsmarketing.es/api/v1/contacts/{id}/identities', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.WM_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "channelType": "INSTAGRAM",
    "externalId": "laura.perez"
  }),
});
const data = await res.json();
Python
import os, requests

r = requests.post(
    "https://micuenta.whatsmarketing.es/api/v1/contacts/{id}/identities",
    headers={"Authorization": f"Bearer {os.environ['WM_API_KEY']}"},
    json={
        "channelType": "INSTAGRAM",
        "externalId": "laura.perez"
    },
    timeout=30,
)
r.raise_for_status()
data = r.json()
PHP
<?php
$ch = curl_init('https://micuenta.whatsmarketing.es/api/v1/contacts/{id}/identities');
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_CUSTOMREQUEST => 'POST',
  CURLOPT_HTTPHEADER => [
    'Authorization: Bearer ' . getenv('WM_API_KEY'),
    'Content-Type: application/json',
  ],
  CURLOPT_POSTFIELDS => json_encode([
    'channelType' => 'INSTAGRAM',
    'externalId' => 'laura.perez'
  ]),
]);
$data = json_decode(curl_exec($ch), true);
Respuesta 201
{
  "id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
  "contactId": "0b1c2d3e-5f6a-4b7c-8d9e-0f1a2b3c4d5e",
  "channelId": "5f6a7b8c-9d0e-4f1a-8b2c-3d4e5f6a7b8c",
  "channel": {
    "id": "5f6a7b8c-9d0e-4f1a-8b2c-3d4e5f6a7b8c",
    "type": "INSTAGRAM"
  },
  "externalId": "laura.perez"
}

Listar notas de un contacto

GET/contacts/{id}/notes

Notas internas del equipo, de la más reciente a la más antigua, con autor y fecha.

Permisos: contacts:read

Parámetros

NombreDóndeTipoValores
id obligatoriorutastring
pageconsultanumberpor defecto: 1 · 1 – …
pageSizeconsultanumberpor defecto: 20 · 1 – 100
curl
curl "https://micuenta.whatsmarketing.es/api/v1/contacts/{id}/notes?page=1&pageSize=20" \
  -H "Authorization: Bearer $WM_API_KEY"
Node.js
const res = await fetch('https://micuenta.whatsmarketing.es/api/v1/contacts/{id}/notes?page=1&pageSize=20', {
  headers: {
    Authorization: `Bearer ${process.env.WM_API_KEY}`,
  },
});
const data = await res.json();
Python
import os, requests

r = requests.get(
    "https://micuenta.whatsmarketing.es/api/v1/contacts/{id}/notes?page=1&pageSize=20",
    headers={"Authorization": f"Bearer {os.environ['WM_API_KEY']}"},
    timeout=30,
)
r.raise_for_status()
data = r.json()
PHP
<?php
$ch = curl_init('https://micuenta.whatsmarketing.es/api/v1/contacts/{id}/notes?page=1&pageSize=20');
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => [
    'Authorization: Bearer ' . getenv('WM_API_KEY'),
  ],
]);
$data = json_decode(curl_exec($ch), true);
Respuesta 200
{
  "data": [
    {
      "id": "8d9e0f1a-2b3c-4d4e-9f5a-6b7c8d9e0f1a",
      "contactId": "0b1c2d3e-5f6a-4b7c-8d9e-0f1a2b3c4d5e",
      "authorId": "2b3c4d5e-6f7a-4b8c-9d0e-1f2a3b4c5d6e",
      "author": {
        "id": "2b3c4d5e-6f7a-4b8c-9d0e-1f2a3b4c5d6e",
        "fullName": "Ana Gómez"
      },
      "body": "Pidió presupuesto por teléfono",
      "createdAt": "2026-10-09T17:12:00.000Z"
    }
  ],
  "meta": {
    "page": 1,
    "pageSize": 20,
    "total": 1,
    "totalPages": 1
  }
}

Añadir una nota

POST/contacts/{id}/notes

La nota queda a nombre del usuario que creó la clave de API.

Permisos: contacts:write

Parámetros

NombreDóndeTipoValores
id obligatoriorutastring

Cuerpo de la petición CreateContactNote

NombreTipoValores
body obligatoriostring1–… caracteres
curl
curl -X POST "https://micuenta.whatsmarketing.es/api/v1/contacts/{id}/notes" \
  -H "Authorization: Bearer $WM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "body": "Llamada hecha: le interesa el plan Pyme."
}'
Node.js
const res = await fetch('https://micuenta.whatsmarketing.es/api/v1/contacts/{id}/notes', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.WM_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "body": "Llamada hecha: le interesa el plan Pyme."
  }),
});
const data = await res.json();
Python
import os, requests

r = requests.post(
    "https://micuenta.whatsmarketing.es/api/v1/contacts/{id}/notes",
    headers={"Authorization": f"Bearer {os.environ['WM_API_KEY']}"},
    json={
        "body": "Llamada hecha: le interesa el plan Pyme."
    },
    timeout=30,
)
r.raise_for_status()
data = r.json()
PHP
<?php
$ch = curl_init('https://micuenta.whatsmarketing.es/api/v1/contacts/{id}/notes');
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_CUSTOMREQUEST => 'POST',
  CURLOPT_HTTPHEADER => [
    'Authorization: Bearer ' . getenv('WM_API_KEY'),
    'Content-Type: application/json',
  ],
  CURLOPT_POSTFIELDS => json_encode([
    'body' => 'Llamada hecha: le interesa el plan Pyme.'
  ]),
]);
$data = json_decode(curl_exec($ch), true);
Respuesta 201
{
  "id": "4c5d6e7f-8a9b-4c0d-9e1f-2a3b4c5d6e7f",
  "contactId": "0b1c2d3e-5f6a-4b7c-8d9e-0f1a2b3c4d5e",
  "authorId": "2b3c4d5e-6f7a-4b8c-9d0e-1f2a3b4c5d6e",
  "author": {
    "id": "2b3c4d5e-6f7a-4b8c-9d0e-1f2a3b4c5d6e",
    "fullName": "Ana Gómez"
  },
  "body": "Llamada hecha: le interesa el plan Pyme.",
  "createdAt": "2026-10-14T11:00:00.000Z"
}

Esquemas

Consent

NombreTipoValores
given obligatorioboolean
atstring
howstringOTHER · WEBSITE_FORM · PHONE · WHATSAPP_REPLY · CONTRACT