Saltar al contenido
Encuentra tu mascota
API v1

Referencia de la API

Acceso de solo lectura a los anuncios y sus fotos, más el aviso que crea el botón «¡Yo lo tengo!». Sigue la convención JSON:API y necesita una clave que entregamos nosotros.

Lo básico

URL base
https://encuentratumascota.co/api/v1
Tipo de medio
application/vnd.api+json

Toda respuesta sale con ese tipo de medio. Si envías cuerpo, la cabecera Content-Type debe ser exactamente esa cadena: un ; charset=utf-8 añadido se rechaza con 415, como manda la especificación.

Autenticación

Cada consumidor recibe su propia clave. Mándala en cada petición; sin ella la respuesta es 401. Si tu cliente reserva la cabecera Authorization para otra cosa, usa X-Api-Key con el mismo valor.

Cabecera
Authorization: Bearer TU_CLAVE

La clave identifica a tu aplicación y es por lo que contamos los límites de uso. Trátala como una contraseña: no la publiques en código de cliente ni en un repositorio. Si se te filtra, avísanos y la revocamos.

Listar anuncios

GET /api/v1/pet-ads

Devuelve solo los anuncios activos, del más reciente al más antiguo, salvo que pidas otra cosa.

Filtros

Parámetro Valores Qué hace
filter[adType] searching (Se busca), found (Se busca familia) Cuál de las dos pestañas: mascota perdida o encontrada.
filter[petType] dog (Perro), cat (Gato), other (Otra) Especie de la mascota.
filter[status] active (Activo), resolved (Resuelto) Por defecto solo devuelve los activos. Pide «resolved» para los ya resueltos.
filter[city] texto libre Coincidencia parcial, sin distinguir mayúsculas ni el resto del nombre.
filter[name] texto libre Nombre de la mascota, también por coincidencia parcial.

Orden, página y relaciones

  • sort — -createdAt, createdAt, city, -city. Por defecto -createdAt.
  • page[number] y page[size] — 25 por página por defecto, máximo 100. Sigue links.next en vez de armar la URL a mano.
  • include=photos — agrega las fotos completas bajo included. Sin esto igual recibes qué fotos tiene cada anuncio en relationships, pero sin sus URLs.
  • fields[pet-ads] y fields[pet-ad-photos] — lista separada por comas para recortar la respuesta a los campos que de verdad usas.

Un parámetro que no exista, o con un valor fuera de rango, responde 400. Nunca lo ignoramos en silencio: si pediste algo mal, te enteras.

Ejemplo
curl -H 'Accept: application/vnd.api+json' \
     -H "Authorization: Bearer $CLAVE" \
     'https://encuentratumascota.co/api/v1/pet-ads?filter[adType]=searching&filter[city]=Medellin&include=photos&page[size]=10'
Respuesta (recortada)
{
  "data": [
    {
      "type": "pet-ads",
      "id": "1d14daa9-6f6e-4d0a-9f8c-2b0f5a1c7e33",
      "attributes": {
        "adType": "searching",
        "adTypeLabel": "Se busca",
        "status": "active",
        "petType": "cat",
        "petTypeLabel": "Gato",
        "title": "Ilona",
        "name": "Ilona",
        "breed": "Criolla",
        "color": "Gris atigrado",
        "city": "Pereira",
        "zone": "Centro",
        "location": "Centro, Pereira",
        "phoneVisible": true,
        "phone": "573001234567",
        "phoneFormatted": "+57 300 123 4567",
        "whatsappUrl": "https://wa.me/573001234567",
        "acceptsReports": true,
        "createdAt": "2026-08-16T13:33:05+00:00"
      },
      "relationships": {
        "photos": {
          "data": [
            { "type": "pet-ad-photos", "id": "196" }
          ]
        }
      },
      "links": {
        "self": "https://encuentratumascota.co/api/v1/pet-ads/1d14daa9-6f6e-4d0a-9f8c-2b0f5a1c7e33"
      }
    }
  ],
  "included": [
    {
      "type": "pet-ad-photos",
      "id": "196",
      "attributes": {
        "url": "https://.../anuncios/1d14daa9/foto.jpg",
        "isPrimary": true,
        "position": 0
      }
    }
  ],
  "links": {
    "self": "https://encuentratumascota.co/api/v1/pet-ads",
    "next": "https://encuentratumascota.co/api/v1/pet-ads?page%5Bnumber%5D=2"
  },
  "meta": {
    "page": {
      "number": 1,
      "size": 10,
      "total": 102,
      "lastPage": 11
    }
  }
}

El teléfono solo viaja cuando quien publicó eligió mostrarlo y el anuncio sigue activo: al marcarlo como resuelto se retira, porque ya cumplió su propósito. Por eso phoneVisible siempre está, y phone puede no estar. Si está oculto, la forma de llegar a esa persona es crear un aviso.

Ver un anuncio

GET /api/v1/pet-ads/{uuid}

Mismo objeto que en el listado, dentro de data en vez de un arreglo. Acepta include y fields. Devuelve el anuncio esté activo o resuelto; un UUID que no existe da 404.

Ejemplo
curl -H 'Accept: application/vnd.api+json' \
     -H "Authorization: Bearer $CLAVE" \
     'https://encuentratumascota.co/api/v1/pet-ads/1d14daa9-6f6e-4d0a-9f8c-2b0f5a1c7e33?include=photos'

Dejar un aviso

POST /api/v1/pet-ads/{uuid}/reports

La única escritura de la API: alguien vio la mascota y deja su celular para que la familia lo contacte. Guardamos el número y le mandamos el aviso por WhatsApp a quien publicó; el envío va por fuera de la petición, así que un 201 significa «recibido y encolado», no «ya entregado».

El celular son 10 dígitos empezando por 3, sin indicativo de país. Puedes mandarlo con espacios o con «+57» adelante, nosotros lo normalizamos.

Petición
curl -X POST \
     -H 'Content-Type: application/vnd.api+json' \
     -H "Authorization: Bearer $CLAVE" \
     -d '{"data":{"type":"pet-ad-reports","attributes":{"phone":"3009876543"}}}' \
     'https://encuentratumascota.co/api/v1/pet-ads/1d14daa9-6f6e-4d0a-9f8c-2b0f5a1c7e33/reports'
Respuesta 201
{
  "data": {
    "type": "pet-ad-reports",
    "id": "3",
    "attributes": {
      "status": "pending",
      "statusLabel": "Pendiente de envío",
      "notifiedAt": null,
      "createdAt": "2026-08-16T16:04:11+00:00"
    },
    "relationships": {
      "petAd": {
        "data": { "type": "pet-ads", "id": "1d14daa9-6f6e-4d0a-9f8c-2b0f5a1c7e33" }
      }
    }
  }
}

No te devolvemos el celular que enviaste: es de quien lo dejó, y la API no sirve para leer los avisos de otros. Un anuncio ya resuelto responde 409, no 404: el anuncio existe, solo dejó de recibir avisos.

Errores

Todo error llega como una lista errors, con un objeto por cada problema encontrado — así puedes resaltar todos los campos malos de una sola vez.

Forma de un error
{
  "errors": [
    {
      "status": "422",
      "code": "validation_error",
      "title": "Datos inválidos",
      "detail": "El celular debe empezar por 3.",
      "source": { "pointer": "/data/attributes/phone" }
    }
  ]
}
Estado Código Cuándo
400 invalid_query_parameter Un filtro, sort, include o fields que no existe, o con un valor fuera de rango. El error apunta al parámetro en «source.parameter».
401 unauthorized Falta la API key o no corresponde a ningún cliente.
404 not_found No hay ningún anuncio con ese UUID.
406 not_acceptable El «Accept» solo pide el tipo de medio con parámetros añadidos.
409 invalid_resource_type El «data.type» del cuerpo nombra otro recurso.
409 ad_not_accepting_reports El anuncio ya está resuelto y dejó de recibir avisos.
415 unsupported_media_type El cuerpo no viaja como «application/vnd.api+json», o lo hace con parámetros de tipo de medio.
422 validation_error El cuerpo tiene la forma correcta pero un valor no pasa validación. Apunta al miembro en «source.pointer».
429 too_many_requests Se agotó el límite por minuto. La respuesta trae la cabecera «Retry-After».

Límites de uso

  • 120 lecturas por minuto.
  • 2 avisos por minuto, porque cada uno termina en un WhatsApp a una persona real.

Se cuentan por clave, no por dirección IP, así que otro consumidor no te gasta el cupo. Al pasarte recibes 429 con la cabecera Retry-After; espera esos segundos antes de reintentar.

¿Necesitas una clave o encontraste algo que no cuadra con esta página? Escríbenos y lo revisamos.