API Console
L’API Console vous permet d’automatiser les tâches liées à votre newsletter via HTTP, avec une authentification par clé API. C’est la même API que nous utilisons en interne dans la Console.
Premiers pas
- Créez une clé API Console dans Console → Paramètres → Clés API. Chaque clé doit recevoir un ou plusieurs scopes, qui limitent ce à quoi elle peut accéder.
- L’URL de base :
https://post.hyvor.com/api/console - Pour chaque requête, définissez l’en-tête
AuthorizationsurBearer <API_KEY>. - Méthodes HTTP disponibles :
GET- Récupérer une ressourcePOST- Créer une ressource ou effectuer une actionPUT- Mettre à jour une ressourceDELETE- Supprimer une ressource
- Les paramètres de requête peuvent être envoyés en
JSON(recommandé) ou enapplication/x-www-form-urlencoded. - Tous les endpoints renvoient des données JSON. La réponse est un objet ou un tableau d’objets.
Dans cette documentation, tous les objets, paramètres de requête et réponses sont écrits sous forme d'interfaces TypeScript afin de rendre les déclarations de types concises.
Catégories
Les endpoints de l’API Console sont classés selon la ressource avec laquelle ils interagissent.
Aller à une catégorie :
- Newsletter
- Numéro
- Listes
- Abonné
- Métadonnées d’abonné
- Profil d’envoi
- Modèle
- Utilisateur
- Clés API
- Médias
- Importations
- Exportation
Newsletter
Endpoints :
GET /newsletter- Récupérer les données de la newsletterPATCH /newsletter- Mettre à jour une newsletterDELETE /newsletter- Supprimer une newsletter
Objets :
Récupérer les données de la newsletter
GET /newsletter
type Request = {}
type Response = NewsletterMettre Ă jour une newsletter
PATCH /newsletter
type Request = Partial<Newsletter> // except id, created_at
type Response = NewsletterSupprimer une newsletter
DELETE /newsletter
type Request = {}
type Response = {}Numéro
Endpoints :
GET /issues- Récupérer les numérosPOST /issues- Créer un numéroGET /issues/{id}- Récupérer un numéroPATCH /issues/{id}- Mettre à jour un numéroDELETE /issues/{id}- Supprimer un numéroPOST /issues/{id}/send- Envoyer un numéroGET /issues/{id}/preview- Prévisualiser un numéroGET /issues/{id}/progress- Récupérer la progression de l’envoi d’un numéroGET /issues/{id}/sends- Récupérer les envois d’un numéroGET /issues/{id}/report- Récupérer le rapport d’un numéro
Objets :
Récupérer les numéros
GET /issues
type Request = {
limit?: number; // default: 50
offset?: number; // default: 0
}
type Response = Issue[]Créer un numéro
POST /issues
type Request = {}
type Response = IssueRécupérer un numéro
GET /issues/{id}
type Request = {}
type Response = IssueMettre à jour un numéro
PATCH /issues/{id}
type Request = {
subject?: string;
lists?: number[];
content?: string;
sending_profile_id?: number;
}
type Response = IssueSupprimer un numéro
DELETE /issues/{id}
type Request = {}
type Response = {}Envoyer un numéro
POST /issues/{id}/send
type Request = {}
type Response = IssuePrévisualiser un numéro
Génère l’aperçu HTML d’un numéro et renvoie le nombre d’abonnés auxquels il pourrait être envoyé.
GET /issues/{id}/preview
type Request = {}
type Response = {
html: string;
sendable_subscribers_count: number;
}Récupérer la progression de l'envoi d'un numéro
Récupère la progression de l’envoi d’un numéro en cours d’envoi.
GET /issues/{id}/progress
type Request = {}
type Response = {
total: number;
sent: number;
progress: number; // percentage, 0-100
} | null // null if the issue has no sends yetRécupérer les envois d'un numéro
GET /issues/{id}/sends
type Request = {
limit?: number; // default: 50
offset?: number; // default: 0
search?: string;
type?: string;
}
type Response = Send[]Récupérer le rapport d'un numéro
Récupère le nombre de distributions, d’ouvertures, de clics, de rebonds et de plaintes d’un numéro.
GET /issues/{id}/report
type Request = {}
type Response = {
counts: {
total: number;
pending: number;
sent: number;
failed: number;
unsubscribed: number;
bounced: number;
complained: number;
}
}Listes
Endpoints :
POST /lists- Créer une listePATCH /lists/{id}- Mettre à jour une listeDELETE /lists/{id}- Supprimer une liste
Objets :
Créer une liste
POST /lists
type Request = {
name: string; // max length: 255
description?: string;
}
type Response = ListMettre Ă jour une liste
PATCH /lists/{id}
type Request = {
name?: string; // max length: 255
description?: string;
}
type Response = ListSupprimer une liste
DELETE /lists/{id}
type Request = {}
type Response = {}Abonné
Endpoints :
GET /subscribers- Récupérer les abonnésGET /subscribers/email/{email}- Récupérer un abonné par e-mailPOST /subscribers- Créer ou mettre à jour un abonnéPOST /subscribers/{id}/resend-opt-in- Renvoyer l’e-mail de confirmation d’inscriptionDELETE /subscribers/{id}- Supprimer un abonnéPOST /subscribers/bulk- Mettre à jour des abonnés en masse
Objets :
Récupérer les abonnés
GET /subscribers
type Request = {
limit?: number; // default: 50
offset?: number; // default: 0
// filter by status
status?: 'subscribed' | 'unsubscribed' | 'pending';
// filter by list
list_id?: number;
// search by email
search?: string;
}
type Response = Subscriber[]Récupérer un abonné par e-mail
GET /subscribers/email/{email}
type Request = {}
type Response = Subscriber // 404 if not foundCréer ou mettre à jour un abonné
POST /subscribers
type Request = {
// If a subscriber with the given email already exists, it will be updated.
// Otherwise, a new subscriber will be created.
email: string;
// Subscribe to or unsubscribe from lists based
// on the given \`lists_strategy\`.
// an array of list IDs or names.
lists?: (number | string)[];
// The subscriber's subscription status
// default: subscribed
status?: 'subscribed' | 'pending';
// the source of the subscriber
// default: console
source?: 'console' | 'form' | 'import';
// subscriber's IP address
subscribe_ip?: string | null;
// unix timestamp of when the subscriber opted in
// if not set, it will be set to the current time if status is 'subscribed'
subscribed_at?: number | null; // unix timestamp
// additional metadata for the subscriber
// keys must be defined in the Subscriber Metadata Definitions section (or using the API)
metadata?: Record<string, string>;
// ============ SETTINGS ===========
// change how the endpoint behaves
// how \`lists\` field is processed when updating an existing subscriber's list subscriptions.
// merge: merges the lists (default)
// overwrite: overwrites the lists
// remove: removes from the current lists
lists_strategy?: 'merge' | 'overwrite' | 'remove';
// if the subscriber was previously removed from a list,
// define the reason(s) for skipping the re-subscription to that list.
// see below for more info
// default: ['unsubscribe', 'bounce', 'complaint']
list_skip_resubscribe_on?: ('unsubscribe' | 'bounce' | 'complaint' | 'other')[];
// define the reason for removing the subscriber from a list
// (only when updating, see below for more info)
// default: 'unsubscribe'
list_removal_reason?: 'unsubscribe' | 'bounce' | 'complaint' | 'other';
// whether to overwrite or merge the subscriber's metadata
// when updating an existing subscriber.
// default: 'merge'
metadata_strategy?: 'merge' | 'overwrite';
// whether to send a confirmation email when adding a subscriber with 'pending' status
// or when changing an existing subscriber's status to 'pending'.
// default: false
send_pending_confirmation_email?: boolean;
}
type Response = SubscriberGérer les désabonnements et réabonnements aux listes
Pour chaque abonné, Hyvor Post enregistre les listes dont il s’est précédemment désabonné. Cela facilite la création d’automatisations autour des abonnements aux listes, tout en respectant les préférences des abonnés.
list_skip_resubscribe_on : lors de l’ajout d’un abonné existant à une liste dont il a été retiré auparavant, ce paramètre détermine lesquels des motifs de retrait ci-dessous doivent bloquer le réajout. Par défaut, les désabonnements, rebonds et plaintes précédents bloquent tous le réajout ; passez un tableau vide pour toujours réajouter l’abonné, quelle que soit la raison de son départ.
list_removal_reason :
unsubscribe- utilisez ce motif si l’abonné demande explicitement à être retiré de la liste (par exemple, il a décoché une case pour se désabonner). Un désabonnement est alors enregistré, ce qui bloque les réajouts futurs, sauf si le paramètrelist_skip_resubscribe_onde la demande de réajout exclutunsubscribe. Le formulaire de désabonnement par défaut de Hyvor Post utilise ce motif.bounce- enregistré automatiquement lorsqu’un envoi à l’abonné provoque un rebond définitif.complaint- enregistré automatiquement lorsque l’abonné signale un envoi comme spam.other- utilisez ce motif si vous souhaitez retirer l’abonné de la liste sans l’enregistrer sous l’un des motifs ci-dessus (ne bloque pas les réajouts futurs par défaut).
Exemples
{
"email": "example@example.com",
"lists": ["Default"]
}{
"email": "example@example.com",
"lists": [123],
"lists_strategy": "add"
}{
"email": "example@example.com",
"lists": ["Paid Users"],
"lists_strategy": "remove",
// unsubscribe, bounce, or other
"list_removal_reason": "unsubscribe"
}{
"email": "example@example.com",
"lists": ["Default"],
"status": "pending",
"send_pending_confirmation_email": true
}{
"email": "example@example.com",
"lists": ["Default"],
"lists_strategy": "add",
// ignore unsubscription if the subscriber was removed from the list due to a bounce
// but allow re-adding if they previously unsubscribed themselves
"list_skip_resubscribe_on": ["bounce"]
}Pour forcer le réajout malgré les désabonnements et les rebonds précédents, utilisez un tableau
vide pour list_skip_resubscribe_on.
Renvoyer l'e-mail de confirmation d'inscription
Renvoie l’e-mail de confirmation d’inscription à un abonné en attente.
POST /subscribers/{id}/resend-opt-in
type Request = {}
type Response = {}Supprimer un abonné
DELETE /subscribers/{id}
type Request = {}
type Response = {}Mettre à jour des abonnés en masse
POST /subscribers/bulk
type Request = {
subscribers_ids: number[];
action: 'delete' | 'status_change' | 'metadata_update';
status?: 'subscribed' | 'unsubscribed' | 'pending'; // required if action is status_change
metadata?: Record<string, string>; // required if action is metadata_update
}
type Response = {
status: string;
message: string;
subscribers: Subscriber[];
}Métadonnées d'abonné
Les définitions de métadonnées d’abonné vous permettent de définir des champs personnalisés pour les abonnés. Ces champs servent à stocker des informations supplémentaires sur les abonnés.
Endpoints :
POST /subscriber-metadata-definitions- Créer une définition de métadonnée d’abonnéPATCH /subscriber-metadata-definitions/{id}- Mettre à jour une définition de métadonnée d’abonnéDELETE /subscriber-metadata-definitions/{id}- Supprimer une définition de métadonnée d’abonné
Objets :
Créer une définition de métadonnée d'abonné
POST /subscriber-metadata-definitions
type Request = {
key: string; // max length: 255
name: string; // max length: 255
}
type Response = SubscriberMetadataDefinitionkeyne peut contenir que des lettres minuscules, des chiffres et des tirets bas.- Une fois créée, la
keyne peut plus être modifiée.
Mettre à jour une définition de métadonnée d'abonné
PATCH /subscriber-metadata-definitions/{id}
type Request = {
name: string; // max length: 255
}
type Response = SubscriberMetadataDefinitionSupprimer une définition de métadonnée d'abonné
DELETE /subscriber-metadata-definitions/{id}
type Request = {}
type Response = {}Profil d'envoi
Endpoints :
GET /sending-profiles- Récupérer les profils d’envoiPOST /sending-profiles- Créer un profil d’envoiPATCH /sending-profiles/{id}- Mettre à jour un profil d’envoiDELETE /sending-profiles/{id}- Supprimer un profil d’envoi
Objets :
Récupérer les profils d'envoi
GET /sending-profiles
type Request = {}
type Response = SendingProfile[]Créer un profil d'envoi
POST /sending-profiles
type Request = {
from_email: string;
from_name?: string | null;
reply_to_email?: string | null;
brand_name?: string | null;
brand_logo?: string | null; // a publicly accessible URL of the logo
brand_url?: string | null;
}
type Response = SendingProfileMettre Ă jour un profil d'envoi
PATCH /sending-profiles/{id}
type Request = {
from_email?: string;
from_name?: string | null;
reply_to_email?: string | null;
brand_name?: string | null;
brand_logo?: string | null; // a publicly accessible URL of the logo
brand_url?: string | null;
is_default?: boolean;
}
type Response = SendingProfileSupprimer un profil d'envoi
Le profil d’envoi système ne peut pas être supprimé.
DELETE /sending-profiles/{id}
type Request = {}
type Response = SendingProfile[] // the newsletter's remaining sending profilesModèle
Hyvor Post propose un système de modèles de newsletter flexible qui vous permet de personnaliser l’apparence de vos newsletters.
Endpoints :
GET /templates- Récupérer le modèle de la newsletterPATCH /templates- Mettre à jour le modèle de la newsletterPOST /templates/render- Générer le modèle de la newsletter avec du contenu
Objets :
Récupérer le modèle de la newsletter
GET /templates
type Request = {}
type Response = TemplateMettre à jour le modèle de la newsletter
PATCH /templates
type Request = {
template?: string;
}
type Response = TemplateGénérer le modèle de la newsletter avec du contenu
POST /templates/render
type Request = {
template?: string | null;
}
type Response = {
html: string;
}Utilisateur
Les administrateurs de l’organisation propriétaire de la newsletter peuvent être ajoutés comme utilisateurs pour collaborer à sa gestion.
Endpoints :
GET /users- Récupérer les utilisateursPOST /users- Créer un utilisateurDELETE /users- Supprimer un utilisateur
Objets :
Récupérer les utilisateurs
GET /users
type Request = {}
type Response = User[]Créer un utilisateur
POST /users
L’utilisateur doit déjà être membre de l’organisation propriétaire de cette newsletter.
type Request = {
user_id: number; // the user's id in HYVOR (AuthInterface)
// what to do if the user is already added to the newsletter
// throw: return a 400 error (default)
// ignore: return the existing user without an error
on_duplicate?: 'throw' | 'ignore';
}
type Response = User- Renvoie une erreur 400 si l'utilisateur n'est pas membre de l'organisation propriétaire de cette newsletter.
Supprimer un utilisateur
DELETE /users
type Request = {
// one of user_id or id is required
user_id?: number; // the user's id in HYVOR (AuthInterface)
id?: number; // the user's id in this newsletter's user list
}
type Response = {}Clés API
Chaque clé API reçoit un ou plusieurs scopes, qui limitent les ressources et les actions auxquelles elle peut accéder. Scopes disponibles :
newsletter.read/newsletter.write/newsletter.deleteissues.read/issues.writesending_profiles.read/sending_profiles.writesubscribers.read/subscribers.writeusers.read/users.writetemplates.read/templates.writeapi_keys.read/api_keys.writemedia.writedata.read/data.write- listes d’abonnés, importations et exportations
Endpoints :
GET /api-keys- Récupérer les clés APIPOST /api-keys- Créer une clé APIPATCH /api-keys/{id}- Mettre à jour une clé APIPOST /api-keys/{id}- Régénérer une clé APIDELETE /api-keys/{id}- Supprimer une clé API
Objets :
Récupérer les clés API
La clé brute n’est pas renvoyée ; seules ses métadonnées le sont.
GET /api-keys
type Request = {}
type Response = ApiKey[]Créer une clé API
POST /api-keys
type Request = {
name: string; // max length: 255
scopes: string[]; // see the list of scopes above
}
type Response = ApiKeykey (la clé brute) n'est renvoyée qu'une seule fois, à la création.
Conservez-la en lieu sûr : elle ne pourra plus être récupérée. Mettre à jour une clé API
PATCH /api-keys/{id}
type Request = {
name?: string; // max length: 255
is_enabled?: boolean;
scopes?: string[];
}
type Response = ApiKeyRégénérer une clé API
Régénère la clé brute d’une clé API. L’ancienne clé est invalidée immédiatement et la nouvelle clé brute n’est renvoyée qu’une seule fois.
POST /api-keys/{id}
type Request = {}
type Response = ApiKeySupprimer une clé API
Les requêtes effectuées avec la clé supprimée seront rejetées immédiatement.
DELETE /api-keys/{id}
type Request = {}
type Response = {}Médias
Endpoints :
POST /media- Téléverser un média
Objets :
Téléverser un média
POST /media
type Request = {
// max size: 10MB
// supported formats: jpg, jpeg, png, gif, webp
file: File;
folder: 'issue_images' | 'newsletter_images';
}
type Response = MediaExportation
Endpoints :
GET /export- Récupérer les exportations d’abonnésPOST /export- Créer une exportation d’abonnés
Objets :
Récupérer les exportations d'abonnés
GET /export
type Request = {}
type Response = SubscriberExport[]Créer une exportation d'abonnés
POST /export
type Request = {}
type Response = SubscriberExportObjets
Objet Newsletter
interface Newsletter {
id: string;
subdomain: string;
created_at: number; // unix timestamp
name: string;
language_code: string | null;
is_rtl: boolean;
metadata: Record<string, string>;
address: string | null;
unsubscribe_text: string | null;
branding: boolean;
template_color_accent: string | null;
template_color_accent_text: string | null;
template_color_background: string | null;
template_color_background_text: string | null;
template_color_box: string | null;
template_color_box_text: string | null;
template_box_shadow: string | null;
template_box_radius: string | null;
template_box_border: string | null;
template_font_family: string | null;
template_font_size: string | null;
template_font_weight: string | null;
template_font_weight_heading: string | null;
template_font_line_height: string | null;
form_title: string | null;
form_description: string | null;
form_footer_text: string | null;
form_button_text: string | null;
form_success_message: string | null;
form_width: number | null; // null = 100%
form_custom_css: string | null;
form_color_light_text: string | null; // null = inherit
form_color_light_text_light: string | null;
form_color_light_accent: string | null;
form_color_light_accent_text: string | null;
form_color_light_input: string | null;
form_color_light_input_text: string | null;
form_light_input_box_shadow: string | null;
form_light_input_border: string | null;
form_light_border_radius: number | null;
form_color_dark_text: string | null; // null = inherit
form_color_dark_text_light: string | null;
form_color_dark_accent: string | null;
form_color_dark_accent_text: string | null;
form_color_dark_input: string | null;
form_color_dark_input_text: string | null;
form_dark_input_box_shadow: string | null;
form_dark_input_border: string | null;
form_dark_border_radius: number | null;
form_default_color_palette: 'light' | 'dark' | 'os';
form_input_border_radius: number;
}Objet Issue
interface Issue {
id: number;
uuid: string;
created_at: number; // unix timestamp
subject: string | null;
content: string | null;
sending_profile_id: number;
status: 'draft' | 'scheduled' | 'sending' | 'sent';
lists: number[];
scheduled_at: number | null; // unix timestamp
sending_at: number | null; // unix timestamp
sent_at: number | null; // unix timestamp
total_sends: number;
from_email: string | null;
from_name: string | null;
reply_to_email: string | null;
sendable_subscribers_count: number;
}Objet Send
interface Send {
id: number;
created_at: number; // unix timestamp
subscriber: Subscriber | null;
email: string;
status: 'pending' | 'sent' | 'failed';
sent_at: number | null; // unix timestamp
failed_at: number | null; // unix timestamp
delivered_at: number | null; // unix timestamp
unsubscribed_at: number | null; // unix timestamp
bounced_at: number | null; // unix timestamp
hard_bounce: boolean;
complained_at: number | null; // unix timestamp
}Objet List
interface List {
id: number;
created_at: number; // unix timestamp
name: string;
description: string | null;
subscribers_count: number;
}Objet Subscriber
interface Subscriber {
id: number;
email: string;
source: 'console' | 'form' | 'import';
status: 'subscribed' | 'pending';
list_ids: number[];
lists: string[]; // list names
subscribe_ip: string | null;
subscribed_at: number | null; // unix timestamp
metadata: Record<string, string>;
}Objet SubscriberMetadataDefinition
interface SubscriberMetadataDefinition {
id: number;
created_at: number; // unix timestamp
key: string;
name: string;
type: 'text'; // only 'text' is currently supported
}Objet SendingProfile
interface SendingProfile {
id: number;
created_at: number; // unix timestamp
from_email: string;
from_name: string | null;
reply_to_email: string | null;
brand_name: string | null;
brand_logo: string | null;
brand_url: string | null;
is_default: boolean;
is_system: boolean;
}Objet Template
interface Template {
template: string;
}Objet UserMini
interface UserMiniObject {
name: string;
email: string;
username: string | null;
picture_url: string | null;
}Objet User
interface User {
id: number;
role: 'owner' | 'admin';
created_at: number; // unix timestamp
user: UserMiniObject;
}Objet Media
interface Media {
id: number;
created_at: number; // unix timestamp
folder: 'issue_images' | 'newsletter_images' | 'import' | 'export';
url: string;
size: number; // in bytes
extension: string;
}Objet SubscriberExport
interface SubscriberExport {
id: number;
created_at: number; // unix timestamp
status: 'pending' | 'completed' | 'failed';
error_message: string | null;
url: string | null;
}