Documentation développeurs

API REST

Connectez les systèmes de votre organisation à Melora Connect : lisez et modifiez les membres, lisez les événements avec leurs inscriptions, créez des événements en brouillon, lisez les factures de cotisation et abonnez des URL de webhooks.

Présentation

L'API répond en JSON sur HTTPS. Chaque chemin de cette page commence par cette URL de base :

https://app.meloraconnect.com/api/public/v1

Pour être informé des changements au moment où ils se produisent, utilisez les webhooks. Pour utiliser les mêmes opérations depuis un client MCP, consultez le serveur MCP.

Qui peut l'utiliser

L'API est incluse dans toutes les formules Melora Connect. Les clés sont créées dans Melora Connect par le personnel qui peut gérer les paramètres de l'organisation. Si l'API est retirée de la formule de l'organisation, ses clés cessent de fonctionner à la requête suivante et fonctionnent à nouveau dès que la formule l'inclut, sauf si elles ont été révoquées ou ont expiré.

Authentification

Chaque requête porte une clé d'API dans l'en-tête Authorization, après le mot Bearer :

Authorization: Bearer melora_YOUR_KEY

Créer une clé

  1. Dans Melora Connect, ouvrez Settings puis l'onglet API keys.
  2. Donnez à la clé le nom du système qui l'utilisera, choisissez ses permissions et sa date d'expiration, puis cliquez sur Make key.
  3. Copiez la clé et conservez-la sur votre serveur. Elle n'est affichée qu'une fois.

À propos des clés

  • Une clé appartient à une seule organisation. Chaque requête agit dans cette organisation et aucune autre, et rien dans une requête ne peut en choisir une autre. Un enregistrement d'une autre organisation répond 404, comme s'il n'existait pas.
  • Melora Connect ne garde qu'une empreinte de la clé (un hachage SHA-256) et ne peut donc pas l'afficher à nouveau. Conservez-la comme un mot de passe, sur votre serveur, jamais dans une page web ni dans une application mobile.
  • Les clés commencent par melora_ suivi de 43 caractères. L'onglet API keys affiche les 15 premiers caractères de chaque clé, pour les distinguer, et la date de dernière utilisation de chacune.
  • Une clé peut expirer après 30, 90 ou 365 jours, ou jamais, et peut être révoquée à tout moment avec Revoke. Une clé révoquée ou expirée est refusée dès la requête suivante.
  • Une organisation peut avoir jusqu'à 25 clés actives (les clés révoquées et expirées ne comptent pas). Créez une clé par système, pour pouvoir en révoquer une sans toucher aux autres.
  • Les permissions d'une clé sont fixées à sa création. Pour les changer, créez une nouvelle clé et révoquez l'ancienne.

Permissions

Chaque clé ne porte que les permissions choisies pour elle, parmi les permissions qu'utilisent les rôles du personnel dans Melora Connect. La personne qui crée une clé ne peut lui donner que des permissions qu'elle détient. Une requête que la clé n'autorise pas répond 403 avec le code permission_denied.

Permission de la cléCe qu'elle permet
members.readLire les membres : la liste des membres et un membre.
members.writeAjouter des membres, modifier les champs de membre indiqués et désinscrire un membre des emails marketing de l'organisation.
events.readLire les événements, et un événement avec ses inscriptions.
events.manageCréer des événements en brouillon.
members.billing.readLire les factures de cotisation.
settings.manageAbonner et désabonner des URL de webhooks (ce qu'utilise Zapier).

Versions

La version figure dans le chemin, /v1. Au sein de v1, Melora Connect ne fait qu'ajouter : de nouveaux endpoints, de nouveaux paramètres facultatifs et de nouveaux champs dans les réponses ; votre code doit donc ignorer les champs qu'il ne connaît pas. Tout ce qui casserait une intégration qui fonctionne arrive dans une nouvelle version, et v1 continue de fonctionner en parallèle.

Limites

  • Chaque clé peut faire 120 requêtes toutes les 60 secondes. Au-delà, la réponse est 429 avec un en-tête Retry-After en secondes.
  • Toutes clés confondues, une organisation peut faire 600 requêtes toutes les 60 secondes. Au-delà, chaque clé reçoit 429 jusqu'à ce que la fenêtre avance.
  • Une adresse qui présente plus de 30 clés inconnues en 10 minutes reçoit aussi 429.
  • Le corps d'une requête est en JSON, envoyé avec Content-Type: application/json, et peut faire jusqu'à 64 Ko. Un corps plus grand reçoit 413 (payload_too_large) sans être lu.

Listes et formats

Chaque liste accepte page (à partir de 1) et per_page (de 1 à 100, 50 par défaut) et répond avec data, page, per_page et has_more. Demandez la page suivante tant que has_more est vrai.

Les membres arrivent du changement le plus ancien au plus récent. Pour garder une copie à jour, passez le updated_at le plus récent que vous avez comme updated_since : les enregistrements modifiés à ce moment ou après sont renvoyés. Les événements arrivent par heure de début, et les factures de cotisation de la plus ancienne à la plus récente.

Les heures sont au format ISO 8601 avec fuseau horaire (par exemple 2026-11-12T08:00:00-05:00), les dates au format YYYY-MM-DD, les montants en cents, et les id sont des UUID. Un id qui n'est pas un UUID répond 404.

Liste des endpoints

Chaque endpoint, la permission dont sa clé a besoin et ce qu'il fait. Chacun est expliqué plus bas avec un exemple.

RequêtePermission requiseCe qu'il fait
GET /membersmembers.readLister les membres, du changement le plus ancien au plus récent.
GET /members/{id}members.readUn membre.
POST /membersmembers.writeAjouter un membre. Répond 201 avec le nouveau membre.
PATCH /members/{id}members.writeModifier les champs envoyés d'un membre.
POST /members/{id}/email-preferencesmembers.writeDésinscrit un membre des emails marketing de l'organisation, comme le lien de désinscription d'une campagne. Répond 200.
GET /eventsevents.readLister les événements par heure de début.
GET /events/{id}events.readUn événement avec ses inscriptions.
POST /eventsevents.manageCréer un événement en brouillon. Répond 201 avec l'événement.
GET /dues-invoicesmembers.billing.readLister les factures de cotisation, de la plus ancienne à la plus récente.
POST /webhookssettings.manageAbonner une URL de webhook à des événements. C'est ce qu'utilise Zapier.
DELETE /webhooks/{id}settings.manageDésabonner un webhook abonné par l'API.

GET /api/public/v1/members

Lister les membres, du changement le plus ancien au plus récent.

Permission requise : members.read

Paramètres

  • status (facultatif) : active, pending, lapsed, expired, suspended, archived ou at_risk.
  • membership_type_id (facultatif) : l'id d'un des types d'adhésion de l'organisation.
  • updated_since (facultatif) : une date et une heure avec fuseau horaire. Seulement les membres modifiés à ce moment ou après.
  • email_marketing_opt_out (facultatif) : true liste seulement les membres désinscrits des emails marketing de l'organisation, false seulement les autres.
  • page et per_page (facultatifs) : voir Listes et formats.

Chaque membre a les champs ci-dessous. custom_fields contient les champs de membre propres à l'organisation, sous forme de clé du champ et de valeur.

email_marketing_opt_out vaut true quand le membre s'est désinscrit des emails marketing de l'organisation, et email_marketing_opted_out_at indique quand (null tant qu'il ne l'a pas fait). C'est la lecture qu'utilisent les campagnes de Melora Connect : un lien de désinscription ou une plainte depuis l'adresse, pour cette organisation ou pour tout Melora Connect, ou l'interrupteur d'email du membre pour l'organisation désactivé (aussi depuis une audience Mailchimp connectée). Un rebond n'est pas une désinscription, et la désinscription d'une organisation ne désinscrit jamais le membre d'une autre. Une désinscription ne modifie pas updated_at : suivez les webhooks member.unsubscribed et member.resubscribed, et rapprochez de temps en temps avec email_marketing_opt_out=true.

Champs : id, name, first_name, last_name, email, company, title, industry, phone, website, linkedin_url, city, state, zip, bio, status, membership_type_id, membership_category, tier, join_date, renewal_date, tags, show_in_directory, chapter_id, created_at, updated_at, custom_fields, email_marketing_opt_out, email_marketing_opted_out_at.

Exemple de requête

curl "https://app.meloraconnect.com/api/public/v1/members?status=active&per_page=50&page=1" \
  -H "Authorization: Bearer $MELORA_API_KEY"

Exemple de réponse, HTTP 200

{
  "data": [
    {
      "id": "8d2c6f0e-3f59-4a53-9c0e-0f6f5b3a1b21",
      "name": "Ana Ruiz",
      "first_name": "Ana",
      "last_name": "Ruiz",
      "email": "ana@example.org",
      "company": "Ruiz Consulting",
      "status": "active",
      "membership_type_id": "0b7a3c62-7f3e-4d7c-8a57-25a1c0a9d7e4",
      "join_date": "2026-03-02",
      "renewal_date": "2027-03-02",
      "tags": ["board"],
      "updated_at": "2026-09-28T14:03:11.402Z",
      "email_marketing_opt_out": false,
      "email_marketing_opted_out_at": null
    }
  ],
  "page": 1,
  "per_page": 50,
  "has_more": false
}

GET /api/public/v1/members/{id}

Un membre.

Permission requise : members.read

Paramètres

  • id (dans le chemin) : l'id du membre.

Le membre a les mêmes champs que dans la liste. Un membre qui n'existe pas, ou qui appartient à une autre organisation, répond 404.

Exemple de requête

curl "https://app.meloraconnect.com/api/public/v1/members/8d2c6f0e-3f59-4a53-9c0e-0f6f5b3a1b21" \
  -H "Authorization: Bearer $MELORA_API_KEY"

Exemple de réponse, HTTP 200

{
  "data": {
    "id": "8d2c6f0e-3f59-4a53-9c0e-0f6f5b3a1b21",
    "name": "Ana Ruiz",
    "first_name": "Ana",
    "last_name": "Ruiz",
    "email": "ana@example.org",
    "company": "Ruiz Consulting",
    "status": "active",
    "membership_type_id": "0b7a3c62-7f3e-4d7c-8a57-25a1c0a9d7e4",
    "join_date": "2026-03-02",
    "renewal_date": "2027-03-02",
    "tags": [
      "board"
    ],
    "updated_at": "2026-09-28T14:03:11.402Z",
    "email_marketing_opt_out": false,
    "email_marketing_opted_out_at": null,
    "custom_fields": {
      "member_since_year": 2019
    }
  }
}

POST /api/public/v1/members

Ajouter un membre. Répond 201 avec le nouveau membre.

Permission requise : members.write

Paramètres

  • email (obligatoire) : un membre par adresse e-mail dans l'organisation.
  • name, ou first_name et last_name (obligatoire) : au moins l'un d'eux.
  • status (facultatif) : active, la valeur par défaut, ou pending, lapsed, expired, suspended ou archived.
  • join_date et renewal_date (facultatifs) : des dates au format YYYY-MM-DD.
  • membership_type_id (facultatif) : un des types d'adhésion de l'organisation.
  • Également facultatifs : company, title, industry, phone, website, linkedin_url, city, state, zip, bio et tags (une liste de mots).
  • start_welcome_drips (facultatif) : true pour lancer les campagnes New member de l'organisation pour un membre actif.

Un membre actif occupe une des places de membres actifs de la formule ; quand il n'en reste plus, la réponse est 403 limit_reached. Une adresse e-mail qui appartient déjà à un membre de l'organisation répond 409 conflict, avec l'id de ce membre dans details.existing_member_id.

Un membre ajouté par l'API ne rejoint aucune campagne d'e-mails automatique de l'organisation : un système qui copie toute une liste de membres n'envoie donc pas de bienvenue à tout le monde. Pour accueillir un nouveau membre, envoyez start_welcome_drips à true : un membre actif rejoint alors les campagnes New member de l'organisation, comme un membre ajouté à la main, et la réponse contient welcome_drips.enrolled, le nombre de campagnes rejointes (0 pour un membre qui n'est pas actif).

phone doit compter de 7 à 15 chiffres et est enregistré sous forme de chiffres, en gardant un + initial (+1 (703) 555-0142 est enregistré comme +17035550142). website doit être une adresse http ou https et est enregistré avec son schéma (https:// est ajouté s'il manque). linkedin_url doit être une adresse https sur linkedin.com. Une valeur vide efface le champ. Une valeur non valide répond 422 validation_failed, et details nomme le champ.

Exemple de requête

curl -X POST "https://app.meloraconnect.com/api/public/v1/members" \
  -H "Authorization: Bearer $MELORA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"first_name":"Ana","last_name":"Ruiz","email":"ana@example.org","company":"Ruiz Consulting","status":"active","renewal_date":"2027-03-02","tags":["board"]}'

Exemple de réponse, HTTP 201

{
  "data": {
    "id": "8d2c6f0e-3f59-4a53-9c0e-0f6f5b3a1b21",
    "name": "Ana Ruiz",
    "first_name": "Ana",
    "last_name": "Ruiz",
    "email": "ana@example.org",
    "company": "Ruiz Consulting",
    "status": "active",
    "membership_type_id": "0b7a3c62-7f3e-4d7c-8a57-25a1c0a9d7e4",
    "join_date": "2026-03-02",
    "renewal_date": "2027-03-02",
    "tags": [
      "board"
    ],
    "updated_at": "2026-09-28T14:03:11.402Z",
    "email_marketing_opt_out": false,
    "email_marketing_opted_out_at": null,
    "custom_fields": {}
  }
}

PATCH /api/public/v1/members/{id}

Modifier les champs envoyés d'un membre.

Permission requise : members.write

Paramètres

  • id (dans le chemin) : l'id du membre.
  • Corps : n'importe lesquels de name, first_name, last_name, email, company, title, industry, phone, website, linkedin_url, city, state, zip, bio, tags, membership_type_id, status et renewal_date. Envoyez-en au moins un.

Tout autre champ est refusé avec 422. Le statut at_risk est calculé par Melora Connect à partir de l'activité du membre et ne peut pas être fixé, et les points, l'engagement et les données de connexion ne peuvent pas être modifiés. membership_type_id doit être un des types d'adhésion de l'organisation.

Rendre un membre actif occupe une des places de membres actifs de la formule. Si le statut du membre a changé pendant le traitement de votre requête, la réponse est 409 conflict : relisez le membre et réessayez.

phone, website et linkedin_url sont vérifiés comme lors de l'ajout d'un membre. N'envoyez que les champs que vous modifiez : un enregistrement plus ancien peut contenir un numéro de téléphone qui ne passe pas les vérifications actuelles, et renvoyer tout l'enregistrement peut donc être refusé.

Exemple de requête

curl -X PATCH "https://app.meloraconnect.com/api/public/v1/members/8d2c6f0e-3f59-4a53-9c0e-0f6f5b3a1b21" \
  -H "Authorization: Bearer $MELORA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"phone":"+1 555 0100","status":"lapsed"}'

Exemple de réponse, HTTP 200

{
  "data": {
    "id": "8d2c6f0e-3f59-4a53-9c0e-0f6f5b3a1b21",
    "name": "Ana Ruiz",
    "first_name": "Ana",
    "last_name": "Ruiz",
    "email": "ana@example.org",
    "company": "Ruiz Consulting",
    "status": "lapsed",
    "membership_type_id": "0b7a3c62-7f3e-4d7c-8a57-25a1c0a9d7e4",
    "join_date": "2026-03-02",
    "renewal_date": "2027-03-02",
    "tags": [
      "board"
    ],
    "updated_at": "2026-10-04T10:12:45.118Z",
    "email_marketing_opt_out": false,
    "email_marketing_opted_out_at": null,
    "phone": "+15550100"
  }
}

POST /api/public/v1/members/{id}/email-preferences

Désinscrit un membre des emails marketing de l'organisation, comme le lien de désinscription d'une campagne. Répond 200.

Permission requise : members.write

Paramètres

  • id (dans le chemin) : l'id du membre.
  • Corps : email_marketing_opt_out (obligatoire), true. Tout autre champ est refusé avec 422.

La prochaine campagne de l'organisation laisse le membre de côté, son interrupteur d'email pour l'organisation est désactivé et il quitte ses listes de newsletters. Les emails des autres organisations ne sont pas touchés. La réponse contient member_id, email_marketing_opt_out et email_marketing_opted_out_at ; redemander pour un membre déjà désinscrit ne change rien. Le changement figure dans le journal d'audit de l'organisation avec le nom de la clé. Un membre sans adresse email répond 422.

Une clé ne peut pas réinscrire un membre : false répond 422 validation_failed. Seul le membre peut réactiver les emails de l'organisation, dans Melora Connect, et member.resubscribed est alors envoyé.

Exemple de requête

curl -X POST "https://app.meloraconnect.com/api/public/v1/members/8d2c6f0e-3f59-4a53-9c0e-0f6f5b3a1b21/email-preferences" \
  -H "Authorization: Bearer $MELORA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"email_marketing_opt_out":true}'

Exemple de réponse, HTTP 200

{
  "data": {
    "member_id": "8d2c6f0e-3f59-4a53-9c0e-0f6f5b3a1b21",
    "email_marketing_opt_out": true,
    "email_marketing_opted_out_at": "2026-11-05T09:12:44.120Z"
  }
}

GET /api/public/v1/events

Lister les événements par heure de début.

Permission requise : events.read

Paramètres

  • status (facultatif) : draft, published, cancelled, completed ou archived.
  • starts_after (facultatif) : une date et une heure avec fuseau horaire. Seulement les événements qui commencent à ce moment ou après.
  • updated_since (facultatif) : seulement les événements modifiés à ce moment ou après.
  • page et per_page (facultatifs) : voir Listes et formats.

Chaque événement a les champs ci-dessous. Les prix sont en cents.

Champs : id, title, description, event_type, status, starts_at, ends_at, timezone, venue, address, is_virtual, capacity, ticket_price_cents, member_price_cents, highlights, slug, published_at, created_at, updated_at, tags.

Exemple de requête

curl "https://app.meloraconnect.com/api/public/v1/events?starts_after=2026-11-01T00:00:00Z&per_page=20" \
  -H "Authorization: Bearer $MELORA_API_KEY"

Exemple de réponse, HTTP 200

{
  "data": [
    {
      "id": "5e0c1d8a-9b2f-4c1e-8f3a-6a7b8c9d0e1f",
      "title": "Autumn networking breakfast",
      "event_type": "networking",
      "status": "published",
      "starts_at": "2026-11-12T13:00:00+00:00",
      "ends_at": "2026-11-12T14:30:00+00:00",
      "timezone": "America/New_York",
      "venue": "Harbor Hall",
      "is_virtual": false,
      "capacity": 80,
      "ticket_price_cents": 2500,
      "member_price_cents": 1500,
      "published_at": "2026-10-01T15:00:00+00:00"
    }
  ],
  "page": 1,
  "per_page": 20,
  "has_more": false
}

GET /api/public/v1/events/{id}

Un événement avec ses inscriptions.

Permission requise : events.read

Paramètres

  • id (dans le chemin) : l'id de l'événement.

Les champs de l'événement, plus host_committee_name (le comité qui l'organise, ou null) et registrations, chacune avec les champs ci-dessous. Dans une inscription, member_id est la fiche de membre de la personne inscrite, ou null pour un invité.

Champs : id, status, member_id, guest_name, guest_email, ticket_tier_id, checked_in_at, created_at.

Exemple de requête

curl "https://app.meloraconnect.com/api/public/v1/events/5e0c1d8a-9b2f-4c1e-8f3a-6a7b8c9d0e1f" \
  -H "Authorization: Bearer $MELORA_API_KEY"

Exemple de réponse, HTTP 200

{
  "data": {
    "id": "5e0c1d8a-9b2f-4c1e-8f3a-6a7b8c9d0e1f",
    "title": "Autumn networking breakfast",
    "status": "published",
    "starts_at": "2026-11-12T13:00:00+00:00",
    "capacity": 80,
    "registrations": [
      {
        "id": "a1b2c3d4-0000-4000-8000-000000000001",
        "status": "confirmed",
        "member_id": "8d2c6f0e-3f59-4a53-9c0e-0f6f5b3a1b21",
        "guest_name": null,
        "guest_email": null,
        "ticket_tier_id": null,
        "checked_in_at": null,
        "created_at": "2026-10-02T15:20:00+00:00"
      }
    ]
  }
}

POST /api/public/v1/events

Créer un événement en brouillon. Répond 201 avec l'événement.

Permission requise : events.manage

Paramètres

  • title (obligatoire) : de 2 à 120 caractères.
  • event_type (obligatoire) : le type d'événement, par exemple networking.
  • format (obligatoire) : in_person, virtual ou hybrid.
  • starts_at (obligatoire) et ends_at (facultatif) : des dates et heures avec fuseau horaire.
  • timezone (facultatif) : le nom d'un fuseau horaire comme America/New_York, la valeur par défaut.
  • ticket_price_cents et member_price_cents (facultatifs) : des prix en cents, 0 par défaut.
  • capacity (facultatif) : le nombre de places.
  • Également facultatifs : description, venue, address, highlights, tags (une liste de mots) et language (en, es ou fr).

L'événement est enregistré en brouillon. Le personnel le relit et le publie dans Melora Connect, et y ajoute le lien de connexion d'un événement virtuel. Si les événements ne font pas partie de la formule de l'organisation, la réponse est 403 plan_required.

Exemple de requête

curl -X POST "https://app.meloraconnect.com/api/public/v1/events" \
  -H "Authorization: Bearer $MELORA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"title":"Autumn networking breakfast","event_type":"networking","format":"in_person","starts_at":"2026-11-12T08:00:00-05:00","ends_at":"2026-11-12T09:30:00-05:00","timezone":"America/New_York","venue":"Harbor Hall","capacity":80,"ticket_price_cents":2500,"member_price_cents":1500}'

Exemple de réponse, HTTP 201

{
  "data": {
    "id": "5e0c1d8a-9b2f-4c1e-8f3a-6a7b8c9d0e1f",
    "title": "Autumn networking breakfast",
    "event_type": "networking",
    "status": "draft",
    "starts_at": "2026-11-12T13:00:00+00:00",
    "ends_at": "2026-11-12T14:30:00+00:00",
    "timezone": "America/New_York",
    "venue": "Harbor Hall",
    "is_virtual": false,
    "capacity": 80,
    "ticket_price_cents": 2500,
    "member_price_cents": 1500,
    "published_at": null
  }
}

GET /api/public/v1/dues-invoices

Lister les factures de cotisation, de la plus ancienne à la plus récente.

Permission requise : members.billing.read

Paramètres

  • status (facultatif) : open, paid, past_due, void, refunded ou failed.
  • member_id (facultatif) : seulement les factures de ce membre.
  • updated_since (facultatif) : seulement les factures modifiées à ce moment ou après.
  • page et per_page (facultatifs) : voir Listes et formats.

Chaque facture a les champs ci-dessous. Les montants sont en cents. Les factures sont en lecture seule : les paiements se font dans Melora Connect.

Champs : id, invoice_number, member_id, dues_subscription_id, status, amount_cents, subtotal_cents, discount_cents, discount_code, currency, period_start, period_end, due_at, paid_at, paid_via, voided_at, void_reason, replaces_invoice_id, created_at, updated_at.

Exemple de requête

curl "https://app.meloraconnect.com/api/public/v1/dues-invoices?status=paid&updated_since=2026-01-01T00:00:00Z" \
  -H "Authorization: Bearer $MELORA_API_KEY"

Exemple de réponse, HTTP 200

{
  "data": [
    {
      "id": "c4a1e7b2-6d3f-4e8a-9b1c-2d3e4f5a6b7c",
      "invoice_number": "INV-2026-0142",
      "member_id": "8d2c6f0e-3f59-4a53-9c0e-0f6f5b3a1b21",
      "dues_subscription_id": "f1e2d3c4-b5a6-4978-8a9b-0c1d2e3f4a5b",
      "status": "paid",
      "amount_cents": 25000,
      "subtotal_cents": 25000,
      "discount_cents": 0,
      "discount_code": null,
      "currency": "USD",
      "period_start": "2026-03-02",
      "period_end": "2027-03-01",
      "due_at": "2026-03-02T00:00:00+00:00",
      "paid_at": "2026-02-27T16:40:12+00:00",
      "paid_via": "stripe",
      "voided_at": null,
      "void_reason": null,
      "replaces_invoice_id": null,
      "created_at": "2026-02-01T09:00:00+00:00",
      "updated_at": "2026-02-27T16:40:12+00:00"
    }
  ],
  "page": 1,
  "per_page": 50,
  "has_more": false
}

POST /api/public/v1/webhooks

Abonner une URL de webhook à des événements. C'est ce qu'utilise Zapier.

Permission requise : settings.manage

Paramètres

  • url (obligatoire) : une adresse https qui passe les vérifications de l'endpoint.
  • events (obligatoire) : une liste d'un ou plusieurs événements de webhook.
  • include_contact_details (facultatif) : true pour envoyer les coordonnées des membres. La clé a alors aussi besoin de members.read.

Une nouvelle URL répond 201. Abonner à nouveau la même URL remplace ses événements et répond 200. Chaque URL compte dans les 10 endpoints qu'une organisation peut avoir ; au-delà, la réponse est 403 limit_reached.

Une URL que le personnel a déjà ajoutée dans l'onglet Webhooks répond 409 : supprimez-la d'abord à cet endroit. Si les webhooks ne font pas partie de la formule de l'organisation, la réponse est 403 plan_required.

La réponse contient id, url, events et include_contact_details de l'endpoint, mais pas de secret de signature. L'endpoint apparaît dans l'onglet Webhooks comme ajouté par l'API, où le personnel peut émettre un nouveau secret, affiché une fois, pour un récepteur qui vérifie les signatures.

Exemple de requête

curl -X POST "https://app.meloraconnect.com/api/public/v1/webhooks" \
  -H "Authorization: Bearer $MELORA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://hooks.example.com/melora/members","events":["member.created","member.status_changed"]}'

Exemple de réponse, HTTP 201

{
  "data": {
    "id": "2b3c4d5e-6f7a-4b8c-9d0e-1f2a3b4c5d6e",
    "url": "https://hooks.example.com/melora/members",
    "events": [
      "member.created",
      "member.status_changed"
    ],
    "include_contact_details": false
  }
}

DELETE /api/public/v1/webhooks/{id}

Désabonner un webhook abonné par l'API.

Permission requise : settings.manage

Paramètres

  • id (dans le chemin) : l'id renvoyé par l'abonnement.

Répond 204 sans corps, et les envois vers cette URL s'arrêtent. Un endpoint que le personnel a ajouté dans l'onglet Webhooks, ou celui d'une autre organisation, répond 404 : une clé ne supprime jamais un endpoint configuré par le personnel.

Exemple de requête

curl -X DELETE "https://app.meloraconnect.com/api/public/v1/webhooks/2b3c4d5e-6f7a-4b8c-9d0e-1f2a3b4c5d6e" \
  -H "Authorization: Bearer $MELORA_API_KEY"

Exemple de réponse, HTTP 204

Pas de corps.

Erreurs

Chaque erreur est un JSON avec un code qui ne change pas, un message destiné aux personnes et parfois details. Basez votre logique sur le code, pas sur le message.

HTTP/1.1 403 Forbidden
Content-Type: application/json; charset=utf-8

{
  "error": {
    "code": "permission_denied",
    "message": "This API key does not have the members.write permission.",
    "details": { "required_permission": "members.write" }
  }
}
Statut HTTPCode d'erreurSignification
401invalid_api_keyPas de clé, une clé mal formée ou une clé que Melora Connect ne connaît pas. Envoyez la clé après Bearer dans l'en-tête Authorization.
401api_key_revokedLa clé a été révoquée. Créez-en une nouvelle.
401api_key_expiredLa clé a dépassé sa date d'expiration. Créez-en une nouvelle.
403plan_requiredLa formule n'inclut pas l'API (ou la fonctionnalité dont la requête a besoin), la requête est donc refusée.
403permission_deniedLa clé n'a pas la permission dont cette requête a besoin. details.required_permission la nomme.
403billing_holdLe compte Melora Connect est suspendu pour une facture impayée, ce qui met en pause ce type de requête.
403account_restrictedLe compte est restreint : rien de nouveau ne peut être créé.
403limit_reachedUne limite de la formule, par exemple le nombre de membres actifs, serait dépassée.
404not_foundCet enregistrement n'existe pas ici. Les enregistrements des autres organisations ne sont jamais montrés.
422validation_failedLe corps de la requête ou un paramètre de requête n'est pas valide. details liste chaque problème.
409conflictL'enregistrement entre en conflit avec un enregistrement existant.
413payload_too_largeLe corps de la requête dépasse 64 Ko. Envoyez moins de champs ou divisez le travail.
429rate_limitedTrop de requêtes. Attendez le nombre de secondes indiqué par l'en-tête Retry-After.
500internal_errorUn problème est survenu du côté de Melora Connect. Réessayez la requête.

Exemples de code

Node.js

Node.js 18 ou plus récent : lire tous les membres actifs, une page à la fois, en attendant quand la limite est atteinte.

// Node.js 18 or later: read every active member, a page at a time.
const base = "https://app.meloraconnect.com/api/public/v1";
const headers = { Authorization: `Bearer ${process.env.MELORA_API_KEY}` };

async function allActiveMembers() {
  const members = [];
  for (let page = 1; ; page++) {
    const res = await fetch(`${base}/members?status=active&per_page=100&page=${page}`, { headers });
    if (res.status === 429) {
      await new Promise((r) => setTimeout(r, Number(res.headers.get("retry-after") ?? 60) * 1000));
      page--;
      continue;
    }
    const body = await res.json();
    if (!res.ok) throw new Error(`${body.error.code}: ${body.error.message}`);
    members.push(...body.data);
    if (!body.has_more) return members;
  }
}

Python

Python 3 avec requests : ajouter un membre, ou trouver celui qui a déjà cette adresse e-mail.

# Python 3 with requests: add a member, or find the one that already has the email.
import os, requests

base = "https://app.meloraconnect.com/api/public/v1"
headers = {"Authorization": f"Bearer {os.environ['MELORA_API_KEY']}"}

res = requests.post(f"{base}/members", headers=headers, json={
    "first_name": "Ana", "last_name": "Ruiz", "email": "ana@example.org",
})
if res.status_code == 409:
    member_id = res.json()["error"]["details"]["existing_member_id"]
else:
    res.raise_for_status()
    member_id = res.json()["data"]["id"]

Bonnes pratiques

  • Donnez à chaque clé seulement les permissions dont son système a besoin.
  • Gardez les clés sur votre serveur. Révoquez immédiatement une clé qui a pu fuiter.
  • Chaque modification faite avec une clé apparaît dans le journal d'audit de l'organisation avec le nom de la clé.
  • Pour être informé des changements au moment où ils se produisent, plutôt que de redemander sans cesse, utilisez les webhooks.

Découvrez-le avec vos propres données

Prêt à offrir à vos membres la plateforme qu'ils méritent ?

Une présentation guidée avec notre équipe, adaptée au fonctionnement actuel de votre organisation. En service dès 5 semaines après la signature, avec un spécialiste Melora pour la mise en place.

Réserver une démoEstimez votre date de mise en service