Whapier

Sviluppatori

Documentazione API

Un'API REST autenticata con token per messaggi, template, contatti, campagne, flussi e stato di consegna e costo di ogni messaggio. Crea una chiave API nella sezione Strumenti per sviluppatori del tuo account, poi autentica ogni chiamata con Authorization: Bearer <token>.

Esempi completi in PHP, Node.js, Python, Java e Ruby sono disponibili nella documentazione dentro l'app dopo che hai creato un account.

Riferimento leggibile dalle macchine: OpenAPI 3.1 (JSON) · Collezione Postman

Prima di iniziare

Autenticazione

Ogni richiesta porta una chiave API nell'header Authorization come token Bearer. Le chiavi si creano in Strumenti per sviluppatori > Chiavi API e vengono mostrate una sola volta.

Una chiave ha degli scope: read (ogni GET), send (gli endpoint di invio, le campagne e gli avvii di flusso) e manage (creare, modificare ed eliminare contatti, gruppi, risposte automatiche, webhook e template, più le azioni della inbox). Una chiave senza lo scope riceve 403 con il nome dello scope mancante.

Una chiave può scadere: una chiave scaduta riceve 401 con "This API key has expired". Anche un token mancante o sconosciuto è un 401.

Una chiave sandbox valida ogni richiesta, registra il messaggio con stato "sandbox" e non invia nulla a WhatsApp - sviluppa contro l'API reale senza una linea WhatsApp e senza costi.

Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>
Limite di richieste

60 richieste al minuto per chiave API; le richieste senza chiave vengono contate per indirizzo IP.

Ogni risposta porta X-RateLimit-Limit e X-RateLimit-Remaining. Oltre il limite la risposta è un 429 con statusCode 429, un message e un header Retry-After in secondi.

GET /api/usage riporta il limite in rate_limit.per_minute. /api e /api/v2 condividono un unico bucket per chiave.

HTTP/1.1 429 Too Many Requests
Retry-After: 42
{"statusCode": 429, "message": "Too many requests. Try again in 42 seconds."}
Idempotenza

Invia un header Idempotency-Key (da 1 a 128 caratteri, unico per operazione) sugli endpoint POST che creano qualcosa: gli invii, le campagne, i contatti, i gruppi e le risposte automatiche.

La stessa chiave con la stessa richiesta entro 24 ore restituisce la risposta memorizzata con l'header Idempotent-Replayed: true, e nulla viene eseguito di nuovo. Un client che ritenta dopo un timeout non invia più due volte.

La stessa chiave con una richiesta diversa è un 422; la stessa chiave mentre la prima richiesta è ancora in corso è un 409. Vengono memorizzate solo le risposte 2xx e 4xx, quindi un 5xx può essere ritentato con la stessa chiave.

Idempotency-Key: 7c9e6679-7425-40de-944b-e07fc1f90ae7
Date e fusi orari

Ogni data restituita dall'API è in UTC, in ISO-8601 con il suo offset, qualunque sia il fuso orario usato dall'organizzazione nella dashboard.

Le date che invii (scheduled_at, since) vengono lette come UTC, a meno che non portino un offset.

"created_at": "2026-10-05T09:30:00+00:00"
Errori

Ogni risposta è JSON con statusCode e message; un payload rifiutato aggiunge errors, una mappa da nome del campo a elenco dei problemi.

400 input non valido; 401 chiave mancante, non valida o scaduta; 403 scope, abbonamento, limite del piano o account in revisione; 404 uuid sconosciuto, o appartenente a un altro workspace; 409 conflitto (una transizione di campagna non possibile, un Idempotency-Key ancora in corso); 422 rifiutato da una regola (la finestra di 24 ore, STOP, le variabili del template); 429 limite di richieste; 500 colpa nostra.

Le azioni della inbox (assign, close e reopen su /api/conversations/{contact_uuid}) rispondono 409 finché il ticketing è disattivato in Impostazioni > Ticket; leggere la conversazione e aggiungere una nota funzionano in ogni caso.

Su /api (v1) un rifiuto da parte di WhatsApp stesso è un 200 con data.success false e il motivo in data.data.error (code, message, type). Su /api/v2 lo stesso rifiuto è un HTTP 422 - vedi Versioni.

{"statusCode": 400, "message": "The given data was invalid.", "errors": {"phone": ["The phone number is not valid."]}}
Paginazione

Gli endpoint di elenco accettano page (da 1) e per_page (predefinito 10, max 100; /api/messages ha come predefinito 25) e sono ordinati dal più recente.

Contatti, gruppi, risposte automatiche, template, campagne e log delle campagne rispondono con data, links e meta (current_page, last_page, per_page, total). /api/messages risponde con statusCode, data e meta (page, per_page, total, last_page).

Una conversazione è invece paginata per cursore: GET /api/contacts/{uuid}/messages e GET /api/conversations/{contact_uuid} rispondono dal più recente con next_before; passalo come before per ottenere i messaggi più vecchi.

Inviare un template

Un invio di template deve portare esattamente tanti parametri quanti sono i segnaposto del template approvato; Meta rifiuta una discrepanza con l'errore 132000.

GET /api/templates/{uuid} restituisce example_payload: un corpo completo per POST /api/send/template con il numero giusto di parametri per header, corpo e pulsanti URL - sostituisci i valori e invialo.

POST /api/templates invia un template a Meta da una forma JSON piatta e risponde con il motivo di Meta quando viene rifiutato; POST /api/templates/sync scarica i template da Meta dopo una modifica in Meta Business Manager.

GET https://whapier.com/api/templates/{{uuid}}
{"data": {"name": "order_update", "variables": {"header": 0, "body": 1, "buttons": 0}, "example_payload": {"phone": "+40721000001", "template": {"name": "order_update", "language": {"code": "en"}, "components": [{"type": "body", "parameters": [{"type": "text", "text": "Ana"}]}]}}}}
Webhook

I webhook in uscita si configurano in Strumenti per sviluppatori > Webhook oppure tramite API (POST /api/webhooks): un URL https e gli eventi da ricevere. Il secret di firma viene generato per te e mostrato una sola volta. Ogni consegna è un POST con un corpo JSON che porta event e data.

L'header X-Whapier-Signature è "sha256=" seguito dall'HMAC-SHA256 del corpo grezzo della richiesta con quel secret, in esadecimale. Ricalcolalo sui byte che hai ricevuto e confrontalo prima di fidarti del payload.

Rispondi 2xx entro 15 secondi. Una consegna fallita viene ritentata altre due volte, dopo 60 secondi e dopo 5 minuti; dopo il terzo fallimento l'evento viene scartato.

Gli eventi: message.received e message.sent; message.status quando Meta segnala un messaggio come delivered, read o failed (con l'errore e la campagna da cui proviene); campaign.finished con i conteggi finali; ticket.created e ticket.closed; contact.opted_out e contact.opted_in; contact, group e autoreply created, updated e deleted; template.status.update, template.quality.update e account.update come li invia Meta. GET /api/webhooks/events li elenca con una descrizione e POST /api/webhooks/{uuid}/test consegna un esempio.

X-Whapier-Signature: sha256=5d41402abc4b2a76b9719d911017c592...
{"event": "message.status", "data": {"uuid": "64968a32-fdd9-4c1d-8941-b8e538036616", "wam_id": "wamid.HBgM...", "status": "delivered", "timestamp": "2026-10-05T09:30:00+00:00", "failure": null, "contact": {"uuid": "81a2d165-41e2-43f2-847e-d69e08cba0e0", "phone": "+40721000001"}, "campaign": null}}
{"event": "campaign.finished", "data": {"uuid": "3f1c2d0e-5b7a-4c8d-9e0f-1a2b3c4d5e6f", "name": "October offers", "status": "completed", "counts": {"contacts": 120, "sent": 118, "delivered": 110, "read": 64, "failed": 2}, "finished_at": "2026-10-05T09:30:00+00:00"}}
message.received
message.sent
message.status
message.status.update
contact.created
contact.updated
contact.deleted
contact.opted_out
contact.opted_in
group.created
group.updated
group.deleted
autoreply.created
autoreply.updated
autoreply.deleted
campaign.finished
ticket.created
ticket.closed
template.status.update
template.quality.update
account.update
Versioni: v1 e v2

/api (versione 1) resta supportato così com'è. /api/v2 serve gli stessi endpoint, payload e campi con una differenza: lo stato HTTP porta l'esito.

Su v2 un rifiuto da parte di WhatsApp su un invio è un HTTP 422 il cui corpo ha statusCode 422, il message, error (code, message e type di WhatsApp) e data (la risposta v1), invece di un 200 con data.success false. Ogni volta che statusCode nel corpo differisce dallo stato HTTP, lo stato HTTP segue statusCode.

Tutto il resto - autenticazione, scope, limite di richieste, idempotenza, date, paginazione - è identico, e la stessa chiave funziona su entrambi.

POST https://whapier.com/api/v2/send
{"statusCode": 422, "message": "Template name does not exist", "error": {"code": 132001, "message": "Template name does not exist", "type": "OAuthException"}, "data": {"success": false, "message": "Template name does not exist", "data": {"error": {"code": 132001}}}}

Verifica

GET /api/verify Verifica la chiave API
# Conferma che il token Bearer è valido e che l'abbonamento dell'organizzazione è attivo, prima di chiamare gli altri endpoint.
# HTTP 200: token OK. 401: token mancante/non valido. 403: abbonamento non attivo.

curl -X GET \
https://whapier.com/api/verify \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Accept: application/json'

Contatti

GET /api/contacts Ottieni l'elenco dei contatti
# Query facoltativa: ?page=1&per_page=10 (per_page massimo 100).
# Dal più recente. Risposta: data (oggetti contatto), links e meta (current_page, last_page, per_page, total).
# Un contatto: id, uuid, phone, first_name, last_name, email, address, metadata, groups (uuid, name), source, opted_in_at, opted_out_at, created_at, updated_at.
# Filtri di ricerca, combinati con AND: phone (qualsiasi formato leggibile con il paese dell'organizzazione; 400 quando non è un numero), email (esatta, senza distinzione tra maiuscole e minuscole), q (da 2 a 128 caratteri, cercato in nome, email e numero), group (l'uuid di un gruppo di contatti; 400 se sconosciuto), opted_out (true | false), updated_since (una data, UTC), source (api, manual, import, entry point...).

curl -X GET \
"https://whapier.com/api/contacts?page=1&per_page=10" \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Accept: application/json'
GET /api/contacts/{uuid} Ottieni un contatto
# L'oggetto contatto di Ottieni l'elenco dei contatti più unread_messages, last_message_at e ticket (status, assigned_to: name, email).
# ticket è null finché il ticketing è disattivato in Impostazioni > Ticket, o quando la conversazione non ha ancora un ticket. 404 quando l'uuid è sconosciuto, eliminato o appartiene a un altro workspace.

curl -X GET \
https://whapier.com/api/contacts/{{uuid}} \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Accept: application/json'
POST /api/contacts Aggiungi contatto
# Campi del corpo JSON:
#   phone (obbligatorio) — numero internazionale; validato e salvato in formato E.164. Deve essere unico all'interno dell'organizzazione (400 se duplicato).
#   first_name, last_name, email (facoltativi) — omettili, oppure passa null o "" per i contatti senza nome.
#   street, city, state, zip, country (facoltativi) — salvati nel JSON address.
#   metadata (facoltativo) — qualsiasi valore serializzabile in JSON.
#   group (facoltativo) — array di stringhe UUID dei gruppi di contatti.
#   marketing_opt_in (facoltativo, booleano) — true registra il consenso al marketing sul contatto (traccia del consenso GDPR, source: api); false registra un opt-out. Omettilo per lasciare invariato il consenso.
# Risposte: 200 successo { statusCode, id, message }; 400 errore di validazione; 403 abbonamento non attivo o limite di contatti raggiunto.
# Accetta un header Idempotency-Key (vedi Prima di iniziare).

curl -X POST \
https://whapier.com/api/contacts \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{
    "phone": "+40721000001",
    "first_name": "Ana",
    "last_name": "Pop",
    "email": "ana@example.com",
    "group": [
        "d746e4c5-db24-4fb2-be03-590421344d69"
    ],
    "marketing_opt_in": true
}'
POST /api/contacts/bulk Crea o aggiorna contatti in blocco
# contacts (obbligatorio, da 1 a 500 oggetti) con i campi di Aggiungi contatto per ogni riga. Una riga il cui phone esiste già nel workspace viene aggiornata con i campi presenti (come fa Modifica contatto); un numero nuovo viene creato.
# Ogni riga è indipendente: una riga errata fallisce da sola e le altre passano. Risposta: { statusCode, created, updated, failed: [ { index, phone, errors } ], limit_reached, message }.
# La creazione si ferma al limite di contatti del piano: limit_reached diventa true e le righe che non sono entrate sono elencate in failed. Gli aggiornamenti non contano mai verso il limite. Accetta un header Idempotency-Key.

curl -X POST \
https://whapier.com/api/contacts/bulk \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{
    "contacts": [
        {
            "phone": "+40721000001",
            "first_name": "Ana",
            "last_name": "Pop",
            "email": "ana@example.com"
        },
        {
            "phone": "0721 000 002",
            "first_name": "Ion",
            "group": [
                "d746e4c5-db24-4fb2-be03-590421344d69"
            ]
        },
        {
            "phone": "not-a-phone",
            "first_name": "Nobody"
        }
    ]
}'
PUT /api/contacts/{uuid} Modifica contatto
# Stessi campi JSON di Aggiungi contatto. {uuid} nel percorso è l'id del contatto restituito alla creazione.
# phone è facoltativo in un aggiornamento; se lo cambi, il nuovo numero non deve appartenere a un altro contatto (400 duplicato).
# È consentito aggiornare con lo stesso phone di questo contatto.
# I campi che ometti mantengono il loro valore; invia un campo come null o "" per svuotarlo. Le chiavi di metadata che invii vengono unite a quelle salvate, le altre restano.
# marketing_opt_in (facoltativo, booleano) — true registra il consenso al marketing (source: api), false registra un opt-out; se omesso, il consenso resta invariato.
# 404 quando l'uuid è sconosciuto, eliminato o appartiene a un altro workspace.

curl -X PUT \
https://whapier.com/api/contacts/{{uuid}} \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{
    "first_name": "Ana",
    "last_name": "Popescu",
    "metadata": {
        "plan": "platinum"
    }
}'
DELETE /api/contacts/{uuid} Elimina contatto
# Esegue un soft delete del contatto, che esce subito da tutti gli elenchi. 404 quando l'uuid è sconosciuto o già eliminato.
# Risposta: { statusCode, id, message }.

curl -X DELETE \
https://whapier.com/api/contacts/{{uuid}} \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Accept: application/json'

Gruppi di contatti

GET /api/contact-groups Ottieni l'elenco dei gruppi di contatti
# Query facoltativa: ?page=1&per_page=10 (per_page massimo 100).
# Ogni gruppo: uuid, name, contacts_count (membri attivi), created_at, updated_at.

curl -X GET \
"https://whapier.com/api/contact-groups?page=1&per_page=10" \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Accept: application/json'
POST /api/contact-groups Aggiungi gruppo di contatti
# name (obbligatorio) deve essere unico tra i gruppi dell'organizzazione (400 se già in uso).
# Risposta: { statusCode, id, message }. Accetta un header Idempotency-Key.

curl -X POST \
https://whapier.com/api/contact-groups \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{
    "name": "Lead 5"
}'
PUT /api/contact-groups/{uuid} Modifica gruppo di contatti
# Stesso corpo di Aggiungi gruppo di contatti. 404 per un uuid sconosciuto.

curl -X PUT \
https://whapier.com/api/contact-groups/{{uuid}} \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{
    "name": "Lead 5"
}'
DELETE /api/contact-groups/{uuid} Elimina gruppo di contatti
# Rimuove il gruppo e le sue appartenenze; i contatti stessi vengono conservati. 404 per un uuid sconosciuto.

curl -X DELETE \
https://whapier.com/api/contact-groups/{{uuid}} \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Accept: application/json'

Risposte automatiche

GET /api/canned-replies Ottieni l'elenco delle risposte automatiche
# Query facoltativa: ?page=1&per_page=10 (per_page massimo 100).
# Ogni risposta: uuid, name, trigger, match_criteria, response_type, response (il testo, oppure null per i media), file (name, url) oppure null, created_at, updated_at.

curl -X GET \
"https://whapier.com/api/canned-replies?page=1&per_page=10" \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Accept: application/json'
POST /api/canned-replies Aggiungi risposta automatica
# Corpo: name e trigger (max 255), match_criteria (exact match | contains), response_type (text | image | audio), response.
# Per text, response è la risposta (max 4096). Per image o audio invia multipart/form-data con il file come response (png/jpg fino a 5 MB; mp3/aac/ogg/amr/opus/m4a fino a 16 MB); senza file la richiesta è un 400.
# Risposta: { statusCode, id, message }. 403 quando è raggiunto il limite di risposte automatiche del piano. Accetta un header Idempotency-Key.

curl -X POST \
https://whapier.com/api/canned-replies \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{
    "name": "About Us",
    "trigger": "what do you do?",
    "match_criteria": "contains",
    "response_type": "text",
    "response": "We sell shoes"
}'
PUT /api/canned-replies/{uuid} Modifica risposta automatica
# Stessi campi di Aggiungi risposta automatica. Un aggiornamento senza file mantiene il media già presente. 404 per un uuid sconosciuto.

curl -X PUT \
https://whapier.com/api/canned-replies/{{uuid}} \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{
    "name": "About Us",
    "trigger": "what do you do?",
    "match_criteria": "contains",
    "response_type": "text",
    "response": "We sell shoes and clothes"
}'
DELETE /api/canned-replies/{uuid} Elimina risposta automatica
# 404 per un uuid sconosciuto. Risposta: { statusCode, id, message }.

curl -X DELETE \
https://whapier.com/api/canned-replies/{{uuid}} \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Accept: application/json'

Linee WhatsApp

GET /api/whatsapp-connections Elenca le connessioni
# Restituisce l'uuid di ogni linea (da usare come whatsapp_connection su /api/send). Nessun id interno del database.
# Ogni riga: uuid, type, name, phone, display_phone_number e, per una linea WhatsApp Business, verified_name e number_status. 403 quando nessuna linea è connessa.

curl -X GET \
https://whapier.com/api/whatsapp-connections \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Accept: application/json'

Messaggi

POST /api/send Invia messaggio
# Facoltativo: whatsapp_connection (UUID da GET /api/whatsapp-connections). Omettilo per usare la linea predefinita dell'organizzazione.
# phone (obbligatorio) — qualsiasi formato; normalizzato in E.164 con il paese dell'organizzazione. Un numero nuovo diventa un contatto (first_name, last_name, email facoltativi).
# message (obbligatorio, max 4096); header e footer (facoltativi, max 60); buttons (facoltativo, fino a 3 di { id, title }).
# I messaggi liberi richiedono una finestra di 24 ore aperta: 422 quando l'ultimo messaggio del cliente è più vecchio di un giorno. 403: abbonamento, limite del piano, quota giornaliera di prova o account in revisione.
# Risposta: 200 { statusCode, data: { success, data: { chat: { uuid, wam_id, status, type, created_at, contact } } } }. Un rifiuto da parte di WhatsApp è un 200 con data.success false e data.data.error su /api; un HTTP 422 su /api/v2.
# Accetta un header Idempotency-Key.

curl -X POST \
https://whapier.com/api/send \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{
    "phone": "+40721000001",
    "message": "Hello Ana, how are you?",
    "whatsapp_connection": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
    "header": "Example Shoes",
    "footer": "Reply STOP to opt out",
    "buttons": [
        {
            "id": "yes",
            "title": "Fine"
        },
        {
            "id": "no",
            "title": "Not well"
        }
    ]
}'
POST /api/send/media Invia media
# Facoltativo: whatsapp_connection (UUID da GET /api/whatsapp-connections). Omettilo per usare la linea predefinita dell'organizzazione.
# media_type (image | video | audio | document | sticker); media_url (https, un host pubblico; verificato con una richiesta HEAD rispetto ai limiti di dimensione e tipo di WhatsApp - altrimenti 400 con il motivo); caption (facoltativo, non per audio); file_name (obbligatorio per document).
# Stessi controlli e stessa risposta di Invia messaggio.

curl -X POST \
https://whapier.com/api/send/media \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{
    "phone": "+40721000001",
    "media_type": "image",
    "media_url": "https://cdn.example.com/offers/october.jpg",
    "caption": "Our October offers"
}'
POST /api/send/template Invia messaggio template
# Facoltativo: "whatsapp_connection": "<uuid>" per una linea WABA specifica (UUID da GET /api/whatsapp-connections).
# template.name e template.language ("en" oppure { "code": "en" }) sono obbligatori; components segue la struttura di WhatsApp (header, body, parametri dei pulsanti).
# Funziona fuori dalla finestra di 24 ore. A un contatto che ha fatto opt-out (STOP) non viene inviato un template MARKETING: 422. I template di utilità e di autenticazione vengono comunque inviati.
# Stessi controlli e stessa risposta di Invia messaggio.

curl -X POST \
https://whapier.com/api/send/template \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{
    "phone": "+40721000001",
    "template": {
        "name": "order_update",
        "language": {
            "code": "en"
        },
        "components": [
            {
                "type": "header",
                "parameters": [
                    {
                        "type": "text",
                        "text": "48213"
                    }
                ]
            },
            {
                "type": "body",
                "parameters": [
                    {
                        "type": "text",
                        "text": "Ana"
                    },
                    {
                        "type": "text",
                        "text": "48213"
                    },
                    {
                        "type": "date_time",
                        "date_time": {
                            "fallback_value": "October 7, 2026"
                        }
                    }
                ]
            },
            {
                "type": "button",
                "sub_type": "url",
                "index": "0",
                "parameters": [
                    {
                        "type": "text",
                        "text": "48213"
                    }
                ]
            }
        ]
    }
}'
POST /api/send/location Invia posizione
# latitude (da -90 a 90) e longitude (da -180 a 180) obbligatori; name e address facoltativi.
# Stessi controlli e stessa risposta di Invia messaggio.

curl -X POST \
https://whapier.com/api/send/location \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{
    "phone": "+40721000001",
    "latitude": 46.77120000000000032969182939268648624420166015625,
    "longitude": 23.623599999999999710098563809879124164581298828125,
    "name": "Example Shoes",
    "address": "Str. Memorandumului 12, Cluj-Napoca"
}'
POST /api/send/contacts Invia schede contatto
# contacts (da 1 a 10 schede) nella struttura contacts[] di WhatsApp: name.formatted_name obbligatorio; phones[], emails[], addresses[], org facoltativi.
# Stessi controlli e stessa risposta di Invia messaggio.

curl -X POST \
https://whapier.com/api/send/contacts \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{
    "phone": "+40721000001",
    "contacts": [
        {
            "name": {
                "formatted_name": "Example Shoes Support",
                "first_name": "Support"
            },
            "phones": [
                {
                    "phone": "+40700000000",
                    "type": "WORK"
                }
            ],
            "emails": [
                {
                    "email": "support@example.com",
                    "type": "WORK"
                }
            ]
        }
    ]
}'
POST /api/send/reaction Invia reazione
# message_id (il wam_id del messaggio a cui reagire) ed emoji (obbligatorio; "" rimuove la reazione).
# Stessi controlli e stessa risposta di Invia messaggio.

curl -X POST \
https://whapier.com/api/send/reaction \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{
    "phone": "+40721000001",
    "message_id": "wamid.HBgMNDA3MjEwMDAwMDEVAgARGBI5QkY2RkE3RDlCMjc2RjI2QkEA",
    "emoji": "👍"
}'
POST /api/send/location-request Richiedi posizione
# message (obbligatorio, max 1024): il testo mostrato sopra il pulsante "Invia posizione".
# Stessi controlli e stessa risposta di Invia messaggio.

curl -X POST \
https://whapier.com/api/send/location-request \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{
    "phone": "+40721000001",
    "message": "Where should we deliver?"
}'
POST /api/send/request-contact-info Richiedi dati di contatto
# message (obbligatorio, max 1024): chiede a un utente WhatsApp con solo username di condividere il proprio numero di telefono.
# Stessi controlli e stessa risposta di Invia messaggio.

curl -X POST \
https://whapier.com/api/send/request-contact-info \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{
    "phone": "+40721000001",
    "message": "Could you share your number so we can call you back?"
}'
POST /api/send/carousel Invia carosello
# message (obbligatorio, max 1024) e cards (da 2 a 10): header { type: image | video, link } obbligatorio; body (max 160), url_button { text, url } e quick_replies (fino a 3 di { id, title }) facoltativi.
# Stessi controlli e stessa risposta di Invia messaggio.

curl -X POST \
https://whapier.com/api/send/carousel \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{
    "phone": "+40721000001",
    "message": "Our new arrivals",
    "cards": [
        {
            "header": {
                "type": "image",
                "link": "https://cdn.example.com/shoes/1.jpg"
            },
            "body": "Runner, 89 EUR",
            "url_button": {
                "text": "See it",
                "url": "https://example.com/shoes/1"
            }
        },
        {
            "header": {
                "type": "image",
                "link": "https://cdn.example.com/shoes/2.jpg"
            },
            "body": "Trail, 119 EUR",
            "quick_replies": [
                {
                    "id": "trail",
                    "title": "Tell me more"
                }
            ]
        }
    ]
}'

Flussi

POST /api/flows/{uuid}/start Avvia un flusso
# contact (obbligatorio): l'uuid o il phone del contatto (normalizzato con il paese dell'organizzazione).
# 200 { statusCode, success: true, message }; 404 flusso o contatto sconosciuto; 422 flusso non pubblicato; 409 il contatto è già in una sessione di flusso.
# Tutto ciò che il flusso invia è soggetto alla finestra di 24 ore, a meno che non usi nodi template.

curl -X POST \
https://whapier.com/api/flows/{{uuid}}/start \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{
    "contact": "+40721000001"
}'

Campagne

GET /api/campaigns Elenca le campagne
# Facoltativo: ?page=1&per_page=10&search=
# Ogni campagna: uuid, name, status, scheduled_at, created_at, template (uuid, name, language, category, status), whatsapp_connection (uuid, name, type), audience (type: all | group | segment, uuid, name), counts (contacts, sent, delivered, read, failed).

curl -X GET \
"https://whapier.com/api/campaigns?page=1&per_page=10" \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Accept: application/json'
POST /api/campaigns Crea campagna (template WABA con variabili)
# Da usare quando whatsapp_connection è una linea WhatsApp Cloud (WABA) ottenuta da GET /api/whatsapp-connections.
#
# PREREQUISITI
# - template: UUID di una riga di GET /api/templates (limitata all'organizzazione), NON la stringa con il nome pubblico del template.
# - Fai corrispondere il numero di variabili al tuo template approvato: apri i metadati del template nell'interfaccia o in Meta — il BODY usa {{1}}, {{2}}, … in ordine.
# - Devi fornire un parametro del body per ogni segnaposto del BODY, nello stesso ordine. Un numero che non corrisponde al template approvato viene rifiutato subito (422), non da WhatsApp in seguito.
#
# NOTE SUI CAMPI
# - contacts: "all" oppure l'uuid di un gruppo di contatti; oppure segment: l'uuid di un segmento salvato (uno dei due, non entrambi). send_immediately: true, oppure scheduled_at (una data, letta come UTC).
# - header: oggetto facoltativo; se omesso equivale a { "format": "TEXT", "parameters": [] }.
# - body: usa body.parameters[] per le variabili. Formato API (consigliato): { "type": "text", "value": "literal for {{1}}" } per ogni posizione.
#   Alternativa (come nella dashboard): { "selection": "static", "value": "..." } oppure { "selection": "dynamic", "value": "first name" } (mappa i campi del contatto).
# - footer / buttons: facoltativi; usa [] o {} se non servono. I template con variabili negli URL o nelle risposte rapide richiedono buttons[] strutturato come nel modulo campagna web.
# - Header media (IMAGE|VIDEO|DOCUMENT): header.parameters[] con type (IMAGE|VIDEO|DOCUMENT), "selection": "link", "value": "https://..." (URL pubblico; l'API non può caricare file).
#
# RISPOSTA: 200 { "statusCode": 200, "uuid": "...", "message": "..." }. Interroga GET /api/campaigns/{uuid} per il report e GET /api/campaigns/{uuid}/logs per lo stato di ogni destinatario, oppure iscriviti al webhook campaign.finished.
# 403 quando è raggiunto il limite di campagne del piano. Accetta un header Idempotency-Key.

curl -X POST \
https://whapier.com/api/campaigns \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{
    "name": "Billing reminder blast",
    "whatsapp_connection": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
    "contacts": "all",
    "send_immediately": true,
    "template": "281a3383-985c-4084-bcb0-9ec523c952de",
    "header": {
        "format": "TEXT",
        "parameters": []
    },
    "body": {
        "parameters": [
            {
                "type": "text",
                "value": "Ana"
            },
            {
                "type": "text",
                "value": "48213"
            },
            {
                "type": "text",
                "value": "7 October 2026"
            }
        ]
    },
    "footer": {},
    "buttons": []
}'
GET /api/campaigns/{uuid} Ottieni una campagna con il suo report
# L'oggetto campagna di Elenca le campagne più report: counts (contacts, sent, delivered, read, failed, pending), failure_reasons (code, title, count - i dieci più frequenti), started_at, finished_at (null finché la campagna non è conclusa), paused_reason, paused_detail e paused_at (null a meno che lo stato sia paused).
# paused_reason è user (messa in pausa dalla dashboard o dall'API), admin, failing, failure_rate oppure quality (messa in pausa dalla piattaforma; paused_detail spiega perché). 404 per una campagna sconosciuta.

curl -X GET \
https://whapier.com/api/campaigns/{{uuid}} \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Accept: application/json'
POST /api/campaigns/{uuid}/pause Metti in pausa una campagna
# Nessun corpo. Solo una campagna scheduled o ongoing può essere messa in pausa: 409 altrimenti, con lo stato in cui si trova la campagna. I log restano come sono e la ripresa li riprende.
# Risposta: { statusCode, status, message } - status è il nuovo stato della campagna. 404 per una campagna sconosciuta.

curl -X POST \
https://whapier.com/api/campaigns/{{uuid}}/pause \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{}'
POST /api/campaigns/{uuid}/resume Riprendi una campagna
# Nessun corpo. Solo una campagna paused può essere ripresa: 409 altrimenti. Una campagna messa in pausa prima della sua ora torna a scheduled; una messa in pausa durante l'invio torna a ongoing.
# Risposta: { statusCode, status, message }. 404 per una campagna sconosciuta.

curl -X POST \
https://whapier.com/api/campaigns/{{uuid}}/resume \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{}'
POST /api/campaigns/{uuid}/cancel Annulla una campagna
# Nessun corpo. Una campagna scheduled, ongoing o paused può essere annullata: 409 altrimenti. Ciò che non è stato inviato resta non inviato; il report continua a mostrare chi è stato raggiunto.
# Risposta: { statusCode, status, message }. 404 per una campagna sconosciuta.

curl -X POST \
https://whapier.com/api/campaigns/{{uuid}}/cancel \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{}'
GET /api/campaigns/{uuid}/logs Log della campagna
# Facoltativo: ?page=1&per_page=10&search= (cerca per nome/telefono del contatto).
# Ogni riga: contact (uuid, phone, first_name, last_name), status, message (uuid, wam_id, status) oppure null, error (code, title, reason) oppure null, retry_count, created_at, updated_at. 404 per una campagna sconosciuta.

curl -X GET \
"https://whapier.com/api/campaigns/{{uuid}}/logs?page=1&per_page=10" \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Accept: application/json'

Template

GET /api/templates Elenca i template
# Query facoltativa: ?page=1&per_page=10 (per_page massimo 100).
# Ogni template: uuid, name, language, category, status, components (come approvati da WhatsApp), variables (header, body, buttons: quanti segnaposto accetta ciascuna parte), rejection (il motivo del rifiuto, oppure null), quality_score, updated_at.

curl -X GET \
"https://whapier.com/api/templates?page=1&per_page=10" \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Accept: application/json'
GET /api/templates/{uuid} Ottieni un template con un esempio pronto all'invio
# L'oggetto template di Elenca i template più example_payload: un corpo completo per POST /api/send/template con un parametro per ogni segnaposto (gli esempi con cui il template è stato inviato, altrimenti un valore che nomina la posizione), un link per un header multimediale e un suffisso per ogni pulsante URL con variabile.
# Query facoltativa: whatsapp_connection (l'uuid di una linea) quando lo stesso template esiste su più linee. 404 per un uuid sconosciuto.

curl -X GET \
https://whapier.com/api/templates/{{uuid}} \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Accept: application/json'
POST /api/templates Crea template
# name (lettere minuscole, cifre e underscore), category (MARKETING | UTILITY) e language (un codice lingua Meta come en o pt_BR) sono obbligatori; whatsapp_connection (l'uuid di una linea WhatsApp Business) è facoltativo - altrimenti la linea predefinita.
# header (facoltativo): { format: TEXT, text (max 60, un solo {{1}} ammesso), examples } oppure { format: IMAGE | VIDEO | DOCUMENT, media_url: un link https pubblico a un file di esempio }.
# body.text (obbligatorio, max 1024, segnaposto {{1}}, {{2}}, ...) con body.examples, uno per segnaposto; footer (facoltativo, max 60); buttons (facoltativo, fino a 10): { type: QUICK_REPLY | URL | PHONE_NUMBER | COPY_CODE, text, url, phone_number, example }.
# Risposta: 200 { statusCode, uuid, status, message } - status è PENDING finché Meta non lo esamina (il webhook template.status.update ti avvisa). 400 con il motivo di Meta quando Meta lo rifiuta; i template AUTHENTICATION non possono ancora essere inviati tramite API. Una chiave sandbox non può inviare (403). Accetta un header Idempotency-Key.

curl -X POST \
https://whapier.com/api/templates \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{
    "name": "order_update",
    "category": "UTILITY",
    "language": "en",
    "header": {
        "format": "TEXT",
        "text": "Order {{1}}",
        "examples": [
            "48213"
        ]
    },
    "body": {
        "text": "Hi {{1}}, your order {{2}} ships on {{3}}.",
        "examples": [
            "Ana",
            "48213",
            "October 7"
        ]
    },
    "footer": "Example Shoes",
    "buttons": [
        {
            "type": "URL",
            "text": "Track",
            "url": "https://example.com/track/{{1}}",
            "example": "48213"
        },
        {
            "type": "QUICK_REPLY",
            "text": "Stop updates"
        }
    ]
}'
POST /api/templates/sync Sincronizza i template da Meta
# Nessun corpo. Scarica da Meta i template di ogni linea WhatsApp Business, come fa l'aggiornamento della dashboard, così un template modificato in Meta Business Manager compare anche qui.
# Risposta: { statusCode, synced, message } - synced è il numero di template aggiunti o modificati. Una chiave sandbox non può sincronizzare (403); 400 quando Meta ha rifiutato la richiesta.

curl -X POST \
https://whapier.com/api/templates/sync \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{}'

Webhook

GET /api/webhooks Elenca i webhook
# Ogni riga: uuid, url, events, secret_preview (gli ultimi sei caratteri del secret di firma), created_at, updated_at. Il secret completo viene mostrato una sola volta, nella risposta di Aggiungi webhook.
# 403 quando il modulo Webhooks non è incluso nel piano.

curl -X GET \
https://whapier.com/api/webhooks \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Accept: application/json'
GET /api/webhooks/events Elenca gli eventi
# Ogni evento che un webhook può ricevere: data (name, description). La pagina Webhook della dashboard legge lo stesso catalogo.
# Una consegna è { event, data }; la forma di data per ogni evento è in Prima di iniziare > Webhooks, e POST /api/webhooks/{uuid}/test consegna un esempio di ciascuno.

curl -X GET \
https://whapier.com/api/webhooks/events \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Accept: application/json'
POST /api/webhooks Aggiungi webhook
# url (obbligatorio, https, unico per organizzazione) ed events (obbligatorio, uno o più nomi da GET /api/webhooks/events).
# Risposta: { statusCode, uuid, secret, message } - l'unica volta in cui il secret completo viene restituito; conservalo per verificare X-Whapier-Signature. Accetta un header Idempotency-Key.

curl -X POST \
https://whapier.com/api/webhooks \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{
    "url": "https://example.com/hooks/whapier",
    "events": [
        "message.received",
        "message.status",
        "campaign.finished"
    ]
}'
PUT /api/webhooks/{uuid} Modifica webhook
# Stesso corpo di Aggiungi webhook. L'elenco events sostituisce quello memorizzato; il secret resta com'è. 404 per un uuid sconosciuto.

curl -X PUT \
https://whapier.com/api/webhooks/{{uuid}} \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{
    "url": "https://example.com/hooks/whapier",
    "events": [
        "message.received",
        "message.status"
    ]
}'
DELETE /api/webhooks/{uuid} Elimina webhook
# Rimuove l'endpoint e le sue iscrizioni; non gli viene più consegnato nulla. Risposta: { statusCode, uuid, message }. 404 per un uuid sconosciuto.

curl -X DELETE \
https://whapier.com/api/webhooks/{{uuid}} \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Accept: application/json'
POST /api/webhooks/{uuid}/test Invia un evento di prova
# event (obbligatorio): un nome da GET /api/webhooks/events. Il payload di esempio viene inviato in POST all'url come { event, data, test: true }, firmato con il secret in X-Whapier-Signature.
# Risposta: { statusCode, event, delivered, http_status, message } - delivered è false con lo stato con cui ha risposto il tuo endpoint, oppure http_status null quando non è stato raggiungibile. 404 per un uuid sconosciuto.

curl -X POST \
https://whapier.com/api/webhooks/{{uuid}}/test \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{
    "event": "message.status"
}'

Stato dei messaggi

GET /api/messages Elenca i messaggi
# Query facoltativa: status (sent | delivered | read | failed | accepted | played), direction (inbound | outbound), since e until (date, UTC), contact (l'uuid di un contatto), campaign (l'uuid di una campagna: i messaggi che ha prodotto), wam_id (un messaggio per id WhatsApp), api_key (l'uuid di una chiave, oppure current: i messaggi inviati con la chiave che fa la richiesta), page, per_page (predefinito 25, max 100).
# Risposta: { statusCode, data: [ message ], meta: { page, per_page, total, last_page } }. 404 quando contact, campaign o api_key è sconosciuto.
# Un messaggio: uuid, wam_id, direction, status, type, content, created_at, delivered_at, read_at, failed_at, failure (code, title, reason, retryable) oppure null, pricing (category, model, billable, amount, currency, country), api_key (uuid, name) oppure null se non è stato inviato tramite l'API, contact (uuid, phone, first_name, last_name).
# content per type - text: body, header, footer, buttons (type, text); template: name, language, body; image, video, audio, document, sticker: caption, media (type, url, filename); interactive e button: text, payload (ciò che il cliente ha premuto); location: latitude, longitude, name, address; contacts: contacts (name, phones); reaction: emoji, wam_id.

curl -X GET \
"https://whapier.com/api/messages?status=failed&per_page=25" \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Accept: application/json'
GET /api/contacts/{uuid}/messages Conversazione con un contatto
# Gli stessi oggetti messaggio di Elenca i messaggi, per un solo contatto, dal più recente. Query facoltativa: per_page (predefinito 25, max 100), before (l'uuid del messaggio più vecchio che hai già).
# Risposta: { statusCode, data: [ message ], meta: { per_page, has_more, next_before } } - passa next_before come before per ottenere i messaggi più vecchi. 404 per un contatto o un cursore sconosciuto.

curl -X GET \
"https://whapier.com/api/contacts/{{uuid}}/messages?per_page=25" \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Accept: application/json'
GET /api/messages/{uuid} Ottieni un messaggio
# Lo stesso oggetto messaggio più history: un elenco di { status, timestamp, recorded_at }, ogni cambio di stato riportato da WhatsApp. 404 per un uuid sconosciuto.

curl -X GET \
https://whapier.com/api/messages/{{uuid}} \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Accept: application/json'

Utilizzo

GET /api/usage Piano e utilizzo
# Risposta data: plan (name, status, valid_until), limits (contacts, messages, campaigns: used, limit; limit null = illimitato), trial_daily_messages (solo account di prova), messages_sent (today, last_7_days, last_30_days), estimated_cost (last_30_days: amount, currency), rate_limit (per_minute).

curl -X GET \
https://whapier.com/api/usage \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Accept: application/json'

Inbox

GET /api/conversations/{contact_uuid} Ottieni una conversazione
# Risposta data: contact (uuid, phone, first_name, last_name), ticketing (se Impostazioni > Ticket è attivo), ticket (status, assigned_to: name, email; opened_at, waiting_since, resolved_at) oppure null, messages (uuid, wam_id, direction, type, text, status, created_at - i 50 più recenti, dal più nuovo), next_before.
# Query facoltativa: before (l'uuid del messaggio più vecchio che hai) per i messaggi precedenti; 400 quando il cursore non è un messaggio di questo contatto. 404 per un contatto sconosciuto.

curl -X GET \
https://whapier.com/api/conversations/{{uuid}} \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Accept: application/json'
POST /api/conversations/{contact_uuid}/assign Assegna una conversazione
# user_email (obbligatorio, può essere null): l'email di un membro attivo dell'organizzazione; null rimuove l'assegnazione del ticket. Una conversazione senza ticket ne riceve uno.
# Risposta: { statusCode, data: ticket, message } con il ticket come lo mostra Ottieni una conversazione. 409 finché il ticketing è disattivato; 422 quando nessun membro attivo dell'organizzazione ha quell'email; 404 per un contatto sconosciuto.

curl -X POST \
https://whapier.com/api/conversations/{{uuid}}/assign \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{
    "user_email": "maria@example.com"
}'
POST /api/conversations/{contact_uuid}/close Chiudi una conversazione
# Nessun corpo. Risolve il ticket (status closed, resolved_at impostato), come fa il pulsante della inbox. Risposta: { statusCode, data: ticket, message }.
# 409 finché il ticketing è disattivato; 404 per un contatto sconosciuto.

curl -X POST \
https://whapier.com/api/conversations/{{uuid}}/close \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{}'
POST /api/conversations/{contact_uuid}/reopen Riapri una conversazione
# Nessun corpo. Riapre un ticket chiuso (status open, resolved_at azzerato); un ticket aperto viene restituito com'è. Risposta: { statusCode, data: ticket, message }.
# 409 finché il ticketing è disattivato; 404 per un contatto sconosciuto.

curl -X POST \
https://whapier.com/api/conversations/{{uuid}}/reopen \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{}'
POST /api/conversations/{contact_uuid}/notes Aggiungi una nota interna
# note (obbligatorio, max 5000): visibile agli agenti nel thread, mai inviata al contatto. Funziona sia con il ticketing attivo che disattivato.
# Risposta: { statusCode, uuid, created_at, message }. 404 per un contatto sconosciuto. Accetta un header Idempotency-Key.

curl -X POST \
https://whapier.com/api/conversations/{{uuid}}/notes \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{
    "note": "Customer called; wants the order delivered on Friday."
}'

Ottieni una chiave API in due minuti

Prova gratuita, nessuna carta di credito — il pannello sviluppatori è incluso in tutti i piani.

Inizia la prova gratuita