Abonnés
Gérez vos contacts abonnés, importez des listes et suivez l'engagement
Gérez vos contacts abonnés par e-mail. Chaque abonné possède un profil avec suivi de l'engagement, champs personnalisés et gestion des statuts.
Statuts des abonnés
| Statut | Valeur | Description |
|---|---|---|
Active | 0 | Abonné et recevant des e-mails |
Unsubscribed | 1 | Désinscrit des e-mails |
Bounced | 2 | Rebond permanent enregistré |
Complained | 3 | A signalé un spam |
Pending | 4 | Réservé : MailLand n'a pas de flux de double opt-in, donc rien ne définit jamais ce statut |
optInMethod et les champs consent* d'un abonné sont enregistrés uniquement comme preuve : ils ne pilotent aucun workflow de confirmation.
Créer un abonné
POST https://api.mail.land/v1/marketing/subscribers{
"email": "[email protected]",
"firstName": "John",
"lastName": "Doe",
"phone": "+1234567890",
"company": "Acme Corp",
"mailingListId": "ddv6ou6kz4wbto",
"source": "api",
"birthday": "1990-05-14",
"customFields": {
"plan": "enterprise",
"region": "us-west"
}
}| Champ | Type | Requis | Description |
|---|---|---|---|
email | string | Oui | Adresse e-mail |
firstName | string | Non | Prénom |
lastName | string | Non | Nom de famille |
phone | string | Non | Numéro de téléphone |
company | string | Non | Nom de l'entreprise |
mailingListId | string | Non | Liste de diffusion à rejoindre |
source | string | Non | Source de l'abonnement (p. ex. api, form, import) |
birthday | string | Non | YYYY-MM-DD. Lu par le déclencheur d'automatisation DateBased |
customFields | object | Non | Champs personnalisés clé-valeur |
curl -X POST https://api.mail.land/v1/marketing/subscribers \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
-H "Content-Type: application/json" \
-d '{
"email": "[email protected]",
"firstName": "John",
"lastName": "Doe",
"mailingListId": "ddv6ou6kz4wbto",
"source": "api"
}'Réponse
{
"id": "exz31qoqlf01sj",
"email": "[email protected]",
"firstName": "John",
"lastName": "Doe",
"phone": "+1234567890",
"company": "Acme Corp",
"status": "active",
"statusName": "Active",
"source": "api",
"mailingListId": "ddv6ou6kz4wbto",
"mailingListName": "Product Updates",
"customFields": {
"plan": "enterprise",
"region": "us-west"
},
"subscribedAt": "2026-02-17T12:00:00Z",
"unsubscribedAt": null,
"createdAt": "2026-02-17T12:00:00Z",
"updatedAt": "2026-02-17T12:00:00Z"
}Lister les abonnés
GET https://api.mail.land/v1/marketing/subscribers| Paramètre | Type | Défaut | Description |
|---|---|---|---|
cursor | string | - | Curseur opaque issu du nextCursor de la page précédente. À omettre pour la première page. |
limit | int | 20 | Éléments par page |
search | string | - | Recherche par e-mail ou nom (pas par entreprise) |
mailingListId | string | - | Filtrer par liste de diffusion |
status | int | - | Filtrer par statut d'abonné |
sortBy | string | - | Champ de tri |
sortDesc | bool | false | Tri décroissant |
curl "https://api.mail.land/v1/marketing/subscribers?limit=20&mailingListId=ddv6ou6kz4wbto" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."Obtenir les détails d'un abonné
GET https://api.mail.land/v1/marketing/subscribers/{id}Retourne un profil étendu avec les métriques d'engagement :
curl https://api.mail.land/v1/marketing/subscribers/exz31qoqlf01sj \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."{
"id": "exz31qoqlf01sj",
"email": "[email protected]",
"firstName": "John",
"lastName": "Doe",
"phone": "+1234567890",
"company": "Acme Corp",
"status": "active",
"source": "api",
"mailingListId": "ddv6ou6kz4wbto",
"mailingListName": "Product Updates",
"customFields": { "plan": "enterprise" },
"birthday": "1990-05-14",
"emailsSent": 50,
"emailsOpened": 25,
"emailsClicked": 10,
"lastEmailSentAt": "2026-02-17T09:30:00Z",
"lastEmailOpenedAt": "2026-02-16T15:20:00Z",
"lastEmailClickedAt": "2026-02-15T11:10:00Z",
"openRate": 50.0,
"clickRate": 40.0,
"subscribedAt": "2026-01-15T08:00:00Z",
"createdAt": "2026-01-15T08:00:00Z",
"updatedAt": "2026-02-17T12:00:00Z"
}Mettre à jour un abonné
PUT https://api.mail.land/v1/marketing/subscribers/{id}{
"firstName": "Jane",
"lastName": "Smith",
"phone": "+1234567890",
"company": "TechCorp",
"mailingListId": "ddv6ou6kz4wbto",
"customFields": { "plan": "pro" },
"birthday": "1990-05-14",
"status": "Active"
}PUT remplace tout le profil, il ne fusionne pas. firstName, lastName, phone, company et mailingListId sont tous écrasés par null (ou suppression de liste) lorsqu'ils sont omis, et non laissés inchangés. Omettre mailingListId supprime l'appartenance à la liste de l'abonné. Envoyez chaque champ que vous souhaitez conserver, y compris mailingListId. Seuls customFields et status restent inchangés lorsqu'ils sont omis. birthday suit sa propre règle : omettre le champ le laisse inchangé, envoyer "birthday": null l'efface, et une valeur YYYY-MM-DD le définit, une chaîne vide ("") est refusée avec 400. Si le destinataire a déjà un contact sans liste, l'appartenance supprimée est conservée uniquement comme historique : elle n'apparaît plus dans les contacts, et ses désinscriptions, ses preuves de consentement et son historique de campagnes sont préservés.
curl -X PUT https://api.mail.land/v1/marketing/subscribers/exz31qoqlf01sj \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
-H "Content-Type: application/json" \
-d '{
"firstName": "Jane",
"lastName": "Smith",
"company": "TechCorp",
"mailingListId": "ddv6ou6kz4wbto",
"customFields": { "plan": "pro" },
"status": "Active"
}'Désinscrire un abonné
POST https://api.mail.land/v1/marketing/subscribers/{id}/unsubscribeEnregistre une désinscription limitée à la liste de l'abonné, ou à tous les envois marketing si l'abonné n'a pas de liste, et définit le statut de l'abonné sur Unsubscribed avec un horodatage unsubscribedAt. Les e-mails transactionnels ne sont pas affectés par cet appel.
curl -X POST https://api.mail.land/v1/marketing/subscribers/exz31qoqlf01sj/unsubscribe \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."Supprimer un abonné
DELETE https://api.mail.land/v1/marketing/subscribers/{id}Supprime définitivement l'abonné et ses données d'engagement. Les désinscriptions et suppressions sont conservées, donc réajouter la même adresse ne la réabonne pas.
curl -X DELETE https://api.mail.land/v1/marketing/subscribers/exz31qoqlf01sj \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."Importer des abonnés
POST https://api.mail.land/v1/marketing/subscribers/importImportez des abonnés à partir d'un contenu CSV :
{
"mailingListId": "ddv6ou6kz4wbto",
"csvContent": "email,firstName,lastName\n[email protected],John,Doe\n[email protected],Jane,Smith",
"source": "csv_import",
"updateExisting": true
}| Champ | Type | Requis | Description |
|---|---|---|---|
mailingListId | string | Non | Liste de diffusion cible |
csvContent | string | Oui | Données CSV : voir l'avertissement de format ci-dessous, la ligne d'en-tête n'est pas utilisée comme en-tête |
La première ligne est traitée comme un en-tête et ignorée, quel que soit son contenu : elle n'est jamais lue pour mapper les colonnes 1 à 3 aux champs. Les colonnes sont positionnelles : la colonne 1 est toujours email, la colonne 2 toujours firstName, la colonne 3 toujours lastName ; toute autre colonne est ignorée, sauf une intitulée birthday (insensible à la casse, à n'importe quelle position après la colonne 1), qui est lue par le nom de son en-tête et non par sa position. Sa valeur doit être au format YYYY-MM-DD ; une valeur invalide est signalée par ligne dans errors et ce contact est quand même importé, simplement sans anniversaire. Un fichier sans en-tête birthday se comporte exactement comme avant. Les valeurs sont séparées par de simples virgules, donc une valeur contenant une virgule entre guillemets n'est pas prise en charge et sera divisée incorrectement. La réponse ajoute également les compteurs importedNewMembershipForExistingRecipient, updatedMembership, alreadyMember, suppressed et skippedDuplicateInFile en plus de ce qui est montré ci-dessous.
| source | string | Non | Libellé de la source d'import |
| updateExisting | bool | Non | Mettre à jour les abonnés existants (défaut : false) |
curl -X POST https://api.mail.land/v1/marketing/subscribers/import \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
-H "Content-Type: application/json" \
-d '{
"mailingListId": "ddv6ou6kz4wbto",
"csvContent": "email,firstName,lastName\[email protected],John,Doe\[email protected],Jane,Smith",
"source": "csv_import",
"updateExisting": true
}'{
"imported": 50,
"updated": 10,
"skipped": 5,
"errors": [
"Invalid email: not-an-email",
"Could not resolve a recipient identity for: [email protected]"
]
}Les abonnés importés déclenchent l'automatisation SubscriberJoins, pour chaque appartenance que l'import valide réellement : de la même façon qu'une création individuelle via POST /v1/marketing/subscribers. Un contact déjà présent sur la liste cible, un doublon au sein du fichier, ou une ligne perdue à cause d'un conflit (TenantId, Email) n'est pas inscrit. Si la liste cible a une automatisation SubscriberJoins active (ou que le tenant en a une non liée à une liste), importer un fichier de nouveaux contacts envoie désormais cette automatisation à chacun d'eux, dimensionnez l'import en conséquence. La suppression reste appliquée : l'inscription ne contourne jamais un destinataire supprimé.
Exporter les abonnés
GET https://api.mail.land/v1/marketing/subscribers/export| Paramètre | Type | Description |
|---|---|---|
mailingListId | string | Filtrer par liste de diffusion |
status | int | Filtrer par statut |
Retourne un téléchargement de fichier CSV avec le nom subscribers_yyyyMMdd_HHmmss.csv.
curl "https://api.mail.land/v1/marketing/subscribers/export?mailingListId=ddv6ou6kz4wbto" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
-o subscribers_export.csvStatistiques des abonnés
GET https://api.mail.land/v1/marketing/subscribers/stats| Paramètre | Type | Description |
|---|---|---|
mailingListId | string | Filtrer par liste de diffusion |
curl "https://api.mail.land/v1/marketing/subscribers/stats?mailingListId=ddv6ou6kz4wbto" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."{
"total": 1500,
"active": 1200,
"unsubscribed": 200,
"bounced": 80,
"complained": 10,
"pending": 10
}Nombre d'abonnés
GET https://api.mail.land/v1/marketing/subscribers/count| Paramètre | Type | Description |
|---|---|---|
mailingListId | string | Filtrer par liste de diffusion |
curl "https://api.mail.land/v1/marketing/subscribers/count?mailingListId=ddv6ou6kz4wbto" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."{
"count": 1500,
"mailingListId": "ddv6ou6kz4wbto"
}Croissance des abonnés
GET https://api.mail.land/v1/marketing/subscribers/growth| Paramètre | Type | Défaut | Description |
|---|---|---|---|
days | int | 30 | Période d'analyse (max 90) |
mailingListId | string | - | Filtrer par liste de diffusion |
curl "https://api.mail.land/v1/marketing/subscribers/growth?days=30&mailingListId=ddv6ou6kz4wbto" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."{
"dataPoints": [
{
"date": "2026-02-17",
"newSubscribers": 50,
"unsubscribes": 5,
"cumulativeTotal": 1500
}
],
"totalNew": 500,
"totalUnsubscribes": 50,
"netGrowth": 450,
"currentTotal": 1500
}Réponses d'erreur
| Statut | Code | Description |
|---|---|---|
400 | INVALID_EMAIL_FORMAT | Format d'e-mail invalide |
400 | INVALID_REQUEST | L'adresse e-mail de l'abonné existe déjà |
403 | FORBIDDEN | Permissions insuffisantes |
404 | RESOURCE_NOT_FOUND | Abonné introuvable |