1. Go to this page and download the library: Download pimia/pimia-php library. Choose the download type require.
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
pimia / pimia-php example snippets
use GuzzleHttp\Client;
use GuzzleHttp\Psr7\HttpFactory;
use Pimia\{Config, PimiaClient, Scopes};
use Pimia\Http\PsrTransport;
use Pimia\OAuth\{InMemoryTokenStore, OAuthClient, PkceChallenge};
$config = new Config(
baseUrl: 'https://acme.pimia.es',
clientId: getenv('PIMIA_CLIENT_ID'),
clientSecret: getenv('PIMIA_CLIENT_SECRET') ?: null,
redirectUri: 'https://miapp.example/callback',
);
$factory = new HttpFactory();
$transport = new PsrTransport(new Client(), $factory, $factory);
// 1. Autorización
$pkce = PkceChallenge::create(); // guarda $pkce->verifier en sesión
$oauth = new OAuthClient($config, $transport);
$url = $oauth->authorizeUrl([Scopes::INVOICES_READ], PkceChallenge::state(), $pkce);
// 2. Callback: canje + persistencia
$tokens = new InMemoryTokenStore(); // en producción: tu BD
$tokens->save($oauth->exchangeCode($code, PkceChallenge::fromVerifier($verifierDeSesion)));
// 3. Uso
$pimia = new PimiaClient($config, $transport, $tokens);
$invoices = $pimia->invoices->list(['page' => 1]);
$pimia = PimiaClient::withBorrowedToken(
baseUrl: "https://{$tenant}.pimia.es",
accessToken: $bearerDeQuienLlama,
transport: $transport,
// La empresa activa viaja en cabecera, como en todo el API. OMÍTELA cuando
// no la sepas: `company:` vacía es una cabecera presente que no casa con
// ninguna empresa.
headers: $empresa === null ? [] : ['company' => (string) $empresa],
// Atiendes una petición web: los reintentos del SDK DUERMEN, y dormir
// dentro de la petición de un usuario es una petición colgada.
maxRateLimitRetries: 0,
);
$empresa = $pimia->bootstrap->currentCompanyId();
$censo = $pimia->crm->assignableUsers();
$r = $client->requestWithMeta('POST', '/estimates', body: $presupuesto, idempotencyKey: $clave);
if ($r->meta->idempotentReplay) {
// ya existía: no se ha creado nada nuevo
}
use Pimia\Exception\WebhookVerificationException;
use Pimia\Webhooks\WebhookEvent;
use Pimia\Webhooks\WebhookVerifier;
$verifier = new WebhookVerifier(getenv('PIMIA_WEBHOOK_SECRET'));
try {
// ⚠️ El cuerpo CRUDO. En Laravel, $request->getContent() — nunca
// json_encode($request->all()): Pimia firma los bytes que envía y
// reserializar rompe la firma sin que se vea por qué.
$hook = $verifier->verify($request->headers->all(), $request->getContent());
} catch (WebhookVerificationException $e) {
return response($e->reason, 400);
}
// Pimia reintenta: la misma entrega llega con el mismo id.
if ($yaProcesado($hook->delivery)) {
return response('', 200);
}
match ($hook->event) {
WebhookEvent::EstimateAccepted => $facturar($hook->payload['id']),
WebhookEvent::InvoicePaid => $cobrar($hook->payload['id']),
default => null, // incluye el catálogo futuro
};
return response('', 200); // responde rápido; el trabajo pesado, a una cola
use Pimia\OwnerConfirmationRequired;
$result = $pimia->put('/users/42', ['role' => 'admin']);
$pending = OwnerConfirmationRequired::fromResponse($result);
if ($pending !== null) {
mostrarPendiente($pending->message); // $pending->id identifica la solicitud.
} else {
mostrarUsuarioActualizado($result);
}
// Cuotas: es el ÚNICO modo que crea o adopta recurrente al activar.
$client->contracts->create([
'title' => 'Mantenimiento', 'customer_id' => 5, 'starts_at' => '2026-10-01',
'billing_mode' => 'INSTALLMENTS', 'amount' => 12000, 'billing_every' => 'MONTHLY',
]);
// Hitos: total opcional, guía ordenada en céntimos, proyecto y clausulado.
$client->contracts->create([
'title' => 'Reforma', 'customer_id' => 5, 'starts_at' => '2026-10-01',
'billing_mode' => 'MILESTONES', 'total_amount' => 450000,
'project_id' => 11, 'contract_model_version_id' => 9,
'milestones' => [
['description' => 'Fase 1', 'amount' => 150000, 'planned_date' => '2026-11-01', 'position' => 1],
['description' => 'Fase 2', 'amount' => 300000, 'planned_date' => null, 'position' => 2],
],
]);
$diccionario = $client->contracts->models->variables('MILESTONES');
// $diccionario['meta']['limits'] y ['block_types'] vienen del servidor.
$modelo = $client->contracts->models->create([
'name' => 'Mantenimiento',
'draft_revision' => 0,
'content' => [
['type' => 'heading', 'level' => 2, 'text' => [['type' => 'text', 'value' => 'Objeto', 'bold' => true]]],
['type' => 'paragraph', 'text' => [['type' => 'variable', 'key' => 'customer.name']]],
['type' => 'table', 'variable' => 'contract.milestones'],
['type' => 'signature'], // dónde firma el cliente: uno, ni cero ni dos
],
]);
$client->contracts->models->publish($modelo['data']['id']); // versión INMUTABLE