{"openapi":"3.1.0","info":{"title":"API de reservas · Ridelta - Taxi y VTC","version":"1.0.0","description":"Presupuesto y reserva de traslados en vehículo con conductor (VTC) en Castilla-La Mancha. El servicio exige contratación previa: toda reserva queda registrada con su fecha y hora de solicitud. Los precios incluyen IVA y son vinculantes salvo cambio de recorrido, paradas añadidas o espera prolongada.","contact":{"email":"reservas@taxitoledo.app"}},"servers":[{"url":"https://taxitoledo.app"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"Clave de partner del titular, o clave de afiliado (prefijo «afi_»), que además atribuye a ese afiliado toda reserva creada con ella."},"apiKey":{"type":"apiKey","in":"header","name":"X-API-Key"}},"parameters":{"MarketId":{"name":"X-Market-Id","in":"header","required":false,"schema":{"type":"string","example":"co-bogota"},"description":"El mercado en el que se presupuesta o reserva (`GLO-12`): uno de los `id` de `GET /api/mercados`. Sin cabecera, el mercado lo decide el dominio por el que se entra, y en los de Castilla-La Mancha es el de casa. Los importes vuelven en la moneda del mercado. Una clave acotada a unos mercados recibe 403 fuera de ellos."}},"schemas":{"Parada":{"type":"object","required":["address","municipality","lat","lng"],"properties":{"address":{"type":"string","example":"Calle Mayor 3"},"municipality":{"type":"string","description":"El municipio de la parada, no el texto escrito: de él depende que la parada quepa en una tarifa municipal regulada.","example":"Toledo"},"province":{"type":"string"},"region":{"type":"string"},"lat":{"type":"number","description":"Obligatoria. Sin coordenadas no hay tramo que medir, y un desvío que no se puede medir no se puede cobrar."},"lng":{"type":"number"},"waitMinutes":{"type":"integer","minimum":0,"maximum":240,"default":0,"description":"Espera pactada en la parada. Cero es «para y sigue». Se cobra por minuto al precio de espera de la tarifa —no por hora empezada— y cuenta como tiempo ocupado en la agenda del día. Con el vehículo contratado por horas no se cobra: ya está dentro del tiempo contratado."},"notes":{"type":"string","maxLength":200},"position":{"type":"integer","description":"Orden dentro del recorrido, solo al leer. 1 es la primera tras la recogida."},"arrivedAt":{"type":"string","description":"Cuándo marcó el conductor el paso por la parada, solo al leer. `null` si todavía no."},"departedAt":{"type":"string","description":"Cuándo siguió desde ella, solo al leer. La diferencia con `arrivedAt` es la espera que hubo; la que se cobra es la pactada."}}},"PresupuestoPeticion":{"type":"object","required":["origin","destination","pickupAt"],"properties":{"origin":{"type":"string","example":"Illescas"},"destination":{"type":"string","example":"Aeropuerto Madrid-Barajas"},"pickupAt":{"type":"string","description":"Fecha y hora local, formato YYYY-MM-DDTHH:mm","example":"2026-10-04T05:30"},"returnAt":{"type":"string","description":"Vuelta, si se contrata a la vez. Se presupuesta como segundo trayecto."},"passengers":{"type":"integer","minimum":1,"maximum":8,"default":1},"hours":{"type":"number","minimum":1,"maximum":12,"description":"Horas contratadas. Con horas el precio sale de la tarifa por hora y el recorrido no se cobra además: es el vehículo a disposición."},"categorySlug":{"type":"string","description":"Categoría de vehículo"},"originLat":{"type":"number","description":"Coordenadas del punto de recogida. Sin ellas se resuelve el texto contra el catálogo de lugares, que basta para un municipio y no para un portal concreto."},"originLng":{"type":"number"},"originMunicipality":{"type":"string","description":"El municipio del punto elegido, no el texto escrito. De él dependen la regla de ámbito urbano y la ordenanza que aplique: «Calle Mayor 3» no es un municipio."},"originProvince":{"type":"string"},"originRegion":{"type":"string"},"destinationLat":{"type":"number"},"destinationLng":{"type":"number"},"destinationMunicipality":{"type":"string"},"destinationProvince":{"type":"string"},"destinationRegion":{"type":"string"},"stops":{"type":"array","maxItems":5,"description":"Paradas intermedias, en el orden en que se hacen. Cinco como mucho: un trayecto con quince paradas no es un traslado, es un servicio por horas, y se contrata así (`hours`).","items":{"$ref":"#/components/schemas/Parada"}}}},"Presupuesto":{"type":"object","properties":{"total":{"type":"number","description":"Importe total con IVA incluido"},"distanceKm":{"type":"number"},"durationMin":{"type":"integer"},"approximate":{"type":"boolean"},"breakdown":{"type":"array","items":{"type":"object","properties":{"concept":{"type":"string"},"amount":{"type":"number"}}}},"categoryPrices":{"type":"array","items":{"type":"object"}},"stops":{"type":"object","nullable":true,"description":"Qué se ha decidido sobre las paradas pedidas. `null` si no se pidió ninguna.\n\n**`accepted: false` hay que enseñarlo**: significa que `total` es el del trayecto directo —el presupuesto informa, no bloquea— y que el alta va a rechazar esas paradas con este mismo motivo. Un precio sin las paradas presentado como si las llevara devuelve las paradas al campo de observaciones, ahora con un importe delante.","properties":{"accepted":{"type":"boolean","description":"El servicio se puede contratar con estas paradas"},"charged":{"type":"boolean","description":"Su recorrido y su espera se cobran aparte"},"code":{"type":"string","enum":["admitidas","incluidas_en_las_horas","precio_cerrado","fuera_del_municipio","sin_precio_de_espera"]},"reason":{"type":"string","nullable":true,"description":"El motivo, redactado para enseñarlo"},"count":{"type":"integer"},"waitMinutes":{"type":"integer","description":"Espera pactada entre todas las paradas"},"directKm":{"type":"number","description":"El trayecto directo, que es el suelo del precio"},"legs":{"type":"array","description":"Un tramo por cada par de puntos consecutivos, en orden.","items":{"type":"object","properties":{"desde":{"type":"string"},"hasta":{"type":"string"},"distanceKm":{"type":"number"},"durationMin":{"type":"integer"},"approximate":{"type":"boolean"}}}}}},"availability":{"type":"object","description":"Si la hora pedida es atendible, y el siguiente hueco si no lo es"},"partner":{"type":"object","nullable":true,"description":"El precio para el partner de la clave, según su modo: público (el mismo), neto (público menos su comisión) o con descuento. `total` sigue siendo el público, que es el de la reserva. El descuento topa en el 40 %, nunca baja del servicio mínimo de la tarifa y no se aplica a un importe que fija una ordenanza.","properties":{"label":{"type":"string"},"publicTotal":{"type":"number"},"total":{"type":"number","description":"Lo que paga el partner"},"mode":{"type":"string","enum":["publico","neto","descuento"]},"percent":{"type":"number","nullable":true},"capped":{"type":"boolean","description":"El descuento se ha recortado, por el servicio mínimo de la tarifa o por el tope del 40 %. Cuando es cierto, «percent» es el porcentaje que de verdad se ha aplicado, no el pactado."},"description":{"type":"string"}}}}},"ReservaPeticion":{"type":"object","required":["fullName","phone","email","originAddress","originMunicipality","destinationAddress","destinationMunicipality","pickupAt","privacyAccepted"],"properties":{"fullName":{"type":"string"},"phone":{"type":"string"},"email":{"type":"string","format":"email"},"originAddress":{"type":"string"},"originMunicipality":{"type":"string"},"destinationAddress":{"type":"string"},"destinationMunicipality":{"type":"string"},"pickupAt":{"type":"string"},"returnAt":{"type":"string","description":"Vuelta, si se contrata a la vez. Con precio cerrado la vuelta se guarda como otra reserva y las dos se pagan con un solo cobro: la respuesta trae su código en `vuelta`."},"passengers":{"type":"integer"},"hours":{"type":"number","minimum":1,"maximum":12,"description":"Horas contratadas, solo en serviceType DISPOSICION o EVENTO. Con horas el precio sale de la tarifa por hora."},"luggage":{"type":"integer"},"childSeats":{"type":"integer"},"pets":{"type":"boolean"},"flightNumber":{"type":"string"},"notes":{"type":"string"},"travelsOther":{"type":"boolean","description":"Viaja otra persona (huésped, paciente, familiar). Sin mandarlo basta con enviar passengerName o passengerPhone; con false se ignoran los dos."},"passengerName":{"type":"string","maxLength":120,"description":"Nombre de quien viaja, si no es quien contrata. Es el que ve el conductor y el que va en el cartel del aeropuerto."},"passengerPhone":{"type":"string","description":"Teléfono de quien viaja: al que llama el conductor y por el que se le avisa. Quien contrata sigue siendo fullName/phone, y suya es la factura."},"cobroDelCanal":{"type":"boolean","description":"Solo con una clave con la marca `cobra` (ADR 0405): el canal cobra al cliente por su cuenta. La reserva nace como pago en línea esperando el cobro, sin pasarela aquí, y se confirma cuando el canal lo comunica en `POST /api/v1/reservas/{code}/pago`. Sin la marca, `403`."},"paymentMethod":{"type":"string","enum":["EFECTIVO","TARJETA_A_BORDO","TRANSFERENCIA","PAGO_ONLINE","FACTURA_EMPRESA"]},"originLat":{"type":"number"},"originLng":{"type":"number"},"originProvince":{"type":"string"},"originRegion":{"type":"string"},"destinationLat":{"type":"number"},"destinationLng":{"type":"number"},"destinationProvince":{"type":"string"},"destinationRegion":{"type":"string"},"stops":{"type":"array","maxItems":5,"description":"Las mismas paradas que en el presupuesto. Si no caben en el régimen que rige el trayecto, o si una de ellas convierte un tramo en urbano, el alta contesta `422` y **no crea la reserva**.","items":{"$ref":"#/components/schemas/Parada"}},"privacyAccepted":{"type":"boolean","description":"Consentimiento del pasajero, obligatorio (RGPD)"}}}}},"paths":{"/api/mercados":{"get":{"summary":"Ciudades donde se puede reservar","description":"Los mercados publicados, con centro, radio, moneda, idiomas y dominio. Con `lat` y `lng` devuelve además `cercano`: el que cubre ese punto, o `null`. Público, sin clave. Es la lista de valores válidos de `X-Market-Id`.","security":[],"parameters":[{"name":"lat","in":"query","schema":{"type":"number"}},{"name":"lng","in":"query","schema":{"type":"number"}}],"responses":{"200":{"description":"Mercados publicados","content":{"application/json":{"schema":{"type":"object","properties":{"mercados":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","example":"co-bogota"},"nombre":{"type":"string"},"ciudad":{"type":"string","nullable":true},"pais":{"type":"string","example":"CO"},"moneda":{"type":"string","example":"COP"},"idiomas":{"type":"array","items":{"type":"string"}},"zonaHoraria":{"type":"string"},"centro":{"type":"object","nullable":true,"properties":{"lat":{"type":"number"},"lng":{"type":"number"}}},"radioKm":{"type":"number"},"dominio":{"type":"string","nullable":true},"oferta":{"type":"string","enum":["EXTERNO_PRIMERO","MIXTO","PROPIO"]}}}}}}}}}},"tags":["Mercados"]}},"/api/v1/presupuesto":{"post":{"parameters":[{"$ref":"#/components/parameters/MarketId"}],"summary":"Precio de un traslado","description":"Devuelve el importe con IVA incluido, la distancia, el tiempo y el desglose. Es el mismo cálculo que usa la web y el que se cobra al reservar. En `partner` va además el precio para la clave que llama, según su modo (público, neto o con descuento). Con `stops` el recorrido se parte en tramos y el precio sale del encadenado, nunca por debajo del directo; `stops.accepted: false` significa que el importe es el del directo y que el alta las va a rechazar.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PresupuestoPeticion"}}}},"responses":{"200":{"description":"Presupuesto","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Presupuesto"}}}},"401":{"description":"Clave no válida"},"422":{"description":"Punto no reconocido o fuera de ámbito"},"429":{"description":"Límite de peticiones superado"}},"tags":["Precios"]}},"/api/v1/reservas":{"post":{"parameters":[{"$ref":"#/components/parameters/MarketId"}],"summary":"Crear una reserva","description":"Registra la contratación previa. La reserva queda atribuida al partner de la clave. Devuelve el código de seguimiento.\n\nCon `stops`, el alta **corta**: si el régimen de tarifa no admite las paradas, o si una de ellas convierte un tramo del recorrido en un trayecto urbano que la autorización no habilita, contesta `422` con el motivo y no crea nada. El presupuesto informa; esta es la puerta que no se puede saltar.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReservaPeticion"}}}},"responses":{"201":{"description":"Reserva creada"},"400":{"description":"Datos incompletos"},"401":{"description":"Clave no válida"},"409":{"description":"Horario no disponible"},"422":{"description":"Trayecto fuera de ámbito, o paradas que no caben. El cuerpo lleva `error` con el motivo y, cuando son las paradas, `stops.code` y `stops.reason`: el código del régimen de tarifa (`precio_cerrado`, `fuera_del_municipio`, `sin_precio_de_espera`) o `fuera_de_ambito` cuando una parada convierte un tramo del recorrido en un trayecto que la autorización no habilita, y entonces `stops.leg` dice cuál."}},"tags":["Reservas"]}},"/api/v1/reservas/{code}":{"get":{"summary":"Estado de una reserva","parameters":[{"name":"code","in":"path","required":true,"schema":{"type":"string"},"description":"Código de seguimiento"}],"responses":{"200":{"description":"Estado, vehículo y conductor asignados, y `stops[]` con las paradas del trayecto: su orden, su espera pactada y —cuando el conductor lo ha marcado— la hora a la que pasó por cada una y a la que siguió. En un traslado de aeropuerto, con el control de vuelos encendido, incluye `flight`: estado del vuelo, hora real o prevista, retraso, terminal, cinta de equipajes y punto de recogida."},"404":{"description":"No encontrada"}},"tags":["Reservas"]}},"/api/v1/reservas/{code}/cancelar":{"post":{"summary":"Cancela una reserva propia","description":"Solo las reservas que entraron con esta misma clave. Aplica la política de cancelación publicada y devuelve lo que corresponda.","parameters":[{"name":"code","in":"path","required":true,"schema":{"type":"string"},"description":"Código de seguimiento"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"motivo":{"type":"string","maxLength":200}}}}}},"responses":{"200":{"description":"Cancelada, con el detalle de la devolución"},"403":{"description":"La reserva no es de esta clave"},"404":{"description":"No encontrada"},"409":{"description":"Ya cancelada o servicio en marcha"}},"tags":["Reservas"]}},"/api/v1/reservas/{code}/hora":{"post":{"summary":"Cambia la hora de una reserva propia","description":"Con `previsualizar: true` solo contesta si es posible y con qué importe. Sin eso, mueve la reserva. No se mueve si la hoja de ruta ya está emitida, si el servicio está en marcha, si la hora nueva no está disponible, o si está pagada y la hora nueva es más cara.","parameters":[{"name":"code","in":"path","required":true,"schema":{"type":"string"},"description":"Código de seguimiento"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["recogidaEn"],"properties":{"recogidaEn":{"type":"string","example":"2026-09-20T07:30","description":"Fecha y hora locales de la recogida nueva"},"previsualizar":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Hora nueva, importe y si ha quedado sin conductor"},"403":{"description":"La reserva no es de esta clave"},"404":{"description":"No encontrada"},"409":{"description":"No se puede mover: el motivo va en la respuesta"}},"tags":["Reservas"]}},"/api/v1/reservas/{code}/pago":{"post":{"summary":"El canal comunica que ha cobrado su reserva","description":"Solo con una clave con la marca `cobra` y solo sobre reservas dadas de alta con esa misma clave y `cobroDelCanal`. El importe y la moneda tienen que ser los de la reserva (un céntimo de tolerancia). Registra el cobro y confirma la reserva por el mismo camino que un cobro de la pasarela. Repetir con la misma `referencia` no crea otro pago (`repetido: true`).","parameters":[{"name":"code","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["importe","moneda","referencia"],"properties":{"importe":{"type":"number","example":95.5},"moneda":{"type":"string","example":"EUR"},"referencia":{"type":"string","description":"Referencia del cobro en el canal (su pedido)","example":"RMD-7F3K/0c1a2b"}}}}}},"responses":{"200":{"description":"Cobro registrado: `estado` y `pago` de la reserva tras confirmarla"},"400":{"description":"Faltan importe, moneda o referencia"},"403":{"description":"La clave no lleva la marca `cobra`"},"404":{"description":"No hay una reserva de este canal con ese código"},"409":{"description":"Cerrada, ya pagada, sin precio o no dada de alta como cobrada por el canal"},"422":{"description":"Importe o moneda distintos de los de la reserva"}},"tags":["Reservas"]}},"/api/v1/proveedores":{"post":{"summary":"Solicitud de alta de una empresa de traslados desde un canal","description":"La misma solicitud de flota que la del formulario público: queda en la cola de captación de flotas con el origen `api:<etiqueta de la clave>`, y la empresa puede dar servicio a todo lo que se vende, no solo al canal.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["legalName","contactName","email","phone"],"properties":{"kind":{"type":"string","enum":["VTC","TAXI","MIXTA"]},"legalName":{"type":"string"},"tradeName":{"type":"string"},"nif":{"type":"string"},"contactName":{"type":"string"},"email":{"type":"string","format":"email"},"phone":{"type":"string"},"province":{"type":"string"},"municipalities":{"type":"string"},"vehicles":{"type":"integer"},"drivers":{"type":"integer"},"vtcAuthorizations":{"type":"integer"},"taxiLicenses":{"type":"integer"},"message":{"type":"string"}}}}}},"responses":{"201":{"description":"Solicitud registrada: `referencia` es su identificador"},"400":{"description":"Datos incompletos"},"401":{"description":"Clave no válida"}},"tags":["Proveedores"]}},"/api/v1/rutas":{"get":{"summary":"Catálogo de rutas con precio de referencia","description":"Público, sin clave. Pensado para agregadores y asistentes.","security":[],"parameters":[{"name":"provincia","in":"query","schema":{"type":"string"},"description":"Slug de provincia, o «todas»"},{"name":"ref","in":"query","schema":{"type":"string"},"description":"Código de afiliado. Las direcciones del catálogo salen etiquetadas con él, para poder publicar una tabla de precios ya medida."}],"responses":{"200":{"description":"Catálogo"}},"tags":["Catálogo"]}},"/api/v1/productos":{"get":{"summary":"Fichas de los productos turísticos con precio cerrado","description":"Nombre, duración, pasajeros, paradas con su municipio, qué incluye y el importe público con IVA de cada producto turístico publicable. Los que no se pueden publicar salen en `descartados` con el motivo. Público, sin clave: es lo mismo que está impreso en la página de cada producto. El precio de canal sale por el feed, con clave.","security":[],"responses":{"200":{"description":"`publicados[]` y `descartados[]` con su motivo"}},"tags":["Catálogo"]}},"/api/v1/estaciones/{id}/traslados":{"get":{"summary":"Traslados desde una estación, para pintarlos en un producto cruzado","description":"Público, sin clave (ADR 0373). Para webs satélite como radartrenes.com: el traslado que toca desde la estación, con su precio «desde» y su enlace de reserva, y un enlace limpio a la página canónica en el dominio territorial que presta el servicio. Recoger en Madrid depende del cupo de socios y la respuesta lo marca. Reglas para no perder posicionamiento: docs/SATELITES-Y-API.md.","security":[],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Estación vigilada: toledo, madrid-atocha…"},{"name":"producto","in":"query","schema":{"type":"string"},"description":"Producto cruzado del catálogo (radartrenes…); etiqueta las reservas con su UTM"},{"name":"idioma","in":"query","schema":{"type":"string","enum":["es","en"]}}],"responses":{"200":{"description":"Estación, proveedor, enlace limpio y traslados"},"400":{"description":"«producto» no es del catálogo"},"404":{"description":"Estación sin traslados publicados"}},"tags":["Catálogo"]}},"/api/v1/feed/{formato}":{"get":{"summary":"Feed de rutas y precios para un marketplace","description":"Rutas con precio por categoría de vehículo, tiempo y antelación mínima, al precio de la clave que llama. Formatos: «csv» (columnas genéricas del sector) y «json». Requiere una clave con la marca «feed» y con un modo de precio que descuente algo: a precio público la comisión del marketplace saldría de nuestro margen y se contesta 409. No publica disponibilidad: cada fila sale como «bajo_confirmacion» con su antelación mínima. Solo se publican rutas cuyo precio respaldaría el sistema en una reserva real —ni distancias estimadas, ni el precio de una flota con tarifa propia—; lo descartado viaja en «descartadas» (JSON) o en las cabeceras X-VTC-Feed-* (CSV).","parameters":[{"name":"formato","in":"path","required":true,"schema":{"type":"string","enum":["csv","json"]}},{"name":"provincia","in":"query","schema":{"type":"string"},"description":"Slug de provincia, o «todas»"}],"responses":{"200":{"description":"Feed"},"403":{"description":"La clave no tiene el feed habilitado"},"404":{"description":"Formato no disponible"},"409":{"description":"La clave trabaja a precio público"}},"tags":["Feed"]}},"/api/v1/afiliado":{"get":{"summary":"Estado de la cuenta de afiliado","description":"Condiciones, cifras del periodo y saldo disponible. Requiere una clave «afi_». No devuelve datos de los pasajeros: la comisión se paga por la recomendación, no por el viaje.","parameters":[{"name":"dias","in":"query","schema":{"type":"integer","default":30,"minimum":1,"maximum":365},"description":"Ventana de las cifras"}],"responses":{"200":{"description":"Cuenta, condiciones, cifras y saldo"},"401":{"description":"Clave de afiliado no válida"}},"tags":["Afiliados"]}},"/api/v1/afiliado/conversiones":{"get":{"summary":"Conversiones del afiliado","description":"Lista paginada con el código del servicio, el importe, la comisión, el subid y el estado. Sirve para conciliar contra el sistema del afiliado.","parameters":[{"name":"estado","in":"query","schema":{"type":"string","enum":["PENDIENTE","APROBADA","RECHAZADA","LIQUIDADA"]}},{"name":"limite","in":"query","schema":{"type":"integer","default":50,"maximum":200}},{"name":"cursor","in":"query","schema":{"type":"string"},"description":"Identificador devuelto en «cursor» por la página anterior"}],"responses":{"200":{"description":"Conversiones"},"401":{"description":"Clave de afiliado no válida"}},"tags":["Afiliados"]}},"/api/v1/afiliado/feed/{formato}":{"get":{"summary":"Feed de datos del afiliado: catálogo atribuido o conversiones","description":"Con «tipo=catalogo» (por defecto), las rutas con su precio «desde» y dos enlaces por fila —la página de la ruta y el pedido con el trayecto puesto—, los dos por /r/<código> del afiliado que llama y con su «subid». Con «tipo=conversiones», sus conversiones sin datos del pasajero. La atribución sale de la clave «afi_» en la cabecera o del token de solo lectura «fd_» en la URL (para Google Sheets, WP All Import y lectores que no mandan cabeceras), nunca de un parámetro; el token caduca al regenerar o revocar la clave.","security":[{"bearer":[]},{}],"parameters":[{"name":"formato","in":"path","required":true,"schema":{"type":"string","enum":["csv","xml","json"]}},{"name":"tipo","in":"query","schema":{"type":"string","enum":["catalogo","conversiones"],"default":"catalogo"}},{"name":"token","in":"query","schema":{"type":"string","pattern":"^fd_[a-z0-9-]+\\.[A-Za-z0-9_-]{32}$"},"description":"Token de feed del panel, si no se manda la clave"},{"name":"subid","in":"query","schema":{"type":"string","maxLength":64},"description":"Etiqueta de seguimiento de los enlaces"},{"name":"provincia","in":"query","schema":{"type":"string"},"description":"Slug de provincia, o «todas»"},{"name":"dias","in":"query","schema":{"type":"integer","default":90,"minimum":1,"maximum":730},"description":"Ventana de las conversiones"}],"responses":{"200":{"description":"Feed en el formato pedido"},"401":{"description":"Sin clave ni token, o token no válido o caducado"},"404":{"description":"Formato no disponible"},"429":{"description":"Demasiadas peticiones o demasiados tokens fallidos"},"503":{"description":"El servidor no puede comprobar tokens (sin secreto configurado)"}},"tags":["Afiliados"]}},"/api/v1/afiliado/articulo":{"get":{"summary":"Borrador de un artículo dirigido para un trayecto","description":"Título, extracto, contenido HTML y etiquetas de un artículo sobre un trayecto del catálogo, con su precio «desde», distancia, tiempo y enlaces atribuidos al afiliado que llama (subid «articulo» por defecto). Lo usa el plugin de WordPress para crear un borrador: nunca se publica solo. Misma autenticación que el feed: clave «afi_» o token «fd_».","security":[{"bearer":[]},{}],"parameters":[{"name":"ruta","in":"query","required":true,"schema":{"type":"string","pattern":"^[a-z0-9-]{1,120}$"},"description":"Slug de la ruta del catálogo"},{"name":"token","in":"query","schema":{"type":"string"},"description":"Token de feed, si no se manda la clave"},{"name":"subid","in":"query","schema":{"type":"string","maxLength":64}}],"responses":{"200":{"description":"Borrador: titulo, extracto, contenido, etiquetas y estado «borrador»"},"401":{"description":"Sin clave ni token, o token no válido o caducado"},"404":{"description":"Trayecto no encontrado en el catálogo"},"429":{"description":"Demasiadas peticiones o demasiados tokens fallidos"}},"tags":["Afiliados"]}},"/api/v1/afiliado/enlaces":{"get":{"summary":"Enlaces del afiliado","responses":{"200":{"description":"Enlaces con su destino, su etiqueta y sus clics"},"401":{"description":"Clave de afiliado no válida"}},"tags":["Afiliados"]},"post":{"summary":"Crear un enlace medido","description":"Para generar un enlace por artículo desde el propio sistema del afiliado. El destino solo puede ser una ruta de este sitio; cualquier otra cosa se sustituye por la portada.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["nombre"],"properties":{"nombre":{"type":"string","example":"Artículo: cómo llegar a Barajas"},"destino":{"type":"string","example":"/rutas/illescas-a-aeropuerto-madrid-barajas"},"slug":{"type":"string","example":"barajas"},"subid":{"type":"string","example":"post-42"}}}}}},"responses":{"201":{"description":"Enlace creado, con su URL definitiva"},"400":{"description":"Falta el nombre"},"401":{"description":"Clave de afiliado no válida"},"409":{"description":"Máximo de enlaces alcanzado"}},"tags":["Afiliados"]}}},"tags":[{"name":"Mercados","description":"Dónde se puede reservar y con qué moneda e idiomas."},{"name":"Precios","description":"El presupuesto: el mismo cálculo que la web y el que se cobra."},{"name":"Reservas","description":"Alta, estado, cambio de hora, cancelación y cobro por el canal."},{"name":"Catálogo","description":"Rutas, productos y traslados desde estación, sin clave."},{"name":"Feed","description":"Rutas y precios de canal para un marketplace, con clave habilitada."},{"name":"Proveedores","description":"Alta de una empresa de traslados desde un canal."},{"name":"Afiliados","description":"Cifras, conversiones y enlaces del afiliado, con su clave `afi_`."}]}