# Referencia de la Listings API

`PUT /api/listings` crea o actualiza un listado completo en una sola llamada atómica: la API, sus endpoints, el secreto de origen, los planes, las FAQs y las APIs vinculadas. O se guarda todo, o no se guarda nada. Es lo que usan internamente las herramientas MCP `provider_*`, y puedes llamarla directamente desde scripts o CI.

## Acceso

- Cualquier cuenta con **correo verificado**. Las cuentas no verificadas o bloqueadas reciben `403`.
- Autentícate con tu [clave de API](https://zylalabs.com/es/docs/api-keys): `Authorization: Bearer YOUR_API_KEY`.
- Límites de velocidad por cuenta: 30 upserts y 120 lecturas por minuto.
- Los listados nuevos cuentan contra la [cuota de APIs nuevas](https://zylalabs.com/es/docs/quality-rules). Las actualizaciones nunca cuentan.

## Endpoints

| Método | Ruta | Propósito |
|---|---|---|
| PUT | `/api/listings` | Crea o actualiza un listado (o lo elimina con `"delete": true`) |
| GET | `/api/listings` | Tus listados (`status`, `page`, `per_page`) |
| GET | `/api/listings/{product_key}` | Definición completa de un listado (nunca el secreto de origen) |
| GET | `/api/listings/me` | Tu cuenta, límites, nombres de plan válidos y tipos de parámetro |
| GET | `/api/listings/categories` | Ids de categoría |

## Ejemplo

```bash
curl -X PUT https://zylalabs.com/api/listings \
  -H "Authorization: Bearer $ZYLA_API_KEY" \
  -H "Content-Type: application/json" \
  -d @listing.json
```

`listing.json`:

```json
{
  "product_key": "trustpilot-api",
  "publish": true,
  "api": {
    "name": "Trustpilot Reviews API",
    "short_description": "Retrieve Trustpilot company reviews, ratings and reviewer details in JSON.",
    "trial": false
  },
  "access": { "in": "header", "key": "X-Origin-Key", "value": "your-origin-secret" },
  "endpoints": [{
    "name": "Get Company Reviews",
    "description": "Returns the latest public reviews for a company domain with pagination.",
    "method": "GET",
    "base_url": "https://origin.example.com/v1/items/||domain||",
    "path_params": { "domain": "example.com" },
    "parameters": [
      { "key": "page", "type": "number", "description": "Page number, starting at 1.", "value": "1", "required": false }
    ],
    "headers": [{ "key": "Accept", "value": "application/json" }],
    "example_response": { "reviews": [{ "rating": 5 }] }
  }],
  "plans": [
    { "name": "Basic", "interval": "Monthly", "price": 24.99, "max_requests": 1000 },
    { "name": "Pro", "interval": "Monthly", "price": 49.99, "max_requests": 5000 },
    { "name": "ProPlus", "interval": "Monthly", "price": 99.99, "max_requests": 15000, "rate_limit": 120 }
  ],
  "faqs": [{ "question": "What data does it return?", "answer": "Public reviews with rating and text." }],
  "slaves": [{ "name": "Company Reviews Lookup API" }]
}
```

## Reglas

**Identidad.** `product_key` es tu propio id estable para el listado. Una clave nueva crea el listado; una clave que ya usaste lo actualiza. Una clave pertenece a la cuenta que la creó (`403` para cualquier otra). Los listados eliminados no aceptan ediciones (`409`).

**Publicación.** El listado se publica cuando pasa las [reglas de calidad](https://zylalabs.com/es/docs/quality-rules) y tiene al menos un endpoint con una respuesta de ejemplo y planes activos. Sin eso, `"publish": true` devuelve `422`. Omite `publish` para publicarlo en cuanto esté listo, o envía `"publish": false` para mantenerlo como borrador. `false` nunca despublica un listado que ya está en vivo.

**Campos de la API.** `name` sigue las [reglas de nombre](https://zylalabs.com/es/docs/quality-rules): hasta 50 caracteres, incluye la palabra "API", único en el hub. `short_description` de al menos 50 caracteres. Zyla completa el resto de la página del listado por ti: la descripción larga se genera a partir de tu descripción corta, y la categoría y las etiquetas se eligen con IA. Si envías `long_description`, `category_id`, `tags` o `website_url`, se ignoran y se listan en `warnings`.

**Endpoints.** Cuando `endpoints` está presente, es la lista completa: los endpoints se emparejan por método + `base_url` (sin el query string), se crean los nuevos y se eliminan los que falten en la lista. Omite `endpoints` para dejarlos sin cambios.
- Descripción de al menos 40 caracteres. Método GET, POST, PUT, DELETE o PATCH.
- `base_url` debe ser una URL válida. Los parámetros de ruta van entre `||`, como en `/items/||domain||`, con un valor de ejemplo en `path_params`.
- Los parámetros necesitan `key`, `type` (string, number, email, url, domain, date, datetime) y una descripción de al menos 10 caracteres.
- `example_response` es obligatorio, de hasta 10,000 caracteres.

**Secreto de origen (`access`).** Un header o parámetro de consulta que Zyla agrega a cada llamada hacia tu origen, para que tu servidor solo acepte tráfico del hub. Se guarda oculto y nunca se devuelve ni se registra. Omítelo para mantener el actual; envía `null` para eliminarlo.

**Planes.** Nombres exactos: Free, Basic, Pro, ProPlus, Premium, Elite, Ultimate, Pay as you go. `price` en USD; los planes anuales llevan su precio anual final. `max_requests` por ciclo; un plan más barato debe incluir menos solicitudes que uno más caro en el mismo intervalo. `rate_limit` de 60 a 240 por minuto. Deben mantenerse activos al menos tres planes mensuales pagos. Si no envías planes en un listado nuevo, se crea un conjunto por defecto.

**FAQs.** Lista completa cuando está presente, hasta 10. Pregunta de 5 a 100 caracteres, respuesta de 3 a 700.

**APIs vinculadas (`slaves`).** Variantes de tu API con su propio nombre y página que reutilizan sus endpoints. Se emparejan por nombre y siguen los cambios en los endpoints de la principal. La principal necesita endpoints, y una API vinculada no puede tener APIs vinculadas propias.

**Eliminar.** `{"product_key": "...", "delete": true}` elimina el listado. Se rechaza con `409` mientras tenga suscripciones pagas. Las APIs vinculadas se eliminan solo si las nombras en `slaves`.

**No soportado.** Transformaciones de respuesta, cuerpos de solicitud y subida de archivos (`422 not_supported`). Usa el asistente web para eso.

## Respuestas

Éxito: `{"success": true, "listing": {...}, "warnings": []}`, con `201` al crear y `200` al actualizar. `listing.url` se establece en cuanto el listado está en vivo.

| Estado | `code` | Significado |
|---|---|---|
| 401 | `unauthenticated` | Clave ausente o inválida |
| 403 | `forbidden` | Cuenta no verificada o bloqueada, o el `product_key` pertenece a otra cuenta |
| 404 | `not_found` | `product_key` desconocido |
| 409 | `name_taken`, `active_subscriptions`, `endpoints_required`, `listing_deleted`, `slave_of_slave`, `product_key_conflict` | Conflicto; no se cambió nada |
| 422 | `validation_failed`, `ai_validation_failed`, `not_supported` | `errors` indexado por campo, por ejemplo `endpoints.2.parameters.0.description` |
| 429 | `creation_limit_reached` | Se agotó la cuota de APIs nuevas; `retry_after` en segundos y un header `Retry-After` |
| 503 | `ai_unavailable` | La verificación de contenido no respondió; no se guardó nada; vuelve a intentarlo |
| 500 | `server_error` | Falla inesperada; no se guardó nada |


---
Source: https://zylalabs.com/es/docs/listings-api
