{"openapi":"3.1.0","info":{"title":"Smart Sends Express API","version":"1.1.0","description":"API pública de Smart Sends Express para integraciones con VTEX, Shopify, WooCommerce, Magento, BigCommerce y desarrollos propios. Cotiza, crea envíos, rastrea paquetes y recibe webhooks firmados. Todas las operaciones mutantes aceptan el header `Idempotency-Key` para evitar duplicados en caso de reintento.","contact":{"name":"Smart Sends Express","url":"https://smartsendsllc.com/app","email":"dev@smartsendsllc.com"},"license":{"name":"Propietario"}},"servers":[{"url":"https://smartsendsllc.com/app/api/v1","description":"Producción"}],"security":[{"ApiKeyAuth":[]}],"tags":[{"name":"Cotizaciones","description":"Consultar tarifas multi-carrier"},{"name":"Envíos","description":"Crear, listar, cancelar envíos y descargar guías"},{"name":"Rastreo","description":"Consultar eventos de tracking"},{"name":"Direcciones","description":"Validar direcciones destino"},{"name":"Webhooks","description":"Configurar notificaciones outbound"},{"name":"E-commerce","description":"Endpoints listos para integrar con Shopify Carrier Service y VTEX Shipping Provider"}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"http","scheme":"bearer","bearerFormat":"API Key","description":"API key con prefijo `ss_live_`. Genera una desde tu dashboard en `/dashboard/developers`. Envíala en el header `Authorization: Bearer ss_live_...`."}},"parameters":{"IdempotencyKey":{"name":"Idempotency-Key","in":"header","required":false,"description":"UUID o string único ≤255 caracteres. Reintentos con la misma clave devuelven la misma respuesta sin volver a ejecutar la operación. Recomendado en TODAS las llamadas POST/PATCH.","schema":{"type":"string","example":"shp-8f42d7b1-a291-4c6e-9f0d-1b5e77e02c9a"}}},"headers":{"X-RateLimit-Limit":{"description":"Límite máximo de solicitudes por minuto","schema":{"type":"integer","example":60}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes en la ventana actual","schema":{"type":"integer","example":55}},"X-RateLimit-Reset":{"description":"Timestamp Unix cuando se renueva la ventana","schema":{"type":"integer","example":1711036800}},"Retry-After":{"description":"Segundos que el cliente debe esperar antes de reintentar tras un 429","schema":{"type":"integer","example":30}}},"schemas":{"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","enum":["VALIDATION_ERROR","UNAUTHORIZED","FORBIDDEN","NOT_FOUND","RATE_LIMITED","CARRIER_ERROR","INSUFFICIENT_BALANCE","INVOICE_REQUIRED","LABEL_GENERATION_FAILED","INTERNAL_ERROR"],"example":"VALIDATION_ERROR"},"message":{"type":"string","example":"Campo 'origin.city' es requerido"},"details":{"type":"object","additionalProperties":true,"description":"Contexto adicional para debugging"}}}}},"Address":{"type":"object","required":["city","country"],"properties":{"name":{"type":"string","example":"Juan Pérez"},"company":{"type":"string","example":"Acme Corp"},"phone":{"type":"string","example":"3001234567"},"email":{"type":"string","format":"email","example":"juan@acme.co"},"address":{"type":"string","example":"Cra 76 #29-32"},"address_2":{"type":"string","example":"Apto 402"},"city":{"type":"string","example":"Medellin"},"state":{"type":"string","example":"Antioquia"},"country":{"type":"string","description":"ISO 3166-1 alpha-2","example":"CO","minLength":2,"maxLength":2},"postal_code":{"type":"string","example":"050001"}}},"Package":{"type":"object","required":["weight_kg"],"properties":{"weight_kg":{"type":"number","example":2.5,"minimum":0.01},"length_cm":{"type":"number","example":30},"width_cm":{"type":"number","example":20},"height_cm":{"type":"number","example":15},"content":{"type":"string","example":"Ropa deportiva"},"declared_value":{"type":"number","example":50000,"description":"Valor declarado en la moneda local del origen"},"quantity":{"type":"integer","example":1,"minimum":1}}},"Quote":{"type":"object","required":["carrier","service_type","price","currency"],"properties":{"id":{"type":"string","example":"quote_a1b2c3d4e5f6"},"carrier":{"type":"string","example":"DHL"},"service":{"type":"string","example":"Express Worldwide"},"service_type":{"type":"string","description":"Slug estable del servicio","example":"dhl_express_worldwide"},"price":{"type":"number","example":285000},"currency":{"type":"string","example":"COP"},"estimated_days":{"type":"string","example":"2-3 días hábiles"},"carrier_account":{"type":"string","example":"690373480"}}},"Shipment":{"type":"object","required":["id","tracking_number","status"],"properties":{"id":{"type":"string","format":"uuid"},"tracking_number":{"type":"string","example":"SSE-A1B2C3D4"},"status":{"type":"string","enum":["creado","recolectado","en_transito","en_destino","intento_fallido","entregado","devuelto","cancelado"]},"service_type":{"type":"string","example":"dhl_express_worldwide"},"carrier":{"type":"string","example":"DHL"},"price":{"type":"number","example":285000},"currency":{"type":"string","example":"COP"},"origin_city":{"type":"string"},"dest_city":{"type":"string"},"weight_kg":{"type":"number"},"label_url":{"type":"string","format":"uri","nullable":true,"description":"URL firmada al PDF de la guía. Puede tardar segundos en estar disponible."},"tracking_url":{"type":"string","format":"uri","example":"https://smartsendsllc.com/rastreo/SSE-A1B2C3D4"},"created_at":{"type":"string","format":"date-time"}}},"TrackingEvent":{"type":"object","required":["timestamp","status"],"properties":{"timestamp":{"type":"string","format":"date-time"},"description":{"type":"string"},"location":{"type":"string"},"status":{"type":"string"}}},"WebhookConfig":{"type":"object","properties":{"url":{"type":"string","format":"uri","example":"https://mi-tienda.com/webhooks/smartsends"},"events":{"type":"array","items":{"type":"string","enum":["shipment.created","shipment.shipped","shipment.in_transit","shipment.delivered","shipment.cancelled","shipment.exception"]}},"secret":{"type":"string","description":"Solo devuelto una vez al crear/rotar. Úsalo para verificar el HMAC-SHA256 del header `X-SmartSends-Signature`.","example":"whsec_..."}}},"WebhookPayload":{"type":"object","required":["event","created_at","data"],"properties":{"event":{"type":"string","enum":["shipment.created","shipment.shipped","shipment.in_transit","shipment.delivered","shipment.cancelled","shipment.exception"]},"created_at":{"type":"string","format":"date-time"},"data":{"$ref":"#/components/schemas/Shipment"}}}},"responses":{"Unauthorized":{"description":"API key inválida o ausente","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"RateLimited":{"description":"Cuota excedida. Reintenta tras `Retry-After`.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"NotFound":{"description":"Recurso no encontrado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Validation":{"description":"Error de validación en la petición","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/quotes":{"post":{"summary":"Cotizar envío","tags":["Cotizaciones"],"operationId":"getQuotes","description":"Devuelve tarifas de múltiples carriers (DHL directo, TCC, Servientrega, Coordinadora, 4-72, Interrapidísimo, etc.) para un envío nacional o internacional.","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["origin","destination","package"],"properties":{"origin":{"$ref":"#/components/schemas/Address"},"destination":{"$ref":"#/components/schemas/Address"},"package":{"$ref":"#/components/schemas/Package"},"declared_value":{"type":"number","example":50000}}},"examples":{"nacional":{"summary":"Envío nacional CO Bogotá → Medellín","value":{"origin":{"city":"Bogota","state":"Cundinamarca","country":"CO","postal_code":"110111"},"destination":{"city":"Medellin","state":"Antioquia","country":"CO","postal_code":"050001"},"package":{"weight_kg":2,"length_cm":30,"width_cm":20,"height_cm":15}}},"internacional":{"summary":"Envío internacional CO Bogotá → Miami","value":{"origin":{"city":"Bogota","state":"Cundinamarca","country":"CO","postal_code":"110111"},"destination":{"city":"Miami","state":"Florida","country":"US","postal_code":"33101"},"package":{"weight_kg":1.5,"length_cm":20,"width_cm":15,"height_cm":10,"declared_value":120}}}}}}},"responses":{"200":{"description":"Lista de cotizaciones ordenadas por precio ascendente","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"quotes":{"type":"array","items":{"$ref":"#/components/schemas/Quote"}},"meta":{"type":"object","properties":{"count":{"type":"integer"},"currency":{"type":"string"}}}}}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/shipments":{"get":{"summary":"Listar envíos","tags":["Envíos"],"operationId":"listShipments","parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1,"minimum":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20,"maximum":100}},{"name":"status","in":"query","schema":{"type":"string","enum":["creado","en_transito","entregado","cancelado"]}},{"name":"from","in":"query","schema":{"type":"string","format":"date"}},{"name":"to","in":"query","schema":{"type":"string","format":"date"}}],"responses":{"200":{"description":"Lista paginada","content":{"application/json":{"schema":{"type":"object","properties":{"shipments":{"type":"array","items":{"$ref":"#/components/schemas/Shipment"}},"pagination":{"type":"object","properties":{"page":{"type":"integer"},"limit":{"type":"integer"},"total":{"type":"integer"}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}},"post":{"summary":"Crear envío","tags":["Envíos"],"operationId":"createShipment","description":"Crea un envío. Idempotencia recomendada: envía `Idempotency-Key` con un UUID único por envío para que los reintentos no dupliquen la guía.\n\n**Regla de Commercial Invoice para envíos internacionales:**\n- Si `package.declared_value > 200 USD` → **debes** enviar `invoice_pdf_base64` con tu Commercial Invoice. Se anexa vía Paperless Trade a DHL.\n- Si `package.declared_value <= 200 USD` → la Commercial Invoice se genera automáticamente por DHL a partir de los line items y se devuelve en `shipment.invoice.data_url`.\n- Envíos nacionales (`origin.country == destination.country`) no requieren invoice.","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["service_type","origin","destination","package"],"properties":{"service_type":{"type":"string","example":"dhl_express_worldwide"},"carrier_account":{"type":"string","example":"envia:tcc","description":"Sub-cuenta específica del carrier. Omitir para que el sistema resuelva."},"origin":{"$ref":"#/components/schemas/Address"},"destination":{"$ref":"#/components/schemas/Address"},"package":{"$ref":"#/components/schemas/Package"},"invoice_pdf_base64":{"type":"string","description":"PDF de la Commercial Invoice codificado en base64 (sin prefijo `data:`). Requerido si el envío es internacional y `package.declared_value > 200 USD`. Máx ~5 MB. Se anexa como Paperless Trade en DHL."},"reference":{"type":"string","description":"ID externo (pedido de la tienda) para reconciliación","example":"SHOP-8421"}}},"examples":{"nacional":{"summary":"Envío nacional CO","value":{"service_type":"courier_nacional","origin":{"name":"Tienda X","phone":"3001234567","address":"Cra 76 #29-32","city":"Bogota","state":"Cundinamarca","country":"CO"},"destination":{"name":"Juan Pérez","phone":"3009876543","address":"Cll 10 #20-30","city":"Medellin","state":"Antioquia","country":"CO"},"package":{"weight_kg":2,"length_cm":30,"width_cm":20,"height_cm":15,"content":"Ropa","declared_value":50000}}},"internacional_bajo_umbral":{"summary":"Internacional bajo USD 200 (invoice auto)","value":{"service_type":"dhl_express_worldwide","origin":{"name":"Tienda X","phone":"3001234567","address":"Cra 7 #71-52","city":"Bogota","state":"Cundinamarca","country":"CO"},"destination":{"name":"John Doe","phone":"+13055551234","address":"1 SE 3rd Ave","city":"Miami","state":"FL","country":"US","postal_code":"33101"},"package":{"weight_kg":1.5,"length_cm":20,"width_cm":15,"height_cm":10,"content":"Sample garment","declared_value":120}}},"internacional_alto_umbral":{"summary":"Internacional > USD 200 (invoice requerida)","value":{"service_type":"dhl_express_worldwide","origin":{"name":"Tienda X","phone":"3001234567","address":"Cra 7 #71-52","city":"Bogota","state":"Cundinamarca","country":"CO"},"destination":{"name":"John Doe","phone":"+13055551234","address":"1 SE 3rd Ave","city":"Miami","state":"FL","country":"US","postal_code":"33101"},"package":{"weight_kg":3.5,"length_cm":40,"width_cm":30,"height_cm":20,"content":"Electronics","declared_value":850},"invoice_pdf_base64":"JVBERi0xLjQKJcfsj6IK...(base64 de tu Commercial Invoice PDF)..."}}}}}},"responses":{"201":{"description":"Envío creado","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"shipment":{"allOf":[{"$ref":"#/components/schemas/Shipment"},{"type":"object","properties":{"invoice":{"type":"object","properties":{"source":{"type":"string","enum":["uploaded","dhl_generated","none"],"description":"`uploaded` = tú subiste la factura (>USD 200). `dhl_generated` = DHL generó a partir de los line items (≤USD 200). `none` = no aplica (nacional o carrier no-DHL)."},"data_url":{"type":"string","nullable":true,"description":"Data URL `data:application/pdf;base64,...` de la Commercial Invoice cuando `source == dhl_generated`. Null en los otros casos."},"threshold_usd":{"type":"integer","example":200}}}}}]}}}}}},"400":{"description":"Validación (incluye `INVOICE_REQUIRED` cuando declared_value > USD 200 y falta invoice_pdf_base64)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"413":{"description":"invoice_pdf_base64 excede el tamaño máximo (~5 MB)"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/shipments/{id}":{"get":{"summary":"Obtener envío","tags":["Envíos"],"operationId":"getShipment","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Detalle del envío","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Shipment"}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/shipments/{id}/label":{"get":{"summary":"Descargar guía PDF","tags":["Envíos"],"operationId":"downloadLabel","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"PDF de la guía","content":{"application/pdf":{"schema":{"type":"string","format":"binary"}}}},"404":{"description":"Guía todavía no disponible o envío inexistente","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/shipments/{id}/cancel":{"post":{"summary":"Cancelar envío","tags":["Envíos"],"operationId":"cancelShipment","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/IdempotencyKey"}],"responses":{"200":{"description":"Cancelado (con reembolso al wallet cuando aplica)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"refunded":{"type":"number"}}}}}},"400":{"description":"El envío ya está en tránsito o entregado y no admite cancelación","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/tracking/{number}":{"get":{"summary":"Rastrear envío","tags":["Rastreo"],"operationId":"trackShipment","parameters":[{"name":"number","in":"path","required":true,"schema":{"type":"string"},"description":"Número de guía SSE-* o del carrier"}],"responses":{"200":{"description":"Datos de rastreo","content":{"application/json":{"schema":{"type":"object","properties":{"tracking_number":{"type":"string"},"status":{"type":"string"},"carrier":{"type":"string"},"events":{"type":"array","items":{"$ref":"#/components/schemas/TrackingEvent"}},"estimated_delivery":{"type":"string","format":"date-time","nullable":true}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/addresses/validate":{"post":{"summary":"Validar dirección","tags":["Direcciones"],"operationId":"validateAddress","description":"Comprueba que la ciudad + departamento + país existan en la red del carrier y sugiere correcciones cuando hay ambigüedad.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["city","country"],"properties":{"city":{"type":"string"},"state":{"type":"string"},"country":{"type":"string"},"postal_code":{"type":"string"}}}}}},"responses":{"200":{"description":"Resultado de validación","content":{"application/json":{"schema":{"type":"object","properties":{"valid":{"type":"boolean"},"normalized":{"$ref":"#/components/schemas/Address"},"suggestions":{"type":"array","items":{"$ref":"#/components/schemas/Address"}}}}}}}}}},"/webhooks":{"get":{"summary":"Ver configuración de webhook","tags":["Webhooks"],"operationId":"getWebhook","responses":{"200":{"description":"Configuración actual","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookConfig"}}}}}},"put":{"summary":"Configurar webhook","tags":["Webhooks"],"operationId":"updateWebhook","description":"Configura la URL a la que Smart Sends enviará notificaciones. Cada request se firma con HMAC-SHA256 en el header `X-SmartSends-Signature`. El secret se devuelve solo una vez al crear/rotar.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookConfig"}}}},"responses":{"200":{"description":"Webhook actualizado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookConfig"}}}}}}},"/carrier/shopify/rates":{"post":{"summary":"Shopify Carrier Service — rates","tags":["E-commerce"],"operationId":"shopifyRates","description":"Endpoint listo para registrar como Shopify Carrier Service. Recibe el payload nativo de Shopify (`rate`) y devuelve cotizaciones formateadas en el schema que Shopify espera.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"rate":{"type":"object","properties":{"origin":{"type":"object"},"destination":{"type":"object"},"items":{"type":"array","items":{"type":"object"}},"currency":{"type":"string","example":"COP"}}}}}}}},"responses":{"200":{"description":"Tarifas en formato Shopify","content":{"application/json":{"schema":{"type":"object","properties":{"rates":{"type":"array","items":{"type":"object","properties":{"service_name":{"type":"string"},"service_code":{"type":"string"},"total_price":{"type":"string","description":"Precio en centavos"},"currency":{"type":"string"},"min_delivery_date":{"type":"string"},"max_delivery_date":{"type":"string"}}}}}}}}}}}},"/carrier/vtex/notify":{"post":{"summary":"VTEX Shipping Provider — createShipment","tags":["E-commerce"],"operationId":"vtexNotify","description":"Endpoint listo para el contrato VTEX Shipping Provider. Idempotencia por (userId, orderId): si VTEX reintenta la notificación se devuelve la guía existente sin crear duplicados.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"orderId":{"type":"string","example":"V123456-01"},"recipient":{"type":"object"},"packages":{"type":"array","items":{"type":"object"}},"declaredValue":{"type":"number"}}}}}},"responses":{"200":{"description":"Guía creada (o preexistente si duplicate=true)","content":{"application/json":{"schema":{"type":"object","properties":{"trackingNumber":{"type":"string"},"trackingUrl":{"type":"string","format":"uri"},"duplicate":{"type":"boolean"}}}}}}}}},"/carrier/vtex/tracking":{"get":{"summary":"VTEX Shipping Provider — trackingStatus","tags":["E-commerce"],"operationId":"vtexTracking","parameters":[{"name":"trackingNumber","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Estado en formato VTEX","content":{"application/json":{"schema":{"type":"object","properties":{"isDelivered":{"type":"boolean"},"events":{"type":"array","items":{"type":"object"}}}}}}}}}}},"webhooks":{"shipmentStatusChange":{"post":{"summary":"Cambio de estado del envío","tags":["Webhooks"],"description":"Enviado a la URL configurada cada vez que un envío cambia de estado. Verifica siempre `X-SmartSends-Signature = HMAC_SHA256(body, secret)` en hex.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookPayload"}}}},"responses":{"2XX":{"description":"Aceptado. Cualquier 2xx confirma recepción."}}}}}}