POST /v1/actions/create-contact

Upsert un contact par numéro de téléphone avec nom, email, tags et métadonnées optionnels.

Crée un contact, ou met à jour celui qui existe si un contact avec le même téléphone est déjà présent dans votre tenant. Renvoie 201 que la ligne ait été insérée ou mise à jour.

POST /api/v1/actions/create-contact

Corps de la requête

Champ Type Requis Notes
phone string oui Format international avec +. Normalisé côté serveur.
name string non Nom d'affichage
email string non Doit être un email valide si fourni
tags string non Liste séparée par des virgules, p. ex. "vip, beta-testers, fr-FR". Les tags sont créés à la volée s'ils n'existent pas.
metadata object non JSON libre, max ~64 KB
curl -X POST https://www.qyvo.io/api/v1/actions/create-contact \
  -H "Authorization: Bearer YOUR_TOKEN_HERE" \
  -H "Content-Type: application/json" \
  -d '{
    "phone": "+14155550123",
    "name": "Romain",
    "email": "[email protected]",
    "tags": "vip, fr-FR",
    "metadata": { "shopify_id": "12345", "lifetime_value": 8742.00 }
  }'
const contact = await fetch('https://www.qyvo.io/api/v1/actions/create-contact', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.QYVO_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    phone: '+14155550123',
    name: 'Romain',
    email: '[email protected]',
    tags: 'vip, fr-FR',
    metadata: { shopify_id: '12345', lifetime_value: 8742.0 },
  }),
}).then((r) => r.json());
$contact = Http::withToken(env('QYVO_TOKEN'))
    ->post('https://www.qyvo.io/api/v1/actions/create-contact', [
        'phone' => '+14155550123',
        'name' => 'Romain',
        'email' => '[email protected]',
        'tags' => 'vip, fr-FR',
        'metadata' => ['shopify_id' => '12345', 'lifetime_value' => 8742.0],
    ])
    ->json();
import os, httpx
contact = httpx.post(
    'https://www.qyvo.io/api/v1/actions/create-contact',
    headers={'Authorization': f"Bearer {os.environ['QYVO_TOKEN']}"},
    json={
        'phone': '+14155550123',
        'name': 'Romain',
        'email': '[email protected]',
        'tags': 'vip, fr-FR',
        'metadata': {'shopify_id': '12345', 'lifetime_value': 8742.0},
    },
).json()

Réponse — 201 Created

{
  "id": "01J1Y...",
  "phone": "+14155550123",
  "name": "Romain",
  "email": "[email protected]",
  "tags": ["vip", "fr-FR"],
  "created_at": "2026-05-07T08:14:23+00:00"
}

Erreurs

Statut Cause
422 Validation (phone manquant, email invalide, nom trop long)
422 No workspace configured for this account.

Idempotence

L'endpoint fait un upsert sur (tenant_id, phone) — l'appeler deux fois avec le même téléphone ne crée jamais deux contacts. Le second appel met à jour le nom, l'email, les métadonnées et les tags. Pour éviter d'écraser des champs que vous ne voulez pas changer, utilisez update-contact pour les mises à jour partielles.