{
  "openapi": "3.1.1",
  "info": {
    "title": "Adeva Pro Public API",
    "description": "First-class REST API for Adeva Pro clients to raise debts, read their owned data, update their branding, and receive lifecycle events as webhooks.\n\nEvery `/v1/*` request is authenticated with an org-scoped bearer key. Keys come in two modes: `ak_live_…` for production, `ak_test_…` for sandbox. Modes never cross — presenting a live key to the sandbox host (or vice versa) returns `401` before any business logic runs.\n\nWrites accept an `Idempotency-Key` header for safe retries; responses are replayed byte-for-byte for 24 hours. Webhooks carry a Stripe-compatible `Adeva-Signature` header and are retried on a 1m / 5m / 30m / 2h / 12h / 24h schedule.",
    "termsOfService": "https://adevapro.com.au/legal/api-terms",
    "contact": {
      "name": "Adeva Pro engineering",
      "url": "https://adevapro.com.au/docs",
      "email": "engineering@adevapro.com.au"
    },
    "license": {
      "name": "Proprietary",
      "url": "https://adevapro.com.au/legal/api-terms"
    },
    "version": "1.0.0"
  },
  "servers": [
    {
      "url": "https://api.adevapro.com.au",
      "description": "Production — live keys only (`ak_live_…`)."
    },
    {
      "url": "https://sandbox.adevapro.com.au",
      "description": "Sandbox — anonymous sign-up, seeded dataset, Stripe test mode, outbound notifications disabled."
    },
    {
      "url": "https://api.adevapro.com.au",
      "description": "Production — manage live keys via the Adeva Pro client console."
    }
  ],
  "paths": {
    "/healthz": {
      "get": {
        "tags": [
          "Meta"
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "description": "Unique id for this request — include when filing a support ticket so we can find it in Seq.",
                "schema": {
                  "type": "string"
                }
              },
              "Idempotent-Replayed": {
                "description": "Set to `true` when this response is a replay from the idempotency store.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "5XX": {
            "description": "Server error on our side. Safe to retry with exponential backoff.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "type",
                    "title",
                    "status"
                  ],
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Stable URI naming the error code.",
                      "format": "uri"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short error code."
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code mirroring the response status."
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation."
                    }
                  }
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/internal_error",
                  "title": "internal_error",
                  "status": 500,
                  "detail": "An unexpected error occurred. We've been notified."
                }
              }
            }
          }
        }
      }
    },
    "/v1/transactions": {
      "get": {
        "tags": [
          "Transactions"
        ],
        "summary": "List all transactions",
        "description": "Lists every transaction (inbound and outbound, all statuses) on debts owned by your organization. Cursor-paginated. Filter by `debtId` to narrow to one debt. Requires scope `transactions:read`.",
        "operationId": "ListTransactions",
        "parameters": [
          {
            "name": "cursor",
            "in": "query",
            "description": "Opaque continuation token returned by the previous list response as `nextCursor`. Omit on the first page.",
            "schema": {
              "type": "string"
            },
            "example": "MTcyMDAxMTIzNDp1MmZhYjMzNDU2"
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Page size. 1–200. Defaults to 50.",
            "schema": {
              "maximum": 200,
              "minimum": 1,
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int32",
              "default": 50
            },
            "example": 50
          },
          {
            "name": "debtId",
            "in": "query",
            "description": "When set, restricts the list to transactions / payments on this single debt id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "example": "9b0b9e2a-1c8d-4a82-9e3f-2c2c8a8a2e7a"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "description": "Unique id for this request — include when filing a support ticket so we can find it in Seq.",
                "schema": {
                  "type": "string"
                }
              },
              "Idempotent-Replayed": {
                "description": "Set to `true` when this response is a replay from the idempotency store.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PagedResultOfTransactionDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, malformed, or wrong-mode bearer token. The response body is an RFC 7807 problem document with `title: \"unauthenticated\"`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "type",
                    "title",
                    "status"
                  ],
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Stable URI naming the error code.",
                      "format": "uri"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short error code."
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code mirroring the response status."
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation."
                    }
                  }
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/unauthenticated",
                  "title": "unauthenticated",
                  "status": 401,
                  "detail": "Missing or invalid API key."
                }
              }
            }
          },
          "403": {
            "description": "The key authenticated but is missing the scope this operation requires, or is read-only and you attempted a write. Problem title: `forbidden` or `read_only_key`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "type",
                    "title",
                    "status"
                  ],
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Stable URI naming the error code.",
                      "format": "uri"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short error code."
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code mirroring the response status."
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation."
                    }
                  }
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/forbidden",
                  "title": "forbidden",
                  "status": 403,
                  "detail": "The API key does not have the required scope for this resource."
                }
              }
            }
          },
          "429": {
            "description": "Per-key rate limit exceeded. Read `Retry-After` and back off.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the bucket refills.",
                "schema": {
                  "type": "string"
                },
                "example": "42"
              },
              "X-RateLimit-Limit": {
                "description": "Bucket size for the active window.",
                "schema": {
                  "type": "string"
                },
                "example": "1000"
              },
              "X-RateLimit-Remaining": {
                "description": "Calls remaining in the active window.",
                "schema": {
                  "type": "string"
                },
                "example": "0"
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp when the bucket refills.",
                "schema": {
                  "type": "string"
                },
                "example": "1761569042"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "type",
                    "title",
                    "status"
                  ],
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Stable URI naming the error code.",
                      "format": "uri"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short error code."
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code mirroring the response status."
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation."
                    }
                  }
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/rate_limited",
                  "title": "rate_limited",
                  "status": 429,
                  "detail": "Per-key rate limit exceeded. Retry after the suggested interval."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error on our side. Safe to retry with exponential backoff.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "type",
                    "title",
                    "status"
                  ],
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Stable URI naming the error code.",
                      "format": "uri"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short error code."
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code mirroring the response status."
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation."
                    }
                  }
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/internal_error",
                  "title": "internal_error",
                  "status": 500,
                  "detail": "An unexpected error occurred. We've been notified."
                }
              }
            }
          }
        }
      }
    },
    "/v1/payments": {
      "get": {
        "tags": [
          "Payments"
        ],
        "summary": "List successful inbound payments",
        "description": "Convenience alias over `/v1/transactions` filtered to `direction=Inbound` and `status=Succeeded` — i.e. money that has actually arrived from a debtor. Filter by `debtId` to scope to one debt. Cursor-paginated. Requires scope `payments:read`.",
        "operationId": "ListPayments",
        "parameters": [
          {
            "name": "cursor",
            "in": "query",
            "description": "Opaque continuation token returned by the previous list response as `nextCursor`. Omit on the first page.",
            "schema": {
              "type": "string"
            },
            "example": "MTcyMDAxMTIzNDp1MmZhYjMzNDU2"
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Page size. 1–200. Defaults to 50.",
            "schema": {
              "maximum": 200,
              "minimum": 1,
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int32",
              "default": 50
            },
            "example": 50
          },
          {
            "name": "debtId",
            "in": "query",
            "description": "When set, restricts the list to transactions / payments on this single debt id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "example": "9b0b9e2a-1c8d-4a82-9e3f-2c2c8a8a2e7a"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "description": "Unique id for this request — include when filing a support ticket so we can find it in Seq.",
                "schema": {
                  "type": "string"
                }
              },
              "Idempotent-Replayed": {
                "description": "Set to `true` when this response is a replay from the idempotency store.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PagedResultOfTransactionDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, malformed, or wrong-mode bearer token. The response body is an RFC 7807 problem document with `title: \"unauthenticated\"`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "type",
                    "title",
                    "status"
                  ],
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Stable URI naming the error code.",
                      "format": "uri"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short error code."
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code mirroring the response status."
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation."
                    }
                  }
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/unauthenticated",
                  "title": "unauthenticated",
                  "status": 401,
                  "detail": "Missing or invalid API key."
                }
              }
            }
          },
          "403": {
            "description": "The key authenticated but is missing the scope this operation requires, or is read-only and you attempted a write. Problem title: `forbidden` or `read_only_key`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "type",
                    "title",
                    "status"
                  ],
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Stable URI naming the error code.",
                      "format": "uri"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short error code."
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code mirroring the response status."
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation."
                    }
                  }
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/forbidden",
                  "title": "forbidden",
                  "status": 403,
                  "detail": "The API key does not have the required scope for this resource."
                }
              }
            }
          },
          "429": {
            "description": "Per-key rate limit exceeded. Read `Retry-After` and back off.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the bucket refills.",
                "schema": {
                  "type": "string"
                },
                "example": "42"
              },
              "X-RateLimit-Limit": {
                "description": "Bucket size for the active window.",
                "schema": {
                  "type": "string"
                },
                "example": "1000"
              },
              "X-RateLimit-Remaining": {
                "description": "Calls remaining in the active window.",
                "schema": {
                  "type": "string"
                },
                "example": "0"
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp when the bucket refills.",
                "schema": {
                  "type": "string"
                },
                "example": "1761569042"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "type",
                    "title",
                    "status"
                  ],
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Stable URI naming the error code.",
                      "format": "uri"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short error code."
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code mirroring the response status."
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation."
                    }
                  }
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/rate_limited",
                  "title": "rate_limited",
                  "status": 429,
                  "detail": "Per-key rate limit exceeded. Retry after the suggested interval."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error on our side. Safe to retry with exponential backoff.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "type",
                    "title",
                    "status"
                  ],
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Stable URI naming the error code.",
                      "format": "uri"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short error code."
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code mirroring the response status."
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation."
                    }
                  }
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/internal_error",
                  "title": "internal_error",
                  "status": 500,
                  "detail": "An unexpected error occurred. We've been notified."
                }
              }
            }
          }
        }
      }
    },
    "/v1/organization": {
      "get": {
        "tags": [
          "Organization"
        ],
        "summary": "Get the calling organization",
        "description": "Returns the organization the calling API key belongs to. Authenticated calls only (any valid bearer key works — no specific scope required).",
        "operationId": "GetOrganization",
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "description": "Unique id for this request — include when filing a support ticket so we can find it in Seq.",
                "schema": {
                  "type": "string"
                }
              },
              "Idempotent-Replayed": {
                "description": "Set to `true` when this response is a replay from the idempotency store.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrganizationDto"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/not_found",
                  "title": "not_found",
                  "status": 404,
                  "detail": "Resource not found."
                }
              }
            }
          },
          "401": {
            "description": "Missing, malformed, or wrong-mode bearer token. The response body is an RFC 7807 problem document with `title: \"unauthenticated\"`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "type",
                    "title",
                    "status"
                  ],
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Stable URI naming the error code.",
                      "format": "uri"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short error code."
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code mirroring the response status."
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation."
                    }
                  }
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/unauthenticated",
                  "title": "unauthenticated",
                  "status": 401,
                  "detail": "Missing or invalid API key."
                }
              }
            }
          },
          "403": {
            "description": "The key authenticated but is missing the scope this operation requires, or is read-only and you attempted a write. Problem title: `forbidden` or `read_only_key`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "type",
                    "title",
                    "status"
                  ],
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Stable URI naming the error code.",
                      "format": "uri"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short error code."
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code mirroring the response status."
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation."
                    }
                  }
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/forbidden",
                  "title": "forbidden",
                  "status": 403,
                  "detail": "The API key does not have the required scope for this resource."
                }
              }
            }
          },
          "429": {
            "description": "Per-key rate limit exceeded. Read `Retry-After` and back off.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the bucket refills.",
                "schema": {
                  "type": "string"
                },
                "example": "42"
              },
              "X-RateLimit-Limit": {
                "description": "Bucket size for the active window.",
                "schema": {
                  "type": "string"
                },
                "example": "1000"
              },
              "X-RateLimit-Remaining": {
                "description": "Calls remaining in the active window.",
                "schema": {
                  "type": "string"
                },
                "example": "0"
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp when the bucket refills.",
                "schema": {
                  "type": "string"
                },
                "example": "1761569042"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "type",
                    "title",
                    "status"
                  ],
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Stable URI naming the error code.",
                      "format": "uri"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short error code."
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code mirroring the response status."
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation."
                    }
                  }
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/rate_limited",
                  "title": "rate_limited",
                  "status": 429,
                  "detail": "Per-key rate limit exceeded. Retry after the suggested interval."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error on our side. Safe to retry with exponential backoff.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "type",
                    "title",
                    "status"
                  ],
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Stable URI naming the error code.",
                      "format": "uri"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short error code."
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code mirroring the response status."
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation."
                    }
                  }
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/internal_error",
                  "title": "internal_error",
                  "status": 500,
                  "detail": "An unexpected error occurred. We've been notified."
                }
              }
            }
          }
        }
      }
    },
    "/v1/organization/branding": {
      "get": {
        "tags": [
          "Organization"
        ],
        "summary": "Get current branding",
        "description": "Returns the organization's current branding (colours, logo, favicon, tagline). Requires scope `branding:read`.",
        "operationId": "GetBranding",
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "description": "Unique id for this request — include when filing a support ticket so we can find it in Seq.",
                "schema": {
                  "type": "string"
                }
              },
              "Idempotent-Replayed": {
                "description": "Set to `true` when this response is a replay from the idempotency store.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrganizationBrandingDto"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/not_found",
                  "title": "not_found",
                  "status": 404,
                  "detail": "Resource not found."
                }
              }
            }
          },
          "401": {
            "description": "Missing, malformed, or wrong-mode bearer token. The response body is an RFC 7807 problem document with `title: \"unauthenticated\"`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "type",
                    "title",
                    "status"
                  ],
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Stable URI naming the error code.",
                      "format": "uri"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short error code."
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code mirroring the response status."
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation."
                    }
                  }
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/unauthenticated",
                  "title": "unauthenticated",
                  "status": 401,
                  "detail": "Missing or invalid API key."
                }
              }
            }
          },
          "403": {
            "description": "The key authenticated but is missing the scope this operation requires, or is read-only and you attempted a write. Problem title: `forbidden` or `read_only_key`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "type",
                    "title",
                    "status"
                  ],
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Stable URI naming the error code.",
                      "format": "uri"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short error code."
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code mirroring the response status."
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation."
                    }
                  }
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/forbidden",
                  "title": "forbidden",
                  "status": 403,
                  "detail": "The API key does not have the required scope for this resource."
                }
              }
            }
          },
          "429": {
            "description": "Per-key rate limit exceeded. Read `Retry-After` and back off.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the bucket refills.",
                "schema": {
                  "type": "string"
                },
                "example": "42"
              },
              "X-RateLimit-Limit": {
                "description": "Bucket size for the active window.",
                "schema": {
                  "type": "string"
                },
                "example": "1000"
              },
              "X-RateLimit-Remaining": {
                "description": "Calls remaining in the active window.",
                "schema": {
                  "type": "string"
                },
                "example": "0"
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp when the bucket refills.",
                "schema": {
                  "type": "string"
                },
                "example": "1761569042"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "type",
                    "title",
                    "status"
                  ],
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Stable URI naming the error code.",
                      "format": "uri"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short error code."
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code mirroring the response status."
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation."
                    }
                  }
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/rate_limited",
                  "title": "rate_limited",
                  "status": 429,
                  "detail": "Per-key rate limit exceeded. Retry after the suggested interval."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error on our side. Safe to retry with exponential backoff.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "type",
                    "title",
                    "status"
                  ],
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Stable URI naming the error code.",
                      "format": "uri"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short error code."
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code mirroring the response status."
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation."
                    }
                  }
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/internal_error",
                  "title": "internal_error",
                  "status": 500,
                  "detail": "An unexpected error occurred. We've been notified."
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "Organization"
        ],
        "summary": "Update branding",
        "description": "Updates branding (colours, logo, favicon, tagline). Merge-style — only non-null fields touch state. Empty string clears `logoUrl` / `faviconUrl` / `brandTagline`. Hex colours must be `#RRGGBB`. Cache invalidation across all portals happens synchronously before the response returns. Requires scope `branding:write`; read-only keys are rejected with 403 `read_only_key`.",
        "operationId": "UpdateBranding",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Up to 200 characters. Same key + same body within 24h returns the saved response. Same key + different body returns `409 idempotency_conflict`.",
            "schema": {
              "maxLength": 200,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateBrandingRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "description": "Unique id for this request — include when filing a support ticket so we can find it in Seq.",
                "schema": {
                  "type": "string"
                }
              },
              "Idempotent-Replayed": {
                "description": "Set to `true` when this response is a replay from the idempotency store.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrganizationBrandingDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/invalid_request",
                  "title": "invalid_request",
                  "status": 400,
                  "detail": "originalPrincipal must be greater than zero."
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/not_found",
                  "title": "not_found",
                  "status": 404,
                  "detail": "Resource not found."
                }
              }
            }
          },
          "401": {
            "description": "Missing, malformed, or wrong-mode bearer token. The response body is an RFC 7807 problem document with `title: \"unauthenticated\"`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "type",
                    "title",
                    "status"
                  ],
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Stable URI naming the error code.",
                      "format": "uri"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short error code."
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code mirroring the response status."
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation."
                    }
                  }
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/unauthenticated",
                  "title": "unauthenticated",
                  "status": 401,
                  "detail": "Missing or invalid API key."
                }
              }
            }
          },
          "403": {
            "description": "The key authenticated but is missing the scope this operation requires, or is read-only and you attempted a write. Problem title: `forbidden` or `read_only_key`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "type",
                    "title",
                    "status"
                  ],
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Stable URI naming the error code.",
                      "format": "uri"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short error code."
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code mirroring the response status."
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation."
                    }
                  }
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/forbidden",
                  "title": "forbidden",
                  "status": 403,
                  "detail": "The API key does not have the required scope for this resource."
                }
              }
            }
          },
          "429": {
            "description": "Per-key rate limit exceeded. Read `Retry-After` and back off.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the bucket refills.",
                "schema": {
                  "type": "string"
                },
                "example": "42"
              },
              "X-RateLimit-Limit": {
                "description": "Bucket size for the active window.",
                "schema": {
                  "type": "string"
                },
                "example": "1000"
              },
              "X-RateLimit-Remaining": {
                "description": "Calls remaining in the active window.",
                "schema": {
                  "type": "string"
                },
                "example": "0"
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp when the bucket refills.",
                "schema": {
                  "type": "string"
                },
                "example": "1761569042"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "type",
                    "title",
                    "status"
                  ],
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Stable URI naming the error code.",
                      "format": "uri"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short error code."
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code mirroring the response status."
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation."
                    }
                  }
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/rate_limited",
                  "title": "rate_limited",
                  "status": 429,
                  "detail": "Per-key rate limit exceeded. Retry after the suggested interval."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error on our side. Safe to retry with exponential backoff.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "type",
                    "title",
                    "status"
                  ],
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Stable URI naming the error code.",
                      "format": "uri"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short error code."
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code mirroring the response status."
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation."
                    }
                  }
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/internal_error",
                  "title": "internal_error",
                  "status": 500,
                  "detail": "An unexpected error occurred. We've been notified."
                }
              }
            }
          }
        }
      }
    },
    "/v1/webhooks": {
      "get": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Get webhook configuration",
        "description": "Returns the current webhook URL plus the first 12 characters of the signing secret (so you can identify which secret is live without exposing it). `enabled=true` means both URL and secret are set and we'll deliver events to it. Requires scope `webhooks:read`.",
        "operationId": "GetWebhookConfig",
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "description": "Unique id for this request — include when filing a support ticket so we can find it in Seq.",
                "schema": {
                  "type": "string"
                }
              },
              "Idempotent-Replayed": {
                "description": "Set to `true` when this response is a replay from the idempotency store.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookConfigDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, malformed, or wrong-mode bearer token. The response body is an RFC 7807 problem document with `title: \"unauthenticated\"`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "type",
                    "title",
                    "status"
                  ],
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Stable URI naming the error code.",
                      "format": "uri"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short error code."
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code mirroring the response status."
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation."
                    }
                  }
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/unauthenticated",
                  "title": "unauthenticated",
                  "status": 401,
                  "detail": "Missing or invalid API key."
                }
              }
            }
          },
          "403": {
            "description": "The key authenticated but is missing the scope this operation requires, or is read-only and you attempted a write. Problem title: `forbidden` or `read_only_key`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "type",
                    "title",
                    "status"
                  ],
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Stable URI naming the error code.",
                      "format": "uri"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short error code."
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code mirroring the response status."
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation."
                    }
                  }
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/forbidden",
                  "title": "forbidden",
                  "status": 403,
                  "detail": "The API key does not have the required scope for this resource."
                }
              }
            }
          },
          "429": {
            "description": "Per-key rate limit exceeded. Read `Retry-After` and back off.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the bucket refills.",
                "schema": {
                  "type": "string"
                },
                "example": "42"
              },
              "X-RateLimit-Limit": {
                "description": "Bucket size for the active window.",
                "schema": {
                  "type": "string"
                },
                "example": "1000"
              },
              "X-RateLimit-Remaining": {
                "description": "Calls remaining in the active window.",
                "schema": {
                  "type": "string"
                },
                "example": "0"
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp when the bucket refills.",
                "schema": {
                  "type": "string"
                },
                "example": "1761569042"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "type",
                    "title",
                    "status"
                  ],
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Stable URI naming the error code.",
                      "format": "uri"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short error code."
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code mirroring the response status."
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation."
                    }
                  }
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/rate_limited",
                  "title": "rate_limited",
                  "status": 429,
                  "detail": "Per-key rate limit exceeded. Retry after the suggested interval."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error on our side. Safe to retry with exponential backoff.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "type",
                    "title",
                    "status"
                  ],
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Stable URI naming the error code.",
                      "format": "uri"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short error code."
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code mirroring the response status."
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation."
                    }
                  }
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/internal_error",
                  "title": "internal_error",
                  "status": 500,
                  "detail": "An unexpected error occurred. We've been notified."
                }
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Configure webhook URL / rotate secret / disable",
        "description": "Three operations in one request shape:\n\n1. **Set URL:** pass `url` (absolute https). On first configure we mint a signing secret and return it once as `newSecret` (`whsec_…`).\n2. **Rotate secret:** pass `rotateSecret: true`. Old secret stops being valid immediately; new one returned once.\n3. **Disable:** pass `clear: true`. Both URL and secret are cleared, all in-flight deliveries continue with their snapshotted secret but no new events are enqueued.\n\nRequires scope `webhooks:write`. Read-only keys are rejected with 403 `read_only_key`.",
        "operationId": "UpdateWebhookConfig",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Up to 200 characters. Same key + same body within 24h returns the saved response. Same key + different body returns `409 idempotency_conflict`.",
            "schema": {
              "maxLength": 200,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateWebhookRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "description": "Unique id for this request — include when filing a support ticket so we can find it in Seq.",
                "schema": {
                  "type": "string"
                }
              },
              "Idempotent-Replayed": {
                "description": "Set to `true` when this response is a replay from the idempotency store.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UpdateWebhookResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/invalid_request",
                  "title": "invalid_request",
                  "status": 400,
                  "detail": "originalPrincipal must be greater than zero."
                }
              }
            }
          },
          "401": {
            "description": "Missing, malformed, or wrong-mode bearer token. The response body is an RFC 7807 problem document with `title: \"unauthenticated\"`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "type",
                    "title",
                    "status"
                  ],
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Stable URI naming the error code.",
                      "format": "uri"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short error code."
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code mirroring the response status."
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation."
                    }
                  }
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/unauthenticated",
                  "title": "unauthenticated",
                  "status": 401,
                  "detail": "Missing or invalid API key."
                }
              }
            }
          },
          "403": {
            "description": "The key authenticated but is missing the scope this operation requires, or is read-only and you attempted a write. Problem title: `forbidden` or `read_only_key`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "type",
                    "title",
                    "status"
                  ],
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Stable URI naming the error code.",
                      "format": "uri"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short error code."
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code mirroring the response status."
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation."
                    }
                  }
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/forbidden",
                  "title": "forbidden",
                  "status": 403,
                  "detail": "The API key does not have the required scope for this resource."
                }
              }
            }
          },
          "429": {
            "description": "Per-key rate limit exceeded. Read `Retry-After` and back off.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the bucket refills.",
                "schema": {
                  "type": "string"
                },
                "example": "42"
              },
              "X-RateLimit-Limit": {
                "description": "Bucket size for the active window.",
                "schema": {
                  "type": "string"
                },
                "example": "1000"
              },
              "X-RateLimit-Remaining": {
                "description": "Calls remaining in the active window.",
                "schema": {
                  "type": "string"
                },
                "example": "0"
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp when the bucket refills.",
                "schema": {
                  "type": "string"
                },
                "example": "1761569042"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "type",
                    "title",
                    "status"
                  ],
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Stable URI naming the error code.",
                      "format": "uri"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short error code."
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code mirroring the response status."
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation."
                    }
                  }
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/rate_limited",
                  "title": "rate_limited",
                  "status": 429,
                  "detail": "Per-key rate limit exceeded. Retry after the suggested interval."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error on our side. Safe to retry with exponential backoff.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "type",
                    "title",
                    "status"
                  ],
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Stable URI naming the error code.",
                      "format": "uri"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short error code."
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code mirroring the response status."
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation."
                    }
                  }
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/internal_error",
                  "title": "internal_error",
                  "status": 500,
                  "detail": "An unexpected error occurred. We've been notified."
                }
              }
            }
          }
        }
      }
    },
    "/v1/webhooks/test": {
      "post": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Send a synthetic test event",
        "description": "Enqueues a `test.ping` webhook to your configured receiver with a valid `Adeva-Signature` header. Useful for verifying your signature-verification code before depending on real event traffic. Returns 400 `no_webhook_configured` if you haven't set up a URL yet. Requires scope `webhooks:write`.",
        "operationId": "SendTestWebhook",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Up to 200 characters. Same key + same body within 24h returns the saved response. Same key + different body returns `409 idempotency_conflict`.",
            "schema": {
              "maxLength": 200,
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "description": "Unique id for this request — include when filing a support ticket so we can find it in Seq.",
                "schema": {
                  "type": "string"
                }
              },
              "Idempotent-Replayed": {
                "description": "Set to `true` when this response is a replay from the idempotency store.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookTestResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/invalid_request",
                  "title": "invalid_request",
                  "status": 400,
                  "detail": "originalPrincipal must be greater than zero."
                }
              }
            }
          },
          "401": {
            "description": "Missing, malformed, or wrong-mode bearer token. The response body is an RFC 7807 problem document with `title: \"unauthenticated\"`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "type",
                    "title",
                    "status"
                  ],
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Stable URI naming the error code.",
                      "format": "uri"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short error code."
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code mirroring the response status."
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation."
                    }
                  }
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/unauthenticated",
                  "title": "unauthenticated",
                  "status": 401,
                  "detail": "Missing or invalid API key."
                }
              }
            }
          },
          "403": {
            "description": "The key authenticated but is missing the scope this operation requires, or is read-only and you attempted a write. Problem title: `forbidden` or `read_only_key`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "type",
                    "title",
                    "status"
                  ],
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Stable URI naming the error code.",
                      "format": "uri"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short error code."
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code mirroring the response status."
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation."
                    }
                  }
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/forbidden",
                  "title": "forbidden",
                  "status": 403,
                  "detail": "The API key does not have the required scope for this resource."
                }
              }
            }
          },
          "429": {
            "description": "Per-key rate limit exceeded. Read `Retry-After` and back off.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the bucket refills.",
                "schema": {
                  "type": "string"
                },
                "example": "42"
              },
              "X-RateLimit-Limit": {
                "description": "Bucket size for the active window.",
                "schema": {
                  "type": "string"
                },
                "example": "1000"
              },
              "X-RateLimit-Remaining": {
                "description": "Calls remaining in the active window.",
                "schema": {
                  "type": "string"
                },
                "example": "0"
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp when the bucket refills.",
                "schema": {
                  "type": "string"
                },
                "example": "1761569042"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "type",
                    "title",
                    "status"
                  ],
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Stable URI naming the error code.",
                      "format": "uri"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short error code."
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code mirroring the response status."
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation."
                    }
                  }
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/rate_limited",
                  "title": "rate_limited",
                  "status": 429,
                  "detail": "Per-key rate limit exceeded. Retry after the suggested interval."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error on our side. Safe to retry with exponential backoff.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "type",
                    "title",
                    "status"
                  ],
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Stable URI naming the error code.",
                      "format": "uri"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short error code."
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code mirroring the response status."
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation."
                    }
                  }
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/internal_error",
                  "title": "internal_error",
                  "status": 500,
                  "detail": "An unexpected error occurred. We've been notified."
                }
              }
            }
          }
        }
      }
    },
    "/v1/debts": {
      "get": {
        "tags": [
          "Debts"
        ],
        "summary": "List debts",
        "description": "Lists every debt owned by the authenticated organization, newest first. Use the `cursor` from the previous response to fetch the next page; `hasMore=false` and `nextCursor=null` indicate the end. Requires scope `debts:read`.",
        "operationId": "ListDebts",
        "parameters": [
          {
            "name": "cursor",
            "in": "query",
            "description": "Opaque continuation token returned by the previous list response as `nextCursor`. Omit on the first page.",
            "schema": {
              "type": "string"
            },
            "example": "MTcyMDAxMTIzNDp1MmZhYjMzNDU2"
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Page size. 1–200. Defaults to 50.",
            "schema": {
              "maximum": 200,
              "minimum": 1,
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int32",
              "default": 50
            },
            "example": 50
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "description": "Unique id for this request — include when filing a support ticket so we can find it in Seq.",
                "schema": {
                  "type": "string"
                }
              },
              "Idempotent-Replayed": {
                "description": "Set to `true` when this response is a replay from the idempotency store.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PagedResultOfDebtDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, malformed, or wrong-mode bearer token. The response body is an RFC 7807 problem document with `title: \"unauthenticated\"`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "type",
                    "title",
                    "status"
                  ],
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Stable URI naming the error code.",
                      "format": "uri"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short error code."
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code mirroring the response status."
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation."
                    }
                  }
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/unauthenticated",
                  "title": "unauthenticated",
                  "status": 401,
                  "detail": "Missing or invalid API key."
                }
              }
            }
          },
          "403": {
            "description": "The key authenticated but is missing the scope this operation requires, or is read-only and you attempted a write. Problem title: `forbidden` or `read_only_key`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "type",
                    "title",
                    "status"
                  ],
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Stable URI naming the error code.",
                      "format": "uri"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short error code."
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code mirroring the response status."
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation."
                    }
                  }
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/forbidden",
                  "title": "forbidden",
                  "status": 403,
                  "detail": "The API key does not have the required scope for this resource."
                }
              }
            }
          },
          "429": {
            "description": "Per-key rate limit exceeded. Read `Retry-After` and back off.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the bucket refills.",
                "schema": {
                  "type": "string"
                },
                "example": "42"
              },
              "X-RateLimit-Limit": {
                "description": "Bucket size for the active window.",
                "schema": {
                  "type": "string"
                },
                "example": "1000"
              },
              "X-RateLimit-Remaining": {
                "description": "Calls remaining in the active window.",
                "schema": {
                  "type": "string"
                },
                "example": "0"
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp when the bucket refills.",
                "schema": {
                  "type": "string"
                },
                "example": "1761569042"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "type",
                    "title",
                    "status"
                  ],
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Stable URI naming the error code.",
                      "format": "uri"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short error code."
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code mirroring the response status."
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation."
                    }
                  }
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/rate_limited",
                  "title": "rate_limited",
                  "status": 429,
                  "detail": "Per-key rate limit exceeded. Retry after the suggested interval."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error on our side. Safe to retry with exponential backoff.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "type",
                    "title",
                    "status"
                  ],
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Stable URI naming the error code.",
                      "format": "uri"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short error code."
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code mirroring the response status."
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation."
                    }
                  }
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/internal_error",
                  "title": "internal_error",
                  "status": 500,
                  "detail": "An unexpected error occurred. We've been notified."
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Debts"
        ],
        "summary": "Create a debt",
        "description": "Creates a new debt against an existing or new debtor in your organization. Provide either `debtorId` OR the inline debtor identity (`debtorReferenceId` + names + at least one of `debtorEmail` / `debtorPhone`). If the reference id matches an existing debtor, that debtor is reused. Pass an `Idempotency-Key` header so retries can't double-create. Fires the `debt.created` webhook to your configured receiver. Requires scope `debts:write`; read-only keys are rejected with 403 `read_only_key`.",
        "operationId": "CreateDebt",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Up to 200 characters. Same key + same body within 24h returns the saved response. Same key + different body returns `409 idempotency_conflict`.",
            "schema": {
              "maxLength": 200,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateDebtRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "headers": {
              "X-Request-Id": {
                "description": "Unique id for this request — include when filing a support ticket so we can find it in Seq.",
                "schema": {
                  "type": "string"
                }
              },
              "Idempotent-Replayed": {
                "description": "Set to `true` when this response is a replay from the idempotency store.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DebtDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/invalid_request",
                  "title": "invalid_request",
                  "status": 400,
                  "detail": "originalPrincipal must be greater than zero."
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/idempotency_conflict",
                  "title": "idempotency_conflict",
                  "status": 409,
                  "detail": "Idempotency-Key was already used with a different request body."
                }
              }
            }
          },
          "401": {
            "description": "Missing, malformed, or wrong-mode bearer token. The response body is an RFC 7807 problem document with `title: \"unauthenticated\"`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "type",
                    "title",
                    "status"
                  ],
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Stable URI naming the error code.",
                      "format": "uri"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short error code."
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code mirroring the response status."
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation."
                    }
                  }
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/unauthenticated",
                  "title": "unauthenticated",
                  "status": 401,
                  "detail": "Missing or invalid API key."
                }
              }
            }
          },
          "403": {
            "description": "The key authenticated but is missing the scope this operation requires, or is read-only and you attempted a write. Problem title: `forbidden` or `read_only_key`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "type",
                    "title",
                    "status"
                  ],
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Stable URI naming the error code.",
                      "format": "uri"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short error code."
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code mirroring the response status."
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation."
                    }
                  }
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/forbidden",
                  "title": "forbidden",
                  "status": 403,
                  "detail": "The API key does not have the required scope for this resource."
                }
              }
            }
          },
          "429": {
            "description": "Per-key rate limit exceeded. Read `Retry-After` and back off.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the bucket refills.",
                "schema": {
                  "type": "string"
                },
                "example": "42"
              },
              "X-RateLimit-Limit": {
                "description": "Bucket size for the active window.",
                "schema": {
                  "type": "string"
                },
                "example": "1000"
              },
              "X-RateLimit-Remaining": {
                "description": "Calls remaining in the active window.",
                "schema": {
                  "type": "string"
                },
                "example": "0"
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp when the bucket refills.",
                "schema": {
                  "type": "string"
                },
                "example": "1761569042"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "type",
                    "title",
                    "status"
                  ],
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Stable URI naming the error code.",
                      "format": "uri"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short error code."
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code mirroring the response status."
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation."
                    }
                  }
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/rate_limited",
                  "title": "rate_limited",
                  "status": 429,
                  "detail": "Per-key rate limit exceeded. Retry after the suggested interval."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error on our side. Safe to retry with exponential backoff.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "type",
                    "title",
                    "status"
                  ],
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Stable URI naming the error code.",
                      "format": "uri"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short error code."
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code mirroring the response status."
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation."
                    }
                  }
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/internal_error",
                  "title": "internal_error",
                  "status": 500,
                  "detail": "An unexpected error occurred. We've been notified."
                }
              }
            }
          }
        }
      }
    },
    "/v1/debts/{id}": {
      "get": {
        "tags": [
          "Debts"
        ],
        "summary": "Get a debt by id",
        "description": "Returns a single debt by id. Returns 404 (not 403) when the id belongs to a different organization — we don't leak existence across tenants. Requires scope `debts:read`.",
        "operationId": "GetDebt",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Resource id (GUID). Returns 404 if it belongs to another organization.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "example": "9b0b9e2a-1c8d-4a82-9e3f-2c2c8a8a2e7a"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "description": "Unique id for this request — include when filing a support ticket so we can find it in Seq.",
                "schema": {
                  "type": "string"
                }
              },
              "Idempotent-Replayed": {
                "description": "Set to `true` when this response is a replay from the idempotency store.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DebtDto"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/not_found",
                  "title": "not_found",
                  "status": 404,
                  "detail": "Resource not found."
                }
              }
            }
          },
          "401": {
            "description": "Missing, malformed, or wrong-mode bearer token. The response body is an RFC 7807 problem document with `title: \"unauthenticated\"`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "type",
                    "title",
                    "status"
                  ],
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Stable URI naming the error code.",
                      "format": "uri"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short error code."
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code mirroring the response status."
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation."
                    }
                  }
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/unauthenticated",
                  "title": "unauthenticated",
                  "status": 401,
                  "detail": "Missing or invalid API key."
                }
              }
            }
          },
          "403": {
            "description": "The key authenticated but is missing the scope this operation requires, or is read-only and you attempted a write. Problem title: `forbidden` or `read_only_key`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "type",
                    "title",
                    "status"
                  ],
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Stable URI naming the error code.",
                      "format": "uri"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short error code."
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code mirroring the response status."
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation."
                    }
                  }
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/forbidden",
                  "title": "forbidden",
                  "status": 403,
                  "detail": "The API key does not have the required scope for this resource."
                }
              }
            }
          },
          "429": {
            "description": "Per-key rate limit exceeded. Read `Retry-After` and back off.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the bucket refills.",
                "schema": {
                  "type": "string"
                },
                "example": "42"
              },
              "X-RateLimit-Limit": {
                "description": "Bucket size for the active window.",
                "schema": {
                  "type": "string"
                },
                "example": "1000"
              },
              "X-RateLimit-Remaining": {
                "description": "Calls remaining in the active window.",
                "schema": {
                  "type": "string"
                },
                "example": "0"
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp when the bucket refills.",
                "schema": {
                  "type": "string"
                },
                "example": "1761569042"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "type",
                    "title",
                    "status"
                  ],
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Stable URI naming the error code.",
                      "format": "uri"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short error code."
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code mirroring the response status."
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation."
                    }
                  }
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/rate_limited",
                  "title": "rate_limited",
                  "status": 429,
                  "detail": "Per-key rate limit exceeded. Retry after the suggested interval."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error on our side. Safe to retry with exponential backoff.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "type",
                    "title",
                    "status"
                  ],
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Stable URI naming the error code.",
                      "format": "uri"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short error code."
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code mirroring the response status."
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation."
                    }
                  }
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/internal_error",
                  "title": "internal_error",
                  "status": 500,
                  "detail": "An unexpected error occurred. We've been notified."
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "Debts"
        ],
        "summary": "Update mutable fields on a debt",
        "description": "Patches the debt's mutable fields. Only supplied (non-null) fields are touched. Status transitions (accept, dispute, write-off) are deliberately out of scope here — those flow through internal workflows and arrive at your receiver as webhooks (`debt.accepted`, `debt.disputed`). Fires the `debt.updated` webhook on success. Requires scope `debts:write`.",
        "operationId": "UpdateDebt",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Resource id (GUID). Returns 404 if it belongs to another organization.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "example": "9b0b9e2a-1c8d-4a82-9e3f-2c2c8a8a2e7a"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Up to 200 characters. Same key + same body within 24h returns the saved response. Same key + different body returns `409 idempotency_conflict`.",
            "schema": {
              "maxLength": 200,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateDebtRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "description": "Unique id for this request — include when filing a support ticket so we can find it in Seq.",
                "schema": {
                  "type": "string"
                }
              },
              "Idempotent-Replayed": {
                "description": "Set to `true` when this response is a replay from the idempotency store.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DebtDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/invalid_request",
                  "title": "invalid_request",
                  "status": 400,
                  "detail": "originalPrincipal must be greater than zero."
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/not_found",
                  "title": "not_found",
                  "status": 404,
                  "detail": "Resource not found."
                }
              }
            }
          },
          "401": {
            "description": "Missing, malformed, or wrong-mode bearer token. The response body is an RFC 7807 problem document with `title: \"unauthenticated\"`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "type",
                    "title",
                    "status"
                  ],
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Stable URI naming the error code.",
                      "format": "uri"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short error code."
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code mirroring the response status."
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation."
                    }
                  }
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/unauthenticated",
                  "title": "unauthenticated",
                  "status": 401,
                  "detail": "Missing or invalid API key."
                }
              }
            }
          },
          "403": {
            "description": "The key authenticated but is missing the scope this operation requires, or is read-only and you attempted a write. Problem title: `forbidden` or `read_only_key`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "type",
                    "title",
                    "status"
                  ],
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Stable URI naming the error code.",
                      "format": "uri"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short error code."
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code mirroring the response status."
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation."
                    }
                  }
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/forbidden",
                  "title": "forbidden",
                  "status": 403,
                  "detail": "The API key does not have the required scope for this resource."
                }
              }
            }
          },
          "429": {
            "description": "Per-key rate limit exceeded. Read `Retry-After` and back off.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the bucket refills.",
                "schema": {
                  "type": "string"
                },
                "example": "42"
              },
              "X-RateLimit-Limit": {
                "description": "Bucket size for the active window.",
                "schema": {
                  "type": "string"
                },
                "example": "1000"
              },
              "X-RateLimit-Remaining": {
                "description": "Calls remaining in the active window.",
                "schema": {
                  "type": "string"
                },
                "example": "0"
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp when the bucket refills.",
                "schema": {
                  "type": "string"
                },
                "example": "1761569042"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "type",
                    "title",
                    "status"
                  ],
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Stable URI naming the error code.",
                      "format": "uri"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short error code."
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code mirroring the response status."
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation."
                    }
                  }
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/rate_limited",
                  "title": "rate_limited",
                  "status": 429,
                  "detail": "Per-key rate limit exceeded. Retry after the suggested interval."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error on our side. Safe to retry with exponential backoff.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "type",
                    "title",
                    "status"
                  ],
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Stable URI naming the error code.",
                      "format": "uri"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short error code."
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code mirroring the response status."
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation."
                    }
                  }
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/internal_error",
                  "title": "internal_error",
                  "status": 500,
                  "detail": "An unexpected error occurred. We've been notified."
                }
              }
            }
          }
        }
      }
    },
    "/v1/debtors": {
      "get": {
        "tags": [
          "Debtors"
        ],
        "summary": "List debtors",
        "description": "Lists every debtor owned by the authenticated organization, newest first. Cursor-paginated. Requires scope `debtors:read`.",
        "operationId": "ListDebtors",
        "parameters": [
          {
            "name": "cursor",
            "in": "query",
            "description": "Opaque continuation token returned by the previous list response as `nextCursor`. Omit on the first page.",
            "schema": {
              "type": "string"
            },
            "example": "MTcyMDAxMTIzNDp1MmZhYjMzNDU2"
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Page size. 1–200. Defaults to 50.",
            "schema": {
              "maximum": 200,
              "minimum": 1,
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int32",
              "default": 50
            },
            "example": 50
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "description": "Unique id for this request — include when filing a support ticket so we can find it in Seq.",
                "schema": {
                  "type": "string"
                }
              },
              "Idempotent-Replayed": {
                "description": "Set to `true` when this response is a replay from the idempotency store.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PagedResultOfDebtorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, malformed, or wrong-mode bearer token. The response body is an RFC 7807 problem document with `title: \"unauthenticated\"`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "type",
                    "title",
                    "status"
                  ],
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Stable URI naming the error code.",
                      "format": "uri"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short error code."
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code mirroring the response status."
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation."
                    }
                  }
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/unauthenticated",
                  "title": "unauthenticated",
                  "status": 401,
                  "detail": "Missing or invalid API key."
                }
              }
            }
          },
          "403": {
            "description": "The key authenticated but is missing the scope this operation requires, or is read-only and you attempted a write. Problem title: `forbidden` or `read_only_key`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "type",
                    "title",
                    "status"
                  ],
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Stable URI naming the error code.",
                      "format": "uri"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short error code."
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code mirroring the response status."
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation."
                    }
                  }
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/forbidden",
                  "title": "forbidden",
                  "status": 403,
                  "detail": "The API key does not have the required scope for this resource."
                }
              }
            }
          },
          "429": {
            "description": "Per-key rate limit exceeded. Read `Retry-After` and back off.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the bucket refills.",
                "schema": {
                  "type": "string"
                },
                "example": "42"
              },
              "X-RateLimit-Limit": {
                "description": "Bucket size for the active window.",
                "schema": {
                  "type": "string"
                },
                "example": "1000"
              },
              "X-RateLimit-Remaining": {
                "description": "Calls remaining in the active window.",
                "schema": {
                  "type": "string"
                },
                "example": "0"
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp when the bucket refills.",
                "schema": {
                  "type": "string"
                },
                "example": "1761569042"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "type",
                    "title",
                    "status"
                  ],
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Stable URI naming the error code.",
                      "format": "uri"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short error code."
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code mirroring the response status."
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation."
                    }
                  }
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/rate_limited",
                  "title": "rate_limited",
                  "status": 429,
                  "detail": "Per-key rate limit exceeded. Retry after the suggested interval."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error on our side. Safe to retry with exponential backoff.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "type",
                    "title",
                    "status"
                  ],
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Stable URI naming the error code.",
                      "format": "uri"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short error code."
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code mirroring the response status."
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation."
                    }
                  }
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/internal_error",
                  "title": "internal_error",
                  "status": 500,
                  "detail": "An unexpected error occurred. We've been notified."
                }
              }
            }
          }
        }
      }
    },
    "/v1/debtors/{id}": {
      "get": {
        "tags": [
          "Debtors"
        ],
        "summary": "Get a debtor by id",
        "description": "Returns a single debtor by id. Returns 404 when the id belongs to a different organization. Requires scope `debtors:read`.",
        "operationId": "GetDebtor",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Resource id (GUID). Returns 404 if it belongs to another organization.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "example": "9b0b9e2a-1c8d-4a82-9e3f-2c2c8a8a2e7a"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "description": "Unique id for this request — include when filing a support ticket so we can find it in Seq.",
                "schema": {
                  "type": "string"
                }
              },
              "Idempotent-Replayed": {
                "description": "Set to `true` when this response is a replay from the idempotency store.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DebtorDto"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/not_found",
                  "title": "not_found",
                  "status": 404,
                  "detail": "Resource not found."
                }
              }
            }
          },
          "401": {
            "description": "Missing, malformed, or wrong-mode bearer token. The response body is an RFC 7807 problem document with `title: \"unauthenticated\"`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "type",
                    "title",
                    "status"
                  ],
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Stable URI naming the error code.",
                      "format": "uri"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short error code."
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code mirroring the response status."
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation."
                    }
                  }
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/unauthenticated",
                  "title": "unauthenticated",
                  "status": 401,
                  "detail": "Missing or invalid API key."
                }
              }
            }
          },
          "403": {
            "description": "The key authenticated but is missing the scope this operation requires, or is read-only and you attempted a write. Problem title: `forbidden` or `read_only_key`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "type",
                    "title",
                    "status"
                  ],
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Stable URI naming the error code.",
                      "format": "uri"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short error code."
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code mirroring the response status."
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation."
                    }
                  }
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/forbidden",
                  "title": "forbidden",
                  "status": 403,
                  "detail": "The API key does not have the required scope for this resource."
                }
              }
            }
          },
          "429": {
            "description": "Per-key rate limit exceeded. Read `Retry-After` and back off.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the bucket refills.",
                "schema": {
                  "type": "string"
                },
                "example": "42"
              },
              "X-RateLimit-Limit": {
                "description": "Bucket size for the active window.",
                "schema": {
                  "type": "string"
                },
                "example": "1000"
              },
              "X-RateLimit-Remaining": {
                "description": "Calls remaining in the active window.",
                "schema": {
                  "type": "string"
                },
                "example": "0"
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp when the bucket refills.",
                "schema": {
                  "type": "string"
                },
                "example": "1761569042"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "type",
                    "title",
                    "status"
                  ],
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Stable URI naming the error code.",
                      "format": "uri"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short error code."
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code mirroring the response status."
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation."
                    }
                  }
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/rate_limited",
                  "title": "rate_limited",
                  "status": 429,
                  "detail": "Per-key rate limit exceeded. Retry after the suggested interval."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error on our side. Safe to retry with exponential backoff.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "required": [
                    "type",
                    "title",
                    "status"
                  ],
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Stable URI naming the error code.",
                      "format": "uri"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short error code."
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code mirroring the response status."
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation."
                    }
                  }
                },
                "example": {
                  "type": "https://adevapro.com.au/errors/internal_error",
                  "title": "internal_error",
                  "status": 500,
                  "detail": "An unexpected error occurred. We've been notified."
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "CreateDebtRequest": {
        "type": "object",
        "properties": {
          "debtorId": {
            "type": [
              "null",
              "string"
            ],
            "description": "Existing debtor id in your organization. Mutually exclusive with the inline `debtor*` fields.",
            "format": "uuid"
          },
          "debtorReferenceId": {
            "type": [
              "null",
              "string"
            ],
            "description": "Stable id from your system. Used to find-or-create the debtor."
          },
          "debtorFirstName": {
            "type": [
              "null",
              "string"
            ],
            "description": "Required when creating a new debtor inline."
          },
          "debtorLastName": {
            "type": [
              "null",
              "string"
            ],
            "description": "Required when creating a new debtor inline."
          },
          "debtorEmail": {
            "type": [
              "null",
              "string"
            ],
            "description": "At least one of email or phone is required when creating a new debtor inline."
          },
          "debtorPhone": {
            "type": [
              "null",
              "string"
            ],
            "description": "E.164 preferred. At least one of email or phone is required when creating a new debtor inline."
          },
          "originalPrincipal": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "number",
              "string"
            ],
            "description": "Decimal amount > 0 in the supplied `currency`.",
            "format": "double"
          },
          "currency": {
            "type": "string",
            "description": "ISO-4217. Defaults to `AUD` when omitted."
          },
          "externalAccountId": {
            "type": "string",
            "description": "Required. The id in your billing system this debt corresponds to. Used in the keys list + audit log."
          },
          "clientReferenceNumber": {
            "type": [
              "null",
              "string"
            ],
            "description": "Optional invoice / case number from your system."
          },
          "originalCreditorName": {
            "type": [
              "null",
              "string"
            ],
            "description": "Optional. Shows in debtor-facing communications when the debt was acquired from a third party."
          },
          "dueDateUtc": {
            "type": [
              "null",
              "string"
            ],
            "description": "Optional ISO-8601 timestamp. When set, drives statement messaging.",
            "format": "date-time"
          }
        },
        "description": "Body for `POST /v1/debts`. Either pass `debtorId` (an existing debtor in your org) OR the inline debtor identity (`debtorReferenceId` + first/last name + at least one of email/phone). If the reference id matches an existing debtor in your org, that debtor is reused and the inline fields are ignored.",
        "example": {
          "debtorReferenceId": "CUST-9001",
          "debtorFirstName": "Sample",
          "debtorLastName": "Person",
          "debtorEmail": "sample@example.com",
          "debtorPhone": "+61 412 100 100",
          "originalPrincipal": 1899.00,
          "currency": "AUD",
          "externalAccountId": "INV-2026-00042",
          "clientReferenceNumber": "INV-2026-00042",
          "originalCreditorName": "Acme Billing Pty Ltd",
          "dueDateUtc": "2026-01-15T00:00:00Z"
        }
      },
      "DebtAcceptedEvent": {
        "type": "object",
        "properties": {
          "debtId": {
            "type": "string",
            "format": "uuid"
          },
          "debtorId": {
            "type": "string",
            "format": "uuid"
          },
          "paymentPlanId": {
            "type": "string",
            "format": "uuid"
          },
          "acceptedAtUtc": {
            "type": "string",
            "format": "date-time"
          }
        },
        "description": "Payload of a `debt.accepted` envelope. Fires when the debtor accepts a payment plan in the killer flow."
      },
      "DebtCreatedEvent": {
        "type": "object",
        "properties": {
          "debt": {
            "$ref": "#/components/schemas/DebtDto"
          }
        },
        "description": "Payload of a `debt.created` envelope. Fires after `POST /v1/debts` commits."
      },
      "DebtDisputedEvent": {
        "type": "object",
        "properties": {
          "debtId": {
            "type": "string",
            "format": "uuid"
          },
          "debtorId": {
            "type": "string",
            "format": "uuid"
          },
          "reason": {
            "type": "string",
            "description": "Reason the debtor gave."
          },
          "disputedAtUtc": {
            "type": "string",
            "format": "date-time"
          }
        },
        "description": "Payload of a `debt.disputed` envelope."
      },
      "DebtDto": {
        "required": [
          "id",
          "debtorId",
          "status",
          "currency",
          "clientReferenceNumber",
          "externalAccountId",
          "originalPrincipal",
          "outstandingPrincipal",
          "accruedInterest",
          "accruedFees",
          "openedAtUtc",
          "dueDateUtc",
          "lastPaymentAtUtc",
          "closedAtUtc",
          "createdAtUtc",
          "updatedAtUtc"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "debtorId": {
            "type": "string",
            "format": "uuid"
          },
          "status": {
            "type": "string"
          },
          "currency": {
            "type": "string"
          },
          "clientReferenceNumber": {
            "type": [
              "null",
              "string"
            ]
          },
          "externalAccountId": {
            "type": [
              "null",
              "string"
            ]
          },
          "originalPrincipal": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "number",
              "string"
            ],
            "format": "double"
          },
          "outstandingPrincipal": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "number",
              "string"
            ],
            "format": "double"
          },
          "accruedInterest": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "number",
              "string"
            ],
            "format": "double"
          },
          "accruedFees": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "number",
              "string"
            ],
            "format": "double"
          },
          "openedAtUtc": {
            "type": "string",
            "format": "date-time"
          },
          "dueDateUtc": {
            "type": [
              "null",
              "string"
            ],
            "format": "date-time"
          },
          "lastPaymentAtUtc": {
            "type": [
              "null",
              "string"
            ],
            "format": "date-time"
          },
          "closedAtUtc": {
            "type": [
              "null",
              "string"
            ],
            "format": "date-time"
          },
          "createdAtUtc": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAtUtc": {
            "type": [
              "null",
              "string"
            ],
            "format": "date-time"
          }
        },
        "description": "A single debt owned by your organization. Returned by `GET /v1/debts`, `POST /v1/debts`, and `PATCH /v1/debts/{id}`.",
        "example": {
          "id": "9b0b9e2a-1c8d-4a82-9e3f-2c2c8a8a2e7a",
          "debtorId": "5d2f9b8a-0e22-4b04-9e58-9bb9f7c6d3a2",
          "status": "PendingAssignment",
          "currency": "AUD",
          "clientReferenceNumber": "INV-2026-00042",
          "externalAccountId": "INV-2026-00042",
          "originalPrincipal": 1899.00,
          "outstandingPrincipal": 1899.00,
          "accruedInterest": 0.00,
          "accruedFees": 0.00,
          "openedAtUtc": "2026-05-27T11:42:31.123Z",
          "dueDateUtc": "2026-01-15T00:00:00Z",
          "lastPaymentAtUtc": null,
          "closedAtUtc": null,
          "createdAtUtc": "2026-05-27T11:42:31.123Z",
          "updatedAtUtc": null
        }
      },
      "DebtorDto": {
        "required": [
          "id",
          "referenceId",
          "email",
          "phone",
          "firstName",
          "lastName",
          "preferredName",
          "status",
          "preferredContactMethod",
          "city",
          "state",
          "postalCode",
          "countryCode",
          "createdAtUtc",
          "updatedAtUtc"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "referenceId": {
            "type": "string"
          },
          "email": {
            "type": [
              "null",
              "string"
            ]
          },
          "phone": {
            "type": [
              "null",
              "string"
            ]
          },
          "firstName": {
            "type": "string"
          },
          "lastName": {
            "type": "string"
          },
          "preferredName": {
            "type": [
              "null",
              "string"
            ]
          },
          "status": {
            "type": "string"
          },
          "preferredContactMethod": {
            "type": [
              "null",
              "string"
            ]
          },
          "city": {
            "type": [
              "null",
              "string"
            ]
          },
          "state": {
            "type": [
              "null",
              "string"
            ]
          },
          "postalCode": {
            "type": [
              "null",
              "string"
            ]
          },
          "countryCode": {
            "type": [
              "null",
              "string"
            ]
          },
          "createdAtUtc": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAtUtc": {
            "type": [
              "null",
              "string"
            ],
            "format": "date-time"
          }
        },
        "description": "A debtor owned by your organization.",
        "example": {
          "id": "5d2f9b8a-0e22-4b04-9e58-9bb9f7c6d3a2",
          "referenceId": "CUST-9001",
          "email": "sample@example.com",
          "phone": "+61 412 100 100",
          "firstName": "Sample",
          "lastName": "Person",
          "preferredName": null,
          "status": "Active",
          "preferredContactMethod": "Email",
          "city": "Sydney",
          "state": "NSW",
          "postalCode": "2000",
          "countryCode": "AU",
          "createdAtUtc": "2026-05-27T11:42:31.123Z",
          "updatedAtUtc": null
        }
      },
      "DebtUpdatedEvent": {
        "type": "object",
        "properties": {
          "debt": {
            "$ref": "#/components/schemas/DebtDto"
          }
        },
        "description": "Payload of a `debt.updated` envelope. Fires after `PATCH /v1/debts/{id}`."
      },
      "OrganizationBrandingDto": {
        "required": [
          "primaryColorHex",
          "secondaryColorHex",
          "logoUrl",
          "faviconUrl",
          "brandTagline"
        ],
        "type": "object",
        "properties": {
          "primaryColorHex": {
            "type": "string"
          },
          "secondaryColorHex": {
            "type": "string"
          },
          "logoUrl": {
            "type": [
              "null",
              "string"
            ]
          },
          "faviconUrl": {
            "type": [
              "null",
              "string"
            ]
          },
          "brandTagline": {
            "type": [
              "null",
              "string"
            ]
          }
        },
        "description": "Current branding for your organization.",
        "example": {
          "primaryColorHex": "#0B5E5A",
          "secondaryColorHex": "#14B8A6",
          "logoUrl": "https://cdn.example.com/logo.svg",
          "faviconUrl": "https://cdn.example.com/favicon.ico",
          "brandTagline": "Resolution, not collection."
        }
      },
      "OrganizationDto": {
        "required": [
          "id",
          "name",
          "legalName",
          "tradingName",
          "defaultCurrency",
          "industry",
          "website",
          "supportEmail",
          "supportPhone",
          "timezone"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "legalName": {
            "type": "string"
          },
          "tradingName": {
            "type": [
              "null",
              "string"
            ]
          },
          "defaultCurrency": {
            "type": "string"
          },
          "industry": {
            "type": [
              "null",
              "string"
            ]
          },
          "website": {
            "type": [
              "null",
              "string"
            ]
          },
          "supportEmail": {
            "type": "string"
          },
          "supportPhone": {
            "type": "string"
          },
          "timezone": {
            "type": "string"
          }
        },
        "description": "The organization the calling API key belongs to.",
        "example": {
          "id": "a1b2c3d4-…",
          "name": "Acme Pty Ltd",
          "legalName": "Acme Holdings Pty Ltd",
          "tradingName": "Acme",
          "defaultCurrency": "AUD",
          "industry": "Retail",
          "website": "https://acme.example.com",
          "supportEmail": "support@acme.example.com",
          "supportPhone": "+61 2 5550 0100",
          "timezone": "Australia/Sydney"
        }
      },
      "PagedResultOfDebtDto": {
        "required": [
          "data",
          "nextCursor",
          "hasMore"
        ],
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DebtDto"
            }
          },
          "nextCursor": {
            "type": [
              "null",
              "string"
            ]
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "description": "Cursor-paginated envelope. Pass `cursor` from the previous response to fetch the next page. `hasMore` is `false` and `nextCursor` is `null` when you're at the end."
      },
      "PagedResultOfDebtorDto": {
        "required": [
          "data",
          "nextCursor",
          "hasMore"
        ],
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DebtorDto"
            }
          },
          "nextCursor": {
            "type": [
              "null",
              "string"
            ]
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "description": "Cursor-paginated envelope. Pass `cursor` from the previous response to fetch the next page. `hasMore` is `false` and `nextCursor` is `null` when you're at the end."
      },
      "PagedResultOfTransactionDto": {
        "required": [
          "data",
          "nextCursor",
          "hasMore"
        ],
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TransactionDto"
            }
          },
          "nextCursor": {
            "type": [
              "null",
              "string"
            ]
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "description": "Cursor-paginated envelope. Pass `cursor` from the previous response to fetch the next page. `hasMore` is `false` and `nextCursor` is `null` when you're at the end."
      },
      "PaymentReceivedEvent": {
        "type": "object",
        "properties": {
          "transaction": {
            "$ref": "#/components/schemas/TransactionDto"
          }
        },
        "description": "Payload of a `payment.received` envelope. Fires when an inbound payment settles successfully."
      },
      "PlanActivatedEvent": {
        "type": "object",
        "properties": {
          "debtId": {
            "type": "string",
            "format": "uuid"
          },
          "paymentPlanId": {
            "type": "string",
            "format": "uuid"
          },
          "totalAmount": {
            "type": "number",
            "format": "decimal"
          },
          "instalmentCount": {
            "type": "integer"
          },
          "activatedAtUtc": {
            "type": "string",
            "format": "date-time"
          }
        },
        "description": "Payload of a `plan.activated` envelope. Fires when a payment plan starts."
      },
      "PlanDefaultedEvent": {
        "type": "object",
        "properties": {
          "debtId": {
            "type": "string",
            "format": "uuid"
          },
          "paymentPlanId": {
            "type": "string",
            "format": "uuid"
          },
          "missedInstalments": {
            "type": "integer"
          },
          "defaultedAtUtc": {
            "type": "string",
            "format": "date-time"
          }
        },
        "description": "Payload of a `plan.defaulted` envelope. Fires when missed instalments trip the default threshold."
      },
      "ProblemDetails": {
        "type": "object",
        "properties": {
          "type": {
            "type": [
              "null",
              "string"
            ]
          },
          "title": {
            "type": [
              "null",
              "string"
            ]
          },
          "status": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "detail": {
            "type": [
              "null",
              "string"
            ]
          },
          "instance": {
            "type": [
              "null",
              "string"
            ]
          }
        }
      },
      "TestPingEvent": {
        "type": "object",
        "properties": {
          "message": {
            "type": "string",
            "description": "Human-readable confirmation string."
          },
          "callerKeyId": {
            "type": "string",
            "format": "uuid"
          }
        },
        "description": "Payload of a `test.ping` envelope. Sent from `POST /v1/webhooks/test` for receiver-verification."
      },
      "TransactionDto": {
        "required": [
          "id",
          "debtId",
          "debtorId",
          "direction",
          "status",
          "method",
          "amount",
          "currency",
          "feeAmount",
          "provider",
          "providerRef",
          "processedAtUtc",
          "createdAtUtc"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "debtId": {
            "type": "string",
            "format": "uuid"
          },
          "debtorId": {
            "type": "string",
            "format": "uuid"
          },
          "direction": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "method": {
            "type": "string"
          },
          "amount": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "number",
              "string"
            ],
            "format": "double"
          },
          "currency": {
            "type": "string"
          },
          "feeAmount": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "number",
              "string"
            ],
            "format": "double"
          },
          "provider": {
            "type": "string"
          },
          "providerRef": {
            "type": [
              "null",
              "string"
            ]
          },
          "processedAtUtc": {
            "type": "string",
            "format": "date-time"
          },
          "createdAtUtc": {
            "type": "string",
            "format": "date-time"
          }
        },
        "description": "A single transaction on a debt in your organization. `/v1/payments` filters to `direction=Inbound` + `status=Succeeded`; `/v1/transactions` returns the full ledger.",
        "example": {
          "id": "f1c2d3e4-…",
          "debtId": "9b0b9e2a-…",
          "debtorId": "5d2f9b8a-…",
          "direction": "Inbound",
          "status": "Succeeded",
          "method": "Card",
          "amount": 250.00,
          "currency": "AUD",
          "feeAmount": 0.75,
          "provider": "Stripe",
          "providerRef": "pi_3O…",
          "processedAtUtc": "2026-05-27T12:00:00Z",
          "createdAtUtc": "2026-05-27T12:00:00Z"
        }
      },
      "UpdateBrandingRequest": {
        "type": "object",
        "properties": {
          "primaryColorHex": {
            "type": [
              "null",
              "string"
            ],
            "description": "#RRGGBB. Used for primary actions, brand mark, link colour."
          },
          "secondaryColorHex": {
            "type": [
              "null",
              "string"
            ],
            "description": "#RRGGBB. Used for accents."
          },
          "logoUrl": {
            "type": [
              "null",
              "string"
            ],
            "description": "Absolute URL. Empty string clears."
          },
          "faviconUrl": {
            "type": [
              "null",
              "string"
            ],
            "description": "Absolute URL. Empty string clears."
          },
          "brandTagline": {
            "type": [
              "null",
              "string"
            ],
            "description": "Optional one-liner shown in debtor-facing footers."
          }
        },
        "description": "Body for `PATCH /v1/organization/branding`. Merge-style — only non-null fields are applied. To clear `logoUrl` / `faviconUrl` / `brandTagline`, pass empty string. Branding caches across all portals are invalidated synchronously on success.",
        "example": {
          "primaryColorHex": "#0B5E5A",
          "secondaryColorHex": "#14B8A6",
          "logoUrl": "https://cdn.example.com/logo.svg",
          "brandTagline": "Resolution, not collection."
        }
      },
      "UpdateDebtRequest": {
        "type": "object",
        "properties": {
          "clientReferenceNumber": {
            "type": [
              "null",
              "string"
            ],
            "description": "Replace your private reference for the debt."
          },
          "originalCreditorName": {
            "type": [
              "null",
              "string"
            ],
            "description": "Update the original creditor (e.g. after a portfolio sale)."
          },
          "dueDateUtc": {
            "type": [
              "null",
              "string"
            ],
            "description": "Push or pull the due date.",
            "format": "date-time"
          },
          "category": {
            "type": [
              "null",
              "string"
            ],
            "description": "Optional category bucket for portfolio reporting."
          },
          "portfolioCode": {
            "type": [
              "null",
              "string"
            ],
            "description": "Optional portfolio code for grouping debts across batches."
          },
          "notes": {
            "type": [
              "null",
              "string"
            ],
            "description": "Free-text note appended to the debt's audit trail."
          }
        },
        "description": "Body for `PATCH /v1/debts/{id}`. Only the supplied (non-null) fields are mutated. Status transitions are deliberately out of scope here — those live in internal workflows and surface via webhooks (`debt.accepted`, `debt.disputed`, etc.).",
        "example": {
          "dueDateUtc": "2026-03-31T00:00:00Z",
          "notes": "Pushed due date out 6 weeks at customer request."
        }
      },
      "UpdateWebhookRequest": {
        "type": "object",
        "properties": {
          "url": {
            "type": [
              "null",
              "string"
            ],
            "description": "Absolute http(s) URL. Pass `null` to leave the existing URL unchanged."
          },
          "rotateSecret": {
            "type": "boolean",
            "description": "Set to `true` to mint a fresh signing secret. The old secret stops being accepted immediately."
          },
          "clear": {
            "type": "boolean",
            "description": "Set to `true` to remove the URL and secret entirely (disables webhooks)."
          }
        },
        "description": "Body for `PUT /v1/webhooks`. Supports three operations: set the URL (with auto-mint secret on first configure), rotate the signing secret, or clear (disable webhooks). When `rotateSecret: true` or this is the first configure, the response includes a one-time `newSecret` (`whsec_…`) — store it before the response goes out of scope.",
        "example": {
          "url": "https://your.app/adeva/webhook",
          "rotateSecret": false,
          "clear": false
        }
      },
      "UpdateWebhookResponse": {
        "required": [
          "url",
          "secretPrefix",
          "newSecret",
          "enabled"
        ],
        "type": "object",
        "properties": {
          "url": {
            "type": [
              "null",
              "string"
            ]
          },
          "secretPrefix": {
            "type": [
              "null",
              "string"
            ]
          },
          "newSecret": {
            "type": [
              "null",
              "string"
            ]
          },
          "enabled": {
            "type": "boolean"
          }
        },
        "description": "Response from `PUT /v1/webhooks`. `newSecret` is populated only when a new secret was just minted (first configure or rotation). Store it before the response goes out of scope.",
        "example": {
          "url": "https://your.app/adeva/webhook",
          "secretPrefix": "whsec_AbCd…",
          "newSecret": "whsec_AbCdEf…",
          "enabled": true
        }
      },
      "WebhookConfigDto": {
        "required": [
          "url",
          "secretPrefix",
          "enabled"
        ],
        "type": "object",
        "properties": {
          "url": {
            "type": [
              "null",
              "string"
            ]
          },
          "secretPrefix": {
            "type": [
              "null",
              "string"
            ]
          },
          "enabled": {
            "type": "boolean"
          }
        },
        "description": "Current webhook configuration. `secretPrefix` shows the first 12 chars of the signing secret so you can identify which one is in use without exposing the full value.",
        "example": {
          "url": "https://your.app/adeva/webhook",
          "secretPrefix": "whsec_AbCd…",
          "enabled": true
        }
      },
      "WebhookEventEnvelope": {
        "required": [
          "id",
          "type",
          "createdAt",
          "data"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Globally unique delivery id. Dedupe on this."
          },
          "type": {
            "enum": [
              "debt.created",
              "debt.updated",
              "debt.accepted",
              "debt.disputed",
              "payment.received",
              "plan.activated",
              "plan.defaulted",
              "test.ping"
            ],
            "type": "string",
            "description": "Event type. Stable identifier."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "data": {
            "type": "object",
            "description": "Per-type payload — see linked event schemas."
          }
        },
        "description": "Envelope POSTed to every webhook receiver. `data` shape depends on `type` — see the per-event schemas (`DebtCreatedEvent`, `PaymentReceivedEvent`, etc).",
        "example": {
          "id": "evt_9b0b9e2a1c8d4a82",
          "type": "debt.created",
          "createdAt": "2026-05-27T11:42:31.123Z",
          "data": {
            "debt": {
              "id": "9b0b9e2a-1c8d-4a82-9e3f-2c2c8a8a2e7a",
              "status": "PendingAssignment",
              "originalPrincipal": 1899.00,
              "currency": "AUD"
            }
          }
        }
      },
      "WebhookTestResponse": {
        "required": [
          "deliveryId",
          "eventType",
          "enqueuedAt"
        ],
        "type": "object",
        "properties": {
          "deliveryId": {
            "type": "string",
            "format": "uuid"
          },
          "eventType": {
            "type": "string"
          },
          "enqueuedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      }
    },
    "securitySchemes": {
      "AdevaApiKey": {
        "type": "http",
        "description": "Adeva Pro Public API key. Live keys are minted from the Adeva Pro client console (Developer → API keys); test keys from the sandbox dashboard. Pass as `Authorization: Bearer ak_live_…`. We store only the SHA-256 hash + a 16-char display prefix — the full secret is shown once at creation.",
        "scheme": "bearer",
        "bearerFormat": "ak_live_… (Production) / ak_test_… (Sandbox)"
      }
    }
  },
  "security": [
    {
      "AdevaApiKey": [ ]
    }
  ],
  "tags": [
    {
      "name": "Meta",
      "description": "Liveness probe and other unauthenticated metadata endpoints."
    },
    {
      "name": "Transactions",
      "description": "Raw transaction ledger across your organization's debts — every direction and status."
    },
    {
      "name": "Payments",
      "description": "Inbound, settled payment transactions filtered to your organization's debts. For the full ledger (including outbound transactions and non-settled states) use `/v1/transactions`."
    },
    {
      "name": "Organization",
      "description": "Get the organization the calling key belongs to and update its branding (colours, logo, favicon, tagline). Branding caches across portals are invalidated synchronously on update."
    },
    {
      "name": "Webhooks",
      "description": "Configure a webhook URL, rotate the signing secret, and send a synthetic test event. Adeva POSTs JSON with a Stripe-compatible `Adeva-Signature` header and retries non-2xx deliveries on a 1m → 24h backoff over 6 attempts."
    },
    {
      "name": "Debts",
      "description": "Read and create debt records. Each debt belongs to a debtor in your organization and is the unit of work for collection. Status transitions (accept, dispute, write-off) belong to internal workflows and are surfaced via webhooks rather than direct PATCH calls."
    },
    {
      "name": "Debtors",
      "description": "Read the debtor records owned by your organization. Debtors are also created implicitly via `POST /v1/debts` when you provide an inline debtor identity."
    }
  ],
  "externalDocs": {
    "description": "Guides for humans + agents: getting started, idempotency, webhook signatures, llms.txt",
    "url": "https://api.adevapro.com.au/docs/"
  }
}