Référence de l'API
Abonnements
Démarrez, listez, lisez, mettez à jour, annulez, conservez et changez la formule de l'abonnement d'un client à un tarif.
Un abonnement facture un client pour un tarif, une période de facturation à la fois. Il démarre pending, devient active quand le client paie la première période, est past_due pendant qu'un renouvellement attend d'être payé, et se termine canceled. Voir Statuts.
L'objet subscription
Attributs
idstringIdentifiant unique de l'abonnement.app_idstringL'application à laquelle appartient l'abonnement.customer_idstringLe client qui paie.price_idstringLe tarif que le client paie.statusstringpendingjusqu'à ce que la première période soit payée, puisactive.past_duequand une période payée est terminée et que son renouvellement n'est pas encore payé, puis de nouveauactiveune fois qu'il l'est.canceledune fois qu'il se termine. Voir Statuts.starts_attimestampQuand la première période de facturation démarre, en secondes Unix.activated_attimestampnullableQuand la première période a été payée.canceled_attimestampnullableQuand l'abonnement a été annulé.cancel_attimestampnullableQuand l'abonnement prendra fin, si une annulation est programmée pour la fin de la période payée. Null sinon. L'abonnement resteactivejusque-là.current_period_starttimestampnullableQuand la plus récente période de facturation que le client a payée a démarré, en secondes Unix. Une fois que le client paie un renouvellement en avance, c'est ce renouvellement, qui démarre dans le futur. Null avant le premier paiement. Il reste défini après la fin de l'abonnement.current_period_endtimestampnullableQuand la plus récente période de facturation que le client a payée se termine, en secondes Unix : le client a payé jusqu'à cette date. Null avant le premier paiement. Il reste défini après la fin de l'abonnement.ended_reasonstringnullablePourquoi l'abonnement a pris fin.canceledquand vous ou le client l'avez annulé, maintenant ou à la fin de la période payée.unpaidquand une période de facturation n'a pas été payée avant sa date limite de paiement, y compris une première période jamais payée. Null sauf sistatusestcanceled.metadataobjectVos propres clés et valeurs.{}quand il n'y en a aucune. Un abonnement démarré par une session de paiement reçoit le sien. Voir Métadonnées.created_attimestampQuand l'abonnement a été créé, en secondes Unix.manage_tokenstringLe jeton du lien vers l'espace client. Toute personne qui a le lien peut voir et annuler l'abonnement, alors gardez-le privé.
{
"id": "x9QbL2sK",
"app_id": "8ddhXCDW",
"customer_id": "Cu5tM8rA",
"price_id": "Zt6YbN3q",
"status": "active",
"starts_at": 1727600000,
"activated_at": 1727600100,
"canceled_at": null,
"cancel_at": null,
"current_period_start": 1727600000,
"current_period_end": 1730192000,
"ended_reason": null,
"metadata": {
"user_id": "42"
},
"created_at": 1727600000,
"manage_token": "8c1f4a7d2e9b3c6f0a5d8e1b4c7f2a9d3e6b"
}Créer un abonnement
POST/v1/apps/{appID}/subscriptions
Accepte un en-tête Idempotency-Key.
Démarre un abonnement pending et sa première période de facturation, qui démarre maintenant. Abuna émet la facture de la période et envoie au client un avis avec un lien pour la payer. Pour que le client s'inscrive et paie plutôt sur une page de paiement hébergée, utilisez Créer une session de paiement.
Paramètres
customer_idstringobligatoireLe client à facturer.price_idstringobligatoireLe tarif à lui facturer.metadataobjectVos propres clés et valeurs. Voir Métadonnées pour les limites.
Renvoie un objet avec l'subscription et sa première période de facturation, period, avec le statut 201. Si l'application n'a aucun client ou tarif avec cet ID, renvoie 404 avec le code not_found. Si le tarif est archivé, renvoie 410 avec le code price_archived. Si une application Réelle ne peut pas encore accepter de paiements, renvoie 422 avec le code not_accepting_payments. Si le client dépassait la limite d'abonnés Réels de votre forfait, renvoie 403 avec le code plan_limit.
curl https://api.abuna.app/v1/apps/8ddhXCDW/subscriptions \
-H "Authorization: Bearer sk_test_..." \
-H "Content-Type: application/json" \
-d '{"customer_id": "Cu5tM8rA", "price_id": "Zt6YbN3q"}'{
"subscription": {
"id": "x9QbL2sK",
"app_id": "8ddhXCDW",
"customer_id": "Cu5tM8rA",
"price_id": "Zt6YbN3q",
"status": "pending",
"starts_at": 1727600000,
"activated_at": null,
"canceled_at": null,
"cancel_at": null,
"current_period_start": null,
"current_period_end": null,
"ended_reason": null,
"metadata": {
"user_id": "42"
},
"created_at": 1727600000,
"manage_token": "8c1f4a7d2e9b3c6f0a5d8e1b4c7f2a9d3e6b"
},
"period": {
"id": "T6yVr3Dp",
"subscription_id": "x9QbL2sK",
"price_id": "Zt6YbN3q",
"pay_token": "3a7e1c9f5b2d8a4e6c0f7b3d9a1e5c8f2b6d",
"starts_at": 1727600000,
"ends_at": 1730192000,
"period_index": 0,
"grace_period_ends_at": 1727686400,
"paid_at": null,
"paused_at": null,
"in_force": true,
"created_at": 1727600000
}
}Lister les abonnements
GET/v1/apps/{appID}/subscriptions
Liste les abonnements de l'application, du plus récent au plus ancien, une page à la fois. Chaque élément a les champs de l'abonnement, y compris cancel_at, current_period_start, current_period_end, ended_reason et metadata, sans app_id ni manage_token, plus trois autres.
Paramètres de requête
statusstringRenvoie uniquement les abonnements ayant ce statut :pending,active,past_dueoucanceled.customer_idstringRenvoie uniquement les abonnements de ce client.emailstringRenvoie uniquement les abonnements dont l'e-mail du client contient ce texte. La casse n'a pas d'importance.limitintegerCombien d'abonnements renvoyer, de 1 à 100. Par défaut 50.cursorstringLa valeurnext_cursorde la page précédente. Envoyez les mêmes filtres avec.
Attributs supplémentaires
customerobjectQui paie.Afficher les attributsMasquer les attributs
namestringnullableLe nom du client.emailstringL'adresse e-mail du client.
priceobjectCe qu'il paie.Afficher les attributsMasquer les attributs
namestringLe nom du tarif.amountintegerLe montant pour chaque période, dans la plus petite unité de la devise.currencystringXAF.intervalstringday,week,monthouyear.interval_countintegerCombien d'intervalles composent une période.
next_payment_attimestampnullableQuand le prochain paiement est dû. Tant que la dernière période est impayée, c'est le début de cette période, même s'il est dans le passé. Une fois qu'elle est payée, c'est le début de la période suivante. Null une fois annulé, et null tant qu'une annulation est programmée.
Renvoie items et next_cursor, comme décrit dans Listes et filtres. Un status inconnu ou un limit hors de 1 à 100 renvoie 422 avec le code invalid.
curl "https://api.abuna.app/v1/apps/8ddhXCDW/subscriptions?status=active&customer_id=Cu5tM8rA" \
-H "Authorization: Bearer sk_test_..."{
"items": [
{
"id": "x9QbL2sK",
"customer_id": "Cu5tM8rA",
"price_id": "Zt6YbN3q",
"status": "active",
"starts_at": 1727600000,
"activated_at": 1727600100,
"canceled_at": null,
"cancel_at": null,
"current_period_start": 1727600000,
"current_period_end": 1730192000,
"ended_reason": null,
"metadata": {
"user_id": "42"
},
"created_at": 1727600000,
"customer": {
"name": "Jane Doe",
"email": "jane@example.com"
},
"price": {
"name": "Monthly",
"amount": 5000,
"currency": "XAF",
"interval": "month",
"interval_count": 1
},
"next_payment_at": 1730192000
}
],
"next_cursor": null
}Récupérer un abonnement
GET/v1/apps/{appID}/subscriptions/{id}
Récupère un abonnement avec son client, son tarif, ses périodes de facturation et ses paiements.
Attributs de réponse
subscriptionobjectL'objet subscription.subscription_page_urlstringLe lien vers l'espace client, où le client voit et annule l'abonnement.customerobjectL'objet customer, plustelegram_connected.priceobjectL'objet price.periodsarrayChaque période de facturation en vigueur, de la plus ancienne à la plus récente. La période d'une mise à niveau en attente de paiement, ou une période échue, n'est pas listée. Celle en attente figure danspending_change, et sa facture reste dans la liste des factures.Afficher les attributsMasquer les attributs
idstringL'ID de la période de facturation.starts_attimestampQuand la période démarre.ends_attimestampQuand la période se termine.grace_period_ends_attimestampLa date limite de paiement.paid_attimestampnullableQuand la période a été payée.pay_urlstringLe lien de paiement de la période.invoiceobjectnullableL'objet invoice de la période.invoice_urlstringnullableUn lien vers la page de la facture. Il expire après 7 jours.
paymentsarrayChaque paiement de l'abonnement, du plus récent au plus ancien.pending_changeobjectnullableLe changement de formule en attente : une mise à niveau en attente de paiement, ou une rétrogradation programmée pour la fin de la période payée. Null quand il n'y en a pas. Une annulation programmée figure plutôt danscancel_at.Afficher les attributsMasquer les attributs
idstringLe changement de formule.typestringupgradeoudowngrade.priceobjectLe nouveau tarif :id,name,amount,currency,intervaletinterval_count.requested_bystringcustomerquand le client l'a choisi dans son espace client, oumerchantquand il a confirmé un changement que vous lui avez envoyé.created_attimestampQuand le changement a été demandé.amount_dueintegernullableCe que le client paie pour basculer maintenant. Null pour une rétrogradation.creditintegernullableLe temps inutilisé de la période en cours déduit du nouveau tarif. Null pour une rétrogradation.expires_attimestampnullableSi la mise à niveau n'est pas payée avant, elle expire et la formule actuelle continue. Null pour une rétrogradation.pay_urlstringnullableLe lien de paiement de la mise à niveau. Null pour une rétrogradation.effective_attimestampnullableQuand la rétrogradation démarre. Null pour une mise à niveau.
plan_offerobjectnullableLe changement de formule en attente de confirmation du client, ou null. Il est null une fois dépassé sonexpires_at.plan_changesarrayChaque changement de formule de l'abonnement, du plus récent au plus ancien.Afficher les attributsMasquer les attributs
idstringLe changement de formule.directionstringupgradeoudowngrade.statusstringawaiting_payment(une mise à niveau pas encore payée),scheduled(une rétrogradation en attente de la fin de la période),applied,lapsed(une mise à niveau non payée à temps),undone(une rétrogradation reprise),replaced(un autre changement l'a remplacée), oucanceled(l'abonnement a pris fin avant).from_priceobjectLe tarif d'avant, dans la même forme que ci-dessus.to_priceobjectLe nouveau tarif.requested_bystringcustomeroumerchant.amountintegernullableCe que la mise à niveau facture. Null pour une rétrogradation.creditintegernullableLe temps inutilisé déduit de la mise à niveau. Null pour une rétrogradation.effective_attimestampnullableQuand elle a pris effet, ou pour une rétrogradation, quand elle prendra effet. Null pour une mise à niveau qui n'a pas encore pris effet.created_attimestampQuand elle a été demandée.resolved_attimestampnullableQuand elle a quitté l'état en attente.
Si l'application n'a aucun abonnement avec cet ID, renvoie 404 avec le code not_found.
curl https://api.abuna.app/v1/apps/8ddhXCDW/subscriptions/x9QbL2sK \
-H "Authorization: Bearer sk_test_..."{
"subscription": {
"id": "x9QbL2sK",
"app_id": "8ddhXCDW",
"customer_id": "Cu5tM8rA",
"price_id": "Zt6YbN3q",
"status": "active",
"starts_at": 1727600000,
"activated_at": 1727600100,
"canceled_at": null,
"cancel_at": null,
"current_period_start": 1727600000,
"current_period_end": 1730192000,
"ended_reason": null,
"metadata": {
"user_id": "42"
},
"created_at": 1727600000,
"manage_token": "8c1f4a7d2e9b3c6f0a5d8e1b4c7f2a9d3e6b"
},
"subscription_page_url": "https://app.abuna.app/portal/8c1f4a7d2e9b3c6f0a5d8e1b4c7f2a9d3e6b",
"customer": {
"id": "Cu5tM8rA",
"app_id": "8ddhXCDW",
"name": "Jane Doe",
"phone_number": "+237671234567",
"email": "jane@example.com",
"created_at": 1727600000,
"telegram_connected": false
},
"price": {
"id": "Zt6YbN3q",
"product_id": "pR4dWx9K",
"name": "Monthly",
"currency": "XAF",
"amount": 5000,
"interval": "month",
"interval_count": 1,
"created_at": 1727600000,
"archived_at": null
},
"periods": [
{
"id": "T6yVr3Dp",
"starts_at": 1727600000,
"ends_at": 1730192000,
"grace_period_ends_at": 1727686400,
"paid_at": 1727600100,
"pay_url": "https://app.abuna.app/pay/3a7e1c9f5b2d8a4e6c0f7b3d9a1e5c8f2b6d",
"invoice": {
"id": "V2nC8xEi",
"app_id": "8ddhXCDW",
"period_id": "T6yVr3Dp",
"subscription_id": "x9QbL2sK",
"number": "MYST-000124",
"status": "paid",
"kind": "period",
"amount": 5000,
"credit": 0,
"currency": "XAF",
"item_label": "Monthly",
"buyer_name": "Jane Doe",
"buyer_email": "jane@example.com",
"seller_name": "My store",
"period_start": 1727600000,
"period_end": 1730192000,
"due_at": 1727686400,
"created_at": 1727600000,
"paid_at": 1727600100,
"voided_at": null
},
"invoice_url": "https://app.abuna.app/invoice/V2nC8xEi?exp=1728204800&sig=b4e1c8f2a7d3960e5b1f8c4a2d7e3b9f6a0c5e8d1b4f7a2c9e6d3b0f8a5c1e7d"
}
],
"payments": [
{
"id": "m7Yw4NcJ",
"app_id": "8ddhXCDW",
"period_id": "T6yVr3Dp",
"driver": "sandbox",
"provider": "test",
"provider_reference": "test_9f3b7d1a5c2e8f4b6d0a",
"amount": 5000,
"currency": "XAF",
"status": "succeeded",
"message": null,
"created_at": 1727600090,
"fee": 100,
"session_id": null,
"method_label": "Successful payment (test)"
}
],
"pending_change": {
"id": "H3nM8cGb",
"type": "downgrade",
"price": {
"id": "Kw3FgT7e",
"name": "Basic monthly",
"amount": 2000,
"currency": "XAF",
"interval": "month",
"interval_count": 1
},
"requested_by": "customer",
"created_at": 1728464000,
"amount_due": null,
"credit": null,
"expires_at": null,
"pay_url": null,
"effective_at": 1730192000
},
"plan_offer": null,
"plan_changes": [
{
"id": "H3nM8cGb",
"direction": "downgrade",
"status": "scheduled",
"from_price": {
"id": "Zt6YbN3q",
"name": "Monthly",
"amount": 5000,
"currency": "XAF",
"interval": "month",
"interval_count": 1
},
"to_price": {
"id": "Kw3FgT7e",
"name": "Basic monthly",
"amount": 2000,
"currency": "XAF",
"interval": "month",
"interval_count": 1
},
"requested_by": "customer",
"amount": null,
"credit": null,
"effective_at": 1730192000,
"created_at": 1728464000,
"resolved_at": null
}
]
}Mettre à jour un abonnement
PATCH/v1/apps/{appID}/subscriptions/{id}
Définit le metadata de l'abonnement. La table que vous envoyez remplace toute la table : les clés que vous omettez sont supprimées. Envoyez {} pour l'effacer.
Paramètres
metadataobjectobligatoireLe nouveau metadata. Voir Métadonnées pour les limites.
Renvoie l'abonnement. Un metadata au-delà de ses limites renvoie 422 avec le code invalid et un élément errors pour metadata. Si l'application n'a aucun abonnement avec cet ID, renvoie 404 avec le code not_found.
curl https://api.abuna.app/v1/apps/8ddhXCDW/subscriptions/x9QbL2sK \
-X PATCH \
-H "Authorization: Bearer sk_test_..." \
-H "Content-Type: application/json" \
-d '{"metadata": {"user_id": "42"}}'{
"id": "x9QbL2sK",
"app_id": "8ddhXCDW",
"customer_id": "Cu5tM8rA",
"price_id": "Zt6YbN3q",
"status": "active",
"starts_at": 1727600000,
"activated_at": 1727600100,
"canceled_at": null,
"cancel_at": null,
"current_period_start": 1727600000,
"current_period_end": 1730192000,
"ended_reason": null,
"metadata": {
"user_id": "42"
},
"created_at": 1727600000,
"manage_token": "8c1f4a7d2e9b3c6f0a5d8e1b4c7f2a9d3e6b"
}Annuler un abonnement
POST/v1/apps/{appID}/subscriptions/{id}/cancel
Accepte un en-tête Idempotency-Key.
Met fin à l'abonnement, maintenant ou à la fin de la période payée. Envoyez at_period_end pour choisir. Un corps vide, ou false, annule maintenant, comme toujours. Pour que le client confirme lui-même l'annulation, utilisez Créer une session d'annulation.
Paramètres du corps
at_period_endbooleanFacultatif,falsepar défaut. Avectrue, l'abonnement resteactivejusqu'à la fin de la période payée en cours, puis prend fin tout seul. Une valeur qui n'est pas un booléen renvoie400avec le codeinvalid_json.
Maintenant. L'abonnement est canceled immédiatement, avec canceled_at défini et cancel_at à null. Abuna annule ses factures ouvertes, envoie un événement subscription.canceled avec la raison merchant, et prévient le client. Annuler maintenant un abonnement qui a une annulation programmée le termine maintenant et efface la programmation. Cela annule aussi une mise à niveau en attente de paiement et retire une offre de changement de formule en attente.
À la fin de la période payée. La réponse a status active et cancel_at défini à la fin de la période payée. Abuna envoie un événement subscription.updated et indique au client quand il prend fin et comment le conserver. Jusque-là, il n'émet aucun renouvellement et n'envoie aucun rappel de renouvellement, et next_payment_at dans la liste est null. Quand la date arrive, l'abonnement devient canceled et Abuna envoie subscription.canceled. Envoyer at_period_end de nouveau pendant qu'une annulation est programmée renvoie 200 et ne change rien : aucun nouvel événement et aucun nouvel e-mail. Une annulation programmée remplace une rétrogradation programmée ou une mise à niveau en attente de paiement. Voir Un changement à la fois.
Si la période en cours n'est pas encore payée, ou est déjà terminée, at_period_end: true annule maintenant à la place. Vérifiez status dans la réponse pour voir ce qui s'est passé. Une facture de renouvellement envoyée avant la fin et pas encore payée est annulée, donc le client ne peut pas payer pour une période après la fin. S'il l'a déjà payée, l'abonnement prend fin quand ce renouvellement se termine.
Renvoie l'abonnement. Si l'application n'a aucun abonnement avec cet ID, ou s'il est déjà annulé, renvoie 404 avec le code not_found. Si at_period_end devait remplacer une mise à niveau dont le paiement est en cours, renvoie 409 avec le code payment_in_progress.
curl https://api.abuna.app/v1/apps/8ddhXCDW/subscriptions/x9QbL2sK/cancel \
-X POST \
-H "Authorization: Bearer sk_test_..." \
-H "Content-Type: application/json" \
-d '{"at_period_end": true}'{
"id": "x9QbL2sK",
"app_id": "8ddhXCDW",
"customer_id": "Cu5tM8rA",
"price_id": "Zt6YbN3q",
"status": "active",
"starts_at": 1727600000,
"activated_at": 1727600100,
"canceled_at": null,
"cancel_at": 1730192000,
"current_period_start": 1727600000,
"current_period_end": 1730192000,
"ended_reason": null,
"metadata": {
"user_id": "42"
},
"created_at": 1727600000,
"manage_token": "8c1f4a7d2e9b3c6f0a5d8e1b4c7f2a9d3e6b"
}Conserver un abonnement
POST/v1/apps/{appID}/subscriptions/{id}/resume
Accepte un en-tête Idempotency-Key.
Annule une annulation programmée. La facturation continue comme avant : cancel_at est de nouveau null et le prochain renouvellement est émis à temps. Abuna envoie un événement subscription.updated et indique au client que l'abonnement continue.
Cela annule aussi une rétrogradation programmée, donc la période suivante reste au tarif actuel. Abuna envoie subscription.updated avec un changement downgrade_undone, et aucun e-mail.
Si rien n'est programmé sur un abonnement actif, renvoie 200 et ne change rien. Si l'abonnement est déjà annulé, renvoie 409 avec le code subscription_canceled. Si l'application n'a aucun abonnement avec cet ID, renvoie 404 avec le code not_found.
curl https://api.abuna.app/v1/apps/8ddhXCDW/subscriptions/x9QbL2sK/resume \
-X POST \
-H "Authorization: Bearer sk_test_..."{
"id": "x9QbL2sK",
"app_id": "8ddhXCDW",
"customer_id": "Cu5tM8rA",
"price_id": "Zt6YbN3q",
"status": "active",
"starts_at": 1727600000,
"activated_at": 1727600100,
"canceled_at": null,
"cancel_at": null,
"current_period_start": 1727600000,
"current_period_end": 1730192000,
"ended_reason": null,
"metadata": {
"user_id": "42"
},
"created_at": 1727600000,
"manage_token": "8c1f4a7d2e9b3c6f0a5d8e1b4c7f2a9d3e6b"
}Lister les options de formule
GET/v1/apps/{appID}/subscriptions/{id}/plan-options
Liste les tarifs vers lesquels l'abonnement peut basculer, chacun chiffré à l'instant présent. Les montants changent à mesure que la période s'écoule, alors chiffrez de nouveau juste avant de les afficher. Voir Changer de formule pour la façon dont chaque nombre est calculé.
Chaque option
priceobjectLe tarif :id,name,amount,currency,intervaletinterval_count.directionstringupgradeoudowngrade.amount_dueintegerPour une mise à niveau, ce que le client paie maintenant. Il peut être0. Toujours0pour une rétrogradation.creditintegerPour une mise à niveau, le temps inutilisé de la période en cours déduit du nouveau tarif. Toujours0pour une rétrogradation.new_billing_datetimestampnullablePour une mise à niveau, quand la nouvelle période se terminerait si elle était payée maintenant. Null pour une rétrogradation.effective_attimestampnullablePour une rétrogradation, quand le nouveau tarif démarre : la fin de la période payée. Null pour une mise à niveau.
Renvoie { "data": [...] }. La liste est vide quand aucun autre tarif n'est éligible ou que l'abonnement n'est pas active ou past_due. Si l'application n'a aucun abonnement avec cet ID, renvoie 404 avec le code not_found.
curl https://api.abuna.app/v1/apps/8ddhXCDW/subscriptions/x9QbL2sK/plan-options \
-H "Authorization: Bearer sk_test_..."{
"data": [
{
"price": {
"id": "Hc8LmV2s",
"name": "Pro monthly",
"amount": 10000,
"currency": "XAF",
"interval": "month",
"interval_count": 1
},
"direction": "upgrade",
"amount_due": 6666,
"credit": 3334,
"new_billing_date": 1731142400,
"effective_at": null
},
{
"price": {
"id": "Kw3FgT7e",
"name": "Basic monthly",
"amount": 2000,
"currency": "XAF",
"interval": "month",
"interval_count": 1
},
"direction": "downgrade",
"amount_due": 0,
"credit": 0,
"new_billing_date": null,
"effective_at": 1730192000
}
]
}Statuts
pending: créé, et en attente du premier paiement. Si la première période n'est pas payée avant sa date limite de paiement, l'abonnement estcanceledavecended_reasonunpaid.active: chaque période qui a commencé est payée.past_due: un renouvellement a commencé et n'est pas encore payé.canceled: terminé.ended_reasondit pourquoi. Un abonnement annulé ne peut pas être redémarré.
Renouvellements et past_due
Abuna émet la période de facturation suivante et sa facture avant la fin de la période payée, aussi longtemps à l'avance que l'indique le renewal_lead_days de votre application : 0 à 7, 3 par défaut. Abuna envoie subscription.renewed et invoice.created, et envoie au client par e-mail la facture avec son lien de paiement. L'abonnement reste active, et le client peut payer tout de suite. La nouvelle période démarre toujours quand la période payée se termine, même si elle est payée en avance.
Si le renouvellement est encore impayé quand la période payée se termine, l'abonnement devient past_due et Abuna envoie subscription.past_due. Quand la facture est payée, l'abonnement est de nouveau active, et Abuna envoie subscription.recovered. Un renouvellement payé avant la fin de la période payée ne passe jamais par past_due. Avec renewal_lead_days à 0, ou tant qu'une rétrogradation attend la fin de la période, la facture part à la fin de la période, donc l'abonnement est past_due jusqu'à ce que le client paie.
Si la période n'est pas payée avant sa date limite de paiement, l'abonnement est canceled avec ended_reason unpaid, et Abuna envoie subscription.canceled avec la raison non_payment. La date limite de paiement est legrace_period_ends_at de la période de facturation : le début de la période plus le grace_period_days de votre application, et jamais après la fin de la période.
current_period_start et current_period_end continuent de montrer la dernière période payée tant que l'abonnement est past_due. Un abonnement past_due peut encore :
- Être payé via son lien de paiement, une session de paiement, ou l'espace client.
- Être annulé. Une annulation à la fin de la période payée le termine maintenant, parce que la période en cours n'est pas payée.
- Changer de formule. Une mise à niveau démarre tout de suite une période complète au nouveau tarif, et une rétrogradation attend la fin de la période en cours. Voir Mises à niveau.
Paiements qui arrivent en retard
Un paiement par mobile money que le client a approuvé peut être confirmé par le prestataire des heures plus tard. Si la facture a été annulée entre-temps, Abuna enregistre quand même le paiement : il est succeeded, la facture devient paid, Abuna envoie invoice.paid, et le client reçoit un reçu.
- Si l'abonnement a pris fin uniquement parce que ce paiement n'était pas arrivé (
ended_reasonunpaid), et que la période qu'il paie n'est pas encore terminée, l'abonnement revient :statusestactive,canceled_atetended_reasonsont de nouveau null, et Abuna envoiesubscription.recovered, ousubscription.paidpour un premier paiement. Un premier paiement a besoin de place dans la limite d'abonnés Réels de votre forfait, comme au paiement. - Sinon l'abonnement reste tel quel : annulé par vous ou le client, remplacé, au-delà de la période payée, ou une mise à niveau qui a expiré. Vous voudrez peut-être rembourser le client.
Dans les deux cas, les membres de l'équipe qui reçoivent les e-mails sur les paiements ou les annulations en reçoivent un à ce sujet.
Métadonnées
metadata contient vos propres clés et valeurs sur un abonnement, comme l'ID de votre utilisateur. Définissez-le quand vous créez l'abonnement, transmettez-le à une session de paiement, ou mettez-le à jour plus tard. Chaque lecture le renvoie.
- Jusqu'à 20 clés.
- Chaque clé fait 1 à 40 caractères.
- Chaque valeur est une chaîne de 500 caractères au plus. Les nombres, les booléens, les objets et null ne sont pas autorisés.
Les événements subscription, invoice et plan_offer portent le metadata de cet abonnement. Les événements de session portent plutôt le metadata de la session. Transmettez le metadata sur chaque session que vous créez. Voir Types d'événement.
Annuler un abonnement
Une annulation peut prendre effet maintenant ou à la fin de la période payée. Vous choisissez le moment quand vous annulez dans le tableau de bord ou l'API. Pour les clients qui annulent dans l'espace client, c'est le réglage Quand les clients annulent de l'application qui décide, soit customer_cancel. Les nouvelles applications démarrent avec at_period_end. Une session d'annulation utilise aussi ce réglage, sauf si vous envoyez at_period_end.
- Maintenant. L'abonnement prend fin immédiatement et toute facture impayée est annulée.
- Fin de la période payée. L'abonnement reste
activeet portecancel_at. Le client garde l'accès qu'il a payé. Abuna n'émet aucun renouvellement et n'envoie aucun rappel de renouvellement, et annule une facture de renouvellement déjà envoyée et qui n'est pas payée. Un renouvellement que le client a déjà payé compte comme période payée, donc l'abonnement prend fin quand elle se termine. Le tableau de bord et l'espace client affichent « Prend fin le » avec la date. À ce moment-là, l'abonnement devientcanceled. - Période impayée. Si la période en cours n'est pas encore payée, une annulation de fin de période met fin à l'abonnement maintenant et annule la facture impayée. Le tableau de bord et l'espace client le disent avant que la personne confirme.
- Revenir en arrière. Jusqu'à la date de fin, vous pouvez conserver l'abonnement dans le tableau de bord ou avec l'endpoint de reprise, et le client peut le conserver dans l'espace client. La facturation continue comme avant.
Le client reçoit un e-mail quand une annulation est programmée, avec la date de fin et comment conserver l'abonnement, un quand elle prend fin, et une courte confirmation si elle est annulée. Votre endpoint de webhook reçoit subscription.updated quand une annulation est programmée ou annulée, et subscription.canceled quand l'abonnement prend fin. Voir Notifications aux clients.
Le mode Test fonctionne de la même façon. Abuna enregistre les e-mails pour un client Test au lieu de les envoyer, et les applications Test et Réelles gardent leur propre réglage Quand les clients annulent.
Changer de formule
Un abonnement active ou past_due peut passer à un autre tarif. Le client le fait dans son espace client, ou confirme un changement que vous lui envoyez avec une session de changement de formule. Vous ne pouvez pas changer le tarif directement, parce qu'une mise à niveau a besoin que le client paie.
Quels tarifs
Tout autre tarif du même produit dans la même devise, sauf s'il est archivé. Jamais un tarif d'un autre produit ni dans une autre devise. Si aucun tarif n'est éligible, l'espace client n'affiche aucune option de changement de formule. Un abonnement encore pending ne peut pas changer de formule.
Mise à niveau ou rétrogradation
Abuna compare le coût par jour : le montant du tarif divisé par la durée en jours d'une de ses périodes démarrant maintenant. Un tarif qui coûte plus par jour est une mise à niveau. Un tarif qui coûte autant ou moins est une rétrogradation. Cela fonctionne entre intervalles, donc passer d'un mensuel à un annuel suit la même règle.
Mises à niveau
Si la période en cours est payée, le client paie la différence maintenant et garde l'ancienne formule jusqu'à ce que ce paiement réussisse. Une facture de renouvellement déjà envoyée pour l'ancien tarif et non payée est annulée, et la suivante est émise au nouveau tarif. Si le client a déjà payé la période suivante avant qu'elle commence, une mise à niveau attend que cette période démarre : jusque-là, l'espace client ne propose aucune mise à niveau, et un changement renvoie 409 avec le code renewal_paid_early. À ce moment-là, la nouvelle formule démarre avec une période complète entière au nouveau tarif, et la date de facturation passe à la date de paiement.
Le montant est le nouveau tarif moins la valeur inutilisée de la période en cours. La valeur inutilisée est la valeur de la période multipliée par les jours entiers restants, divisée par les jours de la période. La valeur de la période est ce que sa facture a facturé plus tout crédit qu'elle porte, donc une deuxième mise à niveau dans la même période ne perd rien. Le résultat est arrondi à l'entier inférieur et ne descend jamais sous 0. Avec 20 jours restants sur 30 d'une période de 5 000 FCFA, passer à un tarif de 10 000 FCFA coûte 10000 − 3334 = 6666, et credit vaut 3334.
- Rien à payer. Quand le montant est
0, la mise à niveau prend effet immédiatement. Sa facture est créée déjà payée. - Pas payée à temps. La mise à niveau expire à son
expires_at: les jours de paiement de votre application à partir de la demande, ou la fin de la période en cours si elle arrive avant. Sa facture est annulée et l'ancienne formule continue. Il n'y a aucune pénalité. Si la mise à niveau a remplacé une annulation programmée, l'annulation est reprogrammée à sa date d'origine, etsubscription.updatedporte soncancel_at. - Période en cours impayée. Si la période en cours n'est pas encore payée, comme tant que l'abonnement est
past_due, Abuna annule sa facture et démarre une période complète au nouveau tarif maintenant. La nouvelle formule est en vigueur immédiatement et le client la paie via son lien de paiement, avec les jours de paiement habituels. Il n'y a aucun crédit. Tant qu'un paiement sur l'ancienne facture est en cours, le changement renvoie409avec le codepayment_in_progress.
La facture d'une mise à niveau a kind plan_change et le temps inutilisé dans credit. Son amount est ce que le client paie.
Une mise à niveau avec quelque chose à payer exige que votre application accepte les paiements. Jusque-là, le changement renvoie 422 avec le code not_accepting_payments. Une mise à niveau sans rien à payer, et une rétrogradation, fonctionnent dans les deux cas.
Rétrogradations
Une rétrogradation ne coûte rien maintenant et ne rembourse rien. Le client garde la formule actuelle jusqu'à la fin de la période payée, et la période suivante est émise au nouveau tarif quand la période payée se termine, pas avant. Une facture de renouvellement déjà envoyée pour l'ancien tarif et non payée est annulée. Si le client a déjà payé la période suivante, la rétrogradation démarre quand cette période se termine. Jusque-là, le client peut l'annuler dans son espace client, et vous pouvez le faire avec Conserver un abonnement. Une rétrogradation programmée figure dans pending_change et dans scheduled_price_change sur subscription.updated.
Une rétrogradation peut être programmée tant que la période en cours est encore impayée. Elle démarre tout de même à la fin de cette période, et si la période reste impayée, l'abonnement prend fin pour non-paiement comme d'habitude. Tant qu'une rétrogradation est programmée, le rappel de renouvellement indique le nouveau tarif.
Un changement à la fois
Un abonnement contient au plus l'un de ces éléments : une annulation programmée, une rétrogradation programmée, ou une mise à niveau en attente de paiement. En démarrer un remplace l'autre. Une mise à niveau remplacée a sa facture annulée, et le changement remplacé reçoit le statut replaced. Tant que le paiement de cette mise à niveau est en cours, elle ne peut pas être remplacée : la requête renvoie 409 avec le code payment_in_progress.
Redemander le changement déjà en attente, vers le même tarif, ne change rien et le renvoie tel quel.
Un changement que vous envoyez au client avec une session de changement de formule attend qu'il le confirme. Un abonnement a au plus un changement en attente d'être confirmé. Un nouveau, ou un changement de formule que le client fait dans l'espace client, le remplace. Le confirmer remplace une annulation programmée, une rétrogradation programmée ou une mise à niveau en attente de paiement, et la page de confirmation le dit d'abord. Annuler l'abonnement maintenant annule une mise à niveau en attente de paiement et retire le changement en attente d'être confirmé.
Dans l'espace client
L'espace client liste chaque tarif éligible avec ce qu'il coûte maintenant : le montant à payer et la nouvelle date de facturation pour une mise à niveau, ou la date à laquelle elle démarre pour une rétrogradation. Une mise à niveau envoie le client vers son lien de paiement, sauf s'il n'y a rien à payer. Tant qu'une mise à niveau attend le paiement, l'espace client l'affiche avec son lien de paiement. Conserver l'abonnement dans l'espace client annule aussi une rétrogradation programmée. Pour envoyer un client vers l'espace client avec un lien de retour vers votre application, utilisez Créer une session de portail.
La page de confirmation
L'url d'une session de changement de formule ouvre une page avec la formule actuelle, la nouvelle, et ce que coûte le changement, calculé au chargement de la page. Le client confirme là, et le changement suit les mêmes règles que dans l'espace client. La page cesse de fonctionner quand la session expire (7 jours, ou la fin de la période en cours si elle arrive avant), quand un changement plus récent la remplace, ou une fois qu'elle est utilisée.
Abuna n'envoie pas d'e-mail au client quand vous créez une session de changement de formule, alors envoyez-le vous-même vers son url. Le client reçoit un e-mail quand une mise à niveau prend effet et quand une rétrogradation est programmée. Rien n'est envoyé quand une mise à niveau commence à attendre le paiement, quand elle expire, ou quand une rétrogradation est annulée. Voir Notifications aux clients. En mode Test, Abuna enregistre ces e-mails au lieu de les envoyer.
Étapes suivantes
- Factures et paiementsPériodes de facturation, leurs factures et les paiements associés, et comment lister et lire les factures.
- ÉvénementsLe journal de tout ce qui s'est passé dans une application, et chaque type d'événement.
- Notifications aux clientsCe que vos clients reçoivent par e-mail et Telegram, et à quel moment.