# Essais gratuits > Proposez un essai gratuit, accordez l'accès à partir des webhooks et encaissez le premier paiement à la fin de l'essai. Source : https://abuna.app/docs/guides/trials?hl=fr Accordez un accès gratuit avant la première période payante, sans demander de paiement sur la page d'abonnement. ## Définir un essai sur un prix Créez un prix avec `trial_days`, un entier de 1 à 365. Cet exemple propose 14 jours gratuits, puis 5 000 FCFA par mois. **Créer un prix avec 14 jours d'essai** cURL : ```bash curl https://api.abuna.app/v1/apps/8ddhXCDW/prices \ -H "Authorization: Bearer sk_test_..." \ -H "Content-Type: application/json" \ -d '{ "product_id": "pR4dWx9K", "name": "Monthly", "currency": "XAF", "amount": 5000, "interval": "month", "trial_days": 14 }' ``` Node.js : ```javascript const response = await fetch("https://api.abuna.app/v1/apps/8ddhXCDW/prices", { method: "POST", headers: { Authorization: "Bearer sk_test_...", "Content-Type": "application/json" }, body: JSON.stringify({ product_id: "pR4dWx9K", name: "Monthly", currency: "XAF", amount: 5000, interval: "month", trial_days: 14, }), }); const price = await response.json(); ``` Python : ```python import requests response = requests.post( "https://api.abuna.app/v1/apps/8ddhXCDW/prices", headers={"Authorization": "Bearer sk_test_..."}, json={ "product_id": "pR4dWx9K", "name": "Monthly", "currency": "XAF", "amount": 5000, "interval": "month", "trial_days": 14, }, ) price = response.json() ``` PHP : ```php true, CURLOPT_HTTPHEADER => ["Authorization: Bearer sk_test_...", "Content-Type: application/json"], CURLOPT_POSTFIELDS => json_encode([ "product_id" => "pR4dWx9K", "name" => "Monthly", "currency" => "XAF", "amount" => 5000, "interval" => "month", "trial_days" => 14, ]), CURLOPT_RETURNTRANSFER => true, ]); $price = json_decode(curl_exec($ch), true); ``` Go : ```go body, _ := json.Marshal(map[string]any{ "product_id": "pR4dWx9K", "name": "Monthly", "currency": "XAF", "amount": 5000, "interval": "month", "trial_days": 14, }) req, _ := http.NewRequest("POST", "https://api.abuna.app/v1/apps/8ddhXCDW/prices", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer sk_test_...") req.Header.Set("Content-Type", "application/json") res, err := http.DefaultClient.Do(req) if err != nil { log.Fatal(err) } defer res.Body.Close() var price map[string]any json.NewDecoder(res.Body).Decode(&price) ``` Omettez `trial_days` ou envoyez `null` pour ne pas proposer d'essai. La durée ne peut plus changer après la création du prix. Créez un autre prix pour proposer une autre durée par défaut. ## Envoyer le client vers la page d'abonnement Créez une [session checkout](https://abuna.app/docs/api/sessions.md?hl=fr#create-checkout) depuis votre serveur, puis envoyez le client vers son `url`. Remplacez les identifiants et la clé secrète de l'exemple par vos valeurs Test. **Créer une session avec l'essai du prix** cURL : ```bash curl https://api.abuna.app/v1/apps/8ddhXCDW/sessions \ -H "Authorization: Bearer sk_test_..." \ -H "Content-Type: application/json" \ -H "Idempotency-Key: checkout-user-42-trial-1" \ -d '{ "type": "checkout", "price_id": "Zt6YbN3q", "customer_id": "Cu5tM8rA", "success_url": "https://example.com/subscribed?session_id={SESSION_ID}", "cancel_url": "https://example.com/plans", "metadata": {"user_id": "42"} }' ``` Node.js : ```javascript const response = await fetch("https://api.abuna.app/v1/apps/8ddhXCDW/sessions", { method: "POST", headers: { Authorization: "Bearer sk_test_...", "Content-Type": "application/json", "Idempotency-Key": "checkout-user-42-trial-1", }, body: JSON.stringify({ type: "checkout", price_id: "Zt6YbN3q", customer_id: "Cu5tM8rA", success_url: "https://example.com/subscribed?session_id={SESSION_ID}", cancel_url: "https://example.com/plans", metadata: { user_id: "42" }, }), }); const session = await response.json(); ``` Python : ```python import requests response = requests.post( "https://api.abuna.app/v1/apps/8ddhXCDW/sessions", headers={"Authorization": "Bearer sk_test_...", "Idempotency-Key": "checkout-user-42-trial-1"}, json={ "type": "checkout", "price_id": "Zt6YbN3q", "customer_id": "Cu5tM8rA", "success_url": "https://example.com/subscribed?session_id={SESSION_ID}", "cancel_url": "https://example.com/plans", "metadata": {"user_id": "42"}, }, ) session = response.json() ``` PHP : ```php true, CURLOPT_HTTPHEADER => ["Authorization: Bearer sk_test_...", "Content-Type: application/json", "Idempotency-Key: checkout-user-42-trial-1"], CURLOPT_POSTFIELDS => json_encode([ "type" => "checkout", "price_id" => "Zt6YbN3q", "customer_id" => "Cu5tM8rA", "success_url" => "https://example.com/subscribed?session_id={SESSION_ID}", "cancel_url" => "https://example.com/plans", "metadata" => ["user_id" => "42"], ]), CURLOPT_RETURNTRANSFER => true, ]); $session = json_decode(curl_exec($ch), true); ``` Go : ```go body, _ := json.Marshal(map[string]any{ "type": "checkout", "price_id": "Zt6YbN3q", "customer_id": "Cu5tM8rA", "success_url": "https://example.com/subscribed?session_id={SESSION_ID}", "cancel_url": "https://example.com/plans", "metadata": map[string]any{"user_id": "42"}, }) req, _ := http.NewRequest("POST", "https://api.abuna.app/v1/apps/8ddhXCDW/sessions", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer sk_test_...") req.Header.Set("Content-Type", "application/json") req.Header.Set("Idempotency-Key", "checkout-user-42-trial-1") res, err := http.DefaultClient.Do(req) if err != nil { log.Fatal(err) } defer res.Body.Close() var session map[string]any json.NewDecoder(res.Body).Decode(&session) ``` Le client confirme ses coordonnées, choisit ses rappels et accepte de commencer l'essai. Abuna lui envoie ensuite un code à 6 chiffres par e-mail, et l'essai commence quand il le saisit sur la page d'abonnement. D'ici là, aucun abonnement n'existe et aucun essai n'est utilisé. Aucun paiement n'est demandé. La session se termine et le client rejoint votre `success_url`, avec l'activation habituelle de la messagerie choisie. | Requête de session checkout ou d'abonnement | Durée de l'essai | | --- | --- | | `trial_days` absent | La durée définie sur le prix. | | `trial_days: 1` à `365` | Cette durée remplace celle du prix. | | `trial_days: 0` | Pas d'essai. Le premier paiement habituel s'applique. | > **Remarque :** Un client a droit à un seul essai par produit dans une application, tous prix confondus, même après une résiliation. Si cet essai a déjà été utilisé, Abuna démarre l'abonnement payant habituel, sans erreur ni nouvel essai. ## Démarrer un essai sans page d'abonnement Pour un client existant, [créez directement un abonnement](https://abuna.app/docs/api/subscriptions.md?hl=fr#create). Cet exemple remplace la durée du prix par 7 jours. **Créer un abonnement avec 7 jours d'essai** cURL : ```bash curl https://api.abuna.app/v1/apps/8ddhXCDW/subscriptions \ -H "Authorization: Bearer sk_test_..." \ -H "Content-Type: application/json" \ -H "Idempotency-Key: subscription-user-42-trial-1" \ -d '{ "customer_id": "Cu5tM8rA", "price_id": "Zt6YbN3q", "trial_days": 7, "metadata": {"user_id": "42"} }' ``` Node.js : ```javascript const response = await fetch("https://api.abuna.app/v1/apps/8ddhXCDW/subscriptions", { method: "POST", headers: { Authorization: "Bearer sk_test_...", "Content-Type": "application/json", "Idempotency-Key": "subscription-user-42-trial-1", }, body: JSON.stringify({ customer_id: "Cu5tM8rA", price_id: "Zt6YbN3q", trial_days: 7, metadata: { user_id: "42" }, }), }); const result = await response.json(); ``` Python : ```python import requests response = requests.post( "https://api.abuna.app/v1/apps/8ddhXCDW/subscriptions", headers={"Authorization": "Bearer sk_test_...", "Idempotency-Key": "subscription-user-42-trial-1"}, json={ "customer_id": "Cu5tM8rA", "price_id": "Zt6YbN3q", "trial_days": 7, "metadata": {"user_id": "42"}, }, ) result = response.json() ``` PHP : ```php true, CURLOPT_HTTPHEADER => ["Authorization: Bearer sk_test_...", "Content-Type: application/json", "Idempotency-Key: subscription-user-42-trial-1"], CURLOPT_POSTFIELDS => json_encode([ "customer_id" => "Cu5tM8rA", "price_id" => "Zt6YbN3q", "trial_days" => 7, "metadata" => ["user_id" => "42"], ]), CURLOPT_RETURNTRANSFER => true, ]); $result = json_decode(curl_exec($ch), true); ``` Go : ```go body, _ := json.Marshal(map[string]any{ "customer_id": "Cu5tM8rA", "price_id": "Zt6YbN3q", "trial_days": 7, "metadata": map[string]any{"user_id": "42"}, }) req, _ := http.NewRequest("POST", "https://api.abuna.app/v1/apps/8ddhXCDW/subscriptions", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer sk_test_...") req.Header.Set("Content-Type", "application/json") req.Header.Set("Idempotency-Key", "subscription-user-42-trial-1") res, err := http.DefaultClient.Do(req) if err != nil { log.Fatal(err) } defer res.Body.Close() var result map[string]any json.NewDecoder(res.Body).Decode(&result) ``` L'abonnement démarre avec `status: trialing`. Son `trial_ends_at` indique la fin de l'essai en secondes Unix. Sans essai, ce champ vaut `null`. **Abonnement pendant un essai de 7 jours** ```json { "id": "x9QbL2sK", "app_id": "8ddhXCDW", "customer_id": "Cu5tM8rA", "price_id": "Zt6YbN3q", "status": "trialing", "starts_at": 1727600000, "activated_at": 1727600000, "trial_ends_at": 1728204800, "canceled_at": null, "cancel_at": null, "cancel_at_period_end": false, "current_period_start": 1727600000, "current_period_end": 1728204800, "ended_reason": null, "metadata": { "user_id": "42" }, "created_at": 1727600000, "manage_token": "8c1f4a7d2e9b3c6f0a5d8e1b4c7f2a9d3e6b" } ``` ## Accorder l'accès à partir des webhooks [Vérifiez la signature du webhook](https://abuna.app/docs/guides/webhooks.md?hl=fr#verify-the-signature) avant d'utiliser un événement. Décidez de l'accès à partir de l'abonnement dans l'événement, pas du retour du navigateur. - `subscription.created` est envoyé au début de l'essai. Une session checkout envoie aussi `session.completed`. Accordez l'accès quand `data.subscription.status` vaut `trialing` ; `data.subscription.trial_ends_at` est la fin de l'essai. - `subscription.paid` est envoyé quand le client paie la première facture, pendant ou après l'essai. - `subscription.trial_ending` signale la fin prochaine de l'essai, selon le délai habituel des rappels de renouvellement de votre application. Si votre URL de webhook date d'avant les essais gratuits, activez d'abord cet événement : ouvrez **Webhooks** dans le tableau de bord et modifiez les **Événements**. - Gardez l'accès pour `active` et `past_due`. Retirez-le à la réception de `subscription.canceled`. ## Le premier paiement La première période payante commence à `trial_ends_at`, même si le client paie en avance. Abuna envoie sa facture et son lien de paiement selon le délai de renouvellement de votre application. La date limite de paiement correspond normalement à la fin de l'essai plus `grace_period_days`, sans dépasser la fin de la période payante. Utilisez le `due_at` de la facture pour connaître la date exacte, y compris si la facture arrive plus tard. Le client dispose de 3 jours par défaut ; vous pouvez choisir de 1 à 14 jours. Aucun prélèvement n'est automatique. Si la facture reste impayée, les [règles habituelles des renouvellements impayés](https://abuna.app/docs/api/subscriptions.md?hl=fr#past-due) s'appliquent, avec résiliation après la date limite de paiement. ## Résilier pendant l'essai Un client qui résilie pendant l'essai conserve l'accès jusqu'à sa fin. Toute première facture encore impayée est annulée, sans rien à payer. La résiliation programmée définit `cancel_at` à `trial_ends_at`. Avec l'[API de résiliation](https://abuna.app/docs/api/subscriptions.md?hl=fr#cancel), `at_period_end: true` programme cette même fin. Omettez ce champ ou envoyez `false` pour retirer l'accès immédiatement. ## Limites en Test et en Production Les clients ayant un abonnement `trialing`, qui commence une fois leur e-mail confirmé, comptent dans la limite d'abonnés en production de votre équipe. Le mode Test n'a pas de limite d'abonnés.