Search by

ophelix / ophelix-php

Emile442

Bibliothèque PHP officielle de l'API Ophelix : facturation de l'Assurance Maladie.

v0.1.0 2026-11-07 21:23 UTC

This package is auto-updated.

Last update: 2026-11-07 21:28:39 UTC


README

La bibliothèque PHP officielle de l'API Ophelix : la facturation de l'Assurance Maladie (FSE, SESAM-Vitale) par une API.

  • PHP 8.2 et plus, sans framework.
  • PSR-18 et PSR-17 : Guzzle par défaut, tout autre client sur demande.
  • Un service par ressource, des objets typés pour PHPStan et Psalm, une exception par type d'erreur.
  • Clé d'idempotence tirée pour chaque écriture, reprises sur 429 et 5xx, pagination automatique.
  • Vérification de la signature des webhooks.

Installation

composer require ophelix/ophelix-php

Premier appel, en mode test

Créez une clé secrète dans Développeurs › Clés sur app.ophelix.fr. Une clé sk_test_ travaille sur le simulateur : elle ne touche ni l'Assurance Maladie ni une vraie carte.

use Ophelix\OphelixClient;

$ophelix = new OphelixClient(getenv('OPHELIX_API_KEY'));

// Un praticien naît de la lecture de sa carte CPS, un patient de celle de sa carte Vitale.
$practitioner = $ophelix->practitioners->create(['card' => 'cps_doctor']);
$coverage = $ophelix->coverages->create(['source' => 'vitale_card', 'card' => 'vitale_ok']);

$claim = $ophelix->claims->create([
    'practitioner' => $practitioner->id,
    'patient' => $coverage->patient,
    'third_party_amo' => true,
    'context' => ['care_pathway' => 'treating_doctor', 'common_law_accident' => false],
    'lines' => [['nomenclature' => 'ngap', 'code' => 'ZC', 'service_date' => '2026-11-06', 'unit_price_cents' => 2650]],
]);

$ophelix->claims->finalize($claim->id);
$ophelix->claims->secure($claim->id);

// En mode test, les retours de l'Assurance Maladie se déclenchent à la main.
$ophelix->testHelpers->claims->simulateReturn($claim->id, ['scenario' => 'arl_positive']);
$paid = $ophelix->testHelpers->claims->simulateReturn($claim->id, ['scenario' => 'payment']);

echo $paid->status; // paid

Le parcours complet est dans le guide de démarrage.

Ce que fait le client

Réglage Par défaut Sens
api_version celle que la bibliothèque épingle L'en-tête Ophelix-Version
base_url https://api.ophelix.fr L'adresse de l'API, sans /v1
max_retries 2 Les reprises après un 429, un 5xx ou une coupure
timeout 60 Le délai d'une tentative, en secondes, avec le client Guzzle par défaut
http_client, request_factory, stream_factory Guzzle Un autre client PSR-18 et ses fabriques PSR-17
$ophelix = new OphelixClient($key, ['max_retries' => 4, 'timeout' => 20.0]);
$ophelix->livemode;   // false pour une clé de test

Chaque méthode accepte en dernier argument des options d'appel : idempotency_key, api_version, max_retries.

Objets

Un objet se lit par ses propriétés, ou comme un tableau pour un champ plus récent que la bibliothèque. Un champ lié rend un identifiant, ou l'objet avec expand :

$claim = $ophelix->claims->retrieve('clm_…', ['expand' => ['patient']]);
$claim->patient->quality;                    // un Ophelix\Resources\Patient
$claim->getLastResponse()->requestId;        // à retrouver dans Développeurs › Requêtes

Un objet passé en paramètre part par son identifiant : 'patient' => $claim->patient marche, déplié ou non.

Listes

all() rend la première page. Un foreach les parcourt toutes, en demandant la suivante quand la précédente est lue :

$page = $ophelix->claims->all(['status' => 'paid', 'limit' => 50]);
$page->data;       // cette page
$page->has_more;

foreach ($ophelix->claims->all(['status' => 'paid']) as $claim) {
    // toutes les factures payées
}

Idempotence et reprises

Chaque écriture porte une clé Idempotency-Key tirée pour elle, et la garde d'une reprise à l'autre : un 429, un 5xx ou une coupure se rejouent sans doubler l'écriture. Passez la vôtre pour rejouer un appel d'un processus à l'autre :

$ophelix->claims->create($params, ['idempotency_key' => $commande->uuid]);

Erreurs

Une erreur de l'API lève la sous-classe de son type, qui étend Ophelix\Exception\ApiErrorException :

Exception Type Exemple
InvalidRequestException invalid_request_error paramètre faux, objet inconnu
AuthenticationException authentication_error clé inconnue ou révoquée
PermissionException permission_error droit manquant sur une clé restreinte
RateLimitException rate_limit_error débit dépassé, après les reprises
IdempotencyException idempotency_error même clé, autre corps
ApiException api_error erreur d'Ophelix, moteur indisponible

ApiConnectionException dit que l'API n'a pas répondu. Toutes implémentent Ophelix\Exception\ExceptionInterface.

use Ophelix\Exception\InvalidRequestException;

try {
    $ophelix->claims->retrieve('clm_inconnu');
} catch (InvalidRequestException $exception) {
    $exception->getErrorCode();   // resource_missing
    $exception->getDocUrl();      // https://docs.ophelix.fr/erreurs#resource_missing
    $exception->getRequestId();   // req_…
}

Webhooks

Vérifiez chaque livraison sur le corps brut, avant tout décodage :

use Ophelix\Exception\SignatureVerificationException;
use Ophelix\Webhook;

try {
    $event = Webhook::constructEvent(
        file_get_contents('php://input'),
        $_SERVER['HTTP_OPHELIX_SIGNATURE'] ?? null,
        getenv('OPHELIX_WEBHOOK_SECRET'),
    );
} catch (SignatureVerificationException) {
    http_response_code(400);
    exit;
}

if ($event->type === 'claim.paid') {
    $claim = $event->data['object'];   // un Ophelix\Resources\Claim
}

Une livraison signée il y a plus de cinq minutes est refusée. Webhook::generateTestHeader() signe un corps pour tester votre point de terminaison.

Versions

La bibliothèque suit le versionnage sémantique. Chaque version épingle une version datée de l'API (OphelixClient::API_VERSION) : une réponse n'y perd ni ne renomme jamais un champ. Voir CHANGELOG.md.

Licence

MIT. Voir LICENSE.