Skip to content

Résiliation d'abonnement en ligne

La résiliation en ligne permet à un membre de résilier son abonnement de manière autonome, via votre application ou portail, sans intervention du club.

Retrouvez ce scénario dans notre collection Bruno

Gagnez du temps dans votre implémentation en observant l'enchaînement des appels et en récupérant les requêtes directement depuis Bruno.

Pourquoi la résiliation en ligne est-elle obligatoire ?

Depuis juin 2023, la législation française (loi dite « résiliation en 3 clics ») impose à tout professionnel proposant des abonnements de permettre à ses clients de résilier en ligne, par la même voie que la souscription. Cette obligation s'étend progressivement à d'autres pays européens.

En tant que partenaire, si vous proposez la souscription en ligne via l'API Resamania, vous devez également proposer la résiliation en ligne. Ce document décrit les endpoints disponibles pour l'implémenter.

Configuration côté club

La résiliation en ligne doit être activée par le club dans ses paramètres (Paramètres > Clubs / Juridiques > Onglet Résiliation > "Autoriser la résiliation des abonnements en ligne"). Sans cette activation, vos appels à POST /online_cancellation seront rejetés.


Macro-process


Étape 1 — Récupérer les motifs de résiliation

Les motifs de résiliation sont configurés par le club. Seuls les motifs explicitement inclus dans la configuration onlineCancellation du club sont acceptés pour une résiliation en ligne.

GET /{clientToken}/referentials/cancellation_motives

bash
curl --location 'https://{{baseUrl}}/{{clientToken}}/referentials/cancellation_motives' \
--header 'accept: application/ld+json' \
--header 'authorization: Bearer {{bearer}}' \
--header 'x-user-club-id: {{clubId}}'
json
{
    "@context": "/demoapi/contexts/CancellationMotive",
    "@id": "/demoapi/referentials/cancellation_motives",
    "@type": "hydra:Collection",
    "hydra:member": [
        {
            "@id": "/demoapi/referentials/cancellation_motives/1",
            "@type": "CancellationMotive",
            "id": 1,
            "name": "Déménagement"
        },
        {
            "@id": "/demoapi/referentials/cancellation_motives/2",
            "@type": "CancellationMotive",
            "id": 2,
            "name": "Raisons médicales"
        }
    ],
    "hydra:totalItems": 2
}

WARNING

Ne présentez à l'utilisateur que les motifs configurés pour la résiliation en ligne par le club (champ includedCancellationMotives de la configuration onlineCancellation du club). L'usage d'un motif non autorisé entraînera une erreur api.error.subscription-cancel-online.motive-id-not-include.


Étape 2 — Récupérer les dates de résiliation possibles

Avant de présenter un sélecteur de date à l'utilisateur, récupérez les dates autorisées pour la résiliation de l'abonnement. En mode résiliation en ligne, la résiliation se fait toujours à une date de renouvellement (fin de mois complet), jamais à une date libre.

GET /{clientToken}/subscriptions/{id}/cancellation_dates

ParamètreTypeDescriptionExemple
receptionDatestring (query, optionnel)Date de réception de la demande. Par défaut : aujourd'hui.2024-06-01
restrictboolean (query, optionnel)Restreint les dates aux dates de renouvellement. Par défaut : true.true
bash
curl --location 'https://{{baseUrl}}/{{clientToken}}/subscriptions/{{subscriptionId}}/cancellation_dates?receptionDate=2024-06-01' \
--header 'accept: application/json' \
--header 'authorization: Bearer {{bearer}}' \
--header 'x-user-club-id: {{clubId}}'
json
{
    "dates": [
        { "date": "2024-07-01" },
        { "date": "2024-08-01" },
        { "date": "2024-09-01" }
    ]
}

INFO

Si la réponse est 204 No Content, aucune date de résiliation n'est disponible (ex : abonnement CDD non échu, abonnement déjà résilié).


Étape 3 — Créer la résiliation

Deux endpoints sont disponibles selon le canal d'origine de la demande.

Option A — POST /subscriptions/{id}/online_cancellation (recommandé pour l'espace membre)

Cet endpoint est recommandé pour les résiliations initiées par le membre. Il vérifie l'ensemble des règles configurées par le club (activation de la fonctionnalité, motif autorisé, plafond de dette, tags contact, délai minimum, quota journalier) avant de créer la résiliation.

La résiliation est créée et immédiatement acceptée en une seule opération, avec inputChannel: member.

POST /{clientToken}/subscriptions/{id}/online_cancellation

ParamètreTypeRequisDescription
cancellationDatestring (date ISO)Date effective de résiliation. Doit correspondre à une date retournée par GET /cancellation_dates.
cancellationMotiveIdstring (IRI)IRI du motif de résiliation. Doit figurer dans les motifs autorisés par le club.
commentstringCommentaire libre du membre.
bash
curl --location --request POST 'https://{{baseUrl}}/{{clientToken}}/subscriptions/{{subscriptionId}}/online_cancellation' \
--header 'accept: application/ld+json' \
--header 'authorization: Bearer {{bearer}}' \
--header 'x-user-club-id: {{clubId}}' \
--header 'Content-Type: application/json' \
--data '{
    "cancellationDate": "2024-07-01",
    "cancellationMotiveId": "/demoapi/referentials/cancellation_motives/1",
    "comment": "Je déménage à l'\''étranger."
}'
json
{
    "@context": "/demoapi/contexts/Subscription",
    "@id": "/demoapi/subscriptions/42",
    "@type": "Subscription",
    "id": 42,
    "cancellations": [
        "/demoapi/cancellations/99"
    ]
}

Codes d'erreur

Code HTTPMessage d'erreurCause
400api.error.subscription-cancel-online.missing-dateLe champ cancellationDate est absent du body.
400api.error.subscription-cancel-online.missing-motive-idLe champ cancellationMotiveId est absent du body.
400api.error.subscription-cancel-online.invalid-dateLe format de cancellationDate est invalide.
400api.error.subscription-cancel-online.already-canceledL'abonnement est déjà résilié.
400api.error.subscription-cancel-online.invalid-cancel-dateLa date est dans le passé, antérieure à la fin d'engagement, ou ne respecte pas le préavis configuré.
400api.error.subscription-cancel-online.cancellation-date-invalidLa date ne figure pas parmi les dates autorisées (non retournée par GET /cancellation_dates).
400api.error.subscription-cancel-online.subscription-contact-different-clubL'abonnement et le contact appartiennent à des clubs différents.
400api.error.subscription-cancel-online.not-enabledLa résiliation en ligne n'est pas activée sur ce club pour ce type d'abonnement.
400api.error.subscription-cancel-online.motive-id-not-includeLe motif fourni n'est pas dans la liste des motifs autorisés pour la résiliation en ligne.
400api.error.subscription-cancel-online.contact-tag-not-eligibleLe contact ne possède pas les tags requis pour résilier en ligne.
400api.error.subscription-cancel-online.contact-tag-prohibitedLe contact possède un tag qui l'exclut de la résiliation en ligne.
400api.error.subscription-cancel-online.contact-debt-over-limitLa dette du contact dépasse le plafond autorisé par le club.
409(Conflict)Une résiliation est déjà en cours de traitement sur cet abonnement (verrou concurrent).

Option B — POST /cancellations (back-office ou admin)

Cet endpoint crée directement une résiliation sans vérifier les règles de la résiliation en ligne. Il est adapté aux cas back-office (résiliation saisie par un employé du club depuis votre interface) ou aux imports.

Le champ inputChannel distingue l'origine de la saisie :

  • admin : résiliation saisie par un employé depuis le back-office ou votre application partenaire.
  • member : résiliation initiée par le membre (préférer POST /online_cancellation dans ce cas).

Workflow à deux étapes

Contrairement à POST /online_cancellation, une résiliation créée ici a le statut submitted. Elle doit ensuite être acceptée via POST /{clientToken}/cancellations/{id}/transitions avec { "transition": "accept" } pour prendre effet sur l'abonnement.

POST /{clientToken}/cancellations

ParamètreTypeRequisDescription
subscriptionstring (IRI)✅*IRI de l'abonnement à résilier. Exclusif avec subscriptionOption.
subscriptionOptionstring (IRI)✅*IRI de l'option à résilier. Exclusif avec subscription.
receptionDatestring (date ISO)Date de réception de la demande de résiliation.
cancellationDatestring (date ISO)Date effective de la résiliation.
cancellationMotiveIdstring (IRI)IRI du motif de résiliation.
inputChannelstringCanal de saisie : admin ou member.
commentstringCommentaire interne.
refundPolicystringPolitique de remboursement : period_end (défaut), period_start, prorata.
createCreditNotebooleanGénérer un avoir. Par défaut true.

* L'un des deux est obligatoire, mais pas les deux simultanément.

bash
curl --location --request POST 'https://{{baseUrl}}/{{clientToken}}/cancellations' \
--header 'accept: application/ld+json' \
--header 'authorization: Bearer {{bearer}}' \
--header 'x-user-club-id: {{clubId}}' \
--header 'Content-Type: application/json' \
--data '{
    "subscription": "/demoapi/subscriptions/42",
    "receptionDate": "2024-06-01",
    "cancellationDate": "2024-07-01",
    "cancellationMotiveId": "/demoapi/referentials/cancellation_motives/1",
    "comment": "Résiliation demandée par le membre",
    "inputChannel": "admin"
}'
json
{
    "@context": "/demoapi/contexts/Cancellation",
    "@id": "/demoapi/cancellations/99",
    "@type": "Cancellation",
    "subscription": "/demoapi/subscriptions/42",
    "subscriptionOption": null,
    "receptionDate": "2024-06-01",
    "cancellationDate": "2024-07-01",
    "cancellationMotiveId": "/demoapi/referentials/cancellation_motives/1",
    "comment": "Résiliation demandée par le membre",
    "status": "submitted",
    "inputChannel": "admin",
    "type": "simple",
    "contact": {
        "@id": "/demoapi/contacts/123",
        "familyName": "Doe",
        "givenName": "John",
        "number": "C123"
    }
}

Statuts d'une résiliation

StatutDescription
submittedRésiliation créée, en attente de validation.
acceptedRésiliation acceptée — l'abonnement s'arrêtera à la cancellationDate.
rejectedRésiliation refusée.
canceledRésiliation annulée.

Points d'attention

Abonnements CDD et comptants

Les abonnements à durée déterminée (CDD) ou comptants ne peuvent pas être résiliés avant leur date de fin via la résiliation en ligne.

Options liées

La résiliation d'un abonnement principal entraîne automatiquement la résiliation de ses options liées. Les options obligatoires et les options appartenant à un package ne sont pas résiliables indépendamment.

Réseau multi-clubs

Dans un réseau, un contact rattaché au club A ne peut pas résilier en ligne un abonnement souscrit dans le club B.