Skip to content

Online Subscription Cancellation

Online cancellation allows a member to cancel their subscription autonomously, via your application or portal, without any intervention from the club.

Why is online cancellation mandatory?

Since June 2023, French law (known as the "3-click cancellation" law) requires any professional offering subscriptions to allow customers to cancel online, through the same channel used to subscribe. This obligation is being progressively extended to other European countries.

As a partner, if you offer online subscription via the Resamania API, you must also offer online cancellation. This document describes the endpoints available to implement it.

Club-side configuration

Online cancellation must be enabled by the club in its settings (Settings > Clubs / Legal > Cancellation tab > "Allow online subscription cancellation"). Without this activation, calls to POST /online_cancellation will be rejected.


Macro-process


Step 1 — Retrieve cancellation motives

Cancellation motives are configured by the club. Only motives explicitly included in the club's onlineCancellation configuration are accepted for online cancellation.

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": "Relocation"
        },
        {
            "@id": "/demoapi/referentials/cancellation_motives/2",
            "@type": "CancellationMotive",
            "id": 2,
            "name": "Medical reasons"
        }
    ],
    "hydra:totalItems": 2
}

WARNING

Only present to the user the motives configured for online cancellation by the club (field includedCancellationMotives in the club's onlineCancellation configuration). Using an unauthorized motive will result in an api.error.subscription-cancel-online.motive-id-not-include error.


Step 2 — Retrieve available cancellation dates

Before presenting a date picker to the user, retrieve the authorized cancellation dates for the subscription. In online cancellation mode, cancellation always occurs on a renewal date (end of a full billing period), never on a free date.

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

ParameterTypeDescriptionExample
receptionDatestring (query, optional)Date the request was received. Defaults to today.2024-06-01
restrictboolean (query, optional)Restricts dates to renewal dates. Defaults to 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

A 204 No Content response means no cancellation date is available (e.g. fixed-term subscription not yet expired, subscription already cancelled).


Step 3 — Create the cancellation

Two endpoints are available depending on the origin of the request.

Option A — POST /subscriptions/{id}/online_cancellation (recommended for the member area)

This endpoint is recommended for cancellations initiated by the member. It verifies all rules configured by the club (feature activation, authorized motive, debt limit, contact tags, minimum delay, daily quota) before creating the cancellation.

The cancellation is created and immediately accepted in a single operation, with inputChannel: member.

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

ParameterTypeRequiredDescription
cancellationDatestring (ISO date)Effective cancellation date. Must match a date returned by GET /cancellation_dates.
cancellationMotiveIdstring (IRI)IRI of the cancellation motive. Must be in the club's authorized motive list.
commentstringFree-text comment from the member.
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": "I am moving abroad."
}'
json
{
    "@context": "/demoapi/contexts/Subscription",
    "@id": "/demoapi/subscriptions/42",
    "@type": "Subscription",
    "id": 42,
    "cancellations": [
        "/demoapi/cancellations/99"
    ]
}

Error codes

HTTP codeError messageCause
400api.error.subscription-cancel-online.missing-dateThe cancellationDate field is missing from the request body.
400api.error.subscription-cancel-online.missing-motive-idThe cancellationMotiveId field is missing from the request body.
400api.error.subscription-cancel-online.invalid-dateThe cancellationDate format is invalid.
400api.error.subscription-cancel-online.already-canceledThe subscription is already cancelled.
400api.error.subscription-cancel-online.invalid-cancel-dateThe date is in the past, before the end of the commitment period, or does not respect the configured notice period.
400api.error.subscription-cancel-online.cancellation-date-invalidThe date is not among the authorized dates (not returned by GET /cancellation_dates).
400api.error.subscription-cancel-online.subscription-contact-different-clubThe subscription and the contact belong to different clubs.
400api.error.subscription-cancel-online.not-enabledOnline cancellation is not enabled on this club for this subscription type.
400api.error.subscription-cancel-online.motive-id-not-includeThe provided motive is not in the list of motives authorized for online cancellation.
400api.error.subscription-cancel-online.contact-tag-not-eligibleThe contact does not have the required tags to cancel online.
400api.error.subscription-cancel-online.contact-tag-prohibitedThe contact has a tag that excludes them from online cancellation.
400api.error.subscription-cancel-online.contact-debt-over-limitThe contact's debt exceeds the club's authorized limit.
409(Conflict)A cancellation is already being processed for this subscription (concurrent lock).

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

This endpoint creates a cancellation directly without verifying online cancellation rules. It is suited for back-office cases (cancellation entered by a club employee from your interface) or for imports.

The inputChannel field identifies the origin of the request:

  • admin: cancellation entered by an employee from the back-office or your partner application.
  • member: cancellation initiated by the member (prefer POST /online_cancellation in this case).

Two-step workflow

Unlike POST /online_cancellation, a cancellation created here has the status submitted. It must then be accepted via POST /{clientToken}/cancellations/{id}/transitions with { "transition": "accept" } to take effect on the subscription.

POST /{clientToken}/cancellations

ParameterTypeRequiredDescription
subscriptionstring (IRI)✅*IRI of the subscription to cancel. Mutually exclusive with subscriptionOption.
subscriptionOptionstring (IRI)✅*IRI of the option to cancel. Mutually exclusive with subscription.
receptionDatestring (ISO date)Date the cancellation request was received.
cancellationDatestring (ISO date)Effective cancellation date.
cancellationMotiveIdstring (IRI)IRI of the cancellation motive.
inputChannelstringOrigin channel: admin or member.
commentstringInternal comment.
refundPolicystringRefund policy: period_end (default), period_start, prorata.
createCreditNotebooleanGenerate a credit note. Defaults to true.

* One of the two is required, but not both simultaneously.

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": "Cancellation requested by the member",
    "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": "Cancellation requested by the member",
    "status": "submitted",
    "inputChannel": "admin",
    "type": "simple",
    "contact": {
        "@id": "/demoapi/contacts/123",
        "familyName": "Doe",
        "givenName": "John",
        "number": "C123"
    }
}

Cancellation statuses

StatusDescription
submittedCancellation created, pending validation.
acceptedCancellation accepted — the subscription will stop on the cancellationDate.
rejectedCancellation rejected.
canceledCancellation voided.

Important notes

Fixed-term and upfront subscriptions

Fixed-term (CDD) or upfront-payment subscriptions cannot be cancelled before their end date via online cancellation.

Linked options

Cancelling a main subscription automatically cancels its linked options. Mandatory options and options belonging to a package cannot be cancelled independently.

Multi-club networks

In a network, a contact attached to club A cannot cancel online a subscription taken out in club B.