{
  "openapi": "3.1.0",
  "info": {
    "title": "API de Ruta",
    "version": "v1",
    "description": "Referencia generada del contrato del servidor (`contract/openapi.json`): sólo la API pública `/api/v1`, los enlaces firmados de comprobantes y los webhooks. Las guías (autenticación, idempotencia, firma de webhooks, errores y límites) están en [la documentación](index.html)."
  },
  "servers": [
    {
      "url": "/",
      "description": "El dominio de tu courier"
    }
  ],
  "tags": [
    {
      "name": "Entregas",
      "description": "Crear (una o en lote), consultar, corregir y cancelar entregas."
    },
    {
      "name": "Comprobantes y etiquetas",
      "description": "Comprobante con enlaces firmados de 5 minutos y etiqueta PDF."
    },
    {
      "name": "Zonas",
      "description": "Zonas activas de la empresa."
    },
    {
      "name": "Entorno de prueba",
      "description": "Simulador del recorrido, sólo con claves ruta_test_."
    },
    {
      "name": "Webhooks",
      "description": "Los POST firmados que Ruta envía a tu sistema."
    }
  ],
  "x-tagGroups": [
    {
      "name": "API",
      "tags": [
        "Entregas",
        "Comprobantes y etiquetas",
        "Zonas",
        "Entorno de prueba"
      ]
    },
    {
      "name": "Eventos",
      "tags": [
        "Webhooks"
      ]
    }
  ],
  "paths": {
    "/api/public/proof-assets/{assetId}": {
      "get": {
        "operationId": "publicProofAsset_file",
        "parameters": [
          {
            "in": "path",
            "name": "assetId",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/octet-stream": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            },
            "description": "Correcto"
          },
          "default": {
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Error: problem detail RFC 9457 con un code estable (ver Errores)."
          }
        },
        "security": [],
        "tags": [
          "Comprobantes y etiquetas"
        ],
        "summary": "Archivo de un enlace firmado",
        "description": "Sin clave: la firma es la credencial. Vencido: `410 SIGNED_URL_EXPIRED`; alterado: `404`."
      }
    },
    "/api/v1/deliveries": {
      "get": {
        "operationId": "publicDelivery_list",
        "parameters": [
          {
            "in": "query",
            "name": "limit",
            "schema": {
              "type": "integer",
              "maximum": 100,
              "minimum": 1
            }
          },
          {
            "description": "El nextCursor de la página anterior.",
            "in": "query",
            "name": "cursor",
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Sólo las entregas con esta referencia de tu pedido.",
            "in": "query",
            "name": "externalReference",
            "schema": {
              "type": "string",
              "pattern": "[A-Za-z0-9][A-Za-z0-9_.:#/-]{0,63}"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicDeliveryPage"
                }
              }
            },
            "description": "Correcto"
          },
          "default": {
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Error: problem detail RFC 9457 con un code estable (ver Errores)."
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "tags": [
          "Entregas"
        ],
        "summary": "Listar entregas",
        "description": "Permiso `deliveries:read`. De la más nueva a la más vieja; seguí `nextCursor` hasta `null`.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "curl",
            "source": "curl \"$RUTA_API/api/v1/deliveries?limit=50\" \\\n  -H \"Authorization: Bearer $RUTA_API_KEY\""
          },
          {
            "lang": "JavaScript",
            "label": "JavaScript",
            "source": "// Node.js 18+ (fetch incluido)\nconst response = await fetch(`${process.env.RUTA_API}/api/v1/deliveries?limit=50`, {\n  method: 'GET',\n  headers: {\n    Authorization: `Bearer ${process.env.RUTA_API_KEY}`,\n  },\n})\nif (!response.ok) throw new Error(`Ruta respondió ${response.status}`)\nconst page = await response.json()"
          },
          {
            "lang": "Python",
            "label": "Python",
            "source": "# Python 3 con requests (pip install requests)\nimport os\n\nimport requests\n\nresponse = requests.get(\n    f\"{os.environ['RUTA_API']}/api/v1/deliveries?limit=50\",\n    headers={\n        \"Authorization\": f\"Bearer {os.environ['RUTA_API_KEY']}\",\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\npage = response.json()"
          },
          {
            "lang": "PHP",
            "label": "PHP",
            "source": "<?php // PHP 8 con la extensión curl\n$ch = curl_init(getenv('RUTA_API') . '/api/v1/deliveries?limit=50');\ncurl_setopt_array($ch, [\n    CURLOPT_CUSTOMREQUEST => 'GET',\n    CURLOPT_HTTPHEADER => [\n        'Authorization: Bearer ' . getenv('RUTA_API_KEY'),\n    ],\n    CURLOPT_RETURNTRANSFER => true,\n    CURLOPT_TIMEOUT => 30,\n]);\n$body = curl_exec($ch);\n$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);\nif ($status >= 400) throw new RuntimeException(\"Ruta respondió $status\");\n$page = json_decode($body, true);"
          }
        ]
      },
      "post": {
        "operationId": "publicDelivery_create",
        "parameters": [
          {
            "description": "La misma clave con el mismo cuerpo repite el 201 original.",
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "[A-Za-z0-9_.:-]{1,128}"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicDeliveryCreateInput"
              }
            }
          },
          "description": "Objeto cerrado: una clave desconocida o repetida es 400; null y ausente son lo mismo.",
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicDelivery"
                }
              }
            },
            "description": "Correcto"
          },
          "default": {
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Error: problem detail RFC 9457 con un code estable (ver Errores)."
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "tags": [
          "Entregas"
        ],
        "summary": "Crear una entrega",
        "description": "Permiso `deliveries:write`. `201`; la misma `Idempotency-Key` con el mismo cuerpo repite la respuesta con `Idempotent-Replayed: true`. Ver [Entregas](entregas.html#crear-una-entrega) e [Idempotencia](idempotencia.html).",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "curl",
            "source": "curl -X POST \"$RUTA_API/api/v1/deliveries\" \\\n  -H \"Authorization: Bearer $RUTA_API_KEY\" \\\n  -H \"Idempotency-Key: pedido-1042\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n       \"customerName\": \"Ana Pérez\",\n       \"address\": \"Av. Italia 1234, apto 5\",\n       \"recipientPhone\": \"+59899123456\",\n       \"externalReference\": \"1042\"\n     }'"
          },
          {
            "lang": "JavaScript",
            "label": "JavaScript",
            "source": "// Node.js 18+ (fetch incluido)\nconst response = await fetch(`${process.env.RUTA_API}/api/v1/deliveries`, {\n  method: 'POST',\n  headers: {\n    Authorization: `Bearer ${process.env.RUTA_API_KEY}`,\n    'Idempotency-Key': 'pedido-1042',\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    \"customerName\": \"Ana Pérez\",\n    \"address\": \"Av. Italia 1234, apto 5\",\n    \"recipientPhone\": \"+59899123456\",\n    \"externalReference\": \"1042\"\n  }),\n})\nif (!response.ok) throw new Error(`Ruta respondió ${response.status}`)\nconst delivery = await response.json()"
          },
          {
            "lang": "Python",
            "label": "Python",
            "source": "# Python 3 con requests (pip install requests)\nimport os\n\nimport requests\n\nresponse = requests.post(\n    f\"{os.environ['RUTA_API']}/api/v1/deliveries\",\n    headers={\n        \"Authorization\": f\"Bearer {os.environ['RUTA_API_KEY']}\",\n        \"Idempotency-Key\": \"pedido-1042\",\n    },\n    json={\n        \"customerName\": \"Ana Pérez\",\n        \"address\": \"Av. Italia 1234, apto 5\",\n        \"recipientPhone\": \"+59899123456\",\n        \"externalReference\": \"1042\",\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\ndelivery = response.json()"
          },
          {
            "lang": "PHP",
            "label": "PHP",
            "source": "<?php // PHP 8 con la extensión curl\n$ch = curl_init(getenv('RUTA_API') . '/api/v1/deliveries');\ncurl_setopt_array($ch, [\n    CURLOPT_CUSTOMREQUEST => 'POST',\n    CURLOPT_HTTPHEADER => [\n        'Authorization: Bearer ' . getenv('RUTA_API_KEY'),\n        'Idempotency-Key: pedido-1042',\n        'Content-Type: application/json',\n    ],\n    CURLOPT_POSTFIELDS => json_encode([\n        'customerName' => 'Ana Pérez',\n        'address' => 'Av. Italia 1234, apto 5',\n        'recipientPhone' => '+59899123456',\n        'externalReference' => '1042',\n    ], JSON_UNESCAPED_UNICODE),\n    CURLOPT_RETURNTRANSFER => true,\n    CURLOPT_TIMEOUT => 30,\n]);\n$body = curl_exec($ch);\n$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);\nif ($status >= 400) throw new RuntimeException(\"Ruta respondió $status\");\n$delivery = json_decode($body, true);"
          }
        ]
      }
    },
    "/api/v1/deliveries/batch": {
      "post": {
        "operationId": "publicDelivery_batch",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicDeliveryBatchInput"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicBatchResult"
                }
              }
            },
            "description": "Correcto"
          },
          "default": {
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Error: problem detail RFC 9457 con un code estable (ver Errores)."
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "tags": [
          "Entregas"
        ],
        "summary": "Crear entregas en lote",
        "description": "Permiso `deliveries:write`. Hasta 100 entregas, cada una con su `idempotencyKey`; `200` con un resultado por ítem. Ver [Crear en lote](entregas.html#crear-en-lote).",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "curl",
            "source": "curl -X POST \"$RUTA_API/api/v1/deliveries/batch\" \\\n  -H \"Authorization: Bearer $RUTA_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n       \"deliveries\": [\n         {\n           \"idempotencyKey\": \"pedido-1042\",\n           \"customerName\": \"Ana Pérez\",\n           \"address\": \"Av. Italia 1234\",\n           \"externalReference\": \"1042\"\n         },\n         {\n           \"idempotencyKey\": \"pedido-1043\",\n           \"customerName\": \"Luis Gómez\",\n           \"address\": \"18 de Julio 1500\",\n           \"externalReference\": \"1043\"\n         }\n       ]\n     }'"
          },
          {
            "lang": "JavaScript",
            "label": "JavaScript",
            "source": "// Node.js 18+ (fetch incluido)\nconst response = await fetch(`${process.env.RUTA_API}/api/v1/deliveries/batch`, {\n  method: 'POST',\n  headers: {\n    Authorization: `Bearer ${process.env.RUTA_API_KEY}`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    \"deliveries\": [\n      {\n        \"idempotencyKey\": \"pedido-1042\",\n        \"customerName\": \"Ana Pérez\",\n        \"address\": \"Av. Italia 1234\",\n        \"externalReference\": \"1042\"\n      },\n      {\n        \"idempotencyKey\": \"pedido-1043\",\n        \"customerName\": \"Luis Gómez\",\n        \"address\": \"18 de Julio 1500\",\n        \"externalReference\": \"1043\"\n      }\n    ]\n  }),\n})\nif (!response.ok) throw new Error(`Ruta respondió ${response.status}`)\nconst result = await response.json()"
          },
          {
            "lang": "Python",
            "label": "Python",
            "source": "# Python 3 con requests (pip install requests)\nimport os\n\nimport requests\n\nresponse = requests.post(\n    f\"{os.environ['RUTA_API']}/api/v1/deliveries/batch\",\n    headers={\n        \"Authorization\": f\"Bearer {os.environ['RUTA_API_KEY']}\",\n    },\n    json={\n        \"deliveries\": [\n            {\n                \"idempotencyKey\": \"pedido-1042\",\n                \"customerName\": \"Ana Pérez\",\n                \"address\": \"Av. Italia 1234\",\n                \"externalReference\": \"1042\",\n            },\n            {\n                \"idempotencyKey\": \"pedido-1043\",\n                \"customerName\": \"Luis Gómez\",\n                \"address\": \"18 de Julio 1500\",\n                \"externalReference\": \"1043\",\n            },\n        ],\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"
          },
          {
            "lang": "PHP",
            "label": "PHP",
            "source": "<?php // PHP 8 con la extensión curl\n$ch = curl_init(getenv('RUTA_API') . '/api/v1/deliveries/batch');\ncurl_setopt_array($ch, [\n    CURLOPT_CUSTOMREQUEST => 'POST',\n    CURLOPT_HTTPHEADER => [\n        'Authorization: Bearer ' . getenv('RUTA_API_KEY'),\n        'Content-Type: application/json',\n    ],\n    CURLOPT_POSTFIELDS => json_encode([\n        'deliveries' => [\n            [\n                'idempotencyKey' => 'pedido-1042',\n                'customerName' => 'Ana Pérez',\n                'address' => 'Av. Italia 1234',\n                'externalReference' => '1042',\n            ],\n            [\n                'idempotencyKey' => 'pedido-1043',\n                'customerName' => 'Luis Gómez',\n                'address' => '18 de Julio 1500',\n                'externalReference' => '1043',\n            ],\n        ],\n    ], JSON_UNESCAPED_UNICODE),\n    CURLOPT_RETURNTRANSFER => true,\n    CURLOPT_TIMEOUT => 30,\n]);\n$body = curl_exec($ch);\n$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);\nif ($status >= 400) throw new RuntimeException(\"Ruta respondió $status\");\n$result = json_decode($body, true);"
          }
        ]
      }
    },
    "/api/v1/deliveries/{id}": {
      "get": {
        "operationId": "publicDelivery_get",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicDelivery"
                }
              }
            },
            "description": "Correcto"
          },
          "default": {
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Error: problem detail RFC 9457 con un code estable (ver Errores)."
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "tags": [
          "Entregas"
        ],
        "summary": "Consultar una entrega",
        "description": "Permiso `deliveries:read`. Otra empresa u otro comercio: `404`.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "curl",
            "source": "curl \"$RUTA_API/api/v1/deliveries/6f1c1d0e-2f5e-4bb5-9c1a-1c1b1f0e9a77\" \\\n  -H \"Authorization: Bearer $RUTA_API_KEY\""
          },
          {
            "lang": "JavaScript",
            "label": "JavaScript",
            "source": "// Node.js 18+ (fetch incluido)\nconst response = await fetch(`${process.env.RUTA_API}/api/v1/deliveries/6f1c1d0e-2f5e-4bb5-9c1a-1c1b1f0e9a77`, {\n  method: 'GET',\n  headers: {\n    Authorization: `Bearer ${process.env.RUTA_API_KEY}`,\n  },\n})\nif (!response.ok) throw new Error(`Ruta respondió ${response.status}`)\nconst delivery = await response.json()"
          },
          {
            "lang": "Python",
            "label": "Python",
            "source": "# Python 3 con requests (pip install requests)\nimport os\n\nimport requests\n\nresponse = requests.get(\n    f\"{os.environ['RUTA_API']}/api/v1/deliveries/6f1c1d0e-2f5e-4bb5-9c1a-1c1b1f0e9a77\",\n    headers={\n        \"Authorization\": f\"Bearer {os.environ['RUTA_API_KEY']}\",\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\ndelivery = response.json()"
          },
          {
            "lang": "PHP",
            "label": "PHP",
            "source": "<?php // PHP 8 con la extensión curl\n$ch = curl_init(getenv('RUTA_API') . '/api/v1/deliveries/6f1c1d0e-2f5e-4bb5-9c1a-1c1b1f0e9a77');\ncurl_setopt_array($ch, [\n    CURLOPT_CUSTOMREQUEST => 'GET',\n    CURLOPT_HTTPHEADER => [\n        'Authorization: Bearer ' . getenv('RUTA_API_KEY'),\n    ],\n    CURLOPT_RETURNTRANSFER => true,\n    CURLOPT_TIMEOUT => 30,\n]);\n$body = curl_exec($ch);\n$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);\nif ($status >= 400) throw new RuntimeException(\"Ruta respondió $status\");\n$delivery = json_decode($body, true);"
          }
        ]
      },
      "patch": {
        "operationId": "publicDelivery_edit",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicDeliveryEditInput"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicDelivery"
                }
              }
            },
            "description": "Correcto"
          },
          "default": {
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Error: problem detail RFC 9457 con un code estable (ver Errores)."
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "tags": [
          "Entregas"
        ],
        "summary": "Corregir una entrega",
        "description": "Permiso `deliveries:write`. Sólo `CREATED` o `ASSIGNED`. Ver [Corregir antes de que salga](entregas.html#corregir-antes-de-que-salga).",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "curl",
            "source": "curl -X PATCH \"$RUTA_API/api/v1/deliveries/6f1c1d0e-2f5e-4bb5-9c1a-1c1b1f0e9a77\" \\\n  -H \"Authorization: Bearer $RUTA_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n       \"address\": \"Av. Italia 1234, apto 7\",\n       \"instructions\": \"\"\n     }'"
          },
          {
            "lang": "JavaScript",
            "label": "JavaScript",
            "source": "// Node.js 18+ (fetch incluido)\nconst response = await fetch(`${process.env.RUTA_API}/api/v1/deliveries/6f1c1d0e-2f5e-4bb5-9c1a-1c1b1f0e9a77`, {\n  method: 'PATCH',\n  headers: {\n    Authorization: `Bearer ${process.env.RUTA_API_KEY}`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    \"address\": \"Av. Italia 1234, apto 7\",\n    \"instructions\": \"\"\n  }),\n})\nif (!response.ok) throw new Error(`Ruta respondió ${response.status}`)\nconst delivery = await response.json()"
          },
          {
            "lang": "Python",
            "label": "Python",
            "source": "# Python 3 con requests (pip install requests)\nimport os\n\nimport requests\n\nresponse = requests.patch(\n    f\"{os.environ['RUTA_API']}/api/v1/deliveries/6f1c1d0e-2f5e-4bb5-9c1a-1c1b1f0e9a77\",\n    headers={\n        \"Authorization\": f\"Bearer {os.environ['RUTA_API_KEY']}\",\n    },\n    json={\n        \"address\": \"Av. Italia 1234, apto 7\",\n        \"instructions\": \"\",\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\ndelivery = response.json()"
          },
          {
            "lang": "PHP",
            "label": "PHP",
            "source": "<?php // PHP 8 con la extensión curl\n$ch = curl_init(getenv('RUTA_API') . '/api/v1/deliveries/6f1c1d0e-2f5e-4bb5-9c1a-1c1b1f0e9a77');\ncurl_setopt_array($ch, [\n    CURLOPT_CUSTOMREQUEST => 'PATCH',\n    CURLOPT_HTTPHEADER => [\n        'Authorization: Bearer ' . getenv('RUTA_API_KEY'),\n        'Content-Type: application/json',\n    ],\n    CURLOPT_POSTFIELDS => json_encode([\n        'address' => 'Av. Italia 1234, apto 7',\n        'instructions' => '',\n    ], JSON_UNESCAPED_UNICODE),\n    CURLOPT_RETURNTRANSFER => true,\n    CURLOPT_TIMEOUT => 30,\n]);\n$body = curl_exec($ch);\n$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);\nif ($status >= 400) throw new RuntimeException(\"Ruta respondió $status\");\n$delivery = json_decode($body, true);"
          }
        ]
      }
    },
    "/api/v1/deliveries/{id}/cancel": {
      "post": {
        "operationId": "publicDelivery_cancel",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicDelivery"
                }
              }
            },
            "description": "Correcto"
          },
          "default": {
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Error: problem detail RFC 9457 con un code estable (ver Errores)."
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "tags": [
          "Entregas"
        ],
        "summary": "Cancelar una entrega",
        "description": "Permiso `deliveries:write`. Sólo `CREATED` o `ASSIGNED`; idempotente.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "curl",
            "source": "curl -X POST \"$RUTA_API/api/v1/deliveries/6f1c1d0e-2f5e-4bb5-9c1a-1c1b1f0e9a77/cancel\" \\\n  -H \"Authorization: Bearer $RUTA_API_KEY\""
          },
          {
            "lang": "JavaScript",
            "label": "JavaScript",
            "source": "// Node.js 18+ (fetch incluido)\nconst response = await fetch(`${process.env.RUTA_API}/api/v1/deliveries/6f1c1d0e-2f5e-4bb5-9c1a-1c1b1f0e9a77/cancel`, {\n  method: 'POST',\n  headers: {\n    Authorization: `Bearer ${process.env.RUTA_API_KEY}`,\n  },\n})\nif (!response.ok) throw new Error(`Ruta respondió ${response.status}`)\nconst delivery = await response.json()"
          },
          {
            "lang": "Python",
            "label": "Python",
            "source": "# Python 3 con requests (pip install requests)\nimport os\n\nimport requests\n\nresponse = requests.post(\n    f\"{os.environ['RUTA_API']}/api/v1/deliveries/6f1c1d0e-2f5e-4bb5-9c1a-1c1b1f0e9a77/cancel\",\n    headers={\n        \"Authorization\": f\"Bearer {os.environ['RUTA_API_KEY']}\",\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\ndelivery = response.json()"
          },
          {
            "lang": "PHP",
            "label": "PHP",
            "source": "<?php // PHP 8 con la extensión curl\n$ch = curl_init(getenv('RUTA_API') . '/api/v1/deliveries/6f1c1d0e-2f5e-4bb5-9c1a-1c1b1f0e9a77/cancel');\ncurl_setopt_array($ch, [\n    CURLOPT_CUSTOMREQUEST => 'POST',\n    CURLOPT_HTTPHEADER => [\n        'Authorization: Bearer ' . getenv('RUTA_API_KEY'),\n    ],\n    CURLOPT_RETURNTRANSFER => true,\n    CURLOPT_TIMEOUT => 30,\n]);\n$body = curl_exec($ch);\n$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);\nif ($status >= 400) throw new RuntimeException(\"Ruta respondió $status\");\n$delivery = json_decode($body, true);"
          }
        ]
      }
    },
    "/api/v1/deliveries/{id}/label": {
      "get": {
        "operationId": "publicDeliveryFiles_label",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            },
            "description": "Correcto"
          },
          "default": {
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Error: problem detail RFC 9457 con un code estable (ver Errores)."
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "tags": [
          "Comprobantes y etiquetas"
        ],
        "summary": "Etiqueta PDF",
        "description": "Permiso `deliveries:read`. Una página de 10 × 15 cm.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "curl",
            "source": "curl \"$RUTA_API/api/v1/deliveries/6f1c1d0e-2f5e-4bb5-9c1a-1c1b1f0e9a77/label\" \\\n  -H \"Authorization: Bearer $RUTA_API_KEY\" \\\n  -o etiqueta.pdf"
          },
          {
            "lang": "JavaScript",
            "label": "JavaScript",
            "source": "// Node.js 18+ (fetch incluido)\nimport { writeFile } from 'node:fs/promises'\n\nconst response = await fetch(`${process.env.RUTA_API}/api/v1/deliveries/6f1c1d0e-2f5e-4bb5-9c1a-1c1b1f0e9a77/label`, {\n  method: 'GET',\n  headers: {\n    Authorization: `Bearer ${process.env.RUTA_API_KEY}`,\n  },\n})\nif (!response.ok) throw new Error(`Ruta respondió ${response.status}`)\nawait writeFile('etiqueta.pdf', Buffer.from(await response.arrayBuffer()))"
          },
          {
            "lang": "Python",
            "label": "Python",
            "source": "# Python 3 con requests (pip install requests)\nimport os\n\nimport requests\n\nresponse = requests.get(\n    f\"{os.environ['RUTA_API']}/api/v1/deliveries/6f1c1d0e-2f5e-4bb5-9c1a-1c1b1f0e9a77/label\",\n    headers={\n        \"Authorization\": f\"Bearer {os.environ['RUTA_API_KEY']}\",\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\nwith open(\"etiqueta.pdf\", \"wb\") as file:\n    file.write(response.content)"
          },
          {
            "lang": "PHP",
            "label": "PHP",
            "source": "<?php // PHP 8 con la extensión curl\n$ch = curl_init(getenv('RUTA_API') . '/api/v1/deliveries/6f1c1d0e-2f5e-4bb5-9c1a-1c1b1f0e9a77/label');\ncurl_setopt_array($ch, [\n    CURLOPT_CUSTOMREQUEST => 'GET',\n    CURLOPT_HTTPHEADER => [\n        'Authorization: Bearer ' . getenv('RUTA_API_KEY'),\n    ],\n    CURLOPT_RETURNTRANSFER => true,\n    CURLOPT_TIMEOUT => 30,\n]);\n$body = curl_exec($ch);\n$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);\nif ($status >= 400) throw new RuntimeException(\"Ruta respondió $status\");\nfile_put_contents('etiqueta.pdf', $body);"
          }
        ]
      }
    },
    "/api/v1/deliveries/{id}/proof": {
      "get": {
        "operationId": "publicDeliveryFiles_proof",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicProof"
                }
              }
            },
            "description": "Correcto"
          },
          "default": {
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Error: problem detail RFC 9457 con un code estable (ver Errores)."
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "tags": [
          "Comprobantes y etiquetas"
        ],
        "summary": "Comprobante de entrega",
        "description": "Permiso `proof:read`. Enlaces firmados de 5 minutos. Ver [Comprobantes](comprobantes-y-etiquetas.html).",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "curl",
            "source": "curl \"$RUTA_API/api/v1/deliveries/6f1c1d0e-2f5e-4bb5-9c1a-1c1b1f0e9a77/proof\" \\\n  -H \"Authorization: Bearer $RUTA_API_KEY\""
          },
          {
            "lang": "JavaScript",
            "label": "JavaScript",
            "source": "// Node.js 18+ (fetch incluido)\nconst response = await fetch(`${process.env.RUTA_API}/api/v1/deliveries/6f1c1d0e-2f5e-4bb5-9c1a-1c1b1f0e9a77/proof`, {\n  method: 'GET',\n  headers: {\n    Authorization: `Bearer ${process.env.RUTA_API_KEY}`,\n  },\n})\nif (!response.ok) throw new Error(`Ruta respondió ${response.status}`)\nconst proof = await response.json()"
          },
          {
            "lang": "Python",
            "label": "Python",
            "source": "# Python 3 con requests (pip install requests)\nimport os\n\nimport requests\n\nresponse = requests.get(\n    f\"{os.environ['RUTA_API']}/api/v1/deliveries/6f1c1d0e-2f5e-4bb5-9c1a-1c1b1f0e9a77/proof\",\n    headers={\n        \"Authorization\": f\"Bearer {os.environ['RUTA_API_KEY']}\",\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\nproof = response.json()"
          },
          {
            "lang": "PHP",
            "label": "PHP",
            "source": "<?php // PHP 8 con la extensión curl\n$ch = curl_init(getenv('RUTA_API') . '/api/v1/deliveries/6f1c1d0e-2f5e-4bb5-9c1a-1c1b1f0e9a77/proof');\ncurl_setopt_array($ch, [\n    CURLOPT_CUSTOMREQUEST => 'GET',\n    CURLOPT_HTTPHEADER => [\n        'Authorization: Bearer ' . getenv('RUTA_API_KEY'),\n    ],\n    CURLOPT_RETURNTRANSFER => true,\n    CURLOPT_TIMEOUT => 30,\n]);\n$body = curl_exec($ch);\n$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);\nif ($status >= 400) throw new RuntimeException(\"Ruta respondió $status\");\n$proof = json_decode($body, true);"
          }
        ]
      }
    },
    "/api/v1/deliveries/{id}/simulate": {
      "post": {
        "operationId": "publicSandbox_simulate",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicSandboxSimulationInput"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicDelivery"
                }
              }
            },
            "description": "Correcto"
          },
          "default": {
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Error: problem detail RFC 9457 con un code estable (ver Errores)."
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "tags": [
          "Entorno de prueba"
        ],
        "summary": "Simular el próximo paso",
        "description": "Sólo claves `ruta_test_…` (permiso `deliveries:write`). Ver [Entorno de prueba](entorno-de-prueba.html#simular-el-recorrido).",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "curl",
            "source": "curl -X POST \"$RUTA_API/api/v1/deliveries/6f1c1d0e-2f5e-4bb5-9c1a-1c1b1f0e9a77/simulate\" \\\n  -H \"Authorization: Bearer $RUTA_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n       \"action\": \"ASSIGN\"\n     }'"
          },
          {
            "lang": "JavaScript",
            "label": "JavaScript",
            "source": "// Node.js 18+ (fetch incluido)\nconst response = await fetch(`${process.env.RUTA_API}/api/v1/deliveries/6f1c1d0e-2f5e-4bb5-9c1a-1c1b1f0e9a77/simulate`, {\n  method: 'POST',\n  headers: {\n    Authorization: `Bearer ${process.env.RUTA_API_KEY}`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    \"action\": \"ASSIGN\"\n  }),\n})\nif (!response.ok) throw new Error(`Ruta respondió ${response.status}`)\nconst delivery = await response.json()"
          },
          {
            "lang": "Python",
            "label": "Python",
            "source": "# Python 3 con requests (pip install requests)\nimport os\n\nimport requests\n\nresponse = requests.post(\n    f\"{os.environ['RUTA_API']}/api/v1/deliveries/6f1c1d0e-2f5e-4bb5-9c1a-1c1b1f0e9a77/simulate\",\n    headers={\n        \"Authorization\": f\"Bearer {os.environ['RUTA_API_KEY']}\",\n    },\n    json={\n        \"action\": \"ASSIGN\",\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\ndelivery = response.json()"
          },
          {
            "lang": "PHP",
            "label": "PHP",
            "source": "<?php // PHP 8 con la extensión curl\n$ch = curl_init(getenv('RUTA_API') . '/api/v1/deliveries/6f1c1d0e-2f5e-4bb5-9c1a-1c1b1f0e9a77/simulate');\ncurl_setopt_array($ch, [\n    CURLOPT_CUSTOMREQUEST => 'POST',\n    CURLOPT_HTTPHEADER => [\n        'Authorization: Bearer ' . getenv('RUTA_API_KEY'),\n        'Content-Type: application/json',\n    ],\n    CURLOPT_POSTFIELDS => json_encode([\n        'action' => 'ASSIGN',\n    ], JSON_UNESCAPED_UNICODE),\n    CURLOPT_RETURNTRANSFER => true,\n    CURLOPT_TIMEOUT => 30,\n]);\n$body = curl_exec($ch);\n$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);\nif ($status >= 400) throw new RuntimeException(\"Ruta respondió $status\");\n$delivery = json_decode($body, true);"
          }
        ]
      }
    },
    "/api/v1/zones": {
      "get": {
        "operationId": "publicZone_list",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicZoneZones"
                }
              }
            },
            "description": "Correcto"
          },
          "default": {
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Error: problem detail RFC 9457 con un code estable (ver Errores)."
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "tags": [
          "Zonas"
        ],
        "summary": "Listar zonas",
        "description": "Permiso `deliveries:read`. Zonas activas de la empresa.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "curl",
            "source": "curl \"$RUTA_API/api/v1/zones\" \\\n  -H \"Authorization: Bearer $RUTA_API_KEY\""
          },
          {
            "lang": "JavaScript",
            "label": "JavaScript",
            "source": "// Node.js 18+ (fetch incluido)\nconst response = await fetch(`${process.env.RUTA_API}/api/v1/zones`, {\n  method: 'GET',\n  headers: {\n    Authorization: `Bearer ${process.env.RUTA_API_KEY}`,\n  },\n})\nif (!response.ok) throw new Error(`Ruta respondió ${response.status}`)\nconst zones = await response.json()"
          },
          {
            "lang": "Python",
            "label": "Python",
            "source": "# Python 3 con requests (pip install requests)\nimport os\n\nimport requests\n\nresponse = requests.get(\n    f\"{os.environ['RUTA_API']}/api/v1/zones\",\n    headers={\n        \"Authorization\": f\"Bearer {os.environ['RUTA_API_KEY']}\",\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\nzones = response.json()"
          },
          {
            "lang": "PHP",
            "label": "PHP",
            "source": "<?php // PHP 8 con la extensión curl\n$ch = curl_init(getenv('RUTA_API') . '/api/v1/zones');\ncurl_setopt_array($ch, [\n    CURLOPT_CUSTOMREQUEST => 'GET',\n    CURLOPT_HTTPHEADER => [\n        'Authorization: Bearer ' . getenv('RUTA_API_KEY'),\n    ],\n    CURLOPT_RETURNTRANSFER => true,\n    CURLOPT_TIMEOUT => 30,\n]);\n$body = curl_exec($ch);\n$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);\nif ($status >= 400) throw new RuntimeException(\"Ruta respondió $status\");\n$zones = json_decode($body, true);"
          }
        ]
      }
    }
  },
  "webhooks": {
    "delivery.assigned": {
      "post": {
        "description": "La entrega se asignó a un repartidor. Verificá Ruta-Signature sobre el cuerpo crudo antes de parsearlo y respondé 2xx en menos de 10 segundos.",
        "operationId": "webhook_delivery_assigned",
        "parameters": [
          {
            "description": "Id del evento; el mismo en reintentos y reenvíos.",
            "in": "header",
            "name": "Ruta-Event-Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Tipo del evento, igual a type del cuerpo.",
            "in": "header",
            "name": "Ruta-Event-Type",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "t=<segundos unix>,v1=<HMAC-SHA256 hex de \"<t>.<cuerpo crudo>\">",
            "in": "header",
            "name": "Ruta-Signature",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEvent"
              }
            }
          },
          "required": true
        },
        "responses": {
          "2XX": {
            "description": "Recibido. Cualquier otra respuesta se reintenta."
          }
        },
        "security": [],
        "summary": "delivery.assigned",
        "tags": [
          "Webhooks"
        ]
      }
    },
    "delivery.cancelled": {
      "post": {
        "description": "La entrega se canceló. Verificá Ruta-Signature sobre el cuerpo crudo antes de parsearlo y respondé 2xx en menos de 10 segundos.",
        "operationId": "webhook_delivery_cancelled",
        "parameters": [
          {
            "description": "Id del evento; el mismo en reintentos y reenvíos.",
            "in": "header",
            "name": "Ruta-Event-Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Tipo del evento, igual a type del cuerpo.",
            "in": "header",
            "name": "Ruta-Event-Type",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "t=<segundos unix>,v1=<HMAC-SHA256 hex de \"<t>.<cuerpo crudo>\">",
            "in": "header",
            "name": "Ruta-Signature",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEvent"
              }
            }
          },
          "required": true
        },
        "responses": {
          "2XX": {
            "description": "Recibido. Cualquier otra respuesta se reintenta."
          }
        },
        "security": [],
        "summary": "delivery.cancelled",
        "tags": [
          "Webhooks"
        ]
      }
    },
    "delivery.collection_settled": {
      "post": {
        "description": "La empresa rindió el cobro contra entrega al comercio. Verificá Ruta-Signature sobre el cuerpo crudo antes de parsearlo y respondé 2xx en menos de 10 segundos.",
        "operationId": "webhook_delivery_collection_settled",
        "parameters": [
          {
            "description": "Id del evento; el mismo en reintentos y reenvíos.",
            "in": "header",
            "name": "Ruta-Event-Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Tipo del evento, igual a type del cuerpo.",
            "in": "header",
            "name": "Ruta-Event-Type",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "t=<segundos unix>,v1=<HMAC-SHA256 hex de \"<t>.<cuerpo crudo>\">",
            "in": "header",
            "name": "Ruta-Signature",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEvent"
              }
            }
          },
          "required": true
        },
        "responses": {
          "2XX": {
            "description": "Recibido. Cualquier otra respuesta se reintenta."
          }
        },
        "security": [],
        "summary": "delivery.collection_settled",
        "tags": [
          "Webhooks"
        ]
      }
    },
    "delivery.created": {
      "post": {
        "description": "Se creó una entrega (panel, app, CSV, formulario, integración o API). Verificá Ruta-Signature sobre el cuerpo crudo antes de parsearlo y respondé 2xx en menos de 10 segundos.",
        "operationId": "webhook_delivery_created",
        "parameters": [
          {
            "description": "Id del evento; el mismo en reintentos y reenvíos.",
            "in": "header",
            "name": "Ruta-Event-Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Tipo del evento, igual a type del cuerpo.",
            "in": "header",
            "name": "Ruta-Event-Type",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "t=<segundos unix>,v1=<HMAC-SHA256 hex de \"<t>.<cuerpo crudo>\">",
            "in": "header",
            "name": "Ruta-Signature",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEvent"
              }
            }
          },
          "required": true
        },
        "responses": {
          "2XX": {
            "description": "Recibido. Cualquier otra respuesta se reintenta."
          }
        },
        "security": [],
        "summary": "delivery.created",
        "tags": [
          "Webhooks"
        ]
      }
    },
    "delivery.delivered": {
      "post": {
        "description": "La entrega se completó; incluye el cobro declarado, si hubo. Verificá Ruta-Signature sobre el cuerpo crudo antes de parsearlo y respondé 2xx en menos de 10 segundos.",
        "operationId": "webhook_delivery_delivered",
        "parameters": [
          {
            "description": "Id del evento; el mismo en reintentos y reenvíos.",
            "in": "header",
            "name": "Ruta-Event-Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Tipo del evento, igual a type del cuerpo.",
            "in": "header",
            "name": "Ruta-Event-Type",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "t=<segundos unix>,v1=<HMAC-SHA256 hex de \"<t>.<cuerpo crudo>\">",
            "in": "header",
            "name": "Ruta-Signature",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEvent"
              }
            }
          },
          "required": true
        },
        "responses": {
          "2XX": {
            "description": "Recibido. Cualquier otra respuesta se reintenta."
          }
        },
        "security": [],
        "summary": "delivery.delivered",
        "tags": [
          "Webhooks"
        ]
      }
    },
    "delivery.failed": {
      "post": {
        "description": "No se pudo entregar; incluye failureReasonCode. Verificá Ruta-Signature sobre el cuerpo crudo antes de parsearlo y respondé 2xx en menos de 10 segundos.",
        "operationId": "webhook_delivery_failed",
        "parameters": [
          {
            "description": "Id del evento; el mismo en reintentos y reenvíos.",
            "in": "header",
            "name": "Ruta-Event-Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Tipo del evento, igual a type del cuerpo.",
            "in": "header",
            "name": "Ruta-Event-Type",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "t=<segundos unix>,v1=<HMAC-SHA256 hex de \"<t>.<cuerpo crudo>\">",
            "in": "header",
            "name": "Ruta-Signature",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEvent"
              }
            }
          },
          "required": true
        },
        "responses": {
          "2XX": {
            "description": "Recibido. Cualquier otra respuesta se reintenta."
          }
        },
        "security": [],
        "summary": "delivery.failed",
        "tags": [
          "Webhooks"
        ]
      }
    },
    "delivery.out_for_delivery": {
      "post": {
        "description": "El repartidor salió a entregar. Verificá Ruta-Signature sobre el cuerpo crudo antes de parsearlo y respondé 2xx en menos de 10 segundos.",
        "operationId": "webhook_delivery_out_for_delivery",
        "parameters": [
          {
            "description": "Id del evento; el mismo en reintentos y reenvíos.",
            "in": "header",
            "name": "Ruta-Event-Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Tipo del evento, igual a type del cuerpo.",
            "in": "header",
            "name": "Ruta-Event-Type",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "t=<segundos unix>,v1=<HMAC-SHA256 hex de \"<t>.<cuerpo crudo>\">",
            "in": "header",
            "name": "Ruta-Signature",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEvent"
              }
            }
          },
          "required": true
        },
        "responses": {
          "2XX": {
            "description": "Recibido. Cualquier otra respuesta se reintenta."
          }
        },
        "security": [],
        "summary": "delivery.out_for_delivery",
        "tags": [
          "Webhooks"
        ]
      }
    },
    "delivery.picked_up": {
      "post": {
        "description": "El repartidor retiró el paquete en la base o en el comercio. Verificá Ruta-Signature sobre el cuerpo crudo antes de parsearlo y respondé 2xx en menos de 10 segundos.",
        "operationId": "webhook_delivery_picked_up",
        "parameters": [
          {
            "description": "Id del evento; el mismo en reintentos y reenvíos.",
            "in": "header",
            "name": "Ruta-Event-Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Tipo del evento, igual a type del cuerpo.",
            "in": "header",
            "name": "Ruta-Event-Type",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "t=<segundos unix>,v1=<HMAC-SHA256 hex de \"<t>.<cuerpo crudo>\">",
            "in": "header",
            "name": "Ruta-Signature",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEvent"
              }
            }
          },
          "required": true
        },
        "responses": {
          "2XX": {
            "description": "Recibido. Cualquier otra respuesta se reintenta."
          }
        },
        "security": [],
        "summary": "delivery.picked_up",
        "tags": [
          "Webhooks"
        ]
      }
    },
    "delivery.proof_added": {
      "post": {
        "description": "Se guardó el comprobante de entrega; pedilo con GET /api/v1/deliveries/{id}/proof. Verificá Ruta-Signature sobre el cuerpo crudo antes de parsearlo y respondé 2xx en menos de 10 segundos.",
        "operationId": "webhook_delivery_proof_added",
        "parameters": [
          {
            "description": "Id del evento; el mismo en reintentos y reenvíos.",
            "in": "header",
            "name": "Ruta-Event-Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Tipo del evento, igual a type del cuerpo.",
            "in": "header",
            "name": "Ruta-Event-Type",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "t=<segundos unix>,v1=<HMAC-SHA256 hex de \"<t>.<cuerpo crudo>\">",
            "in": "header",
            "name": "Ruta-Signature",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEvent"
              }
            }
          },
          "required": true
        },
        "responses": {
          "2XX": {
            "description": "Recibido. Cualquier otra respuesta se reintenta."
          }
        },
        "security": [],
        "summary": "delivery.proof_added",
        "tags": [
          "Webhooks"
        ]
      }
    },
    "delivery.retry_scheduled": {
      "post": {
        "description": "Se programó un nuevo intento tras un fallo (attemptNumber + 1). Verificá Ruta-Signature sobre el cuerpo crudo antes de parsearlo y respondé 2xx en menos de 10 segundos.",
        "operationId": "webhook_delivery_retry_scheduled",
        "parameters": [
          {
            "description": "Id del evento; el mismo en reintentos y reenvíos.",
            "in": "header",
            "name": "Ruta-Event-Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Tipo del evento, igual a type del cuerpo.",
            "in": "header",
            "name": "Ruta-Event-Type",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "t=<segundos unix>,v1=<HMAC-SHA256 hex de \"<t>.<cuerpo crudo>\">",
            "in": "header",
            "name": "Ruta-Signature",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEvent"
              }
            }
          },
          "required": true
        },
        "responses": {
          "2XX": {
            "description": "Recibido. Cualquier otra respuesta se reintenta."
          }
        },
        "security": [],
        "summary": "delivery.retry_scheduled",
        "tags": [
          "Webhooks"
        ]
      }
    },
    "delivery.status_changed": {
      "post": {
        "description": "Cambió el estado o el intento de una entrega (genérico, se conserva por compatibilidad). Verificá Ruta-Signature sobre el cuerpo crudo antes de parsearlo y respondé 2xx en menos de 10 segundos.",
        "operationId": "webhook_delivery_status_changed",
        "parameters": [
          {
            "description": "Id del evento; el mismo en reintentos y reenvíos.",
            "in": "header",
            "name": "Ruta-Event-Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Tipo del evento, igual a type del cuerpo.",
            "in": "header",
            "name": "Ruta-Event-Type",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "t=<segundos unix>,v1=<HMAC-SHA256 hex de \"<t>.<cuerpo crudo>\">",
            "in": "header",
            "name": "Ruta-Signature",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEvent"
              }
            }
          },
          "required": true
        },
        "responses": {
          "2XX": {
            "description": "Recibido. Cualquier otra respuesta se reintenta."
          }
        },
        "security": [],
        "summary": "delivery.status_changed",
        "tags": [
          "Webhooks"
        ]
      }
    },
    "webhook.test": {
      "post": {
        "description": "Evento de prueba pedido desde el panel; no corresponde a ninguna entrega. Verificá Ruta-Signature sobre el cuerpo crudo antes de parsearlo y respondé 2xx en menos de 10 segundos.",
        "operationId": "webhook_webhook_test",
        "parameters": [
          {
            "description": "Id del evento; el mismo en reintentos y reenvíos.",
            "in": "header",
            "name": "Ruta-Event-Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Tipo del evento, igual a type del cuerpo.",
            "in": "header",
            "name": "Ruta-Event-Type",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "t=<segundos unix>,v1=<HMAC-SHA256 hex de \"<t>.<cuerpo crudo>\">",
            "in": "header",
            "name": "Ruta-Signature",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEvent"
              }
            }
          },
          "required": true
        },
        "responses": {
          "2XX": {
            "description": "Recibido. Cualquier otra respuesta se reintenta."
          }
        },
        "security": [],
        "summary": "webhook.test",
        "tags": [
          "Webhooks"
        ]
      }
    }
  },
  "components": {
    "schemas": {
      "Problem": {
        "type": "object",
        "description": "Problem detail RFC 9457: decidí por code; error y detail son texto para personas.",
        "properties": {
          "code": {
            "type": "string",
            "description": "Código estable para tu programa.",
            "enum": [
              "VALIDATION_FAILED",
              "AUTHENTICATION_REQUIRED",
              "SESSION_INVALID",
              "CREDENTIALS_INVALID",
              "FORBIDDEN",
              "PLAN_FEATURE_UNAVAILABLE",
              "PLAN_QUOTA_EXCEEDED",
              "PLAN_READ_ONLY",
              "NOT_FOUND",
              "TRACKING_LINK_EXPIRED",
              "GONE",
              "METHOD_NOT_ALLOWED",
              "DELIVERY_STATE_INVALID",
              "IDEMPOTENCY_CONFLICT",
              "PROOF_REQUIRED",
              "FEEDBACK_ALREADY_SUBMITTED",
              "FEEDBACK_NOT_AVAILABLE",
              "CONFLICT",
              "PAYLOAD_TOO_LARGE",
              "UNSUPPORTED_MEDIA_TYPE",
              "RATE_LIMITED",
              "FEATURE_DISABLED",
              "SERVICE_UNAVAILABLE",
              "INTERNAL_ERROR",
              "REQUEST_FAILED",
              "EVIDENCE_EXPIRED",
              "ZONE_INACTIVE",
              "ZONE_NAME_TAKEN",
              "API_KEY_INVALID",
              "API_KEY_REVOKED",
              "API_KEY_SCOPE_MISSING",
              "IDEMPOTENCY_KEY_REQUIRED",
              "INTEGRATION_CREDENTIALS_REQUIRED",
              "INTEGRATION_CONNECTION_PAUSED",
              "INTEGRATION_PAYLOAD_INVALID",
              "INTEGRATION_CAPABILITY_UNAVAILABLE",
              "INTEGRATION_CIRCUIT_OPEN",
              "INTEGRATION_RETRY_EXHAUSTED",
              "INTEGRATION_COMMERCIAL_CONFIGURATION_REQUIRED",
              "INTEGRATION_CREDENTIALS_REJECTED",
              "INTEGRATION_DESTINATION_BLOCKED",
              "INTEGRATION_SCOPE_MISSING",
              "LABEL_NOT_FOUND",
              "EXTERNAL_REFERENCE_IN_USE",
              "EXTERNAL_DRAFTS_DISABLED",
              "NOTICE_TEXT_INVALID",
              "EMAIL_CODE_REQUIRED",
              "EMAIL_CODE_INVALID",
              "EMAIL_CODE_EXPIRED",
              "EMAIL_CODE_ATTEMPTS_EXCEEDED",
              "EMAIL_NOT_SENT",
              "PROMO_CODE_INVALID",
              "EXTERNAL_REFERENCE_TAKEN",
              "TEST_KEY_REQUIRED",
              "SIGNED_URL_EXPIRED",
              "PASSWORD_TOO_COMMON",
              "INVITATION_USED",
              "INVITATION_EXPIRED",
              "PASSWORD_RESET_LINK_INVALID",
              "INTEGRATION_AUTHORIZATION_EXPIRED",
              "RECIPIENT_INSTRUCTIONS_UNAVAILABLE",
              "RECIPIENT_INSTRUCTIONS_LOCKED",
              "OFFER_PENDING",
              "OFFER_EXPIRED",
              "PICKUP_PHOTO_REQUIRED",
              "START_NOT_UNDOABLE",
              "CURRENT_PASSWORD_INVALID",
              "DELIVERY_CHANGED",
              "DELIVERY_ASSIGNMENT_CHANGED",
              "ACCOUNT_OWNER_ONLY",
              "SHIPPER_FORM_CLOSED",
              "DELIVERY_QUOTA_HELD",
              "QUOTA_NO_ROOM",
              "COLLECTION_NOT_CASH",
              "INVALID_CURRENCY",
              "INTEGRATION_STORE_UPDATE_REJECTED",
              "INTEGRATION_ACCOUNT_IN_USE"
            ]
          },
          "detail": {
            "type": "string"
          },
          "error": {
            "type": "string",
            "description": "El mismo texto que detail."
          },
          "expiredAt": {
            "type": "string",
            "format": "date-time",
            "description": "Sólo con EVIDENCE_EXPIRED: cuándo venció."
          },
          "id": {
            "type": "string",
            "description": "Id del incidente, sólo en respuestas 5xx registradas."
          },
          "status": {
            "type": "integer",
            "format": "int32"
          },
          "title": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "example": "about:blank"
          }
        },
        "required": [
          "code",
          "error",
          "status",
          "type"
        ]
      },
      "PublicBatchItem": {
        "type": "object",
        "properties": {
          "delivery": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/PublicDelivery"
              },
              {
                "type": "null"
              }
            ]
          },
          "error": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/PublicBatchProblem"
              },
              {
                "type": "null"
              }
            ]
          },
          "idempotencyKey": {
            "type": [
              "string",
              "null"
            ]
          },
          "index": {
            "type": "integer",
            "format": "int32"
          },
          "replayed": {
            "type": "boolean"
          },
          "status": {
            "type": "integer",
            "format": "int32"
          }
        },
        "required": [
          "delivery",
          "error",
          "idempotencyKey",
          "index",
          "replayed",
          "status"
        ]
      },
      "PublicBatchProblem": {
        "type": "object",
        "properties": {
          "code": {
            "type": [
              "string",
              "null"
            ]
          },
          "detail": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "code",
          "detail"
        ]
      },
      "PublicBatchResult": {
        "type": "object",
        "properties": {
          "created": {
            "type": "integer",
            "format": "int32"
          },
          "failed": {
            "type": "integer",
            "format": "int32"
          },
          "results": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "$ref": "#/components/schemas/PublicBatchItem"
            }
          }
        },
        "required": [
          "created",
          "failed",
          "results"
        ]
      },
      "PublicDelivery": {
        "type": "object",
        "properties": {
          "address": {
            "type": [
              "string",
              "null"
            ]
          },
          "amountToCollect": {
            "type": [
              "string",
              "null"
            ]
          },
          "attemptNumber": {
            "type": "integer",
            "format": "int32"
          },
          "cancelledAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "collectedAmount": {
            "type": [
              "string",
              "null"
            ]
          },
          "collectedAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "collectedCurrency": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "UYU",
              "USD",
              null
            ]
          },
          "collectionMethod": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "CASH",
              "TRANSFER",
              "OTHER",
              null
            ]
          },
          "createdAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "currency": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "UYU",
              "USD",
              null
            ]
          },
          "customerName": {
            "type": [
              "string",
              "null"
            ]
          },
          "deliveredAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "destinationLat": {
            "type": [
              "number",
              "null"
            ],
            "format": "double"
          },
          "destinationLng": {
            "type": [
              "number",
              "null"
            ],
            "format": "double"
          },
          "externalReference": {
            "type": [
              "string",
              "null"
            ]
          },
          "failedAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "failureReasonCode": {
            "type": [
              "string",
              "null"
            ]
          },
          "id": {
            "type": [
              "string",
              "null"
            ]
          },
          "instructions": {
            "type": [
              "string",
              "null"
            ]
          },
          "quotaHeld": {
            "type": "boolean"
          },
          "quotaHeldAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "recipientEmail": {
            "type": [
              "string",
              "null"
            ]
          },
          "recipientPhone": {
            "type": [
              "string",
              "null"
            ]
          },
          "scheduleTimeZone": {
            "type": [
              "string",
              "null"
            ]
          },
          "scheduledDate": {
            "type": [
              "string",
              "null"
            ]
          },
          "settledAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "shipperId": {
            "type": [
              "string",
              "null"
            ]
          },
          "startedAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "status": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "CREATED",
              "ASSIGNED",
              "OUT_FOR_DELIVERY",
              "DELIVERED",
              "FAILED",
              "CANCELLED",
              null
            ]
          },
          "test": {
            "type": "boolean"
          },
          "trackingUrl": {
            "type": [
              "string",
              "null"
            ]
          },
          "windowEnd": {
            "type": [
              "string",
              "null"
            ]
          },
          "windowStart": {
            "type": [
              "string",
              "null"
            ]
          },
          "zoneId": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "address",
          "amountToCollect",
          "attemptNumber",
          "cancelledAt",
          "collectedAmount",
          "collectedAt",
          "collectedCurrency",
          "collectionMethod",
          "createdAt",
          "currency",
          "customerName",
          "deliveredAt",
          "destinationLat",
          "destinationLng",
          "externalReference",
          "failedAt",
          "failureReasonCode",
          "id",
          "instructions",
          "quotaHeld",
          "quotaHeldAt",
          "recipientEmail",
          "recipientPhone",
          "scheduleTimeZone",
          "scheduledDate",
          "settledAt",
          "shipperId",
          "startedAt",
          "status",
          "test",
          "trackingUrl",
          "windowEnd",
          "windowStart",
          "zoneId"
        ]
      },
      "PublicDeliveryBatchInput": {
        "type": "object",
        "properties": {
          "deliveries": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicDeliveryBatchItem"
            },
            "maxItems": 100,
            "minItems": 1
          }
        },
        "required": [
          "deliveries"
        ]
      },
      "PublicDeliveryBatchItem": {
        "type": "object",
        "properties": {
          "address": {
            "type": "string"
          },
          "amountToCollect": {
            "type": [
              "string",
              "null"
            ]
          },
          "currency": {
            "type": [
              "string",
              "null"
            ],
            "default": "UYU",
            "enum": [
              "UYU",
              "USD",
              null
            ]
          },
          "customerName": {
            "type": "string"
          },
          "destinationLat": {
            "type": [
              "number",
              "null"
            ],
            "format": "double"
          },
          "destinationLng": {
            "type": [
              "number",
              "null"
            ],
            "format": "double"
          },
          "externalReference": {
            "type": [
              "string",
              "null"
            ]
          },
          "idempotencyKey": {
            "type": "string",
            "pattern": "[A-Za-z0-9_.:-]{1,128}"
          },
          "instructions": {
            "type": [
              "string",
              "null"
            ]
          },
          "recipientEmail": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 254
          },
          "recipientPhone": {
            "type": [
              "string",
              "null"
            ]
          },
          "scheduledDate": {
            "type": [
              "string",
              "null"
            ]
          },
          "shipperId": {
            "type": [
              "string",
              "null"
            ]
          },
          "windowEnd": {
            "type": [
              "string",
              "null"
            ]
          },
          "windowStart": {
            "type": [
              "string",
              "null"
            ]
          },
          "zoneId": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "address",
          "customerName",
          "idempotencyKey"
        ]
      },
      "PublicDeliveryCreateInput": {
        "type": "object",
        "properties": {
          "address": {
            "type": "string"
          },
          "amountToCollect": {
            "type": [
              "string",
              "null"
            ]
          },
          "currency": {
            "type": [
              "string",
              "null"
            ],
            "default": "UYU",
            "enum": [
              "UYU",
              "USD",
              null
            ]
          },
          "customerName": {
            "type": "string"
          },
          "destinationLat": {
            "type": [
              "number",
              "null"
            ],
            "format": "double"
          },
          "destinationLng": {
            "type": [
              "number",
              "null"
            ],
            "format": "double"
          },
          "externalReference": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "[A-Za-z0-9][A-Za-z0-9_.:#/-]{0,63}"
          },
          "instructions": {
            "type": [
              "string",
              "null"
            ]
          },
          "recipientEmail": {
            "type": [
              "string",
              "null"
            ],
            "example": "cliente@ejemplo.com",
            "maxLength": 254
          },
          "recipientPhone": {
            "type": [
              "string",
              "null"
            ]
          },
          "scheduledDate": {
            "type": [
              "string",
              "null"
            ]
          },
          "shipperId": {
            "type": [
              "string",
              "null"
            ]
          },
          "windowEnd": {
            "type": [
              "string",
              "null"
            ]
          },
          "windowStart": {
            "type": [
              "string",
              "null"
            ]
          },
          "zoneId": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "address",
          "customerName"
        ]
      },
      "PublicDeliveryEditInput": {
        "type": "object",
        "properties": {
          "address": {
            "type": [
              "string",
              "null"
            ]
          },
          "amountToCollect": {
            "type": [
              "string",
              "null"
            ]
          },
          "currency": {
            "type": [
              "string",
              "null"
            ],
            "default": "UYU",
            "enum": [
              "UYU",
              "USD",
              null
            ]
          },
          "customerName": {
            "type": [
              "string",
              "null"
            ]
          },
          "destinationLat": {
            "type": [
              "number",
              "null"
            ],
            "format": "double"
          },
          "destinationLng": {
            "type": [
              "number",
              "null"
            ],
            "format": "double"
          },
          "externalReference": {
            "type": [
              "string",
              "null"
            ]
          },
          "instructions": {
            "type": [
              "string",
              "null"
            ]
          },
          "recipientEmail": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 254
          },
          "recipientPhone": {
            "type": [
              "string",
              "null"
            ]
          },
          "zoneId": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "PublicDeliveryPage": {
        "type": "object",
        "properties": {
          "deliveries": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "$ref": "#/components/schemas/PublicDelivery"
            }
          },
          "nextCursor": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "deliveries",
          "nextCursor"
        ]
      },
      "PublicProof": {
        "type": "object",
        "properties": {
          "deliveryId": {
            "type": [
              "string",
              "null"
            ]
          },
          "expiresAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "photo": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/PublicProofFile"
              },
              {
                "type": "null"
              }
            ]
          },
          "proofId": {
            "type": [
              "string",
              "null"
            ]
          },
          "recipientName": {
            "type": [
              "string",
              "null"
            ]
          },
          "recordedAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "signature": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/PublicProofFile"
              },
              {
                "type": "null"
              }
            ]
          },
          "test": {
            "type": "boolean"
          },
          "urlsExpireAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        },
        "required": [
          "deliveryId",
          "expiresAt",
          "photo",
          "proofId",
          "recipientName",
          "recordedAt",
          "signature",
          "test",
          "urlsExpireAt"
        ]
      },
      "PublicProofFile": {
        "type": "object",
        "properties": {
          "contentType": {
            "type": [
              "string",
              "null"
            ]
          },
          "height": {
            "type": "integer",
            "format": "int32"
          },
          "sizeBytes": {
            "type": "integer",
            "format": "int32"
          },
          "url": {
            "type": [
              "string",
              "null"
            ]
          },
          "width": {
            "type": "integer",
            "format": "int32"
          }
        },
        "required": [
          "contentType",
          "height",
          "sizeBytes",
          "url",
          "width"
        ]
      },
      "PublicSandboxSimulationInput": {
        "type": "object",
        "properties": {
          "action": {
            "type": "string",
            "enum": [
              "ASSIGN",
              "PICK_UP",
              "START",
              "DELIVER",
              "FAIL",
              "RETRY",
              "SETTLE"
            ]
          },
          "collectionMethod": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "CASH",
              "TRANSFER",
              "OTHER",
              null
            ]
          },
          "failureReasonCode": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "RECIPIENT_ABSENT",
              "ADDRESS_NOT_FOUND",
              "ACCESS_UNAVAILABLE",
              "RECIPIENT_REFUSED",
              "UNSAFE_LOCATION",
              "PACKAGE_ISSUE",
              "OTHER",
              null
            ]
          }
        },
        "required": [
          "action"
        ]
      },
      "PublicZoneZones": {
        "type": "object",
        "properties": {
          "zones": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "$ref": "#/components/schemas/ZoneOption"
            }
          }
        },
        "required": [
          "zones"
        ]
      },
      "WebhookEvent": {
        "type": "object",
        "description": "Cuerpo de todo webhook de Ruta. El orden de las claves no está garantizado.",
        "properties": {
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "data": {
            "$ref": "#/components/schemas/WebhookEventData"
          },
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Id del evento (Ruta-Event-Id)."
          },
          "test": {
            "type": "boolean",
            "description": "true para eventos del entorno de prueba y para webhook.test."
          },
          "type": {
            "type": "string",
            "enum": [
              "delivery.created",
              "delivery.status_changed",
              "delivery.assigned",
              "delivery.picked_up",
              "delivery.out_for_delivery",
              "delivery.delivered",
              "delivery.failed",
              "delivery.cancelled",
              "delivery.retry_scheduled",
              "delivery.proof_added",
              "delivery.collection_settled",
              "webhook.test"
            ]
          }
        },
        "required": [
          "createdAt",
          "data",
          "id",
          "test",
          "type"
        ]
      },
      "WebhookEventData": {
        "type": "object",
        "description": "Datos del evento. Nunca incluye datos del destinatario: consultá la entrega por la API.",
        "properties": {
          "attemptNumber": {
            "type": "integer",
            "format": "int32"
          },
          "collectedAmount": {
            "type": "string",
            "description": "Cobrado (delivered, collection_settled), decimal con 2 cifras."
          },
          "collectedAt": {
            "type": "string",
            "format": "date-time"
          },
          "collectionMethod": {
            "type": "string",
            "description": "CASH, TRANSFER u OTHER (delivered, collection_settled)."
          },
          "currency": {
            "type": "string",
            "description": "UYU o USD, la moneda de collectedAmount (delivered con cobro, collection_settled): la recibida, también si el repartidor cobró en la otra moneda; Ruta nunca convierte."
          },
          "deliveryId": {
            "type": "string",
            "description": "Id de la entrega (todos salvo webhook.test)."
          },
          "endpointId": {
            "type": "string",
            "description": "Endpoint probado (webhook.test)."
          },
          "externalReference": {
            "type": "string",
            "description": "Referencia del pedido de la tienda, si se envió."
          },
          "failureReasonCode": {
            "type": "string",
            "description": "Motivo del fallo (FAILED)."
          },
          "message": {
            "type": "string",
            "description": "Texto del evento de prueba (webhook.test)."
          },
          "mode": {
            "type": "string",
            "description": "LIVE o TEST (webhook.test)."
          },
          "pickedUpAt": {
            "type": "string",
            "format": "date-time"
          },
          "place": {
            "type": "string",
            "description": "BASE o SHIPPER (picked_up)."
          },
          "previousStatus": {
            "type": "string",
            "description": "Estado anterior (status_changed y eventos con nombre)."
          },
          "proofId": {
            "type": "string",
            "description": "Id del comprobante (proof_added)."
          },
          "reason": {
            "type": "string",
            "description": "START_UNDONE cuando la entrega volvió de OUT_FOR_DELIVERY a ASSIGNED con el mismo intento («Volver a asignada»; status_changed y assigned). Sólo en ese caso.",
            "enum": [
              "START_UNDONE"
            ]
          },
          "recordedAt": {
            "type": "string",
            "format": "date-time"
          },
          "settledAt": {
            "type": "string",
            "format": "date-time"
          },
          "shipperId": {
            "type": "string",
            "description": "Comercio de la entrega, si tiene."
          },
          "status": {
            "type": "string",
            "description": "Estado actual de la entrega."
          }
        }
      },
      "ZoneOption": {
        "type": "object",
        "properties": {
          "areas": {
            "type": [
              "string",
              "null"
            ]
          },
          "id": {
            "type": [
              "string",
              "null"
            ]
          },
          "name": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "areas",
          "id",
          "name"
        ]
      }
    },
    "securitySchemes": {
      "apiKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "Clave de API de la empresa o de un comercio: `ruta_…` (producción) o `ruta_test_…` (prueba)."
      }
    }
  }
}
