Métodos de la API
Documentación de la Partner API
Esta referencia describe cómo su integración se comunica con Animal-ID en nombre de su organización: autenticación, encabezados obligatorios y los endpoints principales del MVP (propietarios, animales, procedimientos, fotos, diccionarios).
SDK y bibliotecas cliente
SDK oficiales de código abierto que encapsulan la firma de solicitudes y los endpoints de abajo — úsalos en lugar de firmar las solicitudes a mano.
PHP · Composer
SDK de PHP del lado servidor: firma HMAC de solicitudes y clientes tipados para cada endpoint.
composer require animal-id/aid-partner-sdk
JavaScript · npm
Paquetes de frameworks para Node y el navegador, sobre un núcleo común.
npm i @animal-id/partner-core
- @animal-id/partner-coreNúcleo independiente del framework: firma + cliente tipado.
- @animal-id/partner-reactHooks y utilidades de React.
- @animal-id/partner-vueComposables de Vue.
- @animal-id/partner-angularServicios de Angular.
- @animal-id/partner-nestjsMódulo de NestJS para integraciones del lado del servidor.
Autenticación y firma de la solicitud
URL base: https://gw-dev.animal-id.net · todas las rutas llevan el prefijo /v1/partner.
Cada solicitud firmada lleva cuatro encabezados. La firma es un HMAC-SHA256 (hex) de una cadena canónica, con clave de tu clave privada:
stringToSign = METHOD + "\n" + path[?query] + "\n" + sha256_hex(rawBody) + "\n" + timestamp signature = hex( hmac_sha256(stringToSign, privateKey) )
| Encabezado | Valor |
|---|---|
X-Eternity-App-Id | El id de tu aplicación. |
X-Eternity-Public-Key | Tu clave pública. |
X-Eternity-Timestamp | Segundos Unix; debe estar dentro de ±300s respecto a la hora del servidor. |
X-Eternity-Signature | El hex HMAC-SHA256 calculado arriba. |
X-Eternity-Idempotency-Key | UUID, obligatorio en cada POST/PATCH/DELETE. Las repeticiones devuelven la primera respuesta; misma clave + cuerpo distinto → 409. |
X-Eternity-Animal-ID-Version | Versión de fecha opcional (YYYY-MM-DD). Por defecto, la versión fijada cuando se emitió tu aplicación; a partir de 2026-07-04, el registro de animales adjunta propietarios existentes por public_id en lugar de user_gid. |
X-Eternity-Expand | Opcional. Array JSON de claves de expansión para incrustar datos adicionales en los endpoints compatibles (p. ej. ["owners"]). Consulta la sección «Expansión» de un endpoint para ver sus claves permitidas; las claves desconocidas → 422. |
X-Eternity-Lang-Code | Opcional. Código de idioma (uk, en, ru, de, es) para los nombres que devuelve la API — por ejemplo species_name y breed_name en la ficha del animal, y las etiquetas de los diccionarios. Si se omite, se usa el idioma predeterminado de la región. |
Firma y envía los mismos bytes exactos del cuerpo. Para GET/DELETE el cuerpo está vacío (su sha256 es el hash de una cadena vacía). path incluye la cadena de consulta cuando está presente. Para las cargas multipart/form-data (fotos), el cuerpo en bruto tampoco forma parte de la firma: firma con el sha256 de un cuerpo vacío.
Cada respuesta exitosa envuelve los resultados en un array payload. Los endpoints de creación/obtención de un solo recurso devuelven un array de un elemento (p. ej. { "payload": [ { … } ] }); los ejemplos por endpoint que aparecen abajo muestran el objeto único por brevedad.
APP_ID="aid_app_xxx"; PUBLIC_KEY="pk_xxx"; PRIVATE_KEY="sk_xxx"
METHOD="POST"
PATH_Q="/v1/partner/owners" # path (+ "?query" if any), exactly as sent
BODY='{"email":"jane@example.com","consent":{"account_creation":true}}'
TS=$(date +%s)
BODY_HASH=$(printf '%s' "$BODY" | openssl dgst -sha256 | awk '{print $2}')
STRING_TO_SIGN=$(printf '%s\n%s\n%s\n%s' "$METHOD" "$PATH_Q" "$BODY_HASH" "$TS")
SIG=$(printf '%s' "$STRING_TO_SIGN" | openssl dgst -sha256 -hmac "$PRIVATE_KEY" | awk '{print $2}')
curl -X "$METHOD" "https://gw.animal-id.net$PATH_Q" \
-H "X-Eternity-App-Id: $APP_ID" \
-H "X-Eternity-Public-Key: $PUBLIC_KEY" \
-H "X-Eternity-Timestamp: $TS" \
-H "X-Eternity-Signature: $SIG" \
-H "X-Eternity-Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d "$BODY"const crypto = require('crypto');
function sign({ method, pathQ, body = '', privateKey }) {
const ts = Math.floor(Date.now() / 1000).toString();
const bodyHash = crypto.createHash('sha256').update(body).digest('hex');
const stringToSign = [method, pathQ, bodyHash, ts].join('\n');
const signature = crypto.createHmac('sha256', privateKey).update(stringToSign).digest('hex');
return { ts, signature };
}
const body = JSON.stringify({ email: 'jane@example.com' });
const { ts, signature } = sign({ method: 'POST', pathQ: '/v1/partner/owners', body, privateKey: 'sk_xxx' });
await fetch('https://gw.animal-id.net/v1/partner/owners', {
method: 'POST',
headers: {
'X-Eternity-App-Id': 'aid_app_xxx',
'X-Eternity-Public-Key': 'pk_xxx',
'X-Eternity-Timestamp': ts,
'X-Eternity-Signature': signature,
'X-Eternity-Idempotency-Key': crypto.randomUUID(),
'Content-Type': 'application/json',
},
body, // sign and send the SAME bytes
});import hashlib, hmac, time, json, uuid, requests
def sign(method, path_q, body, private_key):
ts = str(int(time.time()))
body_hash = hashlib.sha256(body.encode()).hexdigest()
string_to_sign = "\n".join([method, path_q, body_hash, ts])
signature = hmac.new(private_key.encode(), string_to_sign.encode(), hashlib.sha256).hexdigest()
return ts, signature
body = json.dumps({"email": "jane@example.com"}, separators=(",", ":"))
ts, signature = sign("POST", "/v1/partner/owners", body, "sk_xxx")
requests.post(
"https://gw.animal-id.net/v1/partner/owners",
data=body, # send the SAME bytes you signed
headers={
"X-Eternity-App-Id": "aid_app_xxx",
"X-Eternity-Public-Key": "pk_xxx",
"X-Eternity-Timestamp": ts,
"X-Eternity-Signature": signature,
"X-Eternity-Idempotency-Key": str(uuid.uuid4()),
"Content-Type": "application/json",
},
)<?php
function signRequest(string $method, string $pathQ, string $body, string $privateKey): array {
$ts = (string) time();
$bodyHash = hash('sha256', $body);
$stringToSign = implode("\n", [$method, $pathQ, $bodyHash, $ts]);
$signature = hash_hmac('sha256', $stringToSign, $privateKey);
return [$ts, $signature];
}
$body = json_encode(['email' => 'jane@example.com']);
[$ts, $signature] = signRequest('POST', '/v1/partner/owners', $body, 'sk_xxx');
$ch = curl_init('https://gw.animal-id.net/v1/partner/owners');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $body, // send the SAME bytes you signed
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"X-Eternity-App-Id: aid_app_xxx",
"X-Eternity-Public-Key: pk_xxx",
"X-Eternity-Timestamp: $ts",
"X-Eternity-Signature: $signature",
'X-Eternity-Idempotency-Key: ' . bin2hex(random_bytes(16)),
'Content-Type: application/json',
],
]);
$response = curl_exec($ch);Webhooks
Reciba eventos diferidos — como cuando un propietario aprueba la solicitud de acceso de un veterinario — como solicitudes POST firmadas a su servidor. Configure la URL y encuentre su secreto de firma en la pestaña de claves de API.
Entrega de webhook firmadaFirma y datos del webhook▸Enviamos un POST por cada evento a la URL de webhook que configure, firmado con el secreto de webhook propio de su aplicación (se muestra una sola vez al generarlo). Verifique la firma antes de confiar en una entrega recalculando el HMAC sobre la cadena canónica y comparando en tiempo constante:
canonical = "POST" + "\n" + path[?query] + "\n" + sha256_hex(rawBody) + "\n" + timestamp signature = hex( hmac_sha256(canonical, webhookSecret) )
| Encabezado | Valor |
|---|---|
X-Eternity-Webhook-Id | Identificador único de entrega (UUID); estable entre reenvíos del mismo evento. |
X-Eternity-Webhook-Event | La clave del evento, p. ej. animal_access.approved. |
X-Eternity-Webhook-Timestamp | Segundos Unix en que se firmó la entrega; rechace las entregas con una marca de tiempo desfasada. |
X-Eternity-Webhook-Signature | HMAC-SHA256 (hex) de la cadena canónica, con su secreto de webhook como clave (no su clave privada de API). |
Cuerpo de la entrega (JSON)
{
"id": "5f1c0b8e-3a2d-4c7b-9b1a-2e6f0d4c8a91",
"event": "animal_access.approved",
"occurred_at": "2026-06-24T09:15:00+00:00",
"result": {
"animal_id": "8xK3pQzVnB7rL2qF",
"requester_user_gid": 90231,
"status": "granted",
"requested_at": "2026-06-23T09:00:00+00:00",
"expires_at": "2026-06-30T09:00:00+00:00",
"retry_after_seconds": 0,
"decided_at": "2026-06-24T09:15:00+00:00"
}
}| Campo | Descripción |
|---|---|
id | El identificador único del evento (coincide con el encabezado X-Eternity-Webhook-Id). |
event | La clave del evento, p. ej. animal_access.approved. |
occurred_at | Cuándo ocurrió el evento (ISO 8601). |
result | La decisión de acceso. Refleja GET /v1/partner/animals/{id}/access-request y añade animal_id, requester_user_gid y decided_at. |
Eventos
| Clave | Significado |
|---|---|
animal_access.approved | Un propietario aprobó su solicitud de acceso pendiente: ya puede editar el animal. |
animal_access.denied | Un propietario rechazó su solicitud de acceso: puede volver a solicitarla cuando caduque. |
consent.approved | La persona a la que preguntó lo permitió: puede usar el permiso hasta que venza. |
consent.denied | La persona a la que preguntó lo rechazó. No se concedió nada. |
consent.revoked | Se revocó un permiso que le habían concedido. Si era una clave entregada, deja de funcionar de inmediato. |
consent.expired | Nadie respondió a tiempo y la solicitud caducó. No es una negativa: puede volver a pedirlo. |
Cuerpo del evento de consentimiento
Los eventos de consentimiento se entregan a su aplicación de plataforma, no a una organización: cuando un médico le permite tener credenciales que actúan en su nombre, no interviene ninguna clínica.
{
"id": "282824f1-b65e-40f4-86d1-62a2bac566df",
"event": "consent.revoked",
"occurred_at": "2026-08-26T19:45:00+00:00",
"result": {
"consent_id": "qeHSuvlSZHAWpacF",
"kind": "key_handover",
"status": "revoked",
"doctor_id": "c71ORqKq81fRoTcm",
"clinic_id": null,
"decided_at": "2026-08-26T19:45:00+00:00"
}
}| Campo | Descripción |
|---|---|
consent_id | La solicitud a la que pertenece este resultado: el mismo identificador que devolvió la llamada de aprovisionamiento. |
kind | key_handover (credenciales que actúan como un médico) o clinic_membership (incorporar un médico a una clínica). |
status | approved, denied, revoked o expired. |
doctor_id | El identificador público del médico, para una entrega de clave. Null en los demás casos, y null si la cuenta se eliminó después. |
clinic_id | El identificador público de la clínica, para una pertenencia a clínica. Null en los demás casos. |
decided_at | Cuándo alcanzó este estado (ISO 8601). Para una caducidad es la fecha límite, no el momento en que lo detectamos. |
Gestione consent.revoked. Un permiso puede retirarse en cualquier momento, y una clave entregada deja de funcionar en ese mismo instante: sin este evento solo lo sabría cuando falle su siguiente llamada.
Confirme con cualquier respuesta 2xx. Un estado distinto de 2xx o un tiempo de espera agotado se registra como una entrega fallida, que puede reenviar desde el registro de entregas de webhook en su panel.
const crypto = require('crypto');
// Express: mount with a raw-body parser so you verify the EXACT bytes received.
// app.post('/animal-id/webhook', express.raw({ type: 'application/json' }), handler)
function verify(req, webhookSecret) {
const ts = req.header('X-Eternity-Webhook-Timestamp');
const sig = req.header('X-Eternity-Webhook-Signature');
const path = req.originalUrl; // path (+ ?query) exactly as received
const raw = req.body; // Buffer of the raw request body
const bodyHash = crypto.createHash('sha256').update(raw).digest('hex');
const canonical = ['POST', path, bodyHash, ts].join('\n');
const expected = crypto.createHmac('sha256', webhookSecret).update(canonical).digest('hex');
return sig && crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected));
}<?php
// Verify a webhook delivery from Animal ID before trusting it.
function verifyWebhook(string $rawBody, string $path, string $webhookSecret): bool {
$ts = $_SERVER['HTTP_X_ETERNITY_WEBHOOK_TIMESTAMP'] ?? '';
$sig = $_SERVER['HTTP_X_ETERNITY_WEBHOOK_SIGNATURE'] ?? '';
$canonical = implode("\n", ['POST', $path, hash('sha256', $rawBody), $ts]);
$expected = hash_hmac('sha256', $canonical, $webhookSecret);
return $sig !== '' && hash_equals($expected, $sig);
}
$rawBody = file_get_contents('php://input'); // verify the EXACT bytes received
if (!verifyWebhook($rawBody, $_SERVER['REQUEST_URI'], getenv('AID_WEBHOOK_SECRET'))) {
http_response_code(401);
exit;
}
$event = json_decode($rawBody, true); // ['id' => …, 'event' => …, 'result' => …]
http_response_code(204); // acknowledge with any 2xxMétodos de la API
Empiece a escribir — las secciones se filtran por palabra clave.
Platform API — aprovisionamiento
Crear clínicas y médicos, y pedir a las personas un permiso que no se puede tomar por cuenta propia. Aquí empieza una integración: primero crea las cuentas y luego recoge las credenciales con las que se trabajará.
- Se firma con su clave de plataforma, emitida una sola vez al crear su cuenta de socio. Envíe el uuid de la aplicación de plataforma en X-Eternity-App-Id.
- Nunca alcanza los datos de animales. Una clave de plataforma en una ruta /v1/partner/ responde 401: así funciona la separación, no es un error de configuración.
/v1/platform/organizationsBuscar una clínica que ya existe antes de crear una nueva.▸Autenticación: HMAC with your PLATFORM key.
Campos de la solicitud
| Campo | Obl. | Tipo | Diccionario | Descripción |
|---|---|---|---|---|
query | sí | string | — | Fragmento de nombre o dirección, mínimo 2 caracteres. |
limit | no | int | — | Número máximo de resultados, hasta 50 (por defecto 20). |
Respuesta de ejemplo
{
"payload": [
{
"public_id": "TGo1Gwe2ppRkUFO1",
"org_name": "Лапа",
"full_address": "Україна, Київ, вул. Прикладна, 1",
"status": 3,
"linked": false
}
]
}| Campo | Descripción |
|---|---|
public_id | Páselo al endpoint de abajo para dar de alta a un médico aquí. |
status | Estado de moderación. Una clínica que usted creó permanece fuera del directorio público hasta que su director la reclame. |
linked | true si usted mismo creó esta clínica. |
Estados de la respuesta
| Estado | Significado |
|---|---|
200 | Coincidencias (lista vacía si no hay ninguna). |
422 | Error de validación (falta query o tiene menos de 2 caracteres). |
/v1/platform/organizationsCrear una clínica o resolver la existente por su propio identificador.▸Autenticación: HMAC with your PLATFORM key. Issued separately from clinic keys; it never reaches animal data.
Campos de la solicitud
| Campo | Obl. | Tipo | Diccionario | Descripción |
|---|---|---|---|---|
external_org_id | sí | string | — | Su propio identificador de esta clínica. Una llamada repetida con el mismo valor devuelve la clínica que ya tiene en lugar de crear otra, así que envíe un valor estable. |
name | sí | string | — | Clinic name. |
director_public_id | sí | string | — | El médico que ocupa el puesto de director, por su public_id (de POST /owners o del endpoint de abajo). Una clínica no puede existir sin director, y un médico solo puede dirigir una clínica; nombrar a alguien que ya dirige otra se responde con 409. |
email | no | string | — | Contact email. |
phone | no | string | — | Contact phone (E.164). |
website | no | string | — | Website. |
address | no | string | — | Full address. |
country_id | no | int | countries | Country dictionary id. |
description | no | string | — | Free-text description. |
lat | no | number | — | Latitude. |
lng | no | number | — | Longitude. |
Cuerpo de la solicitud (JSON)
{
"external_org_id": "crm-clinic-118",
"name": "Лапа",
"director_public_id": "V1StGXR8Z5jd",
"email": "clinic@example.com",
"phone": "+380441234567"
}Respuesta de ejemplo
{
"payload": {
"public_id": "yAvgJrSYehJo9JXh",
"name": "Лапа",
"status": 2,
"created": true
}
}| Campo | Descripción |
|---|---|
public_id | Identificador público estable de la clínica: páselo al endpoint de abajo. |
created | true si esta llamada creó la clínica; false si devolvió la que ya tenía. |
status | Estado de moderación. Una clínica creada permanece fuera del catálogo público hasta que su director la reclame. |
Estados de la respuesta
| Estado | Significado |
|---|---|
201 | Clinic created. |
200 | Ya existía una clínica para este external_org_id: se devolvió la misma. |
409 | El director indicado ya dirige otra clínica. Indique otro médico. |
422 | Error de validación (faltan external_org_id, name o director_public_id). |
/v1/platform/organizations/{clinic_public_id}/membersDar de alta a un médico en una clínica y recibir sus credenciales.▸Autenticación: HMAC with your PLATFORM key.
Campos de la solicitud
| Campo | Obl. | Tipo | Diccionario | Descripción |
|---|---|---|---|---|
email | condicional | string | — | Correo del médico. Se requiere correo o teléfono. |
phone | condicional | string | — | Teléfono del médico (E.164). Se requiere correo o teléfono. |
first_name | no | string | — | Nombre de pila. |
last_name | no | string | — | Apellido. |
language | no | string | languages | Idioma preferido. |
clinic_name | no | string | — | Etiqueta que se muestra en las credenciales emitidas. |
external_doctor_id | no | string | — | Su propio identificador de este médico. El mismo campo y las mismas reglas que external_owner_id: se escribe una vez, nunca se sobrescribe y solo usted lo ve. |
consent | sí | object | — | Bloque de consentimiento (auditoría inmutable). |
consent.account_creation | sí | bool | — | Debe ser true. Las credenciales que recibe actúan en nombre de esta persona, por lo que se requiere su consentimiento. |
Cuerpo de la solicitud (JSON)
{
"email": "doctor@example.com",
"first_name": "Ihor",
"last_name": "Melnyk",
"language": "uk",
"external_doctor_id": "crm-doc-4471",
"consent": { "account_creation": true }
}Respuesta de ejemplo
{
"payload": {
"public_id": "LSG9w6B2rwAiPoJD",
"app_id": "4833d2e5-1a97-4572-ac5d-a03c7614e0d7",
"public_key": "94af0494...",
"private_key": "b208c6e0...",
"created": true
}
}| Campo | Descripción |
|---|---|
app_id | App-Id con el que este médico firma las llamadas del plano de datos (X-Eternity-App-Id). |
public_key | Mitad pública del par de claves del médico. |
private_key | Mitad privada. Se muestra en esta respuesta y nunca más: guárdela antes de cerrar la conexión. |
public_id | Identificador público estable del médico: úselo allí donde se nombre a un propietario o director. |
created | true si esta llamada creó la cuenta; false si el médico ya tenía una y fue emparejado. |
Estados de la respuesta
| Estado | Significado |
|---|---|
201 | Médico incorporado; credenciales devueltas. |
409 | Este médico ya tiene una clave para esta clínica, o la clínica no la creó usted y su director no le ha aprobado: primero solicite un consentimiento clinic_membership. |
422 | Error de validación (sin correo/teléfono, o consent.account_creation no aceptado). |
/v1/platform/organizations/{clinic_public_id}/members/{doctor_public_id}/credentialsObtener credenciales que actúan en nombre de un médico que lo aceptó.▸Autenticación: HMAC with your PLATFORM key.
Respuesta de ejemplo
{
"payload": {
"public_id": "LSG9w6B2rwAiPoJD",
"app_id": "dcd4895e-550e-424a-9c5d-5206cbce2956",
"public_key": "11fff5d1...",
"private_key": "00604b9b...",
"created": false
}
}| Campo | Descripción |
|---|---|
private_key | Se muestra una vez y nunca más. La clave es suya y está separada de la propia del médico: cuando él retire el consentimiento, la suya deja de funcionar y la de él no. |
Estados de la respuesta
| Estado | Significado |
|---|---|
201 | Credenciales emitidas. |
409 | El médico no aceptó la entrega, o no puede actuar sobre esa clínica. El mensaje indica cuál. |
/v1/platform/consentsSolicitar permiso a un médico o a una clínica.▸Autenticación: HMAC with your PLATFORM key.
Campos de la solicitud
| Campo | Obl. | Tipo | Diccionario | Descripción |
|---|---|---|---|---|
kind | sí | string | — | key_handover — mantener credenciales que actúan en nombre de este médico; solo el médico puede permitirlo. clinic_membership — dar de alta a este médico en una clínica que usted no creó; lo decide su director. |
doctor_public_id | sí | string | — | El médico al que se refiere la solicitud. |
clinic_public_id | condicional | string | — | Obligatorio para clinic_membership: la clínica cuyo director consulta. |
Cuerpo de la solicitud (JSON)
{
"kind": "clinic_membership",
"doctor_public_id": "LSG9w6B2rwAiPoJD",
"clinic_public_id": "jJlmHf0sgxMT3Gni"
}Respuesta de ejemplo
{
"payload": {
"public_id": "5G5rBYl0hQvpJuCZ",
"kind": "clinic_membership",
"status": "pending",
"expires_at": 1788973565,
"decided_at": null
}
}| Campo | Descripción |
|---|---|
public_id | Con esto consulte el estado. |
status | pending hasta que la persona responda, luego approved o denied. |
expires_at | Segundos Unix. Una solicitud sin respuesta se cierra sola, y la aprobación deja de servir en ese mismo momento: el permiso no es permanente. |
Estados de la respuesta
| Estado | Significado |
|---|---|
201 | Solicitud creada, o devuelta la que ya tenía: preguntar dos veces no crea dos. |
409 | Nadie puede decidirlo (por ejemplo, una clínica sin director). |
422 | Error de validación (kind desconocido o falta clinic_public_id para clinic_membership). |
/v1/platform/consents/{public_id}Consultar el estado de una solicitud de permiso.▸Autenticación: HMAC with your PLATFORM key.
Respuesta de ejemplo
{
"payload": {
"public_id": "5G5rBYl0hQvpJuCZ",
"kind": "clinic_membership",
"status": "approved",
"expires_at": 1788973565,
"decided_at": 1787763211
}
}Estados de la respuesta
| Estado | Significado |
|---|---|
200 | Estado actual. |
404 | No existe tal solicitud, o pertenece a otro socio. |
Partner API — datos
Animales, propietarios, procedimientos y fotos: la superficie del día a día. Cada escritura queda registrada a nombre del médico cuya clave la firmó.
- Se firma con la clave de un médico, devuelta una sola vez al incorporarlo a una clínica o al recoger sus credenciales tras su consentimiento. Envíe el uuid de la aplicación de ese médico en X-Eternity-App-Id.
- No puede aprovisionar nada y deja de funcionar en el momento en que el médico retira su permiso. Los diccionarios no requieren firma alguna.
/v1/partner/dictionariesDiccionarios de referencia (multilingües, con filtro).▸Autenticación: Público (no requiere firma). Cacheable por CDN mediante ETag.
Campos de la solicitud
| Campo | Obl. | Tipo | Diccionario | Descripción |
|---|---|---|---|---|
include | no | string (csv) | — | Claves de diccionario separadas por comas; vacío → todas. Claves: species, pet_species_featured, sex, sizes, lost_statuses, other_identifiers, procedure_types, countries, languages, cites. `pet_species_featured` es la lista canónica de especies populares con un public_id en formato UUID: pase su código a POST /animals como species_public_id. |
q | no | string | — | Filtra las entradas por nombre localizado en cualquier idioma activo. |
lang | no | string | languages | Proyecta los nombres a un solo idioma (uk, en, ru, de, es). Por defecto: todos los activos. |
Respuesta de ejemplo
{
"payload": [
{
"key": "species",
"items": [
{ "code": 3, "names": { "uk": "Собаки", "en": "Dogs", "ru": "Собаки", "de": "Dogs" } },
{ "code": 4, "names": { "uk": "Коти", "en": "Cats" } }
]
},
{
"key": "pet_species_featured",
"items": [
{ "code": "1b289672-0a74-48d2-9600-7104bedacd8c", "names": { "uk": "Собака", "en": "Dog" } },
{ "code": "b0dd3c3a-4d35-4479-91f9-616ae072c400", "names": { "uk": "Домашні коти", "en": "Domestic cats" } }
]
},
{
"key": "countries",
"items": [
{ "code": "804", "alpha2": "UA", "alpha3": "UKR",
"names": { "uk": "Україна", "en": "Ukraine", "ru": "Украина", "de": "Ukraine", "es": "Ukraine" } }
]
},
{
"key": "languages",
"items": [
{ "code": "uk", "native": "Українська",
"names": { "uk": "Українська", "en": "Ukrainian", "ru": "Украинский", "de": "Ukrainian", "es": "Ukrainian" } }
]
}
],
"metadata": { "etag": "W/\"dict-…\"", "generated_at": "2026-05-30T08:00:00+00:00", "languages": ["uk","en","ru","de","es"] },
"links": [],
"message": null
}| Campo | Descripción |
|---|---|
payload[].key | Clave del diccionario. |
payload[].items[].code | Id estable que se usa como valor en los endpoints de escritura. Numérico para la mayoría de los diccionarios (species, sex, …); para pet_species_featured es el public_id canónico de la especie (un UUID) → páselo como species_public_id en POST /animals; para countries es el código numérico ISO 3166-1 rellenado con ceros como cadena (p. ej. "004", "804"); para languages es el código ISO 639-1 (p. ej. "uk"). |
payload[].items[].names | Asigna idioma → nombre localizado. Los idiomas sin traducción recurren al inglés. |
payload[].items[].alpha2 / alpha3 | Solo countries: códigos ISO 3166-1 alpha-2 / alpha-3 para una correspondencia cómoda. |
payload[].items[].native | Solo languages: el nombre propio del idioma (endónimo), útil para selectores de idioma. |
metadata.etag | Devuélvelo en If-None-Match para obtener 304 cuando no haya cambios. |
metadata.languages | Idiomas activos realmente presentes en esta compilación. |
Estados de la respuesta
| Estado | Significado |
|---|---|
200 | OK — diccionarios devueltos. |
304 | No Modificado — tu If-None-Match coincide; reutiliza la copia en caché. |
/v1/partner/dictionaries/speciesBúsqueda de especies (canónica, por public_id).▸Autenticación: Public (no signature required).
Campos de la solicitud
| Campo | Obl. | Tipo | Diccionario | Descripción |
|---|---|---|---|---|
q | no | string | — | Término de búsqueda de especie (cualquier rango taxonómico, subcadena y tolerante a erratas). Omítalo para ver las mejores coincidencias. Complementa el diccionario pet_species_featured, que solo incluye las populares. |
Respuesta de ejemplo
{
"payload": [
{ "public_id": "1b289672-0a74-48d2-9600-7104bedacd8c", "name": "Dog", "rank": "species", "has_breeds": true },
{ "public_id": "9cd7d2a1-4e45-4922-8f9e-fb84c61ca6ae", "name": "Cats", "rank": "genus", "has_breeds": false }
]
}| Campo | Descripción |
|---|---|
payload[].public_id | public_id de la especie: páselo como species_public_id en POST /animals, o a /dictionaries/species/{species_public_id}/breeds. |
payload[].name | Nombre localizado de la especie (idioma de la petición, con respaldo en inglés). |
payload[].rank | Rango taxonómico (especie, género, familia, …). |
payload[].has_breeds | Si la especie tiene lista de razas. |
Estados de la respuesta
| Estado | Significado |
|---|---|
200 | OK — matching species. |
/v1/partner/dictionaries/species/{species_public_id}/breedsRazas de una especie (canónicas, por public_id).▸Autenticación: Public (no signature required).
Campos de la solicitud
| Campo | Obl. | Tipo | Diccionario | Descripción |
|---|---|---|---|---|
species_public_id | sí | string | — | Segmento de ruta: el public_id de la especie (un UUID). Se obtiene mediante pet_species_featured o /dictionaries/species. |
q | no | string | — | Filtro opcional por nombre de raza (subcadena, tolerante a erratas). |
Respuesta de ejemplo
{
"payload": [
{ "public_id": "6bb37956-d7fb-426d-8045-9d2fb854ee43", "name": "Belgian Shepherd Dog", "kind": "purebred" },
{ "public_id": "d1f2a0c8-7b3e-4a1d-9c22-0f5e6b7a8c90", "name": "Mixed breed", "kind": "mixed" }
]
}| Campo | Descripción |
|---|---|
payload[].public_id | public_id canónico de la raza: páselo como breed_public_id en POST /animals. |
payload[].name | Nombre localizado de la raza (idioma de la petición, con respaldo en inglés). |
payload[].kind | purebred | mixed | unknown | crossbreed | variety. mixed/unknown/crossbreed son las opciones especiales de reserva. |
Estados de la respuesta
| Estado | Significado |
|---|---|
200 | OK: razas de la especie (una lista vacía si la especie no tiene razas). |
404 | species_public_id no es un UUID válido (la ruta no coincidió). |
/v1/partner/ownersCrear (o resolver) un propietario; devuelve el ID global del usuario.▸Autenticación: HMAC. Cualquier clave de asociado. · X-Eternity-Idempotency-Key obligatorio
Campos de la solicitud
| Campo | Obl. | Tipo | Diccionario | Descripción |
|---|---|---|---|---|
email | condicional | string | — | Correo electrónico del propietario. Se requiere uno de email/phone: es la forma en que se contacta/autentica al propietario más adelante. |
phone | condicional | string | — | Teléfono del propietario (E.164). Se requiere uno de email/phone. |
first_name | no | string | — | Nombre de pila. |
last_name | no | string | — | Apellido. |
language | no | string | languages | Idioma preferido. |
country | no | string | countries | Código numérico ISO 3166-1 rellenado con ceros como cadena (p. ej. "804"): coincide con el código del diccionario countries. |
external_owner_id | no | string | — | Su propio identificador de esta persona. Se guarda una sola vez, en el primer contacto, y nunca se sobrescribe — envíelo para que ambas partes puedan conciliar a la misma persona más adelante. Máximo 128 caracteres. |
consent | sí | object | — | Bloque de consentimiento (auditoría inmutable). |
consent.account_creation | sí | bool | — | Debe ser true: el propietario aceptó la creación de la cuenta. El momento de la captura se registra en el servidor. |
Cuerpo de la solicitud (JSON)
{
"email": "jane@example.com",
"phone": "+380681234567",
"first_name": "Jane",
"last_name": "Doe",
"language": "uk",
"country": "804",
"external_owner_id": "crm-4471",
"consent": {
"account_creation": true
}
}Respuesta de ejemplo
{
"payload": {
"user_gid": 90231,
"public_id": "V1StGXR8Z5jd",
"has_account": true,
"email": "jane@example.com",
"phone": null,
"display_hint": "Ол*** К.",
"language": "uk",
"country_id": 804,
"external_owner_id": "crm-4471"
}
}| Campo | Descripción |
|---|---|
public_id | Identificador público estable del propietario: pásalo a POST /animals owners[].public_id (versión de API >= 2026-07-04). |
user_gid | Identificador numérico heredado del propietario (adjuntar propietario en versiones anteriores de la API). |
has_account | Si el propietario ya tiene una cuenta utilizable. |
email | Correo electrónico registrado para este propietario (null si se desconoce). |
phone | Teléfono registrado para este propietario (null si se desconoce). |
display_hint | Nombre para mostrar enmascarado (sin datos personales). |
external_owner_id | El identificador que USTED nos envió para esta persona, o null si nunca lo hizo. Limitado a su propia integración — nunca ve cómo llama otro socio a la misma persona. |
Estados de la respuesta
| Estado | Significado |
|---|---|
201 | Creado (o se resolvió un propietario existente: idempotente por email/phone). |
409 | X-Eternity-Idempotency-Key reutilizada con un cuerpo distinto, o aún en proceso. |
422 | Error de validación (falta email/phone, o no se aceptó consent.account_creation). |
/v1/partner/owners/searchBuscar un propietario por email o teléfono exacto.▸Autenticación: HMAC. Cualquier clave de asociado.
Campos de la solicitud
| Campo | Obl. | Tipo | Diccionario | Descripción |
|---|---|---|---|---|
email_or_phone | sí | string | — | Correo electrónico o teléfono exacto (campo único; el correo se detecta por su formato). |
Respuesta de ejemplo
{
"payload": { "user_gid": 90231, "public_id": "V1StGXR8Z5jd", "has_account": true, "email": "jane@example.com", "phone": null, "display_hint": "Ол*** К.", "language": "uk", "country_id": 804, "external_owner_id": "crm-4471" }
}| Campo | Descripción |
|---|---|
public_id | Identificador público estable del propietario: pásalo a POST /animals owners[].public_id (versión de API >= 2026-07-04). |
user_gid | Identificador numérico heredado del propietario (adjuntar propietario en versiones anteriores de la API). |
email | Correo electrónico registrado para este propietario (null si se desconoce). |
phone | Teléfono registrado para este propietario (null si se desconoce). |
external_owner_id | El identificador que USTED nos envió para esta persona, o null si nunca lo hizo. Limitado a su propia integración — nunca ve cómo llama otro socio a la misma persona. |
Estados de la respuesta
| Estado | Significado |
|---|---|
200 | Propietario encontrado. |
404 | No hay ningún propietario con ese email_or_phone. |
422 | email_or_phone es obligatorio. |
/v1/partner/animalsRegistrar un animal (basado en chip).▸Autenticación: HMAC. Clave de veterinario/organización. · X-Eternity-Idempotency-Key obligatorio
Campos de la solicitud
| Campo | Obl. | Tipo | Diccionario | Descripción |
|---|---|---|---|---|
species | condicional | int | species | Id heredado de especie del diccionario. Se requiere exactamente uno de species / species_public_id. |
species_public_id | condicional | string | pet_species_featured | public_id canónico de la especie (un UUID) del diccionario pet_species_featured. Se requiere exactamente uno de species / species_public_id; si está presente, prevalece sobre species. |
is_microchip | sí | bool | — | Si el animal está microchipeado. true → microchip es obligatorio; false → microchip se ignora y el registro asigna un número WC temporal. |
microchip | condicional | string | — | Microchip (transpondedor). Obligatorio solo cuando is_microchip = true. |
nickname | sí | string | — | Nombre del animal. |
qr_tag | no | string | — | Número de serie del pasaporte QR que se adjuntará en el registro. |
owners | no | array | — | Propietarios; el primero se convierte en main_owner, el resto en owners (sin duplicados). Cada entrada adjunta un propietario existente O registra uno nuevo en línea. |
owners[].public_id | condicional | string | — | Modo adjuntar (versión de API >= 2026-07-04): public_id de un propietario existente de POST/GET owners. Omitir para registrar en línea. |
owners[].user_gid | condicional | int | — | Modo adjuntar (versiones de API anteriores a 2026-07-04): identificador numérico heredado del propietario. Omitir para registrar en línea. |
owners[].email | condicional | string | — | Modo en línea: correo del propietario. Se requiere uno de correo/teléfono cuando no hay public_id/user_gid (upsert: sin duplicados). |
owners[].phone | condicional | string | — | Modo en línea: teléfono del propietario (E.164). |
owners[].first_name | no | string | — | Modo en línea: nombre de pila. |
owners[].last_name | no | string | — | Modo en línea: apellido. |
owners[].language | no | string | languages | Modo en línea: idioma preferido. |
owners[].country | no | string | countries | Modo en línea: código numérico ISO 3166-1 rellenado con ceros como cadena (p. ej. "804"): coincide con el código del diccionario countries. |
owners[].external_owner_id | no | string | — | Modo inline: su propio identificador de esta persona — el mismo campo y las mismas reglas que en POST /owners. |
owners[].consent.account_creation | condicional | bool | — | Modo en línea: debe ser true: el propietario aceptó la creación de la cuenta. Obligatorio solo al registrar en línea. |
breed | no | string | — | Raza (texto libre). Solo se usa cuando falta breed_public_id. |
breed_public_id | no | string | — | public_id canónico de la raza (un UUID) de GET /breeds?species_public_id=. Debe pertenecer a la especie; si está presente, prevalece sobre la raza en texto libre. |
color | no | string | — | Color (texto libre, sin diccionario). |
gender_id | no | int | sex | Id del diccionario gender. |
dob | no | date | — | Fecha de nacimiento (ISO 8601). |
microchip_date | no | date | — | Cuándo se implantó el chip (ISO 8601). |
sterilization | no | bool | — | Indicador de esterilizado. |
size | no | int | sizes | Id del diccionario size. |
identifiers | no | array | — | Identificadores adicionales además del microchip/qr. |
identifiers[].type | sí | int | other_identifiers | Id de tipo de identificador del diccionario other_identifiers (tattoo, ring, …). |
identifiers[].value | sí | string | — | Valor del identificador. |
identifiers[].added_at | no | date | — | Cuándo se asignó el identificador (ISO 8601). |
Cuerpo de la solicitud (JSON)
{
"species": 3,
"is_microchip": true,
"microchip": "900263000123456",
"nickname": "Барсік",
"qr_tag": null,
"gender_id": 1,
"breed": "Labrador",
"color": "black",
"dob": "2022-03-01T00:00:00+00:00",
"microchip_date": "2022-11-20T00:00:00+00:00",
"sterilization": true,
"size": 2,
"owners": [
{ "public_id": "V1StGXR8Z5jd" },
{
"email": "jane@example.com",
"phone": "+380681234567",
"first_name": "Jane",
"last_name": "Doe",
"external_owner_id": "crm-4471",
"consent": { "account_creation": true }
}
],
"identifiers": [
{ "type": 3, "value": "TAT-001", "added_at": "2026-05-01T00:00:00+00:00" }
]
}Respuesta de ejemplo
{ "payload": { "id": "8xK3pQzVnB7rL2qF" } }| Campo | Descripción |
|---|---|
id | Id público inadivinable del animal (NanoID). Úsalo en todas las llamadas posteriores del animal. |
Estados de la respuesta
| Estado | Significado |
|---|---|
201 | Animal registrado. |
409 | Conflicto de X-Eternity-Idempotency-Key (misma clave, cuerpo distinto). |
422 | Error de validación: falta nickname/is_microchip, o ni species ni species_public_id; un species_public_id/breed_public_id desconocido o un breed_public_id que no pertenece a la especie; is_microchip=true sin un microchip válido; un microchip duplicado (transpondedor ya registrado, campo "transponder"); o un propietario en línea sin correo/teléfono o sin consent.account_creation. |
/v1/partner/animals/by-identifier/{type}/{value}Búsqueda por un tipo de identificador concreto. Siempre un array.▸Autenticación: HMAC. Cualquier clave de asociado.
Campos de la solicitud
| Campo | Obl. | Tipo | Diccionario | Descripción |
|---|---|---|---|---|
type | sí | path enum | — | microchip o qr_tag. |
value | sí | path string | — | Valor del identificador a buscar. |
Respuesta de ejemplo
{
"payload": [
{ "id": "8xK3pQzVnB7rL2qF", "species": 3,
"species_public_id": "d49c523a-d7ff-41b4-9ab6-0d1d2ce20939", "species_name": "Собака",
"breed": "Labrador", "breed_public_id": null, "breed_name": null,
"color": "black", "gender_id": 1,
"nickname": "Барсік", "microchip": "900263000123456", "qr_tag": null,
"dob": "2022-03-01", "register_date": "2026-05-30", "sterilization_status": true,
"lost_status": null, "deceased": false, "died_at": null, "status": 1,
"abilities": { "can_edit": true } }
]
}| Campo | Descripción |
|---|---|
payload | Array de fichas de animal: normalmente una, pero un valor puede resolverse en varias. |
species_public_id | public_id canónico de la especie: la misma clave que devuelve como species_public_id en POST /animals. |
species_name | Nombre de la especie en el idioma de la petición (con respaldo en inglés y luego en el nombre latino). |
breed_public_id | public_id canónico de la raza, o null cuando el animal solo lleva la raza en texto libre. |
breed_name | Nombre canónico de la raza en el idioma de la petición; null cuando breed_public_id es null: lea entonces `breed`. |
microchip / qr_tag | Identificadores activos. |
lost_status | "active" cuando se reporta perdido, de lo contrario null. |
deceased | True una vez que se registra la eutanasia/muerte. |
Capacidades
Cada objeto de animal incluye un objeto abilities que describe lo que el usuario asociado autenticado puede hacer con este animal. Este es el primer indicador de acceso; se añadirán más con el tiempo.
| Campo | Descripción |
|---|---|
abilities.can_edit | Si el usuario asociado autenticado puede editar este animal: actualizar sus datos, añadir procedimientos y gestionar fotos. True cuando el usuario registró el animal, tiene cualquier relación con él (animal_user_relation), o es miembro activo de una organización cuyo registro lo contiene (org_animals). |
Expansión (X-Eternity-Expand)
Encabezado opcional que lleva un array JSON de claves de expansión (p. ej. ["owners"]). Cada clave solicitada incrusta un campo adicional en cada objeto de animal de la respuesta; omite el encabezado para obtener la ficha simple. Las claves desconocidas se rechazan con 422.
| Clave | Añade | Descripción |
|---|---|---|
owners | owners[] | Los propietarios del animal —el propietario principal más cualquier copropietario— cada uno con datos de contacto y un indicador is_main_owner. Disponible solo en esta superficie de asociados. |
"owners": [
{
"user_gid": 90231,
"public_id": "V1StGXR8Z5jd",
"has_account": true,
"email": "jane@example.com",
"phone": "+380681234567",
"display_hint": "Ja*** D.",
"language": "uk",
"country_id": "804",
"external_owner_id": "crm-4471",
"is_main_owner": true
}
]| Campo | Descripción |
|---|---|
owners[].public_id | Identificador público estable del propietario: pásalo a POST /animals owners[].public_id (versión de API >= 2026-07-04). |
owners[].user_gid | Identificador numérico heredado del propietario (adjuntar propietario en versiones anteriores de la API). |
owners[].has_account | Si el propietario ya tiene una cuenta utilizable. |
owners[].email | Correo electrónico registrado para este propietario (null si se desconoce). |
owners[].phone | Teléfono registrado para este propietario (null si se desconoce). |
owners[].display_hint | Nombre para mostrar enmascarado (sin datos personales). |
owners[].language | Idioma preferido. |
owners[].country_id | Código numérico ISO 3166-1 rellenado con ceros como cadena (p. ej. "804"). |
owners[].external_owner_id | El identificador que USTED nos envió para esta persona, o null si nunca lo hizo. Limitado a su propia integración — nunca ve cómo llama otro socio a la misma persona. |
owners[].is_main_owner | true para el propietario principal (animal_user_relation tipo main_owner); false para los copropietarios. |
Estados de la respuesta
| Estado | Significado |
|---|---|
200 | OK — array (posiblemente vacío). |
/v1/partner/animals/by-identifier/{value}Búsqueda por todos los tipos de identificador a la vez. Siempre un array.▸Autenticación: HMAC. Cualquier clave de asociado.
Campos de la solicitud
| Campo | Obl. | Tipo | Diccionario | Descripción |
|---|---|---|---|---|
value | sí | path string | — | Valor del identificador; se busca en microchip y qr_tag. |
Respuesta de ejemplo
{ "payload": [ { "id": "8xK3pQzVnB7rL2qF", "nickname": "Барсік", "microchip": "900263000123456",
"species": 3, "species_public_id": "d49c523a-d7ff-41b4-9ab6-0d1d2ce20939",
"species_name": "Собака", "breed": "Labrador",
"breed_public_id": null, "breed_name": null } ] }| Campo | Descripción |
|---|---|
species_public_id / breed_public_id | Claves canónicas: las mismas que acepta POST /animals. breed_public_id es null mientras el animal solo lleve la raza en texto libre. |
species_name / breed_name | Nombres en el idioma de la petición (con respaldo en inglés y luego en el nombre latino/canónico). |
Capacidades
Cada objeto de animal incluye un objeto abilities que describe lo que el usuario asociado autenticado puede hacer con este animal. Este es el primer indicador de acceso; se añadirán más con el tiempo.
| Campo | Descripción |
|---|---|
abilities.can_edit | Si el usuario asociado autenticado puede editar este animal: actualizar sus datos, añadir procedimientos y gestionar fotos. True cuando el usuario registró el animal, tiene cualquier relación con él (animal_user_relation), o es miembro activo de una organización cuyo registro lo contiene (org_animals). |
Expansión (X-Eternity-Expand)
Encabezado opcional que lleva un array JSON de claves de expansión (p. ej. ["owners"]). Cada clave solicitada incrusta un campo adicional en cada objeto de animal de la respuesta; omite el encabezado para obtener la ficha simple. Las claves desconocidas se rechazan con 422.
| Clave | Añade | Descripción |
|---|---|---|
owners | owners[] | Los propietarios del animal —el propietario principal más cualquier copropietario— cada uno con datos de contacto y un indicador is_main_owner. Disponible solo en esta superficie de asociados. |
"owners": [
{
"user_gid": 90231,
"public_id": "V1StGXR8Z5jd",
"has_account": true,
"email": "jane@example.com",
"phone": "+380681234567",
"display_hint": "Ja*** D.",
"language": "uk",
"country_id": "804",
"external_owner_id": "crm-4471",
"is_main_owner": true
}
]| Campo | Descripción |
|---|---|
owners[].public_id | Identificador público estable del propietario: pásalo a POST /animals owners[].public_id (versión de API >= 2026-07-04). |
owners[].user_gid | Identificador numérico heredado del propietario (adjuntar propietario en versiones anteriores de la API). |
owners[].has_account | Si el propietario ya tiene una cuenta utilizable. |
owners[].email | Correo electrónico registrado para este propietario (null si se desconoce). |
owners[].phone | Teléfono registrado para este propietario (null si se desconoce). |
owners[].display_hint | Nombre para mostrar enmascarado (sin datos personales). |
owners[].language | Idioma preferido. |
owners[].country_id | Código numérico ISO 3166-1 rellenado con ceros como cadena (p. ej. "804"). |
owners[].external_owner_id | El identificador que USTED nos envió para esta persona, o null si nunca lo hizo. Limitado a su propia integración — nunca ve cómo llama otro socio a la misma persona. |
owners[].is_main_owner | true para el propietario principal (animal_user_relation tipo main_owner); false para los copropietarios. |
Estados de la respuesta
| Estado | Significado |
|---|---|
200 | OK — array (posiblemente vacío). |
/v1/partner/animals/by-ownerBuscar animales por el contacto del propietario. Siempre un array.▸Autenticación: HMAC. Cualquier clave de asociado.
Campos de la solicitud
| Campo | Obl. | Tipo | Diccionario | Descripción |
|---|---|---|---|---|
email_or_phone | sí | string | — | Correo electrónico o teléfono exacto del propietario (campo único; el correo se detecta por su formato). Un teléfono se resuelve primero al propietario. |
Respuesta de ejemplo
{ "payload": [ { "id": "8xK3pQzVnB7rL2qF", "nickname": "Барсік", "species": 3,
"species_public_id": "d49c523a-d7ff-41b4-9ab6-0d1d2ce20939",
"species_name": "Собака", "breed": "Labrador",
"breed_public_id": null, "breed_name": null } ] }| Campo | Descripción |
|---|---|
species_public_id / breed_public_id | Claves canónicas: las mismas que acepta POST /animals. breed_public_id es null mientras el animal solo lleve la raza en texto libre. |
species_name / breed_name | Nombres en el idioma de la petición (con respaldo en inglés y luego en el nombre latino/canónico). |
Capacidades
Cada objeto de animal incluye un objeto abilities que describe lo que el usuario asociado autenticado puede hacer con este animal. Este es el primer indicador de acceso; se añadirán más con el tiempo.
| Campo | Descripción |
|---|---|
abilities.can_edit | Si el usuario asociado autenticado puede editar este animal: actualizar sus datos, añadir procedimientos y gestionar fotos. True cuando el usuario registró el animal, tiene cualquier relación con él (animal_user_relation), o es miembro activo de una organización cuyo registro lo contiene (org_animals). |
Expansión (X-Eternity-Expand)
Encabezado opcional que lleva un array JSON de claves de expansión (p. ej. ["owners"]). Cada clave solicitada incrusta un campo adicional en cada objeto de animal de la respuesta; omite el encabezado para obtener la ficha simple. Las claves desconocidas se rechazan con 422.
| Clave | Añade | Descripción |
|---|---|---|
owners | owners[] | Los propietarios del animal —el propietario principal más cualquier copropietario— cada uno con datos de contacto y un indicador is_main_owner. Disponible solo en esta superficie de asociados. |
"owners": [
{
"user_gid": 90231,
"public_id": "V1StGXR8Z5jd",
"has_account": true,
"email": "jane@example.com",
"phone": "+380681234567",
"display_hint": "Ja*** D.",
"language": "uk",
"country_id": "804",
"external_owner_id": "crm-4471",
"is_main_owner": true
}
]| Campo | Descripción |
|---|---|
owners[].public_id | Identificador público estable del propietario: pásalo a POST /animals owners[].public_id (versión de API >= 2026-07-04). |
owners[].user_gid | Identificador numérico heredado del propietario (adjuntar propietario en versiones anteriores de la API). |
owners[].has_account | Si el propietario ya tiene una cuenta utilizable. |
owners[].email | Correo electrónico registrado para este propietario (null si se desconoce). |
owners[].phone | Teléfono registrado para este propietario (null si se desconoce). |
owners[].display_hint | Nombre para mostrar enmascarado (sin datos personales). |
owners[].language | Idioma preferido. |
owners[].country_id | Código numérico ISO 3166-1 rellenado con ceros como cadena (p. ej. "804"). |
owners[].external_owner_id | El identificador que USTED nos envió para esta persona, o null si nunca lo hizo. Limitado a su propia integración — nunca ve cómo llama otro socio a la misma persona. |
owners[].is_main_owner | true para el propietario principal (animal_user_relation tipo main_owner); false para los copropietarios. |
Estados de la respuesta
| Estado | Significado |
|---|---|
200 | OK — array (vacío si el propietario no tiene un correo registrado para búsquedas solo por teléfono). |
422 | email_or_phone es obligatorio. |
/v1/partner/animals/{id}Ficha completa del animal.▸Autenticación: HMAC. Cualquier clave de asociado.
Campos de la solicitud
| Campo | Obl. | Tipo | Diccionario | Descripción |
|---|---|---|---|---|
id | sí | path string | — | Id público del animal (NanoID). |
Respuesta de ejemplo
{ "payload": { "id": "8xK3pQzVnB7rL2qF", "species": 3,
"species_public_id": "d49c523a-d7ff-41b4-9ab6-0d1d2ce20939", "species_name": "Собака",
"breed": "Labrador", "breed_public_id": null, "breed_name": null,
"nickname": "Барсік", "microchip": "900263000123456", "deceased": false,
"abilities": { "can_edit": true } } }| Campo | Descripción |
|---|---|
species_public_id | public_id canónico de la especie: la misma clave que devuelve como species_public_id en POST /animals. |
species_name | Nombre de la especie en el idioma de la petición (con respaldo en inglés y luego en el nombre latino). |
breed_public_id | public_id canónico de la raza, o null cuando el animal solo lleva la raza en texto libre. |
breed_name | Nombre canónico de la raza en el idioma de la petición; null cuando breed_public_id es null: lea entonces `breed`. |
Capacidades
Cada objeto de animal incluye un objeto abilities que describe lo que el usuario asociado autenticado puede hacer con este animal. Este es el primer indicador de acceso; se añadirán más con el tiempo.
| Campo | Descripción |
|---|---|
abilities.can_edit | Si el usuario asociado autenticado puede editar este animal: actualizar sus datos, añadir procedimientos y gestionar fotos. True cuando el usuario registró el animal, tiene cualquier relación con él (animal_user_relation), o es miembro activo de una organización cuyo registro lo contiene (org_animals). |
Expansión (X-Eternity-Expand)
Encabezado opcional que lleva un array JSON de claves de expansión (p. ej. ["owners"]). Cada clave solicitada incrusta un campo adicional en cada objeto de animal de la respuesta; omite el encabezado para obtener la ficha simple. Las claves desconocidas se rechazan con 422.
| Clave | Añade | Descripción |
|---|---|---|
owners | owners[] | Los propietarios del animal —el propietario principal más cualquier copropietario— cada uno con datos de contacto y un indicador is_main_owner. Disponible solo en esta superficie de asociados. |
"owners": [
{
"user_gid": 90231,
"public_id": "V1StGXR8Z5jd",
"has_account": true,
"email": "jane@example.com",
"phone": "+380681234567",
"display_hint": "Ja*** D.",
"language": "uk",
"country_id": "804",
"external_owner_id": "crm-4471",
"is_main_owner": true
}
]| Campo | Descripción |
|---|---|
owners[].public_id | Identificador público estable del propietario: pásalo a POST /animals owners[].public_id (versión de API >= 2026-07-04). |
owners[].user_gid | Identificador numérico heredado del propietario (adjuntar propietario en versiones anteriores de la API). |
owners[].has_account | Si el propietario ya tiene una cuenta utilizable. |
owners[].email | Correo electrónico registrado para este propietario (null si se desconoce). |
owners[].phone | Teléfono registrado para este propietario (null si se desconoce). |
owners[].display_hint | Nombre para mostrar enmascarado (sin datos personales). |
owners[].language | Idioma preferido. |
owners[].country_id | Código numérico ISO 3166-1 rellenado con ceros como cadena (p. ej. "804"). |
owners[].external_owner_id | El identificador que USTED nos envió para esta persona, o null si nunca lo hizo. Limitado a su propia integración — nunca ve cómo llama otro socio a la misma persona. |
owners[].is_main_owner | true para el propietario principal (animal_user_relation tipo main_owner); false para los copropietarios. |
Estados de la respuesta
| Estado | Significado |
|---|---|
200 | OK. |
404 | Animal no encontrado. |
/v1/partner/animals/{id}Actualizar campos modificables / marcar como fallecido.▸Autenticación: HMAC. Propietario O veterinario con una relación activa con el animal. · X-Eternity-Idempotency-Key obligatorio
Campos de la solicitud
| Campo | Obl. | Tipo | Diccionario | Descripción |
|---|---|---|---|---|
nickname | no | string | — | Nombre nuevo. |
color | no | string | — | Color nuevo (texto libre, sin diccionario). |
sterilization_status | no | bool | — | Establecer el indicador de esterilizado. |
deceased | no | bool | — | true → marcar el animal como muerto. |
Cuerpo de la solicitud (JSON)
{
"nickname": "Барсік",
"color": "black",
"sterilization_status": true,
"deceased": false
}Respuesta de ejemplo
204 No Content
Estados de la respuesta
| Estado | Significado |
|---|---|
204 | Actualizado. |
403 | Sin acceso a este animal: solicítelo (POST /v1/partner/animals/{id}/access-request) y reinténtelo cuando el propietario lo apruebe. |
409 | Conflicto de X-Eternity-Idempotency-Key. |
422 | Error de validación. |
/v1/partner/animals/{id}/access-requestPedir al propietario del animal que le conceda acceso.▸Autenticación: HMAC. Clave de veterinario/organización. · X-Eternity-Idempotency-Key obligatorio
Campos de la solicitud
| Campo | Obl. | Tipo | Diccionario | Descripción |
|---|---|---|---|---|
id | sí | path string | — | Id público del animal (NanoID). |
Respuesta de ejemplo
{
"payload": {
"status": "pending",
"requested_at": "2026-06-23T09:00:00+00:00",
"expires_at": "2026-06-30T09:00:00+00:00",
"retry_after_seconds": 604800
}
}| Campo | Descripción |
|---|---|
status | "granted": ya tienes acceso, no se creó ninguna solicitud; "pending": a la espera del propietario; "denied": el propietario lo rechazó (reconsiderable hasta que caduque). |
requested_at | Cuándo se generó la solicitud (null cuando status="granted"). |
expires_at | Cuándo caduca la solicitud y puedes volver a solicitar (null cuando status="granted"). |
retry_after_seconds | Segundos hasta que puedas volver a solicitar el mismo animal (0 una vez transcurrido; null cuando status="granted"). |
Estados de la respuesta
| Estado | Significado |
|---|---|
201 | Se creó una nueva solicitud de acceso: se ha notificado al propietario por correo electrónico. |
200 | No se creó ninguna solicitud nueva: ya tienes acceso (status "granted"), o ya existe una solicitud activa (status "pending"/"denied"): espera retry_after_seconds antes de volver a solicitar. |
404 | Animal no encontrado. |
/v1/partner/animals/{id}/access-requestComprobar si su solicitud de acceso fue aprobada.▸Autenticación: HMAC. Clave de veterinario/organización.
Campos de la solicitud
| Campo | Obl. | Tipo | Diccionario | Descripción |
|---|---|---|---|---|
id | sí | path string | — | Id público del animal (NanoID). |
Respuesta de ejemplo
{
"payload": {
"status": "granted",
"requested_at": "2026-06-23T09:00:00+00:00",
"expires_at": "2026-06-30T09:00:00+00:00",
"retry_after_seconds": 0
}
}| Campo | Descripción |
|---|---|
status | "granted": el acceso se ha aprobado y está activo; "pending": a la espera del propietario; "denied": rechazado; "none": no hay ninguna solicitud activa. |
Estados de la respuesta
| Estado | Significado |
|---|---|
200 | OK. |
404 | Animal no encontrado. |
/v1/partner/animals/{id}/proceduresRegistrar procedimientos; abre una visita. Objeto único o array.▸Autenticación: HMAC. Clave de veterinario/organización con acceso al animal. · X-Eternity-Idempotency-Key obligatorio
Campos de la solicitud
| Campo | Obl. | Tipo | Diccionario | Descripción |
|---|---|---|---|---|
(body) | sí | object | array | — | Un único objeto de procedimiento o un array de ellos (≤100). |
type | sí | int | procedure_types | Id del catálogo de procedimientos: 10 vacunación, 20 vacunación antirrábica, 30 identificación por transpondedor, 40 identificación por token, 50 desparasitación, 60 esterilización, 70 eutanasia / certificación de defunción. |
occurred_at | sí | datetime | — | Cuándo se realizó (ISO 8601). |
summary | no | string | — | Nota de texto libre. |
revaccination_date | no | date | — | Sobrescribir la fecha de la próxima vacunación (vacunaciones). |
type_specific_payload | no | object | — | Campos por tipo, validados en el servidor: 10/20 → {vaccine_name*, batch_number*}; 30 → {transponder_number* — 15 digits}; 40 → {token_number*}; 50 → {drug*, batch_number?, dose?}; 60 → {method?, anesthesia_type?}; 70 → {reason*, death_date*}. Para el tipo 30: si el animal ya lleva un microchip, se conserva; el nuevo número se almacena como un identificador adicional (other_identifiers tipo 11) en lugar de reemplazar el chip. |
Cuerpo de la solicitud (JSON)
[
{
"type": 10,
"occurred_at": "2026-05-30T08:00:00+00:00",
"summary": "Annual shot",
"revaccination_date": "2027-05-30",
"type_specific_payload": {
"vaccine_name": "Nobivac",
"batch_number": "A123"
}
},
{
"type": 30,
"occurred_at": "2026-05-30T08:05:00+00:00",
"type_specific_payload": {
"transponder_number": "900263000123456"
}
}
]Respuesta de ejemplo
{
"payload": {
"appointment_id": 7741,
"procedures": [
{ "id": 99001, "animal_id": "8xK3pQzVnB7rL2qF", "visit_id": 7741, "type": 10,
"occurred_at": "2026-05-30T08:00:00+00:00", "summary": "Annual shot", "revaccination_date": "2027-05-30",
"type_specific_payload": { "vaccine_name": "Nobivac", "batch_number": "A123" } }
]
}
}| Campo | Descripción |
|---|---|
appointment_id | La visita abierta/utilizada para este lote. |
procedures[] | Los procedimientos registrados: la misma ficha que en GET lista/detalle. |
procedures[].id | Id del registro del procedimiento. |
procedures[].type | Id numérico del tipo (diccionario procedure_types). |
procedures[].type_specific_payload | Carga útil almacenada específica del tipo. |
Estados de la respuesta
| Estado | Significado |
|---|---|
201 | Registrado; visita abierta. |
403 | Sin acceso a este animal: solicítelo (POST /v1/partner/animals/{id}/access-request) y reinténtelo cuando el propietario lo apruebe. |
404 | Animal no encontrado. |
409 | Conflicto de X-Eternity-Idempotency-Key. |
422 | Tipo no admitido, falta occurred_at, o faltan campos específicos del tipo. |
/v1/partner/animals/{id}/proceduresListar los procedimientos de un animal. Siempre un array.▸Autenticación: HMAC. Clave de veterinario/organización.
Campos de la solicitud
| Campo | Obl. | Tipo | Diccionario | Descripción |
|---|---|---|---|---|
type | no | int | procedure_types | Filtrar por id del catálogo de procedimientos. |
since | no | datetime | — | Solo en o después de este momento. |
until | no | datetime | — | Solo en o antes de este momento. |
Respuesta de ejemplo
{
"payload": [
{ "id": 99001, "animal_id": "8xK3pQzVnB7rL2qF", "visit_id": 7741, "type": 10,
"occurred_at": "2026-05-30T08:00:00+00:00", "summary": null, "revaccination_date": "2027-05-30",
"type_specific_payload": { "vaccine_name": "Nobivac", "batch_number": "A123" } }
]
}| Campo | Descripción |
|---|---|
type | Id del catálogo de procedimientos (diccionario procedure_types). |
visit_id | Cita bajo la que se registró el procedimiento. |
type_specific_payload | Campos por tipo. |
Estados de la respuesta
| Estado | Significado |
|---|---|
200 | OK — array (posiblemente vacío). |
404 | Animal no encontrado. |
/v1/partner/procedures/{id}Procedimiento único.▸Autenticación: HMAC. Clave de veterinario/organización.
Campos de la solicitud
| Campo | Obl. | Tipo | Diccionario | Descripción |
|---|---|---|---|---|
id | sí | path int | — | Id del registro del procedimiento. |
Respuesta de ejemplo
{
"payload": {
"id": 99001, "animal_id": "8xK3pQzVnB7rL2qF", "visit_id": 7741, "type": 10,
"occurred_at": "2026-05-30T08:00:00+00:00", "summary": null, "revaccination_date": "2027-05-30",
"type_specific_payload": { "vaccine_name": "Nobivac", "batch_number": "A123" }
}
}Estados de la respuesta
| Estado | Significado |
|---|---|
200 | OK. |
404 | Procedimiento no encontrado. |
/v1/partner/animals/{id}/photosSubir una foto (multipart). Propietario o veterinario con relación.▸Autenticación: HMAC + multipart/form-data. Propietario O veterinario con relación. · X-Eternity-Idempotency-Key obligatorio
Campos de la solicitud
| Campo | Obl. | Tipo | Diccionario | Descripción |
|---|---|---|---|---|
file | sí | file | — | Archivo de imagen. Máximo 8 MB por foto (config partner.photos.max_single_mb). |
kind | no | enum | — | avatar | gallery | nose_print. avatar establece la foto principal. Por defecto gallery. |
Respuesta de ejemplo
{ "payload": { "id": 33015 } }| Campo | Descripción |
|---|---|
id | Id de la foto nueva. |
Estados de la respuesta
| Estado | Significado |
|---|---|
201 | Subido. |
403 | Sin acceso a este animal: solicítelo (POST /v1/partner/animals/{id}/access-request) y reinténtelo cuando el propietario lo apruebe. |
422 | Archivo no válido o de más de 8 MB (reduce el tamaño / baja la calidad). |
413 | La solicitud completa supera los 15 MB. |
/v1/partner/animals/{id}/photos/{photoId}Eliminación lógica de una foto.▸Autenticación: HMAC. Propietario O veterinario con relación. · X-Eternity-Idempotency-Key obligatorio
Campos de la solicitud
| Campo | Obl. | Tipo | Diccionario | Descripción |
|---|---|---|---|---|
id | sí | path string | — | Id público del animal (NanoID). |
photoId | sí | path int | — | Id de la foto. |
Respuesta de ejemplo
204 No Content
Estados de la respuesta
| Estado | Significado |
|---|---|
204 | Eliminado. |
403 | Sin acceso a este animal: solicítelo (POST /v1/partner/animals/{id}/access-request) y reinténtelo cuando el propietario lo apruebe. |