Metadata-Version: 2.4
Name: paywallex
Version: 1.0.0
Summary: SDK serveur officiel de l'API Paywallex /v1 : sessions de paiement Mobile Money, remboursements, litiges, abonnements, webhooks signés.
License: MIT
Project-URL: Homepage, https://paywallex.app/developpeurs
Project-URL: Source, https://github.com/Paywallex/paywallex-kit/tree/dev/sdk/python
Keywords: paywallex,paiement,mobile money,orange money,mtn momo,wave,xof
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: license-file

# paywallex (Python)

SDK serveur officiel de l'API Paywallex `/v1` pour Python 3.9 ou plus récent. Il sert à encaisser par Orange Money, MTN MoMo, Moov Money, Wave ou le solde Paywallex, à rembourser, à suivre les litiges et les abonnements, et à vérifier les webhooks signés.

Aucune dépendance : seule la bibliothèque standard est utilisée.

> Côté serveur uniquement. Ne mettez jamais une clé secrète `pwx_sk_…` dans une page web ou une application mobile.

## Installation

Installez le paquet :

```sh
pip install paywallex
```

## Créer une session de paiement

Passez votre clé à la création du client. Une clé `pwx_sk_test_…` vise le bac à sable, une clé `pwx_sk_live_…` vise la production.

Créez une session, puis redirigez le client vers `url` :

```python
import os
from paywallex import Paywallex

paywallex = Paywallex(os.environ["PAYWALLEX_KEY"])

session = paywallex.checkout_sessions.create(
    currency="XOF",
    line_items=[
        {"name": "Attiéké poisson", "unit_amount": 2500, "quantity": 2},
        {"name": "Jus de bissap", "unit_amount": 500},
    ],
    success_url="https://maboutique.ci/merci",
    metadata={"order": "CMD-1042"},
)
# session["amount"] == 5500, redirigez vers session["url"]
```

Les montants sont en XOF entiers : `2500` veut dire 2 500 F.

## Vérifier un webhook

Vérifiez la signature avant de traiter un événement. Le SDK compare en temps constant et refuse un horodatage de plus de 5 minutes.

Passez-lui le corps brut de la requête, pas un dictionnaire déjà décodé :

```python
from flask import Flask, request
from paywallex import Webhook, PaywallexError

app = Flask(__name__)

@app.post("/webhooks/paywallex")
def paywallex_webhook():
    try:
        event = Webhook.construct_event(request.get_data(), request.headers.get("Paywallex-Signature"), os.environ["PAYWALLEX_WEBHOOK_SECRET"])
    except PaywallexError:
        return "", 400
    if event["type"] == "checkout_session.completed":
        pass  # livrer la commande
    return "", 200
```

## Les erreurs

Chaque erreur est une `PaywallexError` avec un code stable. Testez le code, jamais le message :

```python
from paywallex import PaywallexError

try:
    paywallex.refunds.create(payment=payment_id, amount=1000)
except PaywallexError as e:
    if e.code == "refund_not_eligible":
        ...
    print(e.status, e.code, e.param, e.request_id)
```

Passez `language="en"` au client pour recevoir les messages en anglais.

## Nouvelles tentatives et idempotence

Le SDK réessaie 2 fois en cas de coupure réseau, de `429` ou d'erreur `5xx`, en respectant `Retry-After`. Chaque `POST` garde la même clé d'idempotence d'une tentative à l'autre : un paiement ou un remboursement n'est jamais doublé.

Pour rejouer vous-même une requête sans risque, donnez votre propre clé :

```python
paywallex.refunds.create(payment=payment_id, idempotency_key="remboursement-CMD-1042")
```

## Ce que couvre le SDK

| Objet | Méthodes |
| --- | --- |
| `checkout_sessions` | `create`, `retrieve` |
| `payments`, `refunds`, `disputes` | `list`, `retrieve`, `all` (toutes les pages) ; `refunds.create` |
| `payouts`, `events`, `statements` | `list`, `retrieve` |
| `customers`, `payment_links`, `invoices`, `pots`, `plans`, `coupons`, `subscriptions` | `list`, `create`, `retrieve`, `update`, `action` |
| `webhook_endpoints` | `list`, `create`, `action("rotate_secret")`, `delete_webhook_endpoint()` |
| client | `account()`, `balance()`, `network_status()`, `upload_file()`, `add_dispute_evidence()` |

Accepter un litige (rembourser) ou le contester se fait dans le portail Paywallex, jamais par l'API. Un abonnement ou une hausse de prix est toujours accepté par le client dans Paywallex.

## Tests

Lancez les tests (le bac à sable est testé si `PAYWALLEX_TEST_KEY` est défini) :

```sh
python -m unittest discover tests
```

## Licence

MIT.
