# Les SDK

Node et PHP, sans aucune dépendance. Les mêmes noms que l’API, l’idempotence posée d’office, et les reprises quand le réseau flanche.

## Installer

```bash
npm install payiz
```

```bash
composer require payiz/payiz-php
```

La clé secrète vit dans vos serveurs — dans les variables d’environnement de votre hébergeur —, jamais dans une page web ni une application mobile.

## Encaisser

```javascript
import { Payiz } from 'payiz'

const payiz = new Payiz(process.env.PAYIZ_CLE)

const paiement = await payiz.payments.create({
  amount: 10000,        // entier, dans l'unité mineure de la devise
  currency: 'XOF',
  description: 'Commande 42',
  reference: 'cmd-42',
})

// À envoyer au client, ou à ouvrir avec le widget.
console.log(paiement.payment_url)
```

```php
$payiz = new \Payiz\Payiz(getenv('PAYIZ_CLE'));

$paiement = $payiz->payments->create([
    'amount' => 10000,
    'currency' => 'XOF',
    'description' => 'Commande 42',
    'reference' => 'cmd-42',
]);

header('Location: ' . $paiement['payment_url']);
```

## Ce qu’ils savent faire

| Node | PHP | Ce qu’il fait |
| --- | --- | --- |
| `payiz.account()` | `$payiz->account()` | qui parle, dans quel mode, et ce que la clé peut faire |
| `payiz.payments` | `$payiz->payments` | create, retrieve, list / all, cancel |
| `payiz.payments.attempts` | `$payiz->payments->attempts` | create (lancer, relancer), list / all |
| `payiz.paymentMethods` | `$payiz->paymentMethods` | list / all : les opérateurs ouverts, leurs bornes et frais |
| `payiz.refunds` | `$payiz->refunds` | create, retrieve, list / all, reasons |
| `payiz.paymentLinks` | `$payiz->paymentLinks` | create, retrieve, list / all, deactivate |
| `payiz.balance` | `$payiz->balance` | retrieve |
| `payiz.recipients` | `$payiz->recipients` | list / all, retrieve |
| `payiz.payouts` | `$payiz->payouts` | create, retrieve, list / all |
| `payiz.disputes` | `$payiz->disputes` | retrieve, list / all |
| `payiz.conversions` | `$payiz->conversions` | retrieve, list / all |

## Le paiement direct

Avec `payer`, la demande part aussitôt sur le téléphone du payeur. La clé porte le geste **Paiements · lancer**, et l’appel une clé d’idempotence tirée de votre commande : sans elle, le SDK refuse avant d’appeler. Le guide : [Le paiement direct](https://docs.payiz.app/paiement-direct).

```javascript
const paiement = await payiz.payments.create(
  {
    amount: 10000,
    currency: 'XOF',
    reference: 'cmd-42',
    payer: { phone: '+2290197000000', operator: 'mtn' },
  },
  { idempotencyKey: 'cmd-42' }, // obligatoire : tirée de la commande
)
// paiement.latest_attempt.payer_message : la consigne à montrer au payeur.

// Après un échec, relancer sur le même paiement :
await payiz.payments.attempts.create(
  paiement.id,
  { phone: '+2290196000000', operator: 'moov' },
  { idempotencyKey: 'cmd-42-relance-1' },
)
```

```php
$paiement = $payiz->payments->create([
    'amount' => 10000,
    'currency' => 'XOF',
    'reference' => 'cmd-42',
    'payer' => ['phone' => '+2290197000000', 'operator' => 'mtn'],
], 'cmd-42');

$payiz->payments->attempts->create(
    $paiement['id'],
    ['phone' => '+2290196000000', 'operator' => 'moov'],
    'cmd-42-relance-1'
);
```

## L’idempotence, d’office

Chaque `POST` part avec un en-tête `Idempotency-Key` : rejoué après une coupure, il rend la première réponse au lieu d’encaisser deux fois. Donnez la vôtre pour rejouer sciemment — et toujours quand l’appel touche un téléphone : une clé tirée au hasard à chaque clic n’empêcherait pas deux demandes.

```javascript
await payiz.payments.create({ amount: 10000 }, { idempotencyKey: 'cmd-42' })
```

```php
$payiz->payments->create(['amount' => 10000], 'cmd-42');
```

## Les erreurs

```javascript
import { PayizError, PayizConnectionError } from 'payiz'

try {
  await payiz.payments.create(corps, { idempotencyKey: 'cmd-42' })
} catch (erreur) {
  if (erreur instanceof PayizError) {
    // erreur.code : un code du registre, par exemple 'operator_required'
    // erreur.details : ce qui aide à corriger, ici details.operators
    // erreur.requestId : à citer au support
  } else if (erreur instanceof PayizConnectionError) {
    // le réseau n'a rien dit : rejouez avec la même clé d'idempotence
  }
}
```

```php
try {
    $payiz->payments->create($corps, 'cmd-42');
} catch (\Payiz\ApiException $e) {
    // $e->errorCode, $e->details, $e->requestId, $e->statusCode
}
```

Les codes sont ceux de [Les erreurs](https://docs.payiz.app/api/erreurs) : le SDK Node les exporte dans `ERROR_CODES`, le PHP dans `ApiException::CODES`, et les raisons d’échec d’une demande dans `FAILURE_CODES`. Une panne passagère (408, 429, 5xx) se reprend toute seule, deux fois par défaut. Une demande refusée, jamais.

## Vérifier un webhook

Toujours sur le **corps brut**, avant de le lire en JSON. Voir [Recevoir les webhooks](https://docs.payiz.app/webhooks).

```javascript
import { verifyWebhook } from 'payiz'

const brut = await request.text()
if (!(await verifyWebhook(brut, request.headers.get('payiz-signature'), secret))) {
  return new Response('Signature refusée', { status: 400 })
}
const evenement = JSON.parse(brut)
```

```php
$brut = file_get_contents('php://input');
$entete = $_SERVER['HTTP_PAYIZ_SIGNATURE'] ?? null;

if (!\Payiz\Webhook::verifier($brut, $entete, getenv('PAYIZ_WEBHOOK_SECRET'))) {
    http_response_code(400);
    exit;
}

$evenement = \Payiz\Webhook::lire($brut);
```

## Parcourir une liste

```javascript
for await (const paiement of payiz.paginate((params) => payiz.payments.list(params))) {
  console.log(paiement.id, paiement.status)
}
```

En PHP, passez `starting_after` à `all()` tant que `has_more` est vrai.

