{"openapi":"3.1.0","info":{"title":"YopCreations Agent Commerce API","version":"1.0.0","description":"Catálogo público, presupuestos completos y enlaces de pago Stripe. No procesa tarjetas ni acredita un pedido como pagado. No es una implementación del protocolo ACP ni una integración nativa con ChatGPT."},"servers":[{"url":"https://yopcreations.es"}],"paths":{"/api/agent/v1/products":{"get":{"operationId":"searchProducts","parameters":[{"name":"q","in":"query","schema":{"type":"string","maxLength":100}},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0,"default":0}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":50,"default":20}}],"responses":{"200":{"description":"Respuesta JSON","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Error explicativo. 409: total cambiado, conflicto de clave o pedido en proceso. 429: espera Retry-After. 503: reintentar con la misma clave de compra."},"401":{"description":"Error explicativo. 409: total cambiado, conflicto de clave o pedido en proceso. 429: espera Retry-After. 503: reintentar con la misma clave de compra."},"403":{"description":"Error explicativo. 409: total cambiado, conflicto de clave o pedido en proceso. 429: espera Retry-After. 503: reintentar con la misma clave de compra."},"409":{"description":"Error explicativo. 409: total cambiado, conflicto de clave o pedido en proceso. 429: espera Retry-After. 503: reintentar con la misma clave de compra."},"422":{"description":"Error explicativo. 409: total cambiado, conflicto de clave o pedido en proceso. 429: espera Retry-After. 503: reintentar con la misma clave de compra."},"429":{"description":"Error explicativo. 409: total cambiado, conflicto de clave o pedido en proceso. 429: espera Retry-After. 503: reintentar con la misma clave de compra."},"503":{"description":"Error explicativo. 409: total cambiado, conflicto de clave o pedido en proceso. 429: espera Retry-After. 503: reintentar con la misma clave de compra."}}}},"/api/agent/v1/products/{id}":{"get":{"operationId":"getProduct","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Respuesta JSON","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Error explicativo. 409: total cambiado, conflicto de clave o pedido en proceso. 429: espera Retry-After. 503: reintentar con la misma clave de compra."},"401":{"description":"Error explicativo. 409: total cambiado, conflicto de clave o pedido en proceso. 429: espera Retry-After. 503: reintentar con la misma clave de compra."},"403":{"description":"Error explicativo. 409: total cambiado, conflicto de clave o pedido en proceso. 429: espera Retry-After. 503: reintentar con la misma clave de compra."},"404":{"description":"No encontrado"},"409":{"description":"Error explicativo. 409: total cambiado, conflicto de clave o pedido en proceso. 429: espera Retry-After. 503: reintentar con la misma clave de compra."},"422":{"description":"Error explicativo. 409: total cambiado, conflicto de clave o pedido en proceso. 429: espera Retry-After. 503: reintentar con la misma clave de compra."},"429":{"description":"Error explicativo. 409: total cambiado, conflicto de clave o pedido en proceso. 429: espera Retry-After. 503: reintentar con la misma clave de compra."},"503":{"description":"Error explicativo. 409: total cambiado, conflicto de clave o pedido en proceso. 429: espera Retry-After. 503: reintentar con la misma clave de compra."}}}},"/api/agent/v1/services":{"get":{"operationId":"getCustomServices","responses":{"200":{"description":"Respuesta JSON","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/api/agent/v1/session":{"post":{"operationId":"startOrRefreshShoppingSession","description":"Crear solo al comenzar una compra, nunca al rastrear o leer el catálogo. Guardar y reutilizar la sesión. Si caduca, renovar con refresh_token.","requestBody":{"required":true,"content":{"application/json":{"schema":{"oneOf":[{"type":"object","required":["purpose"],"properties":{"purpose":{"const":"purchase"}}},{"type":"object","required":["refresh_token"],"properties":{"refresh_token":{"type":"string"}}}]}}}},"responses":{"200":{"description":"Respuesta JSON","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Error explicativo. 409: total cambiado, conflicto de clave o pedido en proceso. 429: espera Retry-After. 503: reintentar con la misma clave de compra."},"401":{"description":"Error explicativo. 409: total cambiado, conflicto de clave o pedido en proceso. 429: espera Retry-After. 503: reintentar con la misma clave de compra."},"403":{"description":"Error explicativo. 409: total cambiado, conflicto de clave o pedido en proceso. 429: espera Retry-After. 503: reintentar con la misma clave de compra."},"409":{"description":"Error explicativo. 409: total cambiado, conflicto de clave o pedido en proceso. 429: espera Retry-After. 503: reintentar con la misma clave de compra."},"422":{"description":"Error explicativo. 409: total cambiado, conflicto de clave o pedido en proceso. 429: espera Retry-After. 503: reintentar con la misma clave de compra."},"429":{"description":"Error explicativo. 409: total cambiado, conflicto de clave o pedido en proceso. 429: espera Retry-After. 503: reintentar con la misma clave de compra."},"503":{"description":"Error explicativo. 409: total cambiado, conflicto de clave o pedido en proceso. 429: espera Retry-After. 503: reintentar con la misma clave de compra."}}}},"/api/reference-photos/upload":{"post":{"operationId":"uploadReferencePhoto","security":[{"shoppingSession":[]}],"description":"Subir el archivo autorizado por el cliente; máximo 3 MB, JPG/PNG/WebP. Guardar la ruta devuelta para reference_photos.","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file","path"],"properties":{"file":{"type":"string","format":"binary"},"path":{"type":"string","description":"orders/{user_id}/{UUID-del-archivo}.webp (o .jpg/.png). Usa un nombre único."}}}}}},"responses":{"200":{"description":"Respuesta JSON","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Error explicativo. 409: total cambiado, conflicto de clave o pedido en proceso. 429: espera Retry-After. 503: reintentar con la misma clave de compra."},"401":{"description":"Error explicativo. 409: total cambiado, conflicto de clave o pedido en proceso. 429: espera Retry-After. 503: reintentar con la misma clave de compra."},"403":{"description":"Error explicativo. 409: total cambiado, conflicto de clave o pedido en proceso. 429: espera Retry-After. 503: reintentar con la misma clave de compra."},"409":{"description":"Error explicativo. 409: total cambiado, conflicto de clave o pedido en proceso. 429: espera Retry-After. 503: reintentar con la misma clave de compra."},"422":{"description":"Error explicativo. 409: total cambiado, conflicto de clave o pedido en proceso. 429: espera Retry-After. 503: reintentar con la misma clave de compra."},"429":{"description":"Error explicativo. 409: total cambiado, conflicto de clave o pedido en proceso. 429: espera Retry-After. 503: reintentar con la misma clave de compra."},"503":{"description":"Error explicativo. 409: total cambiado, conflicto de clave o pedido en proceso. 429: espera Retry-After. 503: reintentar con la misma clave de compra."}}}},"/api/agent/v1/quote":{"post":{"operationId":"quoteOrder","security":[{"shoppingSession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Order"}}}},"responses":{"200":{"description":"Respuesta JSON","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Error explicativo. 409: total cambiado, conflicto de clave o pedido en proceso. 429: espera Retry-After. 503: reintentar con la misma clave de compra."},"401":{"description":"Error explicativo. 409: total cambiado, conflicto de clave o pedido en proceso. 429: espera Retry-After. 503: reintentar con la misma clave de compra."},"403":{"description":"Error explicativo. 409: total cambiado, conflicto de clave o pedido en proceso. 429: espera Retry-After. 503: reintentar con la misma clave de compra."},"409":{"description":"Error explicativo. 409: total cambiado, conflicto de clave o pedido en proceso. 429: espera Retry-After. 503: reintentar con la misma clave de compra."},"422":{"description":"Error explicativo. 409: total cambiado, conflicto de clave o pedido en proceso. 429: espera Retry-After. 503: reintentar con la misma clave de compra."},"429":{"description":"Error explicativo. 409: total cambiado, conflicto de clave o pedido en proceso. 429: espera Retry-After. 503: reintentar con la misma clave de compra."},"503":{"description":"Error explicativo. 409: total cambiado, conflicto de clave o pedido en proceso. 429: espera Retry-After. 503: reintentar con la misma clave de compra."}},"description":"Calcula todos los conceptos sin crear pedidos ni sesiones Stripe. Los precios, regalos y envío proceden del mismo motor que la web. No reserva stock."}},"/api/agent/v1/checkout":{"post":{"operationId":"createCheckout","security":[{"shoppingSession":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","format":"uuid"},"description":"Una UUID por compra; reutilizar en cada reintento con el mismo contenido."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Order"}}}},"responses":{"200":{"description":"Respuesta JSON","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Error explicativo. 409: total cambiado, conflicto de clave o pedido en proceso. 429: espera Retry-After. 503: reintentar con la misma clave de compra."},"401":{"description":"Error explicativo. 409: total cambiado, conflicto de clave o pedido en proceso. 429: espera Retry-After. 503: reintentar con la misma clave de compra."},"403":{"description":"Error explicativo. 409: total cambiado, conflicto de clave o pedido en proceso. 429: espera Retry-After. 503: reintentar con la misma clave de compra."},"409":{"description":"Error explicativo. 409: total cambiado, conflicto de clave o pedido en proceso. 429: espera Retry-After. 503: reintentar con la misma clave de compra."},"422":{"description":"Error explicativo. 409: total cambiado, conflicto de clave o pedido en proceso. 429: espera Retry-After. 503: reintentar con la misma clave de compra."},"429":{"description":"Error explicativo. 409: total cambiado, conflicto de clave o pedido en proceso. 429: espera Retry-After. 503: reintentar con la misma clave de compra."},"503":{"description":"Error explicativo. 409: total cambiado, conflicto de clave o pedido en proceso. 429: espera Retry-After. 503: reintentar con la misma clave de compra."}},"description":"Crea un pedido pendiente y devuelve url de Stripe, total_cents, status awaiting_payment y expires_at. Requiere confirmación del total y términos. Crear el enlace no paga el pedido. No reintentar con otra clave si se desconoce el resultado."}}},"components":{"securitySchemes":{"shoppingSession":{"type":"http","scheme":"bearer","bearerFormat":"Supabase JWT"}},"schemas":{"Order":{"type":"object","additionalProperties":false,"required":["items","address"],"properties":{"items":{"type":"array","minItems":1,"maxItems":20,"items":{"oneOf":[{"type":"object","additionalProperties":false,"required":["kind","product_id"],"properties":{"kind":{"const":"catalog"},"product_id":{"type":"string","format":"uuid"},"quantity":{"type":"integer","minimum":1,"maximum":50,"default":1}}},{"type":"object","additionalProperties":false,"required":["kind","service","reference_photos","details"],"properties":{"kind":{"const":"personalized"},"service":{"type":"string","enum":["funko_individual","funko_couple","funko_pet","kit_individual","kit_couple","kit_pet","cartoon_individual","cartoon_couple"]},"quantity":{"type":"integer","minimum":1,"maximum":50,"default":1},"reference_photos":{"type":"array","minItems":1,"maxItems":10,"items":{"type":"string"},"description":"Rutas devueltas por la subida autenticada. Solo se aceptan fotos de la misma sesión, nunca URLs externas."},"details":{"type":"string","minLength":1,"maxLength":2000,"description":"Pose, ropa, colores, identidad de cada persona/mascota y detalles del encargo. Describe también cada extra seleccionado."},"name_on_base":{"type":"string","maxLength":40,"description":"Solo Funko con campaña activa."},"box_name":{"type":"string","maxLength":100},"accessories":{"type":"array","maxItems":12,"uniqueItems":true,"items":{"enum":["guitar","weapon","bag","surfboard","racket","piano","djtable","drums","bike","motorcycle","car"]}},"free_accessory_id":{"enum":["guitar","weapon","bag","surfboard","racket","piano","djtable","drums","bike","motorcycle","car"],"description":"Solo Funko con campaña activa; debe estar incluido en accessories. Como máximo uno gratis."},"small_accessories_count":{"type":"integer","minimum":0,"maximum":3,"default":0},"logos_count":{"type":"integer","minimum":0,"maximum":3,"default":0},"extra_people":{"type":"integer","minimum":0,"maximum":2,"default":0},"extra_pets":{"type":"integer","minimum":0,"maximum":2,"default":0},"pet_size":{"enum":["small","medium","large"],"description":"Solo mascotas."},"cartoon_base":{"enum":["simple","texto","diorama"],"description":"Solo Cartoon."},"urgent":{"type":"boolean","default":false},"requested_delivery_date":{"type":"string","format":"date"}}}]}},"address":{"type":"object","additionalProperties":false,"required":["first_name","last_name","email","phone","address","city","state","zip_code","country"],"properties":{"first_name":{"type":"string"},"last_name":{"type":"string"},"email":{"type":"string","format":"email"},"phone":{"type":"string"},"address":{"type":"string"},"city":{"type":"string"},"state":{"type":"string"},"zip_code":{"type":"string"},"country":{"type":"string","description":"Nombre del país, por ejemplo España. La cobertura se comprueba al cotizar."}}},"coupon_code":{"type":"string","maxLength":30},"expected_total_cents":{"type":"integer","minimum":1,"description":"Obligatorio para checkout: total_cents devuelto por quote y aceptado por el cliente."},"terms_accepted":{"type":"boolean","description":"Obligatorio true para checkout después de que el cliente acepte los términos."}}}}}}