Search by

dbout / dendreo-sdk-php

dimitriBouteille

PHP SDK for the Dendreo API v2 (training management software), generated from the official OpenAPI specification.

v2.0.0-alpha.1 2026-11-10 19:54 UTC

README

Logo Dendreo

Dendreo SDK for PHP

Latest Version Total Downloads Tests status

Click here to read the Dendreo API v2 documentation

Important

Version 2 targets the Dendreo API v2 and is not compatible with version 1.x, see the upgrade guide.

Version 2 is a pre-release (2.0.0-alpha): the Dendreo API v2 is still being published, and class names may change until the stable release.

Warning

Some resources of the API v1 are not available in the API v2 yet: inscriptions (laps), modules, contacts, créneaux, formateurs... Dendreo publishes them progressively, starting with the modules.

If you need them, stay on version 1.x, which targets the API v1: Dendreo keeps maintaining it, with no end-of-life date yet. Both API versions read and write the same data with the same identifiers, but both versions of this SDK cannot be installed in the same project.

The Dendreo SDK for PHP makes it easy for developers to access the Dendreo API in their PHP code.

The SDK is generated from the official OpenAPI specification of the Dendreo API, so it follows the API closely. Dendreo is developed by a French company, so most of the code (models, properties...) is in French, to stay consistent with the API.

Please note that this SDK is developed by a developer who does not work at Dendreo. If you have any questions directly related to Dendreo, please contact support: https://www.dendreo.com/contact.

Resources

Supported API

Every resource of the API v2 is supported. Each resource has its own service, in the Dbout\DendreoSdk\Api namespace:

Resource Endpoint Service Methods
Actions commerciales /v2/actions-commerciales ActionsCommercialesApi index, show
Actions de formation /v2/actions-de-formation ActionsDeFormationApi index, show, store, update, destroy, restore
Administrateurs /v2/administrateurs AdministrateursApi index, show, store, update, destroy, restore
Budgets /v2/budgets BudgetsApi index, show, store, update, destroy
Catalogue public /v2/catalogue-prochaines-sessions CatalogueProchainesSessionsApi index
Catégories de module /v2/module-categories ModuleCategoriesApi index, show, store, update, destroy, restore
Centres de formation /v2/centres-de-formation CentresDeFormationApi index, show
Entreprises /v2/entreprises EntreprisesApi index, show
Étapes ADF /v2/adf-etapes AdfEtapesApi index, show, store, update, destroy
Étapes d'opportunité /v2/opportunite-etapes OpportuniteEtapesApi index, show, store, update, destroy, restore
Financeurs /v2/financeurs FinanceursApi index, show, update
Participants /v2/participants ParticipantsApi index, show, store, update, destroy, restore, taches
Salles de formation /v2/salles-de-formation SallesDeFormationApi index, show, store, update, destroy, restore
Sessions permanentes /v2/sessions-permanentes SessionsPermanentesApi index, show, store, update, destroy, restore
Sources /v2/sources SourcesApi index, show, store, update, destroy
Tâches /v2/taches TachesApi index
Types de produit /v2/produit-types ProduitTypesApi index, show, store, update, destroy, restore

If a resource you need is missing, it is probably not available in the API v2 yet: ask Dendreo, it will be added to the SDK as soon as it is published.

Installation

Requirements

  • An API key
  • Your account identifier: what follows pro.dendreo.com/ in the address of your Dendreo space
  • PHP 8.2 or later, with the json extension

Installation

You can use Composer. Follow the installation instructions if you do not already have composer installed.

composer require dbout/dendreo-sdk-php:^2.0@alpha

For the API v1, install version 1.x: composer require dbout/dendreo-sdk-php:^1.0.

In your PHP script, make sure you include the autoloader:

require __DIR__ . '/vendor/autoload.php';

Using the library

Client

Create a Client once, with your credentials. It is then given to every service:

use Dbout\DendreoSdk\Client;
use Dbout\DendreoSdk\Config;

$client = new Client(
    (new Config())
        ->setApiKey('the-api-key')     // sent as `Authorization: Bearer the-api-key`
        ->setUsername('my-account')    // sent as the `of` header
);

Config also accepts:

Method Default Description
setTimeout(float) 30 Request timeout, in seconds
setProxy(?string) null Proxy, e.g. http://my-proxy:3128
setHost(string) https://api.dendreo.com API host

The HTTP requests are sent with Guzzle. You can give your own Guzzle client (middlewares, retries, logs...) as the second argument of the Client; the timeout and proxy options of Config then have to be set on your client.

$client = new Client($config, new \GuzzleHttp\Client(['timeout' => 10]));

Services

All services work the same way:

use Dbout\DendreoSdk\Api\ParticipantsApi;

$participants = new ParticipantsApi($client);

List

index() returns one page of results. Filters are set on a filter object (ParticipantFilter, EntrepriseFilter...), include loads related resources, sort sorts the list (prefix a field by - for a descending order):

use Dbout\DendreoSdk\Model\ParticipantFilter;

$filter = (new ParticipantFilter())
    ->setNom('Dupont')
    ->setId([12, 15])                       // several values
    ->setCreatedAt('>=2026-01-01');         // date filters accept an operator: >=, <=, >, <, =, <>

$result = $participants->index(
    filter: $filter,
    include: ['entreprise', 'centres'],
    sort: ['-created_at'],
    page: 1,
    per_page: 50,                           // 15 by default, 100 at most
);

foreach ($result->getData() as $participant) {
    echo $participant->getPrenom() . ' ' . $participant->getNom();
}

The available filters, include and sort values of each resource are listed in the API documentation. A value that is not allowed throws a BadRequestException: this is the case of most include values of the API v1 (modules, participants, formateurs...), the error message gives the endpoint that replaces them.

The relations loaded with include are typed in the models, for example $participant->getEntreprise() with include: ['entreprise']. Without the include, they are null.

To go through every page, follow links.next until it is null:

$page = 1;
do {
    $result = $participants->index(filter: $filter, page: $page++, per_page: 100);
    foreach ($result->getData() as $participant) {
        // ...
    }
} while ($result->getLinks()->getNext() !== null);

Retrieve

$participant = $participants->show(42, include: ['entreprise'])->getData();

Create

use Dbout\DendreoSdk\Model\ParticipantsStoreRequest;

$request = (new ParticipantsStoreRequest())
    ->setIdEntreprise('7')
    ->setNom('Dupont')
    ->setPrenom('Marie')
    ->setStatutBpf(ParticipantsStoreRequest::STATUT_BPF_SALARIE)
    ->setEmail('marie.dupont@example.com');

$participant = $participants->store($request)->getData();

The request is validated before being sent: a missing required field throws an InvalidArgumentException listing the invalid properties.

Update, delete, restore

use Dbout\DendreoSdk\Model\ParticipantsUpdateRequest;

$participants->update(42, (new ParticipantsUpdateRequest())->setPortable('0601020304'));
$participants->destroy(42);
$participants->restore(42);

Dates

Dates are returned as \DateTime objects. The API sends date-times without timezone (2026-01-31 09:00:00), in Paris time (Europe/Paris): the SDK creates them in this timezone, whatever the default timezone of PHP. The \DateTime values sent to the API are converted to Paris time.

The dates entered in Dendreo (start and end of a training session...) are the local time of the training centre, as entered: for a centre outside the Paris timezone, use the wall-clock value (->format('Y-m-d H:i:s')) and ignore the timezone. Date filters expect their values in the timezone of the filtered field. See Dates et fuseau horaire in the API documentation.

Additional fields

The additional fields of your account are returned under their own name, but they are not part of the models. Read them with the array syntax:

$participant = $participants->show(42)->getData();
$value = $participant['my_additional_field'] ?? null;

Errors

Every error throws an exception extending Dbout\DendreoSdk\ApiException, with the message returned by Dendreo:

HTTP status Exception
No response Dbout\DendreoSdk\Exception\ConnectionException
400 Dbout\DendreoSdk\Exception\BadRequestException
401 Dbout\DendreoSdk\Exception\AuthenticationException
403 Dbout\DendreoSdk\Exception\ForbiddenException
404 Dbout\DendreoSdk\Exception\NotFoundException
409 Dbout\DendreoSdk\Exception\ConflictException
422 Dbout\DendreoSdk\Exception\ValidationException
429 Dbout\DendreoSdk\Exception\RateLimitException
5xx Dbout\DendreoSdk\Exception\ServerException
use Dbout\DendreoSdk\ApiException;
use Dbout\DendreoSdk\Exception\NotFoundException;
use Dbout\DendreoSdk\Exception\RateLimitException;
use Dbout\DendreoSdk\Exception\ValidationException;

try {
    $participants->store($request);
} catch (ValidationException $e) {
    $e->getErrors();            // ['email' => ['Cet email est déjà utilisé.']]
} catch (NotFoundException $e) {
    // ...
} catch (RateLimitException $e) {
    $e->getRetryAfter();        // seconds to wait, when the API sends the `Retry-After` header
} catch (ApiException $e) {
    $e->getCode();              // HTTP status
    $e->getResponseBody();
}

The API allows 100 requests per 10 seconds and 100,000 requests per day (the monthly limit depends on your subscription), see the rate limits.

Extending a service

Services can be extended, for example to add your own shortcuts:

use Dbout\DendreoSdk\Api\ParticipantsApi;
use Dbout\DendreoSdk\Model\ParticipantFilter;

class MyParticipantsApi extends ParticipantsApi
{
    public function findByEmail(string $email): array
    {
        return $this->index(filter: (new ParticipantFilter())->setEmail($email))->getData();
    }
}

$participants = new MyParticipantsApi($client);

Upgrading from 1.x

See the upgrade guide.

Getting help/support

This SDK is developed by a developer who does not work at Dendreo. Thus:

Contributing

💕 🦄 We encourage you to contribute to this repository, so everyone can benefit from new features, bug fixes, and any other improvements. Have a look at our contributing guidelines to find out how to raise a pull request.

Licence

Licensed under the MIT license, see LICENSE.