{
  "openapi": "3.1.0",
  "info": {
    "title": "ShippyPro API v2",
    "version": "2.0.0",
    "description": "ShippyPro Public API v2 — customer-facing spec for external partners and integrators.\n\n## Authentication\n\nEvery API request must be authenticated with a **Bearer token** — your\n**API Key**, sent in the `Authorization` header. The only exception is\n`GET /v2/status`, which is public.\n\nYou can find or generate your **API Key** under the API section\n[Here](https://www.shippypro.com/panel/apikeys.html) in ShippyPro (e.g.\n`your-API-Key`).\n\nSend it with every request as follows:\n\n`Authorization: Bearer your-API-Key`\n\nRequests with a missing, malformed, invalid, or revoked API Key are rejected\nwith `401`.\n\n## Conventions\n\n- All field names use **camelCase**\n- Timestamps use **RFC 3339** format (`2026-03-30T10:30:00Z`)\n- Enum values use **UPPER_SNAKE_CASE**\n- Errors follow **RFC 9457** (Problem Details for HTTP APIs)\n- Pagination is **cursor-based** by default\n- Resource URLs returned in `Location`, `Content-Location` and `links`\n  carry the internal `/api/v2` path prefix. Replace it with `/v2` before\n  you call them.\n",
    "x-logo": {
      "url": "https://public-website-hb.shippypro.com/hubfs/ShippyProLogo%20-%20AppIcon.png",
      "altText": "ShippyPro"
    },
    "contact": {
      "name": "ShippyPro Engineering"
    },
    "license": {
      "name": "Proprietary"
    }
  },
  "servers": [
    {
      "url": "https://api.shippypro.com",
      "description": "Production"
    }
  ],
  "security": [
    {
      "apiKey": []
    }
  ],
  "tags": [
    {
      "name": "Carriers",
      "description": "Carrier catalog and carrier configuration"
    },
    {
      "name": "Optimizer",
      "description": "Optimizer data export endpoints"
    },
    {
      "name": "Status",
      "description": "API health check"
    }
  ],
  "paths": {
    "/v2/optimizer-exports": {
      "post": {
        "operationId": "createOptimizerExport",
        "summary": "Create an optimizer data export",
        "description": "Triggers an asynchronous export of optimizer data for the authenticated user.\nReturns **202 Accepted** immediately with an export resource in `PENDING`\nstate; poll `GET /v2/optimizer-exports/{exportId}` until `status` is\n`COMPLETED` (then `downloadUrl` is populated) or `FAILED`.\n",
        "tags": [
          "Optimizer"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "UUID v4 for safe retries. See API v2 Standards §7."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateOptimizerExportRequest"
              },
              "example": {
                "exportType": "EXPORT",
                "name": "Q1 2026 report",
                "filters": {
                  "createdAt": {
                    "gte": "2026-01-01",
                    "lte": "2026-03-30"
                  },
                  "carriers": [
                    "DHL",
                    "UPS"
                  ],
                  "senderCountries": [
                    "IT"
                  ],
                  "recipientCountries": [
                    "DE",
                    "FR"
                  ]
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Export accepted and queued for processing",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                },
                "description": "URI of the created export resource (URL-encoded)",
                "example": "/v2/optimizer-exports/reports%2Foptimizer%2Fcsv%2F2026%2F04%2F20%2F136930%2Fexport_136930_1776685072.csv"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "X-Ignored-Fields": {
                "$ref": "#/components/headers/XIgnoredFields"
              },
              "Idempotent-Replayed": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                },
                "description": "Present and `true` only when this response was replayed from a prior Idempotency-Key match."
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OptimizerExport"
                },
                "example": {
                  "id": "reports/optimizer/csv/2026/04/20/136930/export_136930_1776685072.csv",
                  "userId": 136930,
                  "status": "PENDING",
                  "exportType": "EXPORT",
                  "name": "Q1 2026 report",
                  "createdAt": "2026-04-20T11:37:51+00:00",
                  "updatedAt": "2026-04-20T11:37:51+00:00"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitExceeded"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      },
      "get": {
        "operationId": "listOptimizerExports",
        "summary": "List optimizer exports",
        "description": "Returns a cursor-paginated list of the authenticated user's exports,\nnewest first. Cursors in `links.next` / `links.prev` are opaque\nbase64url strings — clients must not parse them.\n",
        "tags": [
          "Optimizer"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "pageSize",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            },
            "description": "Items per page (max 100)."
          },
          {
            "name": "startingAfter",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Opaque cursor from a previous `links.next`. Mutually exclusive with `endingBefore`."
          },
          {
            "name": "endingBefore",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Opaque cursor from a previous `links.prev`. Mutually exclusive with `startingAfter`."
          }
        ],
        "responses": {
          "200": {
            "description": "A page of exports",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControlPrivate"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OptimizerExportList"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitExceeded"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/v2/optimizer-exports/{exportId}": {
      "parameters": [
        {
          "name": "exportId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "maxLength": 1024,
            "description": "Full S3 key of the export (the DynamoDB sort key). May contain\nslashes and dots; clients MUST URL-encode the value when\nconstructing the URL.\n",
            "pattern": "^[a-zA-Z0-9!_.*'()/\\-]+$"
          },
          "example": "reports/optimizer/csv/2026/04/20/136930/export_136930_1776683002.csv"
        }
      ],
      "get": {
        "operationId": "getOptimizerExport",
        "summary": "Get an optimizer export by ID",
        "description": "Retrieve the status and details of an optimizer data export. Poll this\nendpoint to check if the export is ready for download (`status ==\nCOMPLETED`, at which point `downloadUrl` is populated).\n",
        "tags": [
          "Optimizer"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "Export details",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OptimizerExport"
                },
                "examples": {
                  "pending": {
                    "summary": "Export still processing",
                    "value": {
                      "id": "reports/optimizer/csv/2026/04/20/136930/export_136930_1776685072.csv",
                      "userId": 136930,
                      "status": "PENDING",
                      "exportType": "EXPORT",
                      "name": "Q1 2026 report",
                      "createdAt": "2026-04-20T11:37:51+00:00",
                      "updatedAt": "2026-04-20T11:37:51+00:00"
                    }
                  },
                  "completed": {
                    "summary": "Export ready for download",
                    "value": {
                      "id": "reports/optimizer/csv/2026/04/20/136930/export_136930_1776685072.csv",
                      "userId": 136930,
                      "status": "COMPLETED",
                      "exportType": "EXPORT",
                      "name": "Q1 2026 report",
                      "createdAt": "2026-04-20T11:37:51+00:00",
                      "updatedAt": "2026-04-20T11:40:15+00:00",
                      "downloadUrl": "https://cdn.shippypro.com/reports/optimizer/csv/2026/04/20/136930/export_136930_1776685072.csv"
                    }
                  }
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitExceeded"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "delete": {
        "operationId": "deleteOptimizerExport",
        "summary": "Delete an optimizer export",
        "description": "Deletes the export record and its backing S3 file. Subsequent reads of\nthe same `exportId` return 404.\n",
        "tags": [
          "Optimizer"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "UUID v4 for safe retries. See API v2 Standards §7."
          }
        ],
        "responses": {
          "204": {
            "description": "Export deleted",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Idempotent-Replayed": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                },
                "description": "Present and `true` only when this response was replayed from a prior Idempotency-Key match."
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitExceeded"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/v2/optimizer-shipments": {
      "get": {
        "operationId": "listOptimizerShipments",
        "summary": "List optimizer shipments",
        "description": "Returns the same per-row dataset as the optimizer CSV export\n(`POST /v2/optimizer-exports`), but synchronous and\ncursor-paginated so partners can consume it programmatically\nwithout polling for file completion.\n\nRows are ordered newest-first by `createdAt`, with `id` as the\ndeterministic tiebreaker. Cursors in `links.next` / `links.prev`\nare opaque base64url strings — clients must not parse them or\ndepend on their internal shape.\n\n**`total` is intentionally omitted from `pagination`** — an exact\ncount would require a second pass against the analytics\nmaterialized view that backs this endpoint and would roughly\ndouble query cost. Use `hasMore` to detect the end of the\ndataset.\n\n**Date windows.** Filter by shipment creation (`createdAt`) and/or\nby last tracking activity (`lastTrackingStatusDate` — \"which\nshipments changed since my last sync\", for incremental pulls).\n**At least one** window is required; supply either alone or both.\nEach supplied window requires both its `[gte]` and `[lte]` bounds.\nWhen both windows are supplied they are combined with **AND** (not\nOR) — a shipment must fall inside *both* its `createdAt` and its\n`lastTrackingStatusDate` window to match.\n\n**Date range cap.** Each supplied window is capped at 365 days\n(per-environment, configurable). A window spanning wider returns\n`422 Validation Error` (`code: INVALID_FORMAT`) with a field error\non that window (`createdAt` or `lastTrackingStatusDate`).\n",
        "tags": [
          "Optimizer"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "createdAt[gte]",
            "in": "query",
            "required": false,
            "description": "Inclusive lower bound of the `createdAt` window. Accepts\neither a date-only value (`YYYY-MM-DD`) — treated as\nmidnight UTC of that day — or an RFC 3339 datetime\n(`2026-01-01T06:00:00Z`). Optional, but at least one of\n`createdAt` or `lastTrackingStatusDate` must be supplied; if\n`createdAt[gte]` is present, `createdAt[lte]` is required too.\n",
            "schema": {
              "type": "string"
            },
            "examples": {
              "dateOnly": {
                "value": "2026-01-01"
              },
              "datetime": {
                "value": "2026-01-01T00:00:00Z"
              }
            }
          },
          {
            "name": "createdAt[lte]",
            "in": "query",
            "required": false,
            "description": "Inclusive upper bound of the `createdAt` window. Accepts\neither a date-only value or an RFC 3339 datetime. For\ndate-only input the entire day is included — the server\nuses an exclusive next-day-midnight bound internally so\nsub-second timestamps on the boundary day are preserved.\nRequired when `createdAt[gte]` is present.\n",
            "schema": {
              "type": "string"
            },
            "examples": {
              "dateOnly": {
                "value": "2026-01-31"
              },
              "datetime": {
                "value": "2026-01-31T23:59:59Z"
              }
            }
          },
          {
            "name": "lastTrackingStatusDate[gte]",
            "in": "query",
            "required": false,
            "description": "Inclusive lower bound of the last-tracking-activity window —\nselects shipments whose most recent tracking update falls in\nthe range, enabling incremental \"updated since X\" syncs.\nAccepts a date-only value (`YYYY-MM-DD`, midnight UTC) or an\nRFC 3339 datetime. Optional, but at least one of `createdAt`\nor `lastTrackingStatusDate` must be supplied; if\n`lastTrackingStatusDate[gte]` is present,\n`lastTrackingStatusDate[lte]` is required too.\n\nFiltering on tracking activity queries the full analytics\nview (not the recent-window optimization), so shipments\ncreated long ago but updated recently are still returned.\n",
            "schema": {
              "type": "string"
            },
            "examples": {
              "dateOnly": {
                "value": "2026-03-01"
              },
              "datetime": {
                "value": "2026-03-01T00:00:00Z"
              }
            }
          },
          {
            "name": "lastTrackingStatusDate[lte]",
            "in": "query",
            "required": false,
            "description": "Inclusive upper bound of the last-tracking-activity window.\nAccepts a date-only value or an RFC 3339 datetime; for\ndate-only input the entire day is included (exclusive\nnext-day-midnight bound server-side). Required when\n`lastTrackingStatusDate[gte]` is present.\n",
            "schema": {
              "type": "string"
            },
            "examples": {
              "dateOnly": {
                "value": "2026-03-02"
              },
              "datetime": {
                "value": "2026-03-02T23:59:59Z"
              }
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            },
            "description": "Items per page (max 100)."
          },
          {
            "name": "startingAfter",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Opaque cursor from a previous response's `links.next`.\nMutually exclusive with `endingBefore`.\n"
          },
          {
            "name": "endingBefore",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Opaque cursor from a previous response's `links.prev`.\nMutually exclusive with `startingAfter`.\n"
          },
          {
            "name": "carriers",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Comma-separated carrier names. Matching is case-insensitive\non the underlying `carrier_name`. Multiple values combine\nas OR within the carrier filter.\n",
            "example": "DHL,UPS"
          },
          {
            "name": "carrierIds",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "pattern": "^\\s*[1-9][0-9]*\\s*(,\\s*[1-9][0-9]*\\s*)*$"
            },
            "description": "Comma-separated positive carrier IDs. Whitespace around\ntokens is tolerated.\n\n**Must be combined with `carriers`.** ShippyPro's carrier\nIDs are not globally unique — the same numeric id can map\nto different carriers (e.g. id `123` exists for both BRT\nand InPost). Sending `carrierIds` without `carriers`\nreturns `422 Validation Error`.\n\nWhen combined, IDs apply per-name: each name in `carriers`\nis paired with the full id list, and the resulting\nselectors are OR'd together\n(`(name=DHL AND id IN (…)) OR (name=UPS AND id IN (…))`).\n",
            "example": "12,47"
          },
          {
            "name": "senderCountries",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Comma-separated ISO 3166-1 alpha-2 country codes for the\norigin (sender) address. Case-insensitive; uppercased\nserver-side before matching.\n",
            "example": "IT,US"
          },
          {
            "name": "recipientCountries",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Comma-separated ISO 3166-1 alpha-2 country codes for the\ndestination (recipient) address. Case-insensitive;\nuppercased server-side before matching.\n",
            "example": "DE,FR"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of shipments",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControlPrivate"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OptimizerShipmentList"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "description": "Validation failed",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetail"
                },
                "examples": {
                  "missingDateRange": {
                    "summary": "Neither date window supplied",
                    "value": {
                      "type": "https://api.shippypro.com/problems/validation-error",
                      "title": "Validation Error",
                      "status": 422,
                      "detail": "The request body contains invalid fields.",
                      "errors": [
                        {
                          "detail": "At least one of createdAt or lastTrackingStatusDate must be provided.",
                          "pointer": "/createdAt",
                          "code": "INVALID_FORMAT"
                        }
                      ]
                    }
                  },
                  "dateRangeCapExceeded": {
                    "summary": "Date range exceeds the configured cap",
                    "value": {
                      "type": "https://api.shippypro.com/problems/validation-error",
                      "title": "Validation Error",
                      "status": 422,
                      "detail": "The request body contains invalid fields.",
                      "errors": [
                        {
                          "detail": "Date range spans 400 days; the maximum allowed is 365.",
                          "pointer": "/createdAt",
                          "code": "INVALID_FORMAT"
                        }
                      ]
                    }
                  },
                  "carrierIdsWithoutCarriers": {
                    "summary": "carrierIds sent without the required carriers filter",
                    "value": {
                      "type": "https://api.shippypro.com/problems/validation-error",
                      "title": "Validation Error",
                      "status": 422,
                      "detail": "The request body contains invalid fields.",
                      "errors": [
                        {
                          "detail": "carrierIds requires carriers to also be set; carrier ids are not unique without a carrier name.",
                          "pointer": "/carrierIds",
                          "code": "INVALID_FORMAT"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimitExceeded"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/v2/carriers": {
      "get": {
        "operationId": "listCarriers",
        "summary": "List carriers",
        "description": "Returns the carriers that can be configured. The catalog is identical\nfor every caller, so responses carry `Cache-Control: public, max-age=300`.\n",
        "tags": [
          "Carriers"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "supportedCountry",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "minLength": 2,
              "maxLength": 2
            },
            "description": "ISO 3166-1 alpha-2 country code. Returns only the carriers whose\nshipment service covers that country. Case-insensitive.\n",
            "example": "IT"
          }
        ],
        "responses": {
          "200": {
            "description": "The carrier catalog",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControlPublic"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CarrierList"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitExceeded"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/v2/carriers/{carrierSlug}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/CarrierSlug"
        }
      ],
      "get": {
        "operationId": "getCarrier",
        "summary": "Get a carrier",
        "description": "Returns one carrier from the catalog with the services it supports.\nThis is the same document as\n`GET /v2/carriers/{carrierSlug}/capabilities`.\n",
        "tags": [
          "Carriers"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/CarrierDocument"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitExceeded"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/v2/carriers/{carrierSlug}/capabilities": {
      "parameters": [
        {
          "$ref": "#/components/parameters/CarrierSlug"
        }
      ],
      "get": {
        "operationId": "getCarrierCapabilities",
        "summary": "Get carrier capabilities",
        "description": "Returns the services and features the carrier supports. The document is\nthe same one `GET /v2/carriers/{carrierSlug}` returns.\n",
        "tags": [
          "Carriers"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/CarrierDocument"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitExceeded"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/v2/carriers/{carrierSlug}/schema": {
      "parameters": [
        {
          "$ref": "#/components/parameters/CarrierSlug"
        }
      ],
      "get": {
        "operationId": "getCarrierConfigSchema",
        "summary": "Get the config schema of a carrier",
        "description": "Returns the schema that describes the fields a config for this carrier\nmust contain. Use it to build the `config` object sent to\n`POST /v2/carriers/{carrierSlug}/configs`.\n\nThe document is returned unwrapped, because a schema is a single\ndocument rather than a collection.\n\nA carrier without a published schema answers `404`.\n",
        "tags": [
          "Carriers"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "The config schema",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControlPublic"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CarrierConfigSchema"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitExceeded"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/v2/carrier-configs": {
      "get": {
        "operationId": "listCarrierConfigs",
        "summary": "List carrier configs across every carrier",
        "description": "Returns a cursor-paginated page of the caller's carrier configs, for\nevery carrier. Only configs owned by the caller are returned.\n\n`total` is omitted because counting the partition means reading every\nitem in it. Use `hasMore` to detect the end of the dataset.\n\nCursors are opaque and are signed for the calling user. A cursor that\nfails verification answers `422` instead of restarting from the first\npage.\n",
        "tags": [
          "Carriers"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ConfigPageSize"
          },
          {
            "$ref": "#/components/parameters/ConfigStartingAfter"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/CarrierConfigPage"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitExceeded"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/v2/carriers/{carrierSlug}/configs": {
      "parameters": [
        {
          "$ref": "#/components/parameters/CarrierSlug"
        }
      ],
      "get": {
        "operationId": "listCarrierConfigsForCarrier",
        "summary": "List the caller's configs for one carrier",
        "description": "Returns a cursor-paginated page of the caller's configs for this\ncarrier. The envelope, the cursor rules and the cache policy match\n`GET /v2/carrier-configs`.\n",
        "tags": [
          "Carriers"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ConfigPageSize"
          },
          {
            "$ref": "#/components/parameters/ConfigStartingAfter"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/CarrierConfigPage"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitExceeded"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "post": {
        "operationId": "createCarrierConfig",
        "summary": "Create a carrier config",
        "description": "Creates a config for this carrier, owned by the caller. The owner comes\nfrom the API Key and the `id` is always generated by the server, so\nneither can be set from the request body.\n\nThe `config` object is validated against the carrier schema returned by\n`GET /v2/carriers/{carrierSlug}/schema`. An unknown `carrierSlug`\nanswers `422`.\n",
        "tags": [
          "Carriers"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateCarrierConfigRequest"
              },
              "example": {
                "config": {
                  "clientId": "your-client-id",
                  "clientSecret": "your-client-secret",
                  "accountNumber": "123456"
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Config created",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                },
                "description": "URI of the created config, always in the canonical ULID form. See **Conventions** for the path prefix.",
                "example": "/api/v2/carriers/upsv2/configs/01kg2fbj26w7db1jq4e8vvjwpz"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControlNoStore"
              },
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/IdempotentReplayed"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CarrierConfig"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitExceeded"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/v2/carriers/{carrierSlug}/configs/{carrierConfigId}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/CarrierSlug"
        },
        {
          "$ref": "#/components/parameters/CarrierConfigId"
        }
      ],
      "get": {
        "operationId": "getCarrierConfig",
        "summary": "Get a carrier config",
        "description": "Returns one of the caller's configs. A config owned by another user\nanswers `404`, the same as one that does not exist.\n\nWhen the config is addressed by the legacy `CarrierID`, the response\ncarries `Content-Location` with the canonical ULID URL.\n",
        "tags": [
          "Carriers"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "The carrier config",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControlNoStore"
              },
              "Content-Location": {
                "$ref": "#/components/headers/ContentLocation"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CarrierConfig"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitExceeded"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "put": {
        "operationId": "updateCarrierConfig",
        "summary": "Replace the config object",
        "description": "Replaces the `config` object of one of the caller's configs. The owner\ncomes from the API Key, so the body carries no `userId`.\n\nThis operation ignores `Idempotency-Key`, because a replacement is\nalready idempotent.\n",
        "tags": [
          "Carriers"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateCarrierConfigRequest"
              },
              "example": {
                "config": {
                  "clientId": "your-client-id",
                  "clientSecret": "your-new-client-secret",
                  "accountNumber": "123456"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated config",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControlNoStore"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CarrierConfig"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitExceeded"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "patch": {
        "operationId": "patchCarrierConfig",
        "summary": "Update the state of a carrier config",
        "description": "Updates `active`, `label` or `test` on one of the caller's configs. The\ncredentials inside `config` are not reachable from this operation. Use\n`PUT` for those.\n\nA body that sets none of the three fields changes nothing and answers\n`204`.\n\nThis operation ignores `Idempotency-Key`.\n",
        "tags": [
          "Carriers"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PatchCarrierConfigRequest"
              },
              "example": {
                "active": true,
                "label": "Main UPS account"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated config",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControlNoStore"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CarrierConfig"
                }
              }
            }
          },
          "204": {
            "description": "The body set no supported field, so nothing changed",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitExceeded"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "delete": {
        "operationId": "deleteCarrierConfig",
        "summary": "Delete a carrier config",
        "description": "Deletes one of the caller's configs. Later reads of the same id answer\n`404`.\n",
        "tags": [
          "Carriers"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "204": {
            "description": "Config deleted",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControlNoStore"
              },
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/IdempotentReplayed"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitExceeded"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/v2/status": {
      "get": {
        "operationId": "getApiStatus",
        "summary": "API health check",
        "description": "Returns the current API status. No authentication required.",
        "tags": [
          "Status"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "API is healthy",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "status",
                    "version"
                  ],
                  "properties": {
                    "status": {
                      "type": "string",
                      "enum": [
                        "HEALTHY"
                      ]
                    },
                    "version": {
                      "type": "string",
                      "example": "2.0.0"
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "apiKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "Bearer token authentication with your ShippyPro API Key.\n\nSend the API Key as the token.\n\nSee the **Authentication** section for more information.\n"
      }
    },
    "headers": {
      "XRequestId": {
        "description": "Unique request identifier for tracing",
        "schema": {
          "type": "string",
          "example": "req_abc123def456"
        }
      },
      "RateLimitPolicy": {
        "description": "Rate limit policy descriptor (IETF draft).\nFormat: `\"{policy_name}\";q={limit};w={window_seconds}`\n",
        "schema": {
          "type": "string",
          "example": "\"standard\";q=100;w=60"
        }
      },
      "RateLimit": {
        "description": "Current rate limit state (IETF draft).\nFormat: `\"{policy_name}\";r={remaining};t={seconds_until_reset}`\n",
        "schema": {
          "type": "string",
          "example": "\"standard\";r=42;t=18"
        }
      },
      "XRateLimitLimit": {
        "description": "Legacy — request limit in the current window. Will be removed in a future version.",
        "schema": {
          "type": "integer",
          "example": 100
        }
      },
      "XRateLimitRemaining": {
        "description": "Legacy — requests remaining in the current window. Will be removed in a future version.",
        "schema": {
          "type": "integer",
          "example": 42
        }
      },
      "XRateLimitReset": {
        "description": "Legacy — Unix timestamp when the rate limit window resets. Will be removed in a future version.",
        "schema": {
          "type": "integer",
          "example": 1776685072
        }
      },
      "ETag": {
        "description": "Entity tag for the returned representation. Use with `If-None-Match` for conditional requests.",
        "schema": {
          "type": "string",
          "example": "W/\"a1b2c3d4\""
        }
      },
      "CacheControlPrivate": {
        "description": "Cache directives. Set to `private, max-age=0` on user-specific list endpoints to prevent intermediate caching.",
        "schema": {
          "type": "string",
          "example": "private, max-age=0"
        }
      },
      "CacheControlPublic": {
        "description": "Cache directives. Set to `public, max-age=300` on the carrier catalog, which is identical for every caller.",
        "schema": {
          "type": "string",
          "example": "public, max-age=300"
        }
      },
      "CacheControlNoStore": {
        "description": "Cache directives. Set to `private, no-store` on carrier configs, which are owned by one account and must not sit in any shared, browser or disk cache.",
        "schema": {
          "type": "string",
          "example": "private, no-store"
        }
      },
      "IdempotentReplayed": {
        "description": "Present and `true` only when this response was replayed from a prior Idempotency-Key match.",
        "schema": {
          "type": "string",
          "enum": [
            "true"
          ]
        }
      },
      "ContentLocation": {
        "description": "The canonical URL of the returned resource. Emitted only when the\nrequest addressed a carrier config by its legacy `CarrierID` instead of\nits ULID. See **Conventions** for the path prefix.\n",
        "schema": {
          "type": "string"
        },
        "example": "/api/v2/carriers/upsv2/configs/01kg2fbj26w7db1jq4e8vvjwpz"
      },
      "XIgnoredFields": {
        "description": "Comma-separated list of JSON Pointers (RFC 6901) identifying request\nbody fields that were present but not recognised by the server. The\nfields are silently ignored (§11.2 forward-compatibility guarantee);\nthis header surfaces them so partners can catch typos or stale clients.\nOnly emitted when at least one field was ignored.\n",
        "schema": {
          "type": "string",
          "example": "/filters/unknownField,/topLevel"
        }
      }
    },
    "parameters": {
      "IfNoneMatch": {
        "name": "If-None-Match",
        "in": "header",
        "description": "Conditional request — when the resource's current `ETag` matches this value,\nthe server returns `304 Not Modified` with no body.\n",
        "schema": {
          "type": "string"
        },
        "example": "W/\"a1b2c3d4\""
      },
      "CarrierSlug": {
        "name": "carrierSlug",
        "in": "path",
        "required": true,
        "description": "The carrier identifier from `GET /v2/carriers`. Case-insensitive.",
        "schema": {
          "type": "string",
          "pattern": "^[a-zA-Z0-9-]+$"
        },
        "example": "upsv2"
      },
      "CarrierConfigId": {
        "name": "carrierConfigId",
        "in": "path",
        "required": true,
        "description": "The config identifier. Two forms are accepted: the 26-character ULID,\nwhich is canonical, and the legacy numeric `CarrierID` that older\nintegrations already hold. A request that uses the legacy form answers\nwith `Content-Location` pointing at the ULID URL. Always store the ULID.\n",
        "schema": {
          "type": "string",
          "pattern": "^([0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{26}|[0-9]+)$"
        },
        "example": "01kg2fbj26w7db1jq4e8vvjwpz"
      },
      "IdempotencyKey": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": false,
        "description": "UUID v4 for safe retries. See API v2 Standards §7. A replay of a stored\nresponse carries `Idempotent-Replayed: true`. The same key sent with a\ndifferent body answers `409`, and so does a request sent while the first\none is still in flight. A malformed key answers `422`.\n",
        "schema": {
          "type": "string",
          "format": "uuid"
        }
      },
      "ConfigPageSize": {
        "name": "pageSize",
        "in": "query",
        "required": false,
        "description": "Items per page (max 100).",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 100,
          "default": 20
        }
      },
      "ConfigStartingAfter": {
        "name": "startingAfter",
        "in": "query",
        "required": false,
        "description": "Opaque cursor from a previous response's `links.next`.",
        "schema": {
          "type": "string"
        }
      }
    },
    "schemas": {
      "ProblemDetail": {
        "type": "object",
        "required": [
          "type",
          "title",
          "status",
          "detail"
        ],
        "description": "Error response following RFC 9457 (Problem Details for HTTP APIs)",
        "properties": {
          "type": {
            "type": "string",
            "format": "uri",
            "description": "URI identifying the error type (resolves to documentation)",
            "example": "https://api.shippypro.com/problems/validation-error"
          },
          "title": {
            "type": "string",
            "description": "Short, human-readable summary of the error type",
            "example": "Validation Error"
          },
          "status": {
            "type": "integer",
            "description": "HTTP status code (matches the response status)",
            "example": 422
          },
          "detail": {
            "type": "string",
            "description": "Human-readable explanation specific to this occurrence",
            "example": "The request body contains 2 invalid fields."
          },
          "instance": {
            "type": "string",
            "description": "URI identifying this specific error occurrence",
            "example": "/v2/shipments/req_abc123"
          },
          "errors": {
            "type": "array",
            "description": "Field-level error details (for validation errors)",
            "items": {
              "$ref": "#/components/schemas/FieldError"
            }
          }
        }
      },
      "FieldError": {
        "type": "object",
        "required": [
          "detail"
        ],
        "properties": {
          "detail": {
            "type": "string",
            "description": "Human-readable description of the field error",
            "example": "Postal code is required"
          },
          "pointer": {
            "type": "string",
            "description": "JSON Pointer (RFC 6901) to the offending field",
            "example": "/toAddress/postalCode"
          },
          "parameter": {
            "type": "string",
            "description": "Query/path parameter name (mutually exclusive with pointer)"
          },
          "code": {
            "type": "string",
            "description": "Machine-readable error code for this field",
            "enum": [
              "REQUIRED",
              "INVALID_FORMAT",
              "INVALID_RANGE",
              "INVALID_LENGTH",
              "INVALID_ENUM",
              "ALREADY_EXISTS",
              "IDEMPOTENCY_KEY_MISMATCH",
              "IDEMPOTENCY_KEY_IN_FLIGHT"
            ],
            "example": "REQUIRED"
          }
        }
      },
      "Pagination": {
        "type": "object",
        "required": [
          "pageSize",
          "hasMore"
        ],
        "properties": {
          "total": {
            "type": "integer",
            "description": "Total number of items. Included only on endpoints where the count\nis inexpensive to compute; omitted otherwise (see per-endpoint docs).\n",
            "example": 245
          },
          "pageSize": {
            "type": "integer",
            "description": "Number of items requested per page",
            "example": 20
          },
          "hasMore": {
            "type": "boolean",
            "description": "Whether more items exist beyond this page",
            "example": true
          }
        }
      },
      "PaginationNoTotal": {
        "type": "object",
        "required": [
          "pageSize",
          "hasMore"
        ],
        "description": "Pagination envelope for endpoints where `total` is never returned.",
        "properties": {
          "pageSize": {
            "type": "integer",
            "description": "Number of items requested per page",
            "example": 20
          },
          "hasMore": {
            "type": "boolean",
            "description": "Whether more items exist beyond this page",
            "example": true
          }
        }
      },
      "PaginationLinks": {
        "type": "object",
        "properties": {
          "next": {
            "type": "string",
            "description": "URL for the next page of results",
            "example": "/v2/orders?pageSize=20&startingAfter=ord_xyz789"
          },
          "prev": {
            "type": "string",
            "description": "URL for the previous page of results"
          }
        }
      },
      "Money": {
        "type": "object",
        "required": [
          "amount",
          "currency"
        ],
        "properties": {
          "amount": {
            "type": "number",
            "minimum": 0,
            "description": "Monetary amount (max 2 decimal places)",
            "example": 100
          },
          "currency": {
            "type": "string",
            "description": "ISO 4217 currency code",
            "pattern": "^[A-Z]{3}$",
            "example": "EUR"
          }
        }
      },
      "CreateOptimizerExportRequest": {
        "type": "object",
        "description": "Request body for creating an optimizer export. The `filters` object\nmirrors the filter vocabulary of `GET /v2/optimizer-shipments`\nso a single integration can drive both endpoints.\n",
        "properties": {
          "exportType": {
            "type": "string",
            "enum": [
              "EXPORT",
              "EXPORT_NOT_PICKED_UP"
            ],
            "default": "EXPORT",
            "description": "Which dataset to export.\n- `EXPORT`: standard optimizer export.\n- `EXPORT_NOT_PICKED_UP`: orders with printed labels that haven't\n  been handed to the carrier.\n",
            "example": "EXPORT"
          },
          "name": {
            "type": "string",
            "maxLength": 100,
            "pattern": "^[a-zA-Z0-9 \\-_]+$",
            "description": "Optional display name. Letters (a-z, A-Z), digits, spaces, hyphens, underscores.",
            "example": "Q1 2026 report"
          },
          "filters": {
            "$ref": "#/components/schemas/OptimizerExportFilters"
          }
        }
      },
      "OptimizerExportFilters": {
        "type": "object",
        "required": [
          "createdAt"
        ],
        "description": "Filters narrow the dataset the export is built from. `createdAt` is\nrequired; all other fields are optional. Field naming and semantics\nmatch `GET /v2/optimizer-shipments`.\n\nSub-day precision on `createdAt` is accepted for forward compatibility\nbut is currently truncated to the calendar day in UTC, because the\nexport engine queries day-grained partitions.\n",
        "properties": {
          "createdAt": {
            "type": "object",
            "required": [
              "gte",
              "lte"
            ],
            "description": "Inclusive date range, both bounds required.",
            "properties": {
              "gte": {
                "type": "string",
                "description": "Start of the window. `YYYY-MM-DD` or RFC 3339 datetime.",
                "example": "2026-01-01"
              },
              "lte": {
                "type": "string",
                "description": "End of the window. `YYYY-MM-DD` or RFC 3339 datetime. Must be ≥ `gte`.",
                "example": "2026-03-30"
              }
            }
          },
          "carriers": {
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1
            },
            "description": "Carrier display names. Multiple values are OR-combined.",
            "example": [
              "DHL",
              "UPS"
            ]
          },
          "carrierIds": {
            "type": "array",
            "items": {
              "type": "integer",
              "minimum": 1
            },
            "description": "Numeric carrier identifiers. Requires `carriers` to be set in the\nsame request — carrier ids are not globally unique across carriers,\nso the name set scopes them.\n",
            "example": [
              12,
              47
            ]
          },
          "senderCountries": {
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 2,
              "maxLength": 2,
              "description": "ISO 3166-1 alpha-2 country code."
            },
            "example": [
              "IT"
            ]
          },
          "recipientCountries": {
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 2,
              "maxLength": 2,
              "description": "ISO 3166-1 alpha-2 country code."
            },
            "example": [
              "DE",
              "FR"
            ]
          }
        }
      },
      "OptimizerExport": {
        "type": "object",
        "required": [
          "id",
          "userId",
          "status",
          "createdAt",
          "updatedAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "maxLength": 1024,
            "description": "Unique export identifier. In this version the ID is the S3 key\nwhere the export is stored (may contain slashes and dots).\nClients MUST treat it as opaque and URL-encode when constructing\nrequest URLs.\n",
            "example": "reports/optimizer/csv/2026/04/20/136930/export_136930_1776685072.csv"
          },
          "userId": {
            "type": "integer",
            "description": "Owner of the export.",
            "example": 136930
          },
          "status": {
            "type": "string",
            "enum": [
              "PENDING",
              "COMPLETED",
              "FAILED"
            ],
            "description": "Current export status.",
            "example": "PENDING"
          },
          "exportType": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "EXPORT",
              "EXPORT_NOT_PICKED_UP",
              "EXPORT_INSIGHT",
              "EXPORT_SEGMENT",
              null
            ],
            "description": "The export type set at creation. May be `null` on historical records predating this field.",
            "example": "EXPORT"
          },
          "name": {
            "type": [
              "string",
              "null"
            ],
            "description": "Display name (user-provided or auto-generated).",
            "example": "Q1 2026 report"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "description": "RFC 3339 timestamp when the export was queued.",
            "example": "2026-04-20T11:37:51+00:00"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time",
            "description": "RFC 3339 timestamp of the last status update.",
            "example": "2026-04-20T11:40:15+00:00"
          },
          "downloadUrl": {
            "type": "string",
            "format": "uri",
            "description": "URL to fetch the export file. Present **only** when `status ==\nCOMPLETED`. Omitted otherwise.\n",
            "example": "https://cdn.shippypro.com/reports/optimizer/csv/2026/04/20/136930/export_136930_1776685072.csv"
          },
          "kpiSegment": {
            "type": "string",
            "description": "Present only on segment exports."
          },
          "additionalFilters": {
            "type": "object",
            "description": "Present only on segment exports; engine-specific filter metadata.",
            "additionalProperties": true
          }
        }
      },
      "OptimizerExportList": {
        "type": "object",
        "required": [
          "data",
          "pagination"
        ],
        "description": "Cursor-paginated list envelope (per API v2 Standards §3.3). The\nenvelope is used only for collections; single-resource endpoints\nreturn the resource directly.\n",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OptimizerExport"
            }
          },
          "pagination": {
            "$ref": "#/components/schemas/Pagination"
          },
          "links": {
            "$ref": "#/components/schemas/PaginationLinks"
          }
        }
      },
      "OptimizerShipment": {
        "type": "object",
        "required": [
          "id",
          "createdAt"
        ],
        "description": "A single optimizer shipment row, projected from the analytics\nmaterialized view that backs the optimizer export. The field\nset mirrors the CSV export column-for-column so a partner\nswitching from polling exports to this endpoint sees the same\ndata without remapping.\n\nAll fields other than `id` and `createdAt` MAY be `null` when\nthe source row has no value. `Money` fields (`shipmentCost`,\n`cashOnDelivery`, `insurance`) are emitted only when BOTH\namount and currency are present in the source row; a partial\npair is normalized to `null` rather than emitted with a\nmissing half.\n",
        "properties": {
          "id": {
            "type": "string",
            "description": "Shipment identifier (the underlying `ordine_id`, stringified).",
            "example": "99001"
          },
          "transactionId": {
            "type": [
              "string",
              "null"
            ],
            "example": "TX-1"
          },
          "trackingCode": {
            "type": [
              "string",
              "null"
            ],
            "example": "1Z999AA10123456784"
          },
          "returnTrackingCode": {
            "type": [
              "string",
              "null"
            ]
          },
          "marketplacePlatform": {
            "type": [
              "string",
              "null"
            ],
            "example": "shopify"
          },
          "marketplaceId": {
            "type": [
              "string",
              "null"
            ]
          },
          "carrierId": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Internal carrier ID. NOT globally unique — see the\n`carrierIds` query parameter for the implications when\nfiltering.\n",
            "example": 7
          },
          "carrierName": {
            "type": [
              "string",
              "null"
            ],
            "example": "DHL"
          },
          "serviceName": {
            "type": [
              "string",
              "null"
            ],
            "example": "Express"
          },
          "originCountry": {
            "type": [
              "string",
              "null"
            ],
            "description": "ISO 3166-1 alpha-2 country code of the origin address.",
            "example": "IT"
          },
          "originZip": {
            "type": [
              "string",
              "null"
            ],
            "example": "20100"
          },
          "destinationCountry": {
            "type": [
              "string",
              "null"
            ],
            "description": "ISO 3166-1 alpha-2 country code of the destination address.",
            "example": "DE"
          },
          "destinationZip": {
            "type": [
              "string",
              "null"
            ],
            "example": "10115"
          },
          "recipientName": {
            "type": [
              "string",
              "null"
            ]
          },
          "recipientPhone": {
            "type": [
              "string",
              "null"
            ]
          },
          "recipientEmail": {
            "type": [
              "string",
              "null"
            ],
            "format": "email"
          },
          "senderName": {
            "type": [
              "string",
              "null"
            ]
          },
          "senderCompany": {
            "type": [
              "string",
              "null"
            ]
          },
          "senderStreet": {
            "type": [
              "string",
              "null"
            ]
          },
          "senderCity": {
            "type": [
              "string",
              "null"
            ]
          },
          "senderState": {
            "type": [
              "string",
              "null"
            ]
          },
          "senderZip": {
            "type": [
              "string",
              "null"
            ]
          },
          "senderCountry": {
            "type": [
              "string",
              "null"
            ],
            "description": "ISO 3166-1 alpha-2 country code of the sender's registered address."
          },
          "senderPhone": {
            "type": [
              "string",
              "null"
            ]
          },
          "senderEmail": {
            "type": [
              "string",
              "null"
            ],
            "format": "email"
          },
          "itemsDescription": {
            "type": [
              "string",
              "null"
            ],
            "description": "Free-form contents description from the shipment's custom info payload."
          },
          "totalWeightKg": {
            "type": [
              "number",
              "null"
            ],
            "description": "Total declared weight of the shipment in kilograms.",
            "example": 2.5
          },
          "shipmentCost": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Money"
              },
              {
                "type": "null"
              }
            ],
            "description": "Total cost of the shipment as billed by the carrier. `null`\nwhen either the amount or the currency is missing from the\nsource row.\n"
          },
          "cashOnDelivery": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Money"
              },
              {
                "type": "null"
              }
            ],
            "description": "Cash-on-delivery amount, when applicable. `null` otherwise."
          },
          "insurance": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Money"
              },
              {
                "type": "null"
              }
            ],
            "description": "Declared insurance value, when applicable. `null` otherwise."
          },
          "isReturn": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "isDelivered": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "hasException": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "isPudoDelivery": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "Whether the shipment was delivered to a Pick-Up / Drop-Off (PUDO) point rather than the recipient's address."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "description": "RFC 3339 timestamp of when the shipment row was created.",
            "example": "2026-01-15T12:34:56+00:00"
          },
          "manifestNumber": {
            "type": [
              "string",
              "null"
            ]
          },
          "manifestedAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "transitTimeDays": {
            "type": [
              "number",
              "null"
            ],
            "description": "Time in transit, in days (pickup → final delivery).",
            "example": 2.1
          },
          "transitTimeWithoutWeekendsDays": {
            "type": [
              "number",
              "null"
            ],
            "description": "Transit time excluding both Saturday and Sunday."
          },
          "transitTimeWithoutSaturdaysDays": {
            "type": [
              "number",
              "null"
            ],
            "description": "Transit time excluding Saturdays."
          },
          "transitTimeWithoutSundaysDays": {
            "type": [
              "number",
              "null"
            ],
            "description": "Transit time excluding Sundays."
          },
          "firstDeliveryAttemptDays": {
            "type": [
              "number",
              "null"
            ],
            "description": "Days from pickup to the first delivery attempt."
          },
          "firstDeliveryAttemptWithoutWeekendsDays": {
            "type": [
              "number",
              "null"
            ]
          },
          "firstDeliveryAttemptWithoutSaturdaysDays": {
            "type": [
              "number",
              "null"
            ]
          },
          "firstDeliveryAttemptWithoutSundaysDays": {
            "type": [
              "number",
              "null"
            ]
          },
          "deliveryAttempts": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Number of delivery attempts recorded against this shipment."
          },
          "parcelsCount": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Number of parcels associated with the shipment."
          },
          "lastTrackingStatus": {
            "type": [
              "string",
              "null"
            ],
            "description": "Human-readable status text from the last tracking event.",
            "example": "Delivered"
          },
          "lastTrackingStatusCode": {
            "type": [
              "integer",
              "null"
            ],
            "description": "ShippyPro internal tracking status code (numeric)."
          },
          "lastTrackingStatusMessage": {
            "type": [
              "string",
              "null"
            ],
            "description": "Free-form message attached to the last tracking event."
          },
          "lastTrackingStatusAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "firstInTransitStatusAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "First timestamp the shipment entered an `IN_TRANSIT` status."
          },
          "firstScanHubStatusAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "firstCustomerDropOffStatusAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "firstAvailableInPudoStatusAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "firstOutForDeliveryStatusAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "firstFailedDeliveryAttemptStatusAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "firstSuccessDeliveryStatusAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "firstIsReturningStatusAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        }
      },
      "OptimizerShipmentList": {
        "type": "object",
        "required": [
          "data",
          "pagination"
        ],
        "description": "Cursor-paginated list envelope for optimizer shipments. `total` is\nnever returned — see the endpoint description for the rationale.\n",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OptimizerShipment"
            }
          },
          "pagination": {
            "$ref": "#/components/schemas/PaginationNoTotal"
          },
          "links": {
            "$ref": "#/components/schemas/PaginationLinks"
          }
        }
      },
      "Carrier": {
        "type": "object",
        "required": [
          "slug",
          "name",
          "version",
          "logoUrl",
          "supportedCountries",
          "authType",
          "isLegacy"
        ],
        "description": "One entry of the carrier catalog.",
        "properties": {
          "slug": {
            "type": "string",
            "description": "Carrier identifier. Use it in every `/v2/carriers/{carrierSlug}` path.",
            "example": "upsv2"
          },
          "name": {
            "type": "string",
            "description": "Display name.",
            "example": "UPS"
          },
          "version": {
            "type": "string",
            "description": "Version of the carrier integration.",
            "example": "2"
          },
          "logoUrl": {
            "type": "string",
            "format": "uri",
            "description": "CDN URL of the carrier logo."
          },
          "supportedCountries": {
            "type": "array",
            "description": "ISO 3166-1 alpha-2 codes the shipment service covers. Regional\ngroups are expanded into single countries. Empty when the carrier\nhas no shipment service.\n",
            "items": {
              "type": "string",
              "minLength": 2,
              "maxLength": 2
            },
            "example": [
              "IT",
              "DE",
              "FR"
            ]
          },
          "authType": {
            "type": "string",
            "enum": [
              "client_credentials",
              "oauth2_refresh",
              "none"
            ],
            "description": "How a config for this carrier authenticates against the carrier.",
            "example": "client_credentials"
          },
          "isLegacy": {
            "type": "boolean",
            "description": "Whether a newer version of the same carrier exists.",
            "example": false
          }
        }
      },
      "CarrierList": {
        "type": "object",
        "required": [
          "data",
          "pagination"
        ],
        "description": "List envelope for the carrier catalog. The catalog is returned whole, so\n`pagination.hasMore` is always `false` and there is no `links` object.\n",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Carrier"
            }
          },
          "pagination": {
            "$ref": "#/components/schemas/PaginationNoTotal"
          }
        }
      },
      "CarrierCapabilities": {
        "type": "object",
        "required": [
          "slug",
          "services"
        ],
        "description": "The services one carrier supports.",
        "properties": {
          "slug": {
            "type": "string",
            "example": "upsv2"
          },
          "services": {
            "type": "object",
            "description": "One entry per service, keyed by service name (`shipment`,\n`tracking`, `auth` and others). The key set depends on the carrier.\n",
            "additionalProperties": {
              "$ref": "#/components/schemas/ServiceCapability"
            }
          }
        }
      },
      "ServiceCapability": {
        "type": "object",
        "required": [
          "available"
        ],
        "description": "What one service supports for this carrier. New fields can appear, so\ntreat the object as open.\n",
        "additionalProperties": true,
        "properties": {
          "available": {
            "type": "boolean",
            "description": "Whether the service can be used with this carrier."
          },
          "reason": {
            "type": [
              "string",
              "null"
            ],
            "description": "Why the service is unavailable. `null` when it is available."
          },
          "authType": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "client_credentials",
              "oauth2_refresh",
              "none",
              null
            ],
            "description": "Authentication method. Set on the `auth` service, `null` elsewhere."
          },
          "serviceTypes": {
            "type": "array",
            "description": "The shipping services that can be selected for this carrier.",
            "items": {
              "type": "object",
              "properties": {
                "code": {
                  "type": "string",
                  "description": "The carrier's own code for the service."
                },
                "readable": {
                  "type": "string",
                  "description": "Display name."
                },
                "value": {
                  "type": "string",
                  "description": "The value to send to ShippyPro when you book this service."
                }
              }
            }
          },
          "labelTypes": {
            "type": "array",
            "description": "The label formats the carrier can return.",
            "items": {
              "type": "object",
              "properties": {
                "carrierCode": {
                  "type": "string",
                  "description": "The carrier's own code for the label format."
                },
                "format": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "description": "File format, for example `PDF` or `ZPL`."
                },
                "readable": {
                  "type": "string",
                  "description": "Display name."
                },
                "value": {
                  "type": "string",
                  "description": "The value to send to ShippyPro when you ask for this format."
                }
              }
            }
          },
          "features": {
            "type": "object",
            "description": "One entry per feature, keyed by feature name.",
            "additionalProperties": {
              "type": "object",
              "properties": {
                "supported": {
                  "type": "boolean",
                  "description": "Whether the carrier integration implements the feature."
                },
                "declared": {
                  "type": "boolean",
                  "description": "Whether the carrier declares the feature in its own capability data."
                },
                "details": {
                  "type": "object",
                  "description": "Feature-specific metadata. The field set depends on the feature.",
                  "additionalProperties": true
                }
              }
            }
          }
        }
      },
      "CarrierConfigSchema": {
        "type": "object",
        "description": "The schema of the `config` object for one carrier, as a JSON Schema\ndocument with ShippyPro `ui:` extensions. `ui:sections` groups the\nfields for display. The field set differs per carrier, so read it at\nruntime rather than hard-coding it.\n",
        "additionalProperties": true
      },
      "CarrierConfig": {
        "type": "object",
        "required": [
          "id",
          "slug",
          "isActive",
          "userId",
          "config",
          "test",
          "createdAt",
          "updatedAt"
        ],
        "description": "One carrier connection owned by the calling account.",
        "properties": {
          "id": {
            "type": "string",
            "description": "ULID of the config. This is the canonical identifier.",
            "example": "01kg2fbj26w7db1jq4e8vvjwpz"
          },
          "slug": {
            "type": "string",
            "description": "The carrier this config belongs to.",
            "example": "upsv2"
          },
          "isActive": {
            "type": "boolean",
            "description": "Whether the config is enabled.",
            "example": true
          },
          "userId": {
            "type": "string",
            "description": "Owner of the config.",
            "example": "136930"
          },
          "label": {
            "type": [
              "string",
              "null"
            ],
            "description": "Display name given by the account.",
            "example": "Main UPS account"
          },
          "config": {
            "type": "object",
            "description": "The carrier credentials and settings. The field set comes from\n`GET /v2/carriers/{carrierSlug}/schema`. Values are encrypted at\nrest and are returned as they were saved, so treat the object as\nsecret.\n",
            "additionalProperties": true
          },
          "test": {
            "type": "boolean",
            "description": "Whether the config points at the carrier test environment.",
            "example": false
          },
          "oldConfigRef": {
            "type": [
              "string",
              "null"
            ],
            "description": "The legacy `CarrierID` of this config, when it has one."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "example": "2026-07-28T09:15:42.000000Z"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time",
            "example": "2026-07-28T09:15:42.000000Z"
          },
          "links": {
            "type": "object",
            "description": "Present on list responses only.",
            "properties": {
              "self": {
                "type": "string",
                "description": "Canonical URL of this config.",
                "example": "/api/v2/carriers/upsv2/configs/01kg2fbj26w7db1jq4e8vvjwpz"
              }
            }
          }
        }
      },
      "CarrierConfigList": {
        "type": "object",
        "required": [
          "data",
          "pagination"
        ],
        "description": "Cursor-paginated list envelope for carrier configs. `total` is never\nreturned, and paging is forward-only, so `links` carries `next` alone.\n",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CarrierConfig"
            }
          },
          "pagination": {
            "$ref": "#/components/schemas/PaginationNoTotal"
          },
          "links": {
            "$ref": "#/components/schemas/PaginationLinks"
          }
        }
      },
      "CreateCarrierConfigRequest": {
        "type": "object",
        "required": [
          "config"
        ],
        "description": "Body of `POST /v2/carriers/{carrierSlug}/configs`. The carrier comes\nfrom the path, the owner from the API Key and the id from the server, so\nnone of the three can be set here.\n",
        "properties": {
          "config": {
            "type": "object",
            "description": "Carrier credentials and settings, per the carrier schema.",
            "additionalProperties": true
          }
        }
      },
      "UpdateCarrierConfigRequest": {
        "type": "object",
        "required": [
          "config"
        ],
        "description": "Body of `PUT /v2/carriers/{carrierSlug}/configs/{carrierConfigId}`.",
        "properties": {
          "config": {
            "type": "object",
            "description": "The replacement credentials and settings, per the carrier schema.",
            "additionalProperties": true
          }
        }
      },
      "PatchCarrierConfigRequest": {
        "type": "object",
        "description": "Body of `PATCH /v2/carriers/{carrierSlug}/configs/{carrierConfigId}`.\nSend only the fields to change. A body with none of them answers `204`.\n",
        "properties": {
          "active": {
            "type": "boolean",
            "description": "Enable or disable the config."
          },
          "label": {
            "type": "string",
            "description": "Display name."
          },
          "test": {
            "type": "boolean",
            "description": "Point the config at the carrier test environment."
          }
        }
      }
    },
    "responses": {
      "CarrierDocument": {
        "description": "One carrier with the services it supports. `GET /v2/carriers/{carrierSlug}`\nand `GET /v2/carriers/{carrierSlug}/capabilities` both return it.\n",
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/XRequestId"
          },
          "Cache-Control": {
            "$ref": "#/components/headers/CacheControlPublic"
          },
          "RateLimit-Policy": {
            "$ref": "#/components/headers/RateLimitPolicy"
          },
          "RateLimit": {
            "$ref": "#/components/headers/RateLimit"
          },
          "X-RateLimit-Limit": {
            "$ref": "#/components/headers/XRateLimitLimit"
          },
          "X-RateLimit-Remaining": {
            "$ref": "#/components/headers/XRateLimitRemaining"
          },
          "X-RateLimit-Reset": {
            "$ref": "#/components/headers/XRateLimitReset"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/CarrierCapabilities"
            }
          }
        }
      },
      "CarrierConfigPage": {
        "description": "A page of carrier configs owned by the caller.",
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/XRequestId"
          },
          "Cache-Control": {
            "$ref": "#/components/headers/CacheControlNoStore"
          },
          "RateLimit-Policy": {
            "$ref": "#/components/headers/RateLimitPolicy"
          },
          "RateLimit": {
            "$ref": "#/components/headers/RateLimit"
          },
          "X-RateLimit-Limit": {
            "$ref": "#/components/headers/XRateLimitLimit"
          },
          "X-RateLimit-Remaining": {
            "$ref": "#/components/headers/XRateLimitRemaining"
          },
          "X-RateLimit-Reset": {
            "$ref": "#/components/headers/XRateLimitReset"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/CarrierConfigList"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Authentication failed",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/ProblemDetail"
            },
            "example": {
              "type": "https://api.shippypro.com/problems/auth-failed",
              "title": "Authentication Failed",
              "status": 401,
              "detail": "The provided API key is invalid or has been revoked."
            }
          }
        }
      },
      "NotFound": {
        "description": "Resource not found",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/ProblemDetail"
            },
            "example": {
              "type": "https://api.shippypro.com/problems/resource-not-found",
              "title": "Resource Not Found",
              "status": 404,
              "detail": "The requested resource does not exist."
            }
          }
        }
      },
      "NotModified": {
        "description": "Resource has not changed since the supplied `If-None-Match`. No body is returned.\n",
        "headers": {
          "ETag": {
            "$ref": "#/components/headers/ETag"
          },
          "X-Request-Id": {
            "$ref": "#/components/headers/XRequestId"
          }
        }
      },
      "Conflict": {
        "description": "Resource conflict — typically an `Idempotency-Key` reused with different\nrequest parameters, or a version/state conflict on the target resource.\n",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/ProblemDetail"
            },
            "example": {
              "type": "https://api.shippypro.com/problems/resource-conflict",
              "title": "Resource Conflict",
              "status": 409,
              "detail": "The supplied Idempotency-Key was previously used with different request parameters.",
              "errors": [
                {
                  "detail": "Idempotency-Key reused with mismatched request body",
                  "pointer": "/Idempotency-Key",
                  "code": "ALREADY_EXISTS"
                }
              ]
            }
          }
        }
      },
      "ServiceUnavailable": {
        "description": "Service is temporarily unavailable. Returned for fail-closed behavior of\nPOST/DELETE when the idempotency store is unreachable (per API v2\nStandards §7.2), or during planned maintenance.\n",
        "headers": {
          "Retry-After": {
            "schema": {
              "type": "integer"
            },
            "description": "Seconds until the client should retry.",
            "example": 30
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/ProblemDetail"
            },
            "example": {
              "type": "https://api.shippypro.com/problems/service-unavailable",
              "title": "Service Unavailable",
              "status": 503,
              "detail": "The service is temporarily unavailable. Please retry after 30 seconds."
            }
          }
        }
      },
      "ValidationError": {
        "description": "Validation failed",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/ProblemDetail"
            },
            "example": {
              "type": "https://api.shippypro.com/problems/validation-error",
              "title": "Validation Error",
              "status": 422,
              "detail": "The request body contains invalid fields.",
              "errors": [
                {
                  "detail": "The filters.createdAt.gte field is required.",
                  "pointer": "/filters/createdAt/gte",
                  "code": "REQUIRED"
                }
              ]
            }
          }
        }
      },
      "RateLimitExceeded": {
        "description": "Rate limit exceeded",
        "headers": {
          "Retry-After": {
            "schema": {
              "type": "integer"
            },
            "description": "Seconds until the rate limit resets",
            "example": 60
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/ProblemDetail"
            },
            "example": {
              "type": "https://api.shippypro.com/problems/rate-limit-exceeded",
              "title": "Rate Limit Exceeded",
              "status": 429,
              "detail": "You have exceeded the rate limit. Please retry after 60 seconds."
            }
          }
        }
      },
      "InternalError": {
        "description": "Internal server error",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/ProblemDetail"
            },
            "example": {
              "type": "https://api.shippypro.com/problems/internal-error",
              "title": "Internal Error",
              "status": 500,
              "detail": "An unexpected error occurred. Please try again later."
            }
          }
        }
      }
    }
  }
}