SDK de PHP
constaia/constaia-php, cliente oficial para PHP 8.1+ con integración para Laravel. Análisis, lotes, webhooks, excepciones tipadas y reintentos.
constaia/constaia-php es el cliente oficial de Constaia para PHP. Solo necesita las extensiones curl y json, e incluye un ServiceProvider y una facade para Laravel.
composer require constaia/constaia-phpRequisitos: PHP 8.1 o superior, ext-curl, ext-json. Recomendado: ext-fileinfo para detectar mejor el tipo MIME de los ficheros.
Configuración
$constaia = new \Constaia\Client(); // lee CONSTAIA_API_KEY del entorno
// o con opciones explícitas
$constaia = new \Constaia\Client(getenv('CONSTAIA_API_KEY'), [
'timeout' => 60, // segundos por intento (por defecto 60)
'max_retries' => 2, // reintentos en 429, 5xx y errores de red (por defecto 2)
]);| Opción | Por defecto | Descripción |
|---|---|---|
base_url | https://api.constaia.com | URL base (o CONSTAIA_BASE_URL). |
timeout | 60 | Segundos por intento. |
max_retries | 2 | Reintentos automáticos. |
headers | [] | Cabeceras que se añaden a todas las peticiones. |
La clave es secreta: úsala solo en el servidor. Nunca la pongas en JavaScript, en HTML ni en una app móvil.
Analizar un documento
$analysis = $constaia->analyze('dni_valid.jpg', [
'expect' => 'es_dni',
'checks' => [
'not_expired' => true,
'holder' => ['full_name' => 'María García López'],
],
'storage' => 'none',
'language' => 'es',
]);
$analysis->verdictStatus(); // "valid" | "invalid" | "review" | null
$analysis->isValid(); // true
$analysis->isInvalid(); // false
$analysis->needsReview(); // false
$analysis->field('document_number'); // "12345678Z"
$analysis->warnings; // []Las opciones van en snake_case, igual que en la API. Lista completa en Analizar un documento.
Entradas admitidas
| Entrada | Ejemplo |
|---|---|
| Ruta local | 'dni.jpg' o '/var/uploads/dni.pdf' |
| URL http(s) | 'https://example.com/dni.jpg' (se envía como file_url) |
| Stream | fopen('dni.jpg', 'rb') |
SplFileInfo | incluye el UploadedFile de Laravel y Symfony (se conserva el nombre original) |
| Base64 | ['base64' => $b64, 'filename' => 'dni.jpg'] |
| URL explícita | ['file_url' => 'https://…'] |
Si la entrada no trae nombre útil (por ejemplo un stream de memoria), pasa 'filename' => 'dni.jpg' en las opciones.
Leer la respuesta
Las respuestas son objetos ConstaiaObject: puedes leerlas como propiedades o como array, y convertirlas.
$analysis->document->type; // "es_dni"
$analysis['verdict']['reasons']; // lista de motivos
$analysis->toArray(); // array PHP
$analysis->toJson(); // JSON
$constaia->lastResponse->requestId; // req_… de la última peticiónClasificar
$result = $constaia->classify('passport.jpg', ['expect' => ['es_dni', 'passport']]);
$result->document->type; // "passport"
$result->candidates; // [{ type, confidence }, …]
$result->verdict->status; // solo si pasas expectAnálisis guardados
$analysis = $constaia->analyses->get('an_01J…');
// Una página
$page = $constaia->analyses->list(['limit' => 20, 'status' => 'completed', 'type' => 'es_dni']);
foreach ($page as $item) { /* … */ }
$page->hasMore();
// Todas las páginas
foreach ($constaia->analyses->list(['metadata' => ['registration_id' => '123']])->autoPagingIterator() as $item) {
echo $item->id, PHP_EOL;
}
$constaia->analyses->delete('an_01J…');
$bytes = $constaia->analyses->export('an_01J…', 'csv'); // devuelve los bytes
$constaia->analyses->export('an_01J…', 'xlsx', storage_path('a.xlsx')); // o guarda en discoLotes
$batch = $constaia->batches->create([
'files' => ['dni_valid.jpg', 'nie.jpg'], // rutas, streams o UploadedFile
'options' => ['expect' => ['es_dni', 'es_nie'], 'export' => ['xlsx']],
]);
// o con URLs
$batch = $constaia->batches->create([
'items' => [['file_url' => 'https://example.com/1.jpg', 'options' => ['expect' => 'es_dni']]],
]);
$constaia->batches->get($batch->id);Ver Lotes.
Catálogo, saldo y uso
$types = $constaia->documentTypes->list();
$dni = $constaia->documentTypes->get('es_dni');
$balance = $constaia->balance(); // credits_available, credits_reserved, …
$usage = $constaia->usage(['from' => '2026-09-01', 'to' => '2026-09-30']);Webhooks
$endpoint = $constaia->webhookEndpoints->create([
'url' => 'https://tuapp.example/webhooks/constaia',
'events' => ['analysis.completed', 'analysis.failed'],
]);
$endpoint->secret; // whsec_… (solo en la creación)
// En tu handler: cuerpo crudo + cabeceras + secreto
$event = \Constaia\Webhook::verify(file_get_contents('php://input'), getallheaders(), getenv('CONSTAIA_WEBHOOK_SECRET'));Webhook::verify comprueba la firma Standard Webhooks con una tolerancia de 5 minutos y devuelve el evento como array. Si falla, lanza SignatureVerificationException. La versión manual con hash_hmac está en Webhooks.
Opciones por petición
Cualquier método acepta estas opciones, que no se envían como parámetros de la API:
$constaia->analyze($path, [
'expect' => 'es_dni',
'idempotency_key' => 'registration-123-dni',
'timeout' => 90,
'max_retries' => 0,
]);
$constaia->analyses->get('an_01J…', ['timeout' => 10]);En cada POST el SDK envía una Idempotency-Key (la tuya o una generada) y la reutiliza en los reintentos. Ver Idempotencia.
Excepciones
Todas heredan de Constaia\Exception\ConstaiaException y ofrecen getType(), getErrorCode(), getParam(), getRequestId() y getHttpStatus().
Clase (Constaia\Exception\…) | Cuándo |
|---|---|
InvalidRequestException | 400/422: parámetros incorrectos, fichero no admitido o no encontrado… |
AuthenticationException | 401 o falta la clave. |
PermissionException | 403. |
NotFoundException | 404. |
InsufficientCreditsException | 402: no queda saldo. |
RateLimitException | 429 tras agotar reintentos; getRetryAfter() en segundos. |
ApiException | 5xx. |
ConnectionException | Error de red o timeout. |
SignatureVerificationException | Firma de webhook no válida. |
use Constaia\Exception\InsufficientCreditsException;
use Constaia\Exception\InvalidRequestException;
try {
$analysis = $constaia->analyze($path, ['expect' => 'es_dni']);
} catch (InsufficientCreditsException $e) {
// avisa al administrador
} catch (InvalidRequestException $e) {
error_log($e->getErrorCode() . ' ' . $e->getRequestId());
}El SDK reintenta automáticamente las respuestas 429 y 5xx y los errores de red, con espera exponencial y respetando Retry-After (hasta 60 s).
Laravel
El paquete se registra solo gracias al autodescubrimiento de Laravel: añade un singleton Constaia\Client y la facade Constaia.
CONSTAIA_API_KEY=ck_test_…
CONSTAIA_WEBHOOK_SECRET=whsec_…
# opcionales
CONSTAIA_TIMEOUT=60
CONSTAIA_MAX_RETRIES=2Si quieres el fichero de configuración en tu proyecto:
php artisan vendor:publish --tag=constaia-configValidar un documento subido
namespace App\Http\Controllers;
use Constaia;
use Illuminate\Http\Request;
class RegistrationDocumentController
{
public function store(Request $request)
{
$request->validate([
'dni' => ['required', 'file', 'mimes:jpg,jpeg,png,webp,pdf', 'max:20480'],
]);
$analysis = Constaia::analyze($request->file('dni'), [
'expect' => ['es_dni', 'es_nie'],
'checks' => [
'not_expired' => true,
'holder' => ['full_name' => $request->user()->name],
],
'metadata' => ['user_id' => (string) $request->user()->id],
]);
return match ($analysis->verdictStatus()) {
'valid' => back()->with('status', 'Documento verificado.'),
'invalid' => back()->withErrors(['dni' => $analysis->verdict->reasons[0]->message ?? 'Documento no válido.']),
default => back()->with('status', 'Lo revisaremos manualmente.'),
};
}
}Puedes pasar el UploadedFile directamente (conserva el nombre original) o su ruta con getRealPath(). Si prefieres inyección de dependencias, pide Constaia\Client $constaia en el constructor o en el método.
Para webhooks en Laravel (ruta sin CSRF, cuerpo crudo con $request->getContent() e idempotencia con Cache::add), mira el ejemplo completo en Webhooks y la guía de Laravel.
SDK de JavaScript y TypeScript
@constaia/sdk: cliente oficial para Node.js 18+, Bun y Deno, sin dependencias. Análisis, lotes, webhooks, errores tipados y reintentos.
Python
El SDK oficial de Python está en preparación. Mientras tanto, usa la API REST con httpx; aquí tienes un ejemplo completo de análisis y webhooks.