Dribba · Developer docs

Dribba API

Superficie HTTP pública de dribba.com: servicios, casos, artículos, vacantes, datos de empresa y una estimación de presupuesto. Solo lectura, sin clave de API y sin registro. Si eres un agente y solo quieres leer el sitio, empieza por el bundle OKF o por el servidor MCP.

Inicio rápido

No hay entorno de pruebas separado porque no hace falta: la API es de solo lectura y pública, así que producción es el sandbox. Ninguna de estas llamadas modifica nada ni consume cuota de nadie más que la tuya.

# El índice: versiones, contrato y política de límites
curl https://dribba.com/api

# Catálogo de servicios
curl https://dribba.com/api/v1/services

# Presupuesto orientativo de una app iOS + Android
curl -X POST https://dribba.com/api/v1/estimate \
  -H 'Content-Type: application/json' \
  -d '{"platforms":["ios","android"],"complexity":"standard"}'

El contrato completo, con esquemas de petición y respuesta de cada operación, está en /openapi.json (OpenAPI 3.1). El descubrimiento por convención empieza en /.well-known/api-catalog (RFC 9727).

Autenticación

Ninguna. Los endpoints de /api/v1 son públicos y de solo lectura: no hay claves de API, ni OAuth, ni cabeceras que firmar. Tampoco hay webhooks ni operaciones de escritura, así que las convenciones de Idempotency-Key, paginación por cursor y trabajos asíncronos no aplican.

Los endpoints de formulario del propio sitio (/api/contact, /api/apply, /api/resources) sí escriben, y por eso exigen petición del mismo origen: una llamada desde otro servidor recibe 403 origin_not_allowed. Para que un agente nos contacte está la herramienta submit_contact_request del servidor MCP, que pide confirmación explícita antes de enviar.

Endpoints

Todo cuelga de https://dribba.com. La versión mayor va en la ruta.

MétodoRutaDevuelve
GET/api/v1Endpoints, rate-limit policy and deprecation policy of v1.
GET/api/v1/companyLegal identity, offices, team model, distinctions, selected clients.
GET/api/v1/services`{ count, items[] }` — slug, name, summary and canonical URL.
GET/api/v1/services/{slug}A single service object.
GET/api/v1/cases`{ count, items[] }` — industry, client, year, stack.
GET/api/v1/cases/{slug}Challenge, solution, outcome and metrics.
GET/api/v1/articlesArticles with metadata and the URL of their markdown twin.
GET/api/v1/jobsOpenings with location, requirements and salary band.
GET/api/v1/pricingPlatforms, features, multipliers and the €30,000 floor.
GET/api/v1/comparisons`{ count, items[] }` — topic and verdict.
GET/api/v1/comparisons/{slug}A single `{ topic, verdict }`.
POST/api/v1/estimate`{ min, max, mid }` in EUR, plus the inputs it used. Honours `Idempotency-Key`.
POST/api/v1/batch`{ count, results[] }` — up to 20 GET operations resolved in one request.
GET/api/v1/sandboxThe frozen fixtures available for integration tests.
GET/api/v1/sandbox/{resource}Same shape as production, contents frozen. Carries `X-Sandbox: true`.

Cada colección devuelve { count, total, next_cursor, items[] }.

Paginación

Por cursor. Sin limit viene la colección entera y next_cursor es null: son decenas de elementos, y obligar a paginar para leer nueve servicios sería peor servicio, no mejor. Cuando quieras trocear, la forma está documentada y no hay que adivinar el nombre del parámetro.

curl "https://dribba.com/api/v1/cases?limit=5"
# → { "count": 5, "total": 23, "next_cursor": "NQ", "items": [...] }
curl "https://dribba.com/api/v1/cases?limit=5&cursor=NQ"

El cursor es opaco: devuélvelo tal cual, no lo construyas ni lo interpretes. Máximo limit=100.

Idempotencia

Manda Idempotency-Key en cualquier POST. Con la misma clave y el mismo cuerpo recibes la misma respuesta y la cabecera Idempotency-Replayed: true; con la misma clave y otro cuerpo, un 400. Se guarda 24 h.

Honestidad sobre el alcance: hoy el único POST público es el estimador, que es una función pura, así que esto no evita un cobro doble —no hay nada que cobrar—. Evita que tengas que razonarlo, y deja la convención montada y probada.

Lecturas en lote

POST /api/v1/batch resuelve hasta 20 lecturas en una petición, en proceso (sin salir por HTTP otra vez). Cada operación trae su propio estado: una que falla no tumba el resto.

curl -X POST https://dribba.com/api/v1/batch   -H 'Content-Type: application/json'   -d '{"operations":[
        {"id":"svc","path":"/api/v1/services?limit=2"},
        {"id":"co","path":"/api/v1/company"}
      ]}'

Solo GET y solo rutas de /api/v1: un lote que pudiera escribir sería una forma elegante de saltarse el mismo-origen de los formularios.

Sandbox

https://dribba.com/api/v1/sandbox — mismas formas que producción, datos congelados. No aísla escrituras (no hay ninguna): aísla tus tests de nuestros cambios. Un test que afirme «hay 9 servicios» se rompe el día que publiquemos el décimo; contra el sandbox, no. Toda respuesta lleva X-Sandbox: true y sandbox: true en el cuerpo.

No hay trabajos asíncronos y no los fingimos: todo responde en una sola petición. Si algún día hay una operación larga, devolverá 202 con URL de estado y aquí lo dirá.

Errores

Todo 4xx y 5xx sale como application/problem+json (RFC 9457), nunca como HTML. El campo por el que ramificar es code: es estable. title y detail son para humanos y pueden cambiar de redacción.

$ curl -i https://dribba.com/api/v1/no-existe
HTTP/2 404
content-type: application/problem+json; charset=utf-8

{
  "type": "https://dribba.com/docs#api-route-not-found",
  "title": "Unknown API route",
  "status": 404,
  "detail": "No endpoint is published at this path.",
  "instance": "https://dribba.com/api/v1/no-existe",
  "code": "api_route_not_found",
  "resolution": "List the published endpoints at https://dribba.com/api or read https://dribba.com/openapi.json.",
  "documentation_url": "https://dribba.com/docs#errores"
}

api_route_not_found · 404

No endpoint is published at this path. List the published endpoints at https://dribba.com/api or read https://dribba.com/openapi.json.

resource_not_found · 404

The endpoint exists but there is no resource with that identifier. Call the collection endpoint first and use one of the identifiers it returns.

method_not_allowed · 405

This endpoint does not support the request method. Use one of the methods advertised in the Allow response header.

invalid_request · 400

The request parameters or JSON body did not match the documented schema. Check the operation's requestBody schema in https://dribba.com/openapi.json and retry.

unsupported_media_type · 415

The request body was not sent as application/json. Send Content-Type: application/json (or multipart/form-data where documented).

rate_limit_exceeded · 429

Too many requests from this client in the current quota window. Honor the Retry-After header before retrying; the RateLimit header carries the reset.

origin_not_allowed · 403

This write endpoint only accepts same-origin requests from dribba.com. Use the remote MCP server at https://dribba.com/mcp for agent-initiated writes.

internal_error · 500

The request failed for an unexpected reason on our side. Retry with exponential backoff; if it persists, write to hola@dribba.com.

Límites de peticiones

120 peticiones por ventana de 60 segundos y por IP de cliente. Cada respuesta —correcta o no— lleva la cuota en los campos estructurados IETF y en las formas de compatibilidad, para que un agente se auto-frene sin tener que provocar un 429:

RateLimit-Policy: "public-read";q=120;w=60
RateLimit: "public-read";r=118;t=47
RateLimit-Limit: 120
RateLimit-Remaining: 118
RateLimit-Reset: 47

Al agotarla, la respuesta es 429 rate_limit_exceeded con Retry-After en segundos. Respétalo: reintentar antes no adelanta la ventana.

Sinceridad sobre la implementación: el contador es por instancia de servidor, así que con varias instancias vivas la cuota real es un múltiplo de la anunciada. Las cabeceras describen lo que ve la instancia que te atendió.

Versionado y deprecación

La versión mayor va en la ruta y la actual es /api/v1, estable. Dentro de v1 solo se añaden campos: un cliente que ignora los que no conoce nunca se rompe.

Un cambio que rompa peticiones o respuestas estrena /api/v2; v1 sigue funcionando. Antes de retirar una versión mayor:

  • se marca con las cabeceras Deprecation y Link; rel="deprecation" (RFC 9745),
  • se publica un Sunset con fecha, con 90 días de antelación mínima,
  • y la guía de migración se publica en esta misma página.

Hoy no hay ninguna fecha de retirada anunciada: sunset: null en /api y en la extensión x-api-lifecycle del OpenAPI.

Servidor MCP

Hay un servidor Model Context Protocol remoto en https://dribba.com/mcp, transporte Streamable HTTP, sin autenticación. Expone los mismos datos que la API más una herramienta de escritura con confirmación.

# Herramientas disponibles
curl -X POST https://dribba.com/mcp \
  -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

Descubrimiento, en las cuatro URLs que usa el ecosistema:

En el navegador, además, cada página registra herramientas WebMCP vía navigator.modelContext; el manifiesto está en /.well-known/webmcp.json.

Markdown y OKF

Cualquier URL del sitio sirve markdown si lo pides por Accept. La respuesta declara Vary: Accept, así que ninguna caché compartida mezcla representaciones.

curl -H 'Accept: text/markdown' https://dribba.com/servicios
curl https://dribba.com/llms/servicios          # el mismo cuerpo, URL estable
curl -H 'Accept: application/json' https://dribba.com/precios

El sitio completo se publica también como bundle Open Knowledge Format v0.2 —un árbol de markdown con front matter YAML— y como llms.txt / llms-full.txt.

Línea de comandos

La API está pensada para usarse con curl y jq sin instalar nada:

curl -s https://dribba.com/api/v1/cases | jq -r '.items[] | "\(.slug)\t\(.industry)"'
curl -s https://dribba.com/api/v1/jobs  | jq -r '.items[].title'

Cuando publiquemos un cliente de línea de comandos con nombre propio, se anunciará aquí y en llms.txt.

Otros protocolos

Tres cosas más que responde este dominio y que no son la API REST:

  • NLWeb. POST /ask con {"query":"..."} devuelve pasajes literales del sitio con su URL. Con prefer: streaming=true llegan por SSE (start, result, complete). No genera texto: devuelve el pasaje y la síntesis la haces tú, que para eso tienes un modelo.
  • Vista de agente. Añade ?mode=agent a cualquier URL y en vez de la página sale el briefing operativo: endpoints, límites, protocolos y a dónde ir para cada trabajo.
  • Índices por área. /api/llms.txt, /docs/llms.txt y /developers/llms.txt dan el contexto de una sola área en vez del mapa entero del sitio.

Soporte

Dudas de integración, un campo que necesitas o un error que no cuadra: hola@dribba.com. Respondemos en menos de una hora en horario laboral (CET).

Si lo que buscas es contratarnos —producto digital de punta a punta, Flutter, Go o integración de IA— el sitio empieza en /servicios y las reuniones se reservan en /meet.