{ "openapi": "3.0.4", "info": { "title": "Debitura Referral Partner API", "description": "Welcome to the Debitura Referral API. This API allows you to set up new clients and track your revenue share with Debitura. You can also generate bearer tokens for use in the Customer API to create cases, check case status, and access all other endpoints. To get access to this API, please contact us at contact@debitura.com.\n\nπŸ“– Full documentation, guides, and integration walkthroughs: https://docs.debitura.com/referral-partners", "contact": { "name": "Debitura Support", "url": "https://www.debitura.com/integration", "email": "contact@debitura.com" }, "version": "v1" }, "servers": [ { "url": "https://referral-api.debitura.com", "description": "Production" } ], "paths": { "/cases": { "get": { "tags": [ "Cases" ], "summary": "List cases for referral partner clients", "description": "Retrieves a paginated list of debt collection cases for all clients linked to the authenticated referral partner.\n\nCase Lifecycle Stages\nCases progress through a defined lifecycle:\nβ€’ **Pending contract signing** - Client hasn't signed debt collection agreement yet\nβ€’ **Pending Verification Internal** - Case awaiting internal Debitura review\nβ€’ **Pending Verification** - Case awaiting partner verification\nβ€’ **More Info Required** - More information required from creditor\nβ€’ **Collecting Quotes** - Awaiting quote from collection partner\nβ€’ **Pending Quote Selection** - Quote provided by partner\nβ€’ **Active** - Case is being actively collected\nβ€’ **Paused** - Collection temporarily paused\nβ€’ **Closed** - Case is closed (check CloseCode for reason)\n\nFiltering Options\nβ€’ **FromDate/ToDate** - Filter by case creation date range (ISO 8601)\nβ€’ **ExternalTenantId** - Filter to specific client using your identifier\nβ€’ **Statuses** - Filter by lifecycle status(es)\nβ€’ **Query** - Search across reference numbers and debtor name\n\nSorting\nβ€’ **Sort** - Sort field and direction (format: 'field:direction')\nβ€’ Supported fields: DateCreated, GrossAmount, DueDate\nβ€’ Examples: 'DateCreated:desc', 'GrossAmount:asc', 'DueDate:desc'\nβ€’ Default: DateCreated:desc (newest first)", "parameters": [ { "name": "FromDate", "in": "query", "description": "Filter cases from this date (inclusive, based on case creation date). ISO 8601 format.", "schema": { "type": "string", "format": "date-time" } }, { "name": "ToDate", "in": "query", "description": "Filter cases to this date (inclusive, based on case creation date). ISO 8601 format.", "schema": { "type": "string", "format": "date-time" } }, { "name": "ExternalTenantId", "in": "query", "description": "Filter by specific client's external tenant ID", "schema": { "type": "string" } }, { "name": "Statuses", "in": "query", "description": "Filter by case lifecycle status(es). Multiple values can be provided.\nAccepts enum names (e.g. \"Active\", \"Closed\") or descriptions (e.g. \"More Info Required\").", "schema": { "type": "array", "items": { "type": "string" } } }, { "name": "Query", "in": "query", "description": "Search query across case reference, creditor reference, and debtor name", "schema": { "type": "string" } }, { "name": "Page", "in": "query", "description": "Page number (1-indexed)", "schema": { "maximum": 2147483647, "minimum": 1, "type": "integer", "format": "int32" } }, { "name": "PageSize", "in": "query", "description": "Number of results per page (default: 10, max: 100)", "schema": { "maximum": 100, "minimum": 1, "type": "integer", "format": "int32" } }, { "name": "CountryIds", "in": "query", "description": "Filter by debtor country ID(s). Multiple values can be provided.\nOnly cases where the debtor's country matches one of the specified IDs are returned.", "schema": { "type": "array", "items": { "type": "integer", "format": "int32" } } }, { "name": "CollectionPartnerIds", "in": "query", "description": "Filter by collection partner ID(s). Multiple values can be provided.\nOnly cases assigned to one of the specified collection partners are returned.", "schema": { "type": "array", "items": { "type": "string", "format": "uuid" } } }, { "name": "Sort", "in": "query", "description": "Sort field and direction. Format: \"field[:asc|desc]\"\nSupported fields: DateCreated, GrossAmount, DueDate\nExamples: \"DateCreated:desc\", \"GrossAmount:asc\"\nDefault: DateCreated:desc", "schema": { "type": "string" } } ], "responses": { "200": { "description": "Cases retrieved successfully", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Cases.GetCasesResponse" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Cases.GetCasesResponse" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Cases.GetCasesResponse" } } } }, "400": { "description": "Invalid request parameters", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } } } }, "500": { "description": "Internal server error", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } } } } } } }, "/cases/{id}": { "get": { "tags": [ "Cases" ], "summary": "Get case detail with potential revenue breakdown", "description": "Retrieves a single case with all standard fields plus a potential revenue breakdown showing what the referral partner would earn if the full amount is collected.", "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Case retrieved successfully", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Cases.GetCaseDetailResponse" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Cases.GetCaseDetailResponse" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Cases.GetCaseDetailResponse" } } } }, "404": { "description": "Case not found", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } } } }, "500": { "description": "Internal server error", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } } } } } } }, "/cases/{caseId}/files": { "post": { "tags": [ "Cases" ], "summary": "Upload a file to a case. Optionally posts a system chat message to notify the collection partner.", "description": "Uploads a file and associates it with a case owned by one of the referral partner's clients.\n\nFile requirements:\n- Maximum file size: 25 MB\n- Allowed types: PDF, Excel (.xls, .xlsx), CSV, Text (.txt), Images (.jpg, .jpeg, .png, .gif)\n\nWhen sendChatNotification is true (default), a system message is posted on the case chat\nto notify the collection partner that a new file was uploaded.", "parameters": [ { "name": "caseId", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "sendChatNotification", "in": "query", "schema": { "type": "boolean", "default": true } }, { "name": "Idempotency-Key", "in": "header", "description": "Optional idempotency key (max 255 characters) for safely retrying this request. If a previous request used the same key with an identical body, the original terminal response is replayed verbatim. Reusing the key with a different body returns 422 with `Type: \"IdempotencyConflict\"`. Field-level 400 validation errors are not stored, so you may fix the request and retry with the same key.", "schema": { "maxLength": 255, "type": "string" } } ], "requestBody": { "content": { "multipart/form-data": { "schema": { "type": "object", "properties": { "file": { "type": "string", "format": "binary" } } }, "encoding": { "file": { "style": "form" } } } } }, "responses": { "200": { "description": "File uploaded successfully" }, "400": { "description": "Validation error", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } } } }, "404": { "description": "Case not found", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } } } }, "413": { "description": "File too large", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } } } }, "415": { "description": "Unsupported file type", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } } } }, "500": { "description": "Internal server error", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } } } } } } }, "/clients": { "post": { "tags": [ "Clients" ], "summary": "Create and onboard a new client", "description": "Creates a new client (creditor) in the Debitura platform and links them to the authenticated referral partner.\n\nRequest Structure\n- **ExternalTenantId** (required) - Your unique identifier for this client (for correlation and future lookups)\n- **Client** (required) - Company information (name, registration number, country, address, contact details)\n- **Users** (required, 1-N) - At least one user with email and name. For multiple users, exactly one must have IsOnboardingUser=true. Single-user requests auto-infer the onboarding user.\n- **Cases** (optional) - Optionally create multiple collection cases during client creation (validated upfront to prevent orphaned clients)\n\nOnboarding Flow\n1. **New Client (201/202)**\n - Client and users are created in Debitura\n - ReferralPartnerClientLink is established with revenue sharing percentage\n - If onboarding is complete (terms signed), returns 201\n - If onboarding pending (terms not signed), returns 202 with OnboardingLinks.Url for completing the process\n\n **202 Response - Two URL Scenarios:**\n\n **1a. New Client - Full Onboarding URL**\n - Scenario: Client has never signed the SDCA (Standard Debt Collection Agreement)\n - URL Pattern: `{onboardingBase}/companydetails/{referralPartnerClientLinkId}`\n - User Journey: Multi-step onboarding (company details β†’ users β†’ sign SDCA)\n - Use Case: First-time client registration\n\n **1b. Existing Client - Contract Upgrade URL**\n - Scenario: Client previously signed SDCA but terms have been updated (NeedsRefresh=true)\n - URL Pattern: `{onboardingBase}/ContractUpgrade/Sign/{referralPartnerClientLinkId}`\n - User Journey: Streamlined contract re-signing only (no company details re-entry)\n - Use Case: SDCA version upgrade (e.g., new pricing tiers, updated legal terms)\n - Note: This can happen to previously-ready clients (201 β†’ 202 state transition)\n\n **Important:** The `POST /clients` endpoint is idempotent and re-checks SDCA status on every call.\n This means an existing client that previously returned `201 Created` may flip to `202 Accepted`\n if Debitura releases a new SDCA version requiring re-signature.\n\n2. **Existing Client - Needs Linking (409 Conflict)**\n There are TWO distinct 409 conflict scenarios - check the ConflictResponse.Type field to distinguish:\n\n **2a. ClientExistsNeedsLinking** (Type: \"ClientExistsNeedsLinking\")\n - Client already exists in Debitura (matched by user email or support email)\n - A link request is created with an expiration window configured per-partner (`ApprovalTtlDays`, default 7 days, clamped 1–30)\n - Existing client must approve the referral partner link via OnboardingLinks.Url\n - If approved, IsAttributedClient will be FALSE (revenue only on partner-referred cases)\n - Cases submitted in the original request are persisted and replayed against the linked creditor automatically when the user approves. `AllowPendingContracts=true` is forced on replay so cases land in `PendingContractSigning` rather than 422-failing on missing SDCA/PoA/KYC.\n - Returns 409 with OnboardingLinks.Url pointing to approval page\n\n **2b. ClientAlreadyLinkedToAnotherPartner** (Type: \"AlreadyLinkedToAnotherPartner\")\n - Client is already linked to a DIFFERENT referral partner\n - Only one referral partner link per client is supported\n - Cannot proceed - contact Debitura support for resolution\n - Returns 409 with error message and support contact\n\n3. **Idempotency**\n - Repeated calls with same ExternalTenantId return existing client status (201 or 202)\n - No duplicate clients or links are created\n\nResponse Codes\n- **201 Created** - Client created and fully onboarded (terms signed, ready to create cases, IsAttributedClient=true)\n- **202 Accepted** - Client created but onboarding incomplete (OnboardingLinks.Url provided to complete, IsAttributedClient=true)\n- **400 Bad Request** - Validation errors (missing required fields, invalid data, duplicate CreditorReferences within request)\n- **409 Conflict** - Two scenarios (check ConflictResponse.Type):\n - \"ClientExistsNeedsLinking\" - Client exists, needs approval link (if approved, IsAttributedClient=false)\n - \"AlreadyLinkedToAnotherPartner\" - Client already linked to different partner (cannot proceed)\n- **422 Unprocessable Entity** - Business rule violation (field validation errors only, NOT partner matching failures)\n- **500 Internal Server Error** - Unexpected server error\n\nOptional Multi-Case Creation\nIf the Cases array is provided in the request:\n- ALL cases are validated BEFORE client creation (checks field validation and duplicate references)\n- Client is ALWAYS created to ensure referral partner link and future attribution\n- Cases with available collection partners are created successfully (CaseResults.SuccessfulCases)\n- Cases without available partners are NOT created and reported as failures (CaseResults.FailedCases)\n- If validation errors exist (primitives, duplicates), client creation is aborted and 400 is returned\n- Successful cases appear in CaseResults.SuccessfulCases with full case details\n- Failed cases appear in CaseResults.FailedCases with CaseIndex, CreditorReference, and error details (e.g., \"No collection partner available for jurisdiction\")\n\nUser Roles\n- **IsOnboardingUser=true** - User receives CreditorAdmin role (full access)\n- **IsOnboardingUser=false** - User receives CreditorUser role (limited access)\n\nRevenue Sharing (Fee Percentage Locked at Link Creation)\n- The referral fee percentage is snapshot from the partner's current configuration at the exact moment the client link is created\n- **This percentage is IMMUTABLE and will NEVER change for this client** - even if the partner's global fee percentage is updated later\n- The locked percentage is used for ALL revenue calculations for ALL cases created by this client, forever\n- This ensures predictable, stable revenue sharing and prevents disputes over retroactive fee changes\n- To see the locked percentage for a specific client, use GET /clients/{externalTenantId} (included in response)", "requestBody": { "content": { "application/json-patch+json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Clients.CreateClientRequest" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Clients.CreateClientRequest" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Clients.CreateClientRequest" } }, "application/*+json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Clients.CreateClientRequest" } } } }, "responses": { "201": { "description": "Client created and fully onboarded (terms signed)", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Clients.ClientCreatedResponse" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Clients.ClientCreatedResponse" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Clients.ClientCreatedResponse" } } } }, "202": { "description": "Client created but onboarding incomplete (use OnboardingLinks.Url to complete)", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Clients.ClientCreatedResponse" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Clients.ClientCreatedResponse" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Clients.ClientCreatedResponse" } } } }, "400": { "description": "Invalid request (validation errors)", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } } } }, "409": { "description": "Client already exists - approval required to link (use OnboardingLinks.Url for approval)", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Clients.ConflictResponse" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Clients.ConflictResponse" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Clients.ConflictResponse" } } } }, "422": { "description": "Business rule violation (field validation errors only)", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Cases.BusinessErrorResponseApiDTO" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Cases.BusinessErrorResponseApiDTO" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Cases.BusinessErrorResponseApiDTO" } } } }, "500": { "description": "Internal server error", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } } } } } }, "get": { "tags": [ "Clients" ], "summary": "List all linked clients", "description": "Retrieves a paginated list of all clients (creditors) linked to the authenticated referral partner.\n\nResponse Data\nFor each client, the response includes:\n- **ExternalTenantId** - Your unique identifier for this client\n- **OnboardingDone** - Whether the client has completed onboarding (signed debt collection agreements)\n- **OnboardingLinks** - If onboarding incomplete, contains URL to complete the process\n- **Client** - Complete client information (ID, company name, registration number, country, address, contact details)\n- **Users** - List of all users associated with this client (ID, email, name)\n\nFiltering Parameters\n- **ExternalTenantId** - Filter to specific client by your identifier\n- **IsAttributedClient** - Filter by attribution status (true = created by you, false = linked later)\n- **DateCreatedFrom** - Filter clients linked on or after this date (ISO 8601 format)\n- **DateCreatedTo** - Filter clients linked on or before this date (ISO 8601 format)\n- **Query** - Search across company name, email, and registration number (case-insensitive)\n\nPagination\n- **Page** - Page number (default: 1, min: 1)\n- **PageSize** - Results per page (default: 50, min: 1, max: 100)\n- Response includes page metadata: total count, current page size, skip count\n\nSorting\n- **Sort** - Sort field and direction (format: 'field:direction')\n- Supported fields: dateCreated, name\n- Examples: 'dateCreated:desc', 'name:asc'\n- Default: dateCreated:desc (most recent first)\n\nUse Cases\n- List all your clients for dashboard display\n- Search for specific client by name, email, or registration number\n- Filter clients by onboarding status\n- Identify clients created by you vs. existing clients you linked\n- Monitor client link creation dates\n- Paginate through large client lists\n\nClient Attribution and Revenue Rules ⚠️ CRITICAL FOR REVENUE CALCULATIONS\n- **IsAttributedClient=true** - Client was created through the referral partner API\n - Referral partner earns revenue on ALL cases (100% of cases)\n - This is the default for clients created via POST /clients\n\n- **IsAttributedClient=false** - Client existed in Debitura before the link was established (409 conflict scenario)\n - Referral partner earns revenue ONLY on cases created through the referral partnership\n - Cases created directly by the client (not through partner) do NOT generate referral revenue\n - This protects pre-existing client relationships\n\n**This distinction is the most important business rule for revenue calculations.** Always check IsAttributedClient when forecasting or reconciling revenue.\n\nOnly active (non-archived) client links are returned.", "parameters": [ { "name": "Page", "in": "query", "description": "Page number (default: 1)", "schema": { "type": "integer", "format": "int32" } }, { "name": "PageSize", "in": "query", "description": "Results per page (default: 50, max: 100)", "schema": { "type": "integer", "format": "int32" } }, { "name": "Query", "in": "query", "description": "Search query across CompanyName, OfficeEmail, and CompanyRegistrationNumber", "schema": { "type": "string" } }, { "name": "ExternalTenantId", "in": "query", "description": "Filter by exact external tenant ID", "schema": { "type": "string" } }, { "name": "IsAttributedClient", "in": "query", "description": "Filter by attribution status (true = attributed client, false = linked but not attributed)", "schema": { "type": "boolean" } }, { "name": "DateCreatedFrom", "in": "query", "description": "Filter by link creation date (from)", "schema": { "type": "string", "format": "date-time" } }, { "name": "DateCreatedTo", "in": "query", "description": "Filter by link creation date (to)", "schema": { "type": "string", "format": "date-time" } }, { "name": "OnboardingDone", "in": "query", "description": "Filter by onboarding status (true = completed, false = pending)", "schema": { "type": "boolean" } }, { "name": "Sort", "in": "query", "description": "Sort field and direction. Format: \"field[:asc|desc]\"\nSupported fields: dateCreated, name\nExamples: \"dateCreated:desc\", \"name:asc\"\nDefault: dateCreated:desc", "schema": { "type": "string" } } ], "responses": { "200": { "description": "Clients retrieved successfully", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Clients.GetClientsResponse" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Clients.GetClientsResponse" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Clients.GetClientsResponse" } } } }, "400": { "description": "Invalid request parameters", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } } } }, "500": { "description": "Internal server error", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } } } } } } }, "/clients/{externalTenantId}": { "get": { "tags": [ "Clients" ], "summary": "Get client by external tenant ID", "description": "Retrieves detailed information for a specific client using your unique identifier (External Tenant ID).\n\nPath Parameter\n- **externalTenantId** - Your unique identifier for this client (the same value used during client creation)\n\nResponse Data\nThe response includes complete client information:\n- **ExternalTenantId** - Your unique identifier for this client\n- **OnboardingDone** - Whether the client has completed onboarding (signed debt collection agreements)\n- **OnboardingLinks** - If onboarding incomplete, contains URL to complete the process\n- **Client** - Complete client information\n - Debitura-assigned client ID (Guid)\n - Company name and registration number\n - Country and address details\n - Contact information (email, phone)\n- **Users** - List of all users associated with this client\n - User ID, email, first name, last name\n\nUse Cases\n- Look up client details using your internal identifier\n- Check client onboarding status\n- Retrieve Debitura client ID for use with the Customer API (via OAuth token endpoint)\n- Get client information before creating cases\n- Verify client link is still active\n\nError Cases\n- **404 Not Found** - No active client link exists for this External Tenant ID and your partner account\n - Client was never created\n - Client link was archived\n - External Tenant ID belongs to different referral partner\n- **500 Internal Server Error** - Unexpected server error\n\nImportant Notes\n- Only returns active (non-archived) client links\n- External Tenant ID is case-sensitive\n- The client must be linked to your referral partner account\n- Use the returned client ID with the OAuth token endpoint to generate bearer tokens for Customer API access", "parameters": [ { "name": "externalTenantId", "in": "path", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "Client retrieved successfully", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Clients.ClientCreatedResponse" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Clients.ClientCreatedResponse" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Clients.ClientCreatedResponse" } } } }, "404": { "description": "Client not found or link is archived", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } } } }, "500": { "description": "Internal server error", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } } } } } }, "delete": { "tags": [ "Clients" ], "summary": "Reset a client (test environment only)", "description": "Deletes a client and all associated data, allowing you to re-create the client from scratch.\n\n⚠️ **TEST ENVIRONMENT ONLY** - This endpoint is only available on the test environment (testreferral-api.debitura.com).\nCalling this endpoint on production will return 403 Forbidden.\n\nUse Cases\n- Testing the full onboarding flow multiple times\n- Resetting after changing your internal tenant structure during development\n- Cleaning up test data without manual intervention\n\nWhat Gets Deleted (cascade)\n- All collection cases and invoices for the client\n- All leads for the client\n- The Creditor account (removes email from matching algorithm)\n- The ReferralPartnerClientLink is archived\n- Associated users are cleaned up if they have no other relations\n\nAfter Reset\n- You can call POST /clients with any externalTenantId using the same email\n- The matching algorithm will not find the deleted client\n- A completely new client will be created (IsAttributedClient=true)\n\nImportant\n- You can only reset clients that are linked to your partner account\n- Pending link requests (409 scenario) cannot be reset - only actual links", "parameters": [ { "name": "externalTenantId", "in": "path", "required": true, "schema": { "type": "string" } } ], "responses": { "204": { "description": "Client and all associated data successfully deleted" }, "403": { "description": "Endpoint not available in production environment", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } } } }, "404": { "description": "No active client link found for this externalTenantId", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } } } }, "500": { "description": "Internal server error", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } } } } } } }, "/clients/{externalTenantId}/is-deletable": { "get": { "tags": [ "Clients" ], "summary": "Check if a client can be deleted (test environment only)", "description": "Checks whether a client can be safely deleted for testing purposes.\n\n⚠️ **TEST ENVIRONMENT ONLY** - This endpoint is only available on the test environment.\n\nUse this endpoint before calling DELETE to verify the client can be removed.\n\nA client can be deleted if:\n- They have no active collection cases (only pending cases are allowed)\n- They have no leads with active quotes\n\nReturns\n- **isDeletable**: true if the client can be deleted\n- **blockers**: list of reasons why deletion is blocked (if any)", "parameters": [ { "name": "externalTenantId", "in": "path", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "Deletability check completed", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Clients.ClientDeletableResponse" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Clients.ClientDeletableResponse" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Clients.ClientDeletableResponse" } } } }, "403": { "description": "Endpoint not available in production environment", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } } } }, "404": { "description": "No active client link found for this externalTenantId", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } } } }, "500": { "description": "Internal server error", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } } } } } } }, "/clients/{externalTenantId}/withdraw": { "post": { "tags": [ "Clients" ], "summary": "Withdraw an attributed client", "description": "Withdraws a client that never completed onboarding. Archives the referral partner link and closes all pending cases with close code CaseNeverStartedInternal.\n\nThe same externalTenantId can be re-submitted via POST /clients after withdrawal.\n\nPath Parameter\n- **externalTenantId** - Your internal identifier for the client\n\nBusiness Rules\n- Only attributed clients (IsAttributedClient = true) can be withdrawn\n- All cases for this client must be in PendingContractSigning status\n\nWhat Happens\n- The referral partner client link is archived\n- All pending cases are closed with close code CaseNeverStartedInternal\n\nAfter Withdrawal\n- The same externalTenantId can be re-submitted via POST /clients\n- A new client record will be created on re-submission\n\nError Cases\n- **404 Not Found** - No active client link exists for this externalTenantId and your partner account\n- **409 Conflict** - Client cannot be withdrawn because:\n - IsAttributedClient = false (non-attributed clients cannot be withdrawn)\n - One or more cases have progressed beyond PendingContractSigning", "parameters": [ { "name": "externalTenantId", "in": "path", "required": true, "schema": { "type": "string" } } ], "responses": { "204": { "description": "Client withdrawn successfully" }, "404": { "description": "No active client link found for this externalTenantId", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } } } }, "409": { "description": "Cannot withdraw β€” client not attributed or cases have progressed beyond onboarding", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } } } }, "500": { "description": "Internal server error", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } } } } } } }, "/clients/{externalTenantId}/kyc-verification": { "post": { "tags": [ "Clients" ], "summary": "Submit KYC verification for a client", "description": "Submits KYC/AML director verification data for an existing client. Multiple submissions are allowed; the latest record is used for verification checks. When sendChatNotification is true (default), a system message is posted on all active cases for this client to notify the collection partner.", "parameters": [ { "name": "externalTenantId", "in": "path", "required": true, "schema": { "type": "string" } }, { "name": "sendChatNotification", "in": "query", "schema": { "type": "boolean", "default": true } }, { "name": "Idempotency-Key", "in": "header", "description": "Optional idempotency key (max 255 characters) for safely retrying this request. If a previous request used the same key with an identical body, the original terminal response is replayed verbatim. Reusing the key with a different body returns 422 with `Type: \"IdempotencyConflict\"`. Field-level 400 validation errors are not stored, so you may fix the request and retry with the same key.", "schema": { "maxLength": 255, "type": "string" } } ], "requestBody": { "content": { "application/json-patch+json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Clients.SubmitKycVerificationRequest" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Clients.SubmitKycVerificationRequest" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Clients.SubmitKycVerificationRequest" } }, "application/*+json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Clients.SubmitKycVerificationRequest" } } } }, "responses": { "201": { "description": "KYC verification submitted", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Clients.KycVerificationDto" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Clients.KycVerificationDto" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Clients.KycVerificationDto" } } } }, "404": { "description": "Client not found", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } } } }, "500": { "description": "Internal server error", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } } } } } } }, "/coverage": { "get": { "tags": [ "Coverage" ], "summary": "List all jurisdiction coverage", "description": "Returns all jurisdictions where Debitura operates, with the assigned collection partner(s) and conditions for each.\n\nUse this to show potential clients which countries and regions are supported before they register.", "responses": { "200": { "description": "Coverage list returned", "content": { "text/plain": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Coverages.CoverageItemApiDTO" } } }, "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Coverages.CoverageItemApiDTO" } } }, "text/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Coverages.CoverageItemApiDTO" } } } } } } } }, "/referral-partner/filter-options": { "get": { "tags": [ "FilterOptions" ], "summary": "Get available filter options for cases and earnings", "description": "Returns distinct filter options available for the authenticated referral partner's cases and earnings pages.\n\n**Countries** β€” Distinct debtor countries from the referral partner's case history, sorted alphabetically.\n\n**CarveoutPartners** β€” Collection partners from the referral partner's active JurisdictionPricingZone records (DateDeleted == null and DateDeactivated == null), sorted alphabetically.\n\nUse the returned IDs as values for the CountryIds and CollectionPartnerIds query parameters on the cases and reporting/transactions endpoints.", "responses": { "200": { "description": "Filter options retrieved successfully", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.ReferralPartners.GetFilterOptionsResponse" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.ReferralPartners.GetFilterOptionsResponse" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.ReferralPartners.GetFilterOptionsResponse" } } } }, "500": { "description": "Internal server error", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } } } } } } }, "/oauth/token": { "post": { "tags": [ "OAuth" ], "summary": "Get OAuth access token", "description": "Generates a short-lived JWT bearer token for accessing the Customer API on behalf of a specific client.\n\n**How It Works:**\n1. Authenticate with your referral partner API key (XApiKey header)\n2. Provide the externalTenantId of the client you want to access\n3. Receive a Bearer token valid for 30 minutes\n4. Use the token in the Customer API: `Authorization: Bearer {access_token}`\n\n**Requirements:**\n- The externalTenantId must match an active ReferralPartnerClientLink for your partner account\n- The client must be fully onboarded (SDCA signed)\n\n**Token Details:**\n- Type: Bearer (JWT)\n- Lifetime: 30 minutes\n- Scope: Customer API access for the specified client only\n\n**Usage Example:**\n```\nPOST /oauth/token\n{ \"externalTenantId\": \"your-client-id\" }\n\nResponse:\n{ \"accessToken\": \"eyJ...\", \"tokenType\": \"Bearer\", \"expiresIn\": 1800 }\n```", "requestBody": { "description": "Token generation request with externalTenantId", "content": { "application/json-patch+json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.AccessTokens.CreateAccessTokenRequest" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.AccessTokens.CreateAccessTokenRequest" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.AccessTokens.CreateAccessTokenRequest" } }, "application/*+json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.AccessTokens.CreateAccessTokenRequest" } } } }, "responses": { "200": { "description": "Token generated successfully", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.AccessTokens.AccessTokenResponse" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.AccessTokens.AccessTokenResponse" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.AccessTokens.AccessTokenResponse" } } } }, "400": { "description": "Invalid request (missing or invalid externalTenantId)", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } } } }, "404": { "description": "Client not found (no active client link found for externalTenantId)", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } } } }, "500": { "description": "Internal server error", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } } } } } } }, "/cases/preview": { "post": { "tags": [ "PreviewCases" ], "summary": "Preview case pricing", "description": "Preview the success fee pricing for a potential case without creating it.\n\n**What This Endpoint Returns:**\n- IsEligible - Whether the case can be submitted (partner available in this jurisdiction)\n- PricingPreview - Estimated success fee with base rate and any age-based surcharges\n- Jurisdiction - Geographic details for the matched jurisdiction\n\n**Use This To:**\n1. Show your clients the Debitura success fee before they onboard\n2. Check if a jurisdiction is supported before starting the onboarding flow\n3. Display age-adjusted pricing for aged debt portfolios\n\n**Required Fields:**\n- AmountToRecover - Total principal amount\n- CurrencyCode - ISO 4217 currency code (e.g., 'GBP', 'EUR', 'USD')\n- Debtor.Type - 'Company' or 'Private'\n- Debtor.CountryAlpha2 - ISO 3166-1 alpha-2 country code\n- Debtor.StateAlpha2 - Required for US cases only (e.g., 'CA', 'NY')\n\n**Age-Based Pricing (Optional)**\n\n**Single invoice β€” pass `dueDate`:** The simplest way to get age-adjusted pricing. Provide the invoice due date (ISO 8601, e.g. `2024-01-15`) and Debitura computes the age surcharge internally. Cannot be a future date. Mutually exclusive with age bucket fields.\n\n**Multi-invoice portfolio β€” pass age buckets:** For portfolios with invoices at different ages, pass the portion of the total that falls into each age bracket:\n- `AmountToRecoverOver12Months` and `AmountToRecoverOver24Months` must be provided together\n- `AmountToRecoverOver6Months` is optional but improves pricing tier accuracy at the 180-day threshold; can only be provided alongside the 12/24-month fields, must be >= `AmountToRecoverOver12Months`, and must be <= `AmountToRecover`\n\n`dueDate` and age bucket fields are mutually exclusive β€” use one or the other. When no age fields are provided, base pricing is returned without age surcharge.\n\n**Important Notes:**\n- This endpoint does NOT create a case β€” it only previews pricing\n- Pricing is based on the referral partner's agreed rate (jurisdiction pricing zone rate if applicable)\n- No creditor or client account is needed", "requestBody": { "content": { "application/json-patch+json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Cases.Requests.PreviewCaseRequestApiViewModel" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Cases.Requests.PreviewCaseRequestApiViewModel" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Cases.Requests.PreviewCaseRequestApiViewModel" } }, "application/*+json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Cases.Requests.PreviewCaseRequestApiViewModel" } } } }, "responses": { "200": { "description": "Preview completed", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Cases.ReferralPartnerPreviewCaseResponse" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Cases.ReferralPartnerPreviewCaseResponse" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Cases.ReferralPartnerPreviewCaseResponse" } } } }, "400": { "description": "Invalid request (validation errors)", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } } } }, "500": { "description": "Internal server error", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } } } } } } }, "/me": { "get": { "tags": [ "ReferralPartners" ], "summary": "Get authenticated partner information", "description": "Retrieves complete configuration and styling information for the authenticated referral partner.\n\nAuthentication\n- Requires a valid API key in the XApiKey header\n- The API key uniquely identifies the referral partner\n\nResponse Data\n- Partner identification (ID, system name, display name)\n- Branding configuration (logo URLs, colors, fonts)\n- Revenue sharing percentage\n- Partner status and settings\n\nUse Cases\n- Configure white-label branding for client onboarding pages\n- Display partner-specific styling in integrations\n- Verify partner configuration and settings\n- Retrieve commission/fee percentage for revenue calculations\n\nThe styling properties returned can be used to customize the appearance of onboarding pages\nand other partner-facing interfaces to match the referral partner's branding.", "responses": { "200": { "description": "Partner information retrieved successfully", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.ReferralPartners.ReferralPartnerResponse" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.ReferralPartners.ReferralPartnerResponse" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.ReferralPartners.ReferralPartnerResponse" } } } }, "404": { "description": "Referral partner not found (invalid configuration)", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } } } }, "500": { "description": "Internal server error", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } } } } } } }, "/reporting/transactions": { "get": { "tags": [ "Reporting" ], "summary": "Get transaction-level revenue data", "description": "Retrieves comprehensive transaction-level financial data for all clients linked to the authenticated referral partner.\n\n**IMPORTANT: All amounts are returned in USD regardless of the original collection currency.**\n\nRevenue Recognition Stages\nThe response includes a 4-stage revenue breakdown for each transaction, representing the complete lifecycle from collection to payment:\n\n1. **Unrecognized Revenue** - Collections that have occurred but revenue is not yet recognized (typically due to pending verifications or disputes)\n2. **Uninvoiced Recognized Revenue** - Revenue that has been recognized as earned but not yet invoiced to the partner\n3. **Invoiced Revenue** - Revenue that has been invoiced to the partner but not yet paid\n4. **Paid Revenue** - Revenue that has been paid to the partner\n\nExchange Rate Rules (Critical for Revenue Calculations)\n- **Stage 1 (Unrecognized)** - Amounts fluctuate with current exchange rates (recalculated in real-time)\n- **Stages 2-4 (Recognized/Invoiced/Paid)** - Amounts are LOCKED at the exchange rate from the moment revenue was recognized (Stage 1 β†’ Stage 2 transition)\n- This locking prevents exchange rate volatility from affecting recognized revenue, invoices, and payments\n- The locked exchange rate is used for all downstream stages (Stages 2, 3, and 4)\n\nMonthly Invoicing Workflow\nRevenue progresses through stages on a monthly cycle:\n- Collections occur throughout the month (Stage 1)\n- At month-end, unrecognized revenue is reviewed and recognized (Stage 1 β†’ Stage 2, exchange rate locked)\n- Recognized revenue is invoiced to the partner (Stage 2 β†’ Stage 3)\n- Partner pays the invoice (Stage 3 β†’ Stage 4)\n- Use this endpoint to track revenue status before and after monthly invoicing\n\nTransaction Data\nEach transaction includes:\n- Client identification (External Tenant ID, Client ID, Company Name)\n- Case/Invoice details (Case ID, Debitura Reference, Creditor Reference)\n- Debtor information (Name, Country)\n- Financial amounts (Gross Amount in original currency, all revenue stages in USD, Collection Date)\n- Revenue breakdown across all 4 stages (in USD)\n- Referral fee percentage applied to this transaction\n\nFiltering and Pagination\n- **DateFrom/DateTo** - Filter transactions by collection date range (ISO 8601 format)\n- **ExternalTenantId** - Filter to specific client(s)\n- **Page/PageSize** - Paginate results (default: page 1, size 10, max: 100)\n\nSorting\n- **Sort** - Sort field and direction (format: 'field:direction')\n- Supported fields: collectionDate, amount\n- Examples: 'collectionDate:desc', 'amount:asc'\n- Default: collectionDate:desc (most recent first)\n\nUse Cases\n- Generate partner commission reports (all amounts in USD)\n- Track revenue recognition status and exchange rate impact\n- Reconcile monthly invoices and payments\n- Analyze per-client performance\n- Export financial data for accounting systems\n- Monitor outstanding receivables\n- Understand exchange rate fluctuations on Stage 1 (unrecognized) revenue\n\nThe data returned represents real collection activity and actual revenue earned from cases created through the referral partnership.", "parameters": [ { "name": "FromDate", "in": "query", "description": "Filter transactions from this date (inclusive). ISO 8601 format.", "schema": { "type": "string", "format": "date-time" } }, { "name": "ToDate", "in": "query", "description": "Filter transactions to this date (inclusive). ISO 8601 format.", "schema": { "type": "string", "format": "date-time" } }, { "name": "ExternalTenantId", "in": "query", "description": "Filter by specific client's external tenant ID", "schema": { "type": "string" } }, { "name": "HasRecognizedRevenue", "in": "query", "description": "When true, only show transactions where revenue has been recognized (collection partner has paid Debitura).\nWhen false, only show unrecognized transactions.", "schema": { "type": "boolean" } }, { "name": "CommissionPaymentStatuses", "in": "query", "description": "Filter by commission payment status (Unpaid = 0, Paid = 1, Credited = 2).\nTracks whether Debitura has received the collection partner's commission.", "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Debitura.Domain.Model.InvoicePayments.Payouts.Enums.PayoutCommissionPaymentStatus" } } }, { "name": "PlatformInvoicingStatuses", "in": "query", "description": "Filter by platform invoicing status (NotInvoiced = 0, InvoiceIssued = 1, PaymentReceived = 2, InvoiceCredited = 3).\nTracks Debitura's invoicing lifecycle with the collection partner.", "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Debitura.Domain.Model.Core.InvoicePayments.PlatformInvoicingStatus" } } }, { "name": "ReferralInvoicingStatuses", "in": "query", "description": "Filter by referral invoicing status (Pending = 0, Invoiced = 1, Paid = 2)", "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Debitura.Domain.Model.ReferralPartners.Enums.ReferralInvoicingStatus" } } }, { "name": "RevenueStages", "in": "query", "description": "Filter by revenue-lifecycle stage (see Debitura.Web.ReferralPartnerApi.Models.Reporting.TransactionRevenueStage). Use this instead of\ncombining CommissionPaymentStatuses/PlatformInvoicingStatuses/ReferralInvoicingStatuses when you need\na row list for one specific \"Ready to Invoice\" tab bucket β€” it applies the same ConfirmedPipeline\nfold the summary already uses, so the row list matches the badge count exactly for partners in\nConfirmedPipeline mode. ANDed with the other filters above if both are supplied.\n \nOnly narrows the row-list (`data`) β€” the returned `summary` always reports all 7 bucket\ntotals regardless of this filter, since its purpose is to drive tab badge counts and would\notherwise collapse the other buckets toward zero.", "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Reporting.TransactionRevenueStage" } } }, { "name": "Search", "in": "query", "description": "Search text to filter by case reference or client company name (case-insensitive, partial match).\nMinimum 2 characters required for search to be applied.", "schema": { "type": "string" } }, { "name": "Page", "in": "query", "description": "Page number (1-indexed)", "schema": { "maximum": 2147483647, "minimum": 1, "type": "integer", "format": "int32" } }, { "name": "PageSize", "in": "query", "description": "Number of results per page (default: 10, max: 100)", "schema": { "maximum": 100, "minimum": 1, "type": "integer", "format": "int32" } }, { "name": "CountryIds", "in": "query", "description": "Filter by debtor country ID(s). Multiple values can be provided.\nOnly transactions where the debtor's country matches one of the specified IDs are returned.", "schema": { "type": "array", "items": { "type": "integer", "format": "int32" } } }, { "name": "CollectionPartnerIds", "in": "query", "description": "Filter by collection partner ID(s). Multiple values can be provided.\nOnly transactions for cases assigned to one of the specified collection partners are returned.", "schema": { "type": "array", "items": { "type": "string", "format": "uuid" } } }, { "name": "Sort", "in": "query", "description": "Sort field and direction. Format: \"field[:asc|desc]\"\nSupported fields: collectionDate, amount\nExamples: \"collectionDate:desc\", \"amount:asc\"\nDefault: collectionDate:desc", "schema": { "type": "string" } } ], "responses": { "200": { "description": "Transactions retrieved successfully", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Reporting.TransactionsResponse" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Reporting.TransactionsResponse" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Reporting.TransactionsResponse" } } } }, "400": { "description": "Invalid request parameters (e.g., invalid date format, page size too large)", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } } } }, "500": { "description": "Internal server error", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } } } } } } }, "/v1/Webhooks": { "get": { "tags": [ "Webhooks" ], "summary": "Get all webhooks for the authenticated referral partner", "description": "Returns all webhook subscriptions with their configuration (URL, events, status). Note: Secrets are never included in GET responses.", "responses": { "200": { "description": "List of webhook subscriptions", "content": { "text/plain": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Debitura.Domain.Model.Webhooks.Dtos.WebhookDto" } } }, "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Debitura.Domain.Model.Webhooks.Dtos.WebhookDto" } } }, "text/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Debitura.Domain.Model.Webhooks.Dtos.WebhookDto" } } } } }, "401": { "description": "API key is missing or invalid" } } }, "post": { "tags": [ "Webhooks" ], "summary": "Create a new webhook subscription", "description": "Creates webhook subscription for real-time event notifications.\n\n**Available Events:**\n- `client.onboarding.poa_signed` - Client signed Power of Attorney\n- `client.onboarding.contract_signed` - Client signed Service Delivery Agreement\n- `client.linked` - Client successfully linked to your account\n- `client.link_declined` - Client declined to link\n- `client.link_requested` - 409 link request created (awaiting end-user approval)\n- `client.link_expired` - 409 link request reached its TTL without approval/decline\n- `case.created` - Collection case created for linked client\n- `case.updated` - Collection case lifecycle changed (e.g., Active β†’ Closed)\n- `case.closed` - Collection case closed (terminal state)\n- `cases.replay_failed` - A stored case payload failed to create during 409 carry-through (retry via the Customer API)\n\n**Security:** Response includes Base64-encoded signing secret (shown only once). Store it to verify HMAC-SHA256 signatures on deliveries.\n\n**Requirements:** HTTPS URL required (HTTP, localhost, and private IPs rejected). Deliveries retry with exponential backoff (8 attempts). Webhook auto-disables after max failures.", "requestBody": { "content": { "application/json-patch+json": { "schema": { "$ref": "#/components/schemas/Debitura.Domain.Model.Webhooks.Dtos.CreateWebhookRequest" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Domain.Model.Webhooks.Dtos.CreateWebhookRequest" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Domain.Model.Webhooks.Dtos.CreateWebhookRequest" } }, "application/*+json": { "schema": { "$ref": "#/components/schemas/Debitura.Domain.Model.Webhooks.Dtos.CreateWebhookRequest" } } } }, "responses": { "200": { "description": "Webhook created successfully", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Debitura.Domain.Model.Webhooks.Dtos.WebhookDto" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Domain.Model.Webhooks.Dtos.WebhookDto" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Domain.Model.Webhooks.Dtos.WebhookDto" } } } }, "400": { "description": "Invalid request (validation errors)", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } } } }, "401": { "description": "API key is missing or invalid" } } } }, "/v1/Webhooks/{id}": { "get": { "tags": [ "Webhooks" ], "summary": "Get a specific webhook by ID", "description": "Returns webhook configuration including URL, events, active status, and DisabledReason if auto-disabled. Secret is never included (only shown during creation/regeneration).", "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Webhook details", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Debitura.Domain.Model.Webhooks.Dtos.WebhookDto" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Domain.Model.Webhooks.Dtos.WebhookDto" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Domain.Model.Webhooks.Dtos.WebhookDto" } } } }, "401": { "description": "API key is missing or invalid" }, "404": { "description": "Webhook not found or does not belong to this partner", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } } } } } }, "put": { "tags": [ "Webhooks" ], "summary": "Update an existing webhook subscription", "description": "Updates webhook URL, events, or active status. Set RegenerateSecret=true to rotate signing secret (returned in response). Use IsActive=true to re-enable auto-disabled webhooks after fixing delivery issues. Secret only included if RegenerateSecret=true.", "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json-patch+json": { "schema": { "$ref": "#/components/schemas/Debitura.Domain.Model.Webhooks.Dtos.UpdateWebhookRequest" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Domain.Model.Webhooks.Dtos.UpdateWebhookRequest" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Domain.Model.Webhooks.Dtos.UpdateWebhookRequest" } }, "application/*+json": { "schema": { "$ref": "#/components/schemas/Debitura.Domain.Model.Webhooks.Dtos.UpdateWebhookRequest" } } } }, "responses": { "200": { "description": "Webhook updated successfully", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Debitura.Domain.Model.Webhooks.Dtos.WebhookDto" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Domain.Model.Webhooks.Dtos.WebhookDto" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Domain.Model.Webhooks.Dtos.WebhookDto" } } } }, "400": { "description": "Invalid request (validation errors)", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } } } }, "401": { "description": "API key is missing or invalid" }, "404": { "description": "Webhook not found or does not belong to this partner", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } } } } } }, "delete": { "tags": [ "Webhooks" ], "summary": "Delete a webhook subscription", "description": "Permanently deletes webhook subscription. Cannot be undone. Consider setting IsActive=false to temporarily disable instead. Delivery history is lost after deletion.", "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "204": { "description": "Webhook deleted successfully" }, "401": { "description": "API key is missing or invalid" }, "404": { "description": "Webhook not found or does not belong to this partner", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } } } } } } }, "/v1/Webhooks/test": { "post": { "tags": [ "Webhooks" ], "summary": "Trigger a test webhook event (test environment only)", "description": "Triggers a realistic webhook delivery through the real pipeline (queue β†’ dispatcher β†’ HMAC-signed HTTP delivery).\n\n⚠️ **TEST ENVIRONMENT ONLY** - Returns 403 in production. Use testreferral-api.debitura.com for testing.\n\n**How it works:**\n- Looks up real entity data (case or client link) to construct a realistic payload\n- Publishes through the same pipeline as production events (signature verification, retries, etc.)\n- Returns immediately after enqueueing β€” delivery is async via Azure Queue\n\n**Case events** (`case.created`, `case.updated`, `case.closed`):\n- Requires `caseId` β€” must be a real case belonging to a linked client\n- For `case.updated`: optionally provide `oldLifecycle` and `newLifecycle` (defaults to current β†’ Closed)\n- For `case.closed`: optionally provide `closeCode` and `closeComment` (defaults to Paid)\n\n**Client events** (`client.linked`, `client.link_declined`, `client.link_requested`, `client.link_expired`, `client.onboarding.poa_signed`, `client.onboarding.contract_signed`):\n- Requires `externalTenantId` β€” must be an active client link belonging to your account", "requestBody": { "content": { "application/json-patch+json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Webhooks.TriggerTestWebhookRequest" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Webhooks.TriggerTestWebhookRequest" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Webhooks.TriggerTestWebhookRequest" } }, "application/*+json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Webhooks.TriggerTestWebhookRequest" } } } }, "responses": { "200": { "description": "Test event enqueued successfully", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Webhooks.TriggerTestWebhookResponse" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Webhooks.TriggerTestWebhookResponse" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Webhooks.TriggerTestWebhookResponse" } } } }, "400": { "description": "Invalid request (missing required fields or invalid event type)", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } } } }, "401": { "description": "API key is missing or invalid" }, "403": { "description": "Endpoint not available in production environment", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } } } }, "404": { "description": "Case or client link not found", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } }, "text/json": { "schema": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto" } } } } } } } }, "components": { "schemas": { "Debitura.Domain.Model.Base.PageData": { "type": "object", "properties": { "totalResults": { "type": "integer", "description": "Total number of records for the query (filtered or all as applicable).", "format": "int32" }, "pageSize": { "type": "integer", "description": "How many records are returned per page.", "format": "int32" }, "currentPage": { "type": "integer", "description": "Which page number is being shown, calculated from the number of skipped items.", "format": "int32" }, "responseCount": { "type": "integer", "description": "How many records are present in the current page.", "format": "int32" }, "totalPages": { "type": "integer", "description": "Total number of pages available given Debitura.Domain.Model.Base.PageData.TotalResults and Debitura.Domain.Model.Base.PageData.PageSize.", "format": "int32", "readOnly": true } }, "additionalProperties": false, "description": "Paging metadata describing a paged result set." }, "Debitura.Domain.Model.CollectionPartnerLogics.CollectionPartners.SurveyCadenceMode": { "enum": [ 0, 1 ], "type": "integer", "description": "Controls which surveys are generated for cases assigned to this collection partner.", "format": "int32" }, "Debitura.Domain.Model.Core.InvoicePayments.PlatformInvoicingStatus": { "enum": [ 0, 1, 2, 3 ], "type": "integer", "description": "Tracks the invoicing lifecycle for platform fees charged to collection partners.", "format": "int32" }, "Debitura.Domain.Model.Creditors.CreditorKycVerifications.CreditorKycVerificationStatus": { "enum": [ "Processing", "Completed" ], "type": "string", "description": "Partner/staff-settable review status for a Debitura.Domain.Model.Creditors.CreditorKycVerifications.CreditorKycVerification record.\nDistinct from the ReferralPartnerApi `KycStatus` enum, which describes\nwhether a client has submitted KYC data at all β€” this enum describes whether data that has\nalready been submitted has since been reviewed by the collection partner or Debitura staff.\n \nThe unset/not-yet-reviewed state is represented by a null\nDebitura.Domain.Model.Creditors.CreditorKycVerifications.CreditorKycVerification.VerificationStatus column, not a third enum value here.\nA fresh KYC resubmission (a new row via `CreditorKycVerificationService.CreateAsync`)\nnaturally leaves this column unset, resetting review status by design.\n \nWire format is locked to named string values (\"Processing\", \"Completed\") via Newtonsoft.Json\nStringEnumConverter β€” every host this enum is exposed on (CollectionPartnerApi, CoreApi,\nReferralPartnerApi) uses Newtonsoft (AddNewtonsoftJson in Program.cs), so a System.Text.Json\nJsonStringEnumConverter attribute alone would be silently ignored; both are declared so\nSTJ-based consumers (and our own tests) can also deserialize the string form." }, "Debitura.Domain.Model.InvoicePayments.Payouts.Enums.PayoutCommissionPaymentStatus": { "enum": [ 0, 1, 2 ], "type": "integer", "format": "int32" }, "Debitura.Domain.Model.ReferralPartners.Enums.InvoicingTriggerMode": { "enum": [ "PayWhenPaid", "ConfirmedPipeline" ], "type": "string", "description": "Controls what condition triggers a referral partner's payout to become \"ready to invoice\"\nDebitura for their referral fee. Per-partner override; see Debitura.Domain.Model.ReferralPartners.ReferralPartner.InvoicingTriggerMode.\n \nThis enum is also returned directly on the ReferralPartnerApi `GET /me` response\n(`ReferralPartnerResponse.InvoicingTriggerMode`). Wire format is locked to named\nPascalCase string values (\"PayWhenPaid\", \"ConfirmedPipeline\") via Newtonsoft.Json\nStringEnumConverter β€” that host uses Newtonsoft (AddNewtonsoftJson in Program.cs), so a\nSystem.Text.Json JsonStringEnumConverter attribute alone would be silently ignored; both\nare declared so STJ-based consumers (and our own tests) can also deserialize the string form." }, "Debitura.Domain.Model.ReferralPartners.Enums.ReferralInvoicingStatus": { "enum": [ 0, 1, 2, 3 ], "type": "integer", "description": "Tracks the invoicing and payment status for referral fees owed to referral partners.\nThis is separate from collection partner invoicing (PlatformInvoicingStatus).", "format": "int32" }, "Debitura.Domain.Model.Webhooks.Dtos.CreateWebhookRequest": { "required": [ "events", "url" ], "type": "object", "properties": { "url": { "maxLength": 1024, "minLength": 0, "type": "string", "description": "The HTTPS URL where webhook events will be delivered.\nMust be a valid HTTPS URL.", "format": "uri" }, "events": { "minItems": 1, "type": "array", "items": { "type": "string" }, "description": "Array of event types to subscribe to." }, "isTestMode": { "type": "boolean", "description": "When true, the subscription is created with `DataClassification.Test`,\nmeaning it will only receive events for test-classified data.\nDefaults to false (Production classification)." } }, "additionalProperties": false, "description": "Request to create a new webhook subscription." }, "Debitura.Domain.Model.Webhooks.Dtos.UpdateWebhookRequest": { "type": "object", "properties": { "url": { "maxLength": 1024, "minLength": 0, "type": "string", "description": "The new HTTPS URL where webhook events will be delivered.\nOptional β€” only provide if changing the URL.", "format": "uri", "nullable": true }, "events": { "type": "array", "items": { "type": "string" }, "description": "Updated list of event types to subscribe to.\nOptional β€” only provide if changing the events.\nNote: Not supported by the ExternalCustomerAPI β€” that endpoint returns 400 if this field is set.", "nullable": true }, "isActive": { "type": "boolean", "description": "Set to true to enable the webhook, false to disable it.\nOptional β€” only provide if changing the active status.", "nullable": true }, "regenerateSecret": { "type": "boolean", "description": "Set to true to regenerate the webhook secret.\nA new secret will be returned in the response." }, "isTestMode": { "type": "boolean", "description": "When set, updates the classification of the subscription.\nTrue maps to `DataClassification.Test`; false maps to `DataClassification.Production`.\nOmit to leave the current classification unchanged.", "nullable": true } }, "additionalProperties": false, "description": "Request to update an existing webhook subscription." }, "Debitura.Domain.Model.Webhooks.Dtos.WebhookDto": { "type": "object", "properties": { "id": { "type": "string", "description": "Unique identifier for the webhook subscription.", "format": "uuid" }, "url": { "type": "string", "description": "The HTTPS URL where webhook events will be delivered.", "nullable": true }, "events": { "type": "array", "items": { "type": "string" }, "description": "Array of event types this subscription is interested in.", "nullable": true }, "isActive": { "type": "boolean", "description": "Whether this webhook subscription is active." }, "createdUtc": { "type": "string", "description": "Timestamp when the webhook subscription was created (UTC).", "format": "date-time" }, "updatedUtc": { "type": "string", "description": "Timestamp when the webhook subscription was last updated (UTC).", "format": "date-time" }, "disabledReason": { "type": "string", "description": "Reason why the webhook was automatically disabled (if IsActive is false).", "nullable": true }, "secret": { "type": "string", "description": "Secret key for HMAC-SHA256 signature verification.\nOnly returned on creation or secret regeneration β€” never exposed again for security.", "nullable": true }, "isTestMode": { "type": "boolean", "description": "True when the subscription has `DataClassification.Test` classification;\nfalse for all other classifications (Production, Demo).\nComputed as `Classification != DataClassification.Production`." } }, "additionalProperties": false, "description": "Represents a webhook subscription configuration." }, "Debitura.Domain.Services.CaseValidation.CaseValidationItemDto": { "type": "object", "properties": { "resolutionArea": { "type": "string", "description": "Enum name of the resolution area (e.g. \"ProvideDocuments\", \"CorrectDebtorAddress\").\nAlways a Debitura.Domain.Services.CaseValidation.CaseValidationHelpers.CreditorFacingAreas member β€” never\n\"InternalReview\" or \"AdminReview\".", "nullable": true }, "description": { "type": "string", "description": "Creditor-safe description of what needs to be fixed.\nSource: Debitura.Domain.Model.Receiveables.CaseValidation.CaseValidationRuleResult.CuratedDescription β€” scoring stripped.", "nullable": true } }, "additionalProperties": false, "description": "A single creditor-facing action item within Debitura.Domain.Services.CaseValidation.CaseValidationStatusDto." }, "Debitura.Domain.Services.CaseValidation.CaseValidationLeanDto": { "type": "object", "properties": { "needsInfo": { "type": "boolean", "description": "True when the latest validation run requires creditor action.\nReads Debitura.Domain.Model.Receiveables.Invoices.Invoice.ValidationNeedsInfo directly." } }, "additionalProperties": false, "description": "Lean validation summary exposed on list endpoints of the External Customer API\nand Collection Partner API. Contains only Debitura.Domain.Services.CaseValidation.CaseValidationLeanDto.NeedsInfo β€” no join required.\nDerived purely from free Debitura.Domain.Model.Receiveables.Invoices.Invoice columns.\n\nWhen Debitura.Domain.Services.CaseValidation.CaseValidationLeanDto.NeedsInfo is `true`, callers should invoke\n`GET /cases/{id}/validation` to retrieve the full item-level breakdown\n(Debitura.Domain.Services.CaseValidation.CaseValidationStatusDto)." }, "Debitura.Domain.Services.CaseValidation.CaseValidationStatusDto": { "type": "object", "properties": { "needsInfo": { "type": "boolean", "description": "True when the latest validation run requires creditor action.\nReads Debitura.Domain.Model.Receiveables.Invoices.Invoice.ValidationNeedsInfo directly β€” do not re-derive from items." }, "creditorRespondedAt": { "type": "string", "description": "When the creditor (or managing partner) last explicitly responded to a needs-info request.\nNull when the creditor has not yet responded, or after the case passes validation.", "format": "date-time", "nullable": true }, "items": { "type": "array", "items": { "$ref": "#/components/schemas/Debitura.Domain.Services.CaseValidation.CaseValidationItemDto" }, "description": "Creditor-facing action items from the latest validation run.\nEmpty when Debitura.Domain.Services.CaseValidation.CaseValidationStatusDto.NeedsInfo is false or no run exists.", "nullable": true } }, "additionalProperties": false, "description": "Sanitized, creditor-safe projection of a case's current validation status.\nSafe to expose on any external surface β€” never contains Rationale, InternalValidationComment,\nInternalReview/AdminReview areas, Confidence, or EvaluationMethod." }, "Debitura.Web.ExternalApi.Contracts.V1.Cases.AssignedUserDto": { "type": "object", "properties": { "email": { "type": "string", "description": "The assigned user's email address.", "nullable": true }, "name": { "type": "string", "description": "The assigned user's full name.", "nullable": true } }, "additionalProperties": false, "description": "Represents the creditor team member assigned to a case." }, "Debitura.Web.ExternalApi.Contracts.V1.Cases.BankAccountDto": { "type": "object", "properties": { "id": { "type": "integer", "description": "Bank account identifier", "format": "int32" }, "label": { "type": "string", "description": "User-friendly label (e.g., \"Main EUR Account\")", "nullable": true }, "scheme": { "type": "string", "description": "Account scheme: IBAN, SWIFT, or LOCAL", "nullable": true }, "currencyCode": { "type": "string", "description": "Currency code (ISO 4217)", "nullable": true }, "bankCountryCode": { "type": "string", "description": "Bank country code (ISO Alpha-2)", "nullable": true }, "accountHolderName": { "type": "string", "description": "Account holder name (beneficiary)", "nullable": true }, "iban": { "type": "string", "description": "IBAN (for IBAN scheme accounts)", "nullable": true }, "bic": { "type": "string", "description": "BIC/SWIFT code (for IBAN and SWIFT scheme accounts)", "nullable": true }, "accountNumber": { "type": "string", "description": "Account number (for SWIFT and LOCAL scheme accounts)", "nullable": true }, "localIdentifier": { "type": "string", "description": "Local identifier (for LOCAL scheme accounts, e.g., sort code + account number)", "nullable": true }, "localIdentifierType": { "type": "string", "description": "Type of local identifier (e.g., \"Sort Code\", \"Routing Number\")", "nullable": true }, "bankName": { "type": "string", "description": "Bank name (optional)", "nullable": true }, "bankAddress": { "type": "string", "description": "Bank address (optional)", "nullable": true }, "bankCity": { "type": "string", "description": "Bank city (optional)", "nullable": true }, "bankZipCode": { "type": "string", "description": "Bank zip/postal code (optional)", "nullable": true }, "bankState": { "type": "string", "description": "Bank state/region (optional)", "nullable": true } }, "additionalProperties": false, "description": "Bank account information for partner API.\nFull details provided as partners need this to:\n1. Provide payment instructions to debtors (when debtor pays client directly)\n2. Execute payouts to clients (when partner receives payment and pays out remainder)" }, "Debitura.Web.ExternalApi.Contracts.V1.Cases.BusinessErrorApiDTO": { "type": "object", "properties": { "type": { "type": "string", "description": "The type of business error (e.g., \"MissingDebtCollectionContract\", \"MissingPowerOfAttorney\", \"NoPartnerAvailable\").", "nullable": true }, "message": { "type": "string", "description": "A human-readable description of the error.", "nullable": true }, "solutionUrl": { "type": "string", "description": "A URL where the user can resolve this specific error (e.g., sign a contract).\n \n\nPartners who want a single URL that walks the user through every pending\nsigning in one chain β€” instead of forwarding one URL per\n`BusinessErrorApiDTO` β€” should use\nDebitura.Web.ExternalApi.Contracts.V1.Cases.BusinessErrorResponseApiDTO.SigningHandoff's `CombinedSigningUrl`.\nThe two are complementary: `SolutionUrl` is granular per-error;\n`CombinedSigningUrl` is the chain-walking alternative for signing-related errors.", "nullable": true } }, "additionalProperties": false, "description": "Represents a business error in the API response." }, "Debitura.Web.ExternalApi.Contracts.V1.Cases.BusinessErrorResponseApiDTO": { "type": "object", "properties": { "businessErrors": { "type": "array", "items": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Cases.BusinessErrorApiDTO" }, "description": "List of business errors that must be resolved before the case can be created.", "nullable": true }, "signingHandoff": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Cases.SigningHandoffDto" } }, "additionalProperties": false, "description": "Response returned when business rule violations prevent case creation." }, "Debitura.Web.ExternalApi.Contracts.V1.Cases.CollectionPartnerDto": { "type": "object", "properties": { "name": { "type": "string", "nullable": true }, "officeEmail": { "type": "string", "nullable": true }, "officePhone": { "type": "string", "nullable": true }, "publicSite": { "type": "string", "nullable": true }, "surveyCadenceMode": { "$ref": "#/components/schemas/Debitura.Domain.Model.CollectionPartnerLogics.CollectionPartners.SurveyCadenceMode" } }, "additionalProperties": false, "description": "V1 Collection Partner DTO for external partner APIs" }, "Debitura.Web.ExternalApi.Contracts.V1.Cases.CreditorDivisionDto": { "type": "object", "properties": { "id": { "type": "string", "description": "Unique identifier for the division", "format": "uuid" }, "name": { "type": "string", "description": "Name of the division", "nullable": true } }, "additionalProperties": false, "description": "Creditor division information for external partner APIs.\nRepresents a specific division or department within a creditor organization." }, "Debitura.Web.ExternalApi.Contracts.V1.Cases.CreditorDto": { "type": "object", "properties": { "id": { "type": "string", "description": "Unique identifier for the creditor", "format": "uuid" }, "companyName": { "type": "string", "description": "Company name of the creditor", "nullable": true }, "companyRegistrationNumber": { "type": "string", "description": "Company registration number (CVR, VAT number, etc.)", "nullable": true }, "officeEmail": { "type": "string", "description": "Primary office email address", "nullable": true }, "officePhone": { "type": "string", "description": "Primary office phone number", "nullable": true }, "address": { "type": "string", "description": "Street address", "nullable": true }, "city": { "type": "string", "description": "City", "nullable": true }, "zipCode": { "type": "string", "description": "Postal/ZIP code", "nullable": true }, "state": { "type": "string", "description": "State or region (if applicable)", "nullable": true }, "country": { "type": "string", "description": "Country name", "nullable": true }, "division": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Cases.CreditorDivisionDto" } }, "additionalProperties": false, "description": "Creditor (client) information for external partner APIs.\nRepresents the party that the debtor owes money to." }, "Debitura.Web.ExternalApi.Contracts.V1.Cases.DebtorDto": { "required": [ "name", "type" ], "type": "object", "properties": { "type": { "minLength": 1, "type": "string", "description": "Debtor type. Valid values: \"Company\" or \"Person\"", "example": "Company" }, "name": { "minLength": 1, "type": "string", "description": "Debtor name (company name or person's full name)", "example": "Pacific Trading LLC" }, "contactPerson": { "type": "string", "description": "Contact person at the company (required for companies, not used for persons)", "nullable": true, "example": "John Smith" }, "companyRegistrationNumber": { "type": "string", "description": "Company registration number (VAT number, CVR, org number, etc.)", "nullable": true, "example": "47-1234567" }, "address": { "type": "string", "description": "Street address", "nullable": true, "example": "123 Market Street, Suite 400" }, "zipCode": { "type": "string", "description": "Postal/ZIP code", "nullable": true, "example": "94105" }, "city": { "type": "string", "description": "City name", "nullable": true, "example": "San Francisco" }, "state": { "type": "string", "description": "State/region/province name", "nullable": true, "example": "California" }, "stateAlpha2": { "type": "string", "description": "US state: two-letter code (e.g., \"CA\"), ISO 3166-2 format (e.g., \"US-CA\"), or full name (e.g., \"California\")", "nullable": true, "example": "CA" }, "countryAlpha2": { "type": "string", "description": "Country code (ISO 3166-1 alpha-2 format)", "nullable": true, "example": "US" }, "country": { "type": "string", "description": "Country name", "nullable": true, "example": "United States" }, "email": { "type": "string", "description": "Email address for debtor contact", "nullable": true, "example": "accounts@pacifictrading.com" }, "phone": { "type": "string", "description": "Phone number (include country code)", "nullable": true, "example": "+1 415 555 0123" } }, "additionalProperties": false, "description": "V1 Debtor DTO for external partner APIs.\nThe debtor is the party that owes the debt." }, "Debitura.Web.ExternalApi.Contracts.V1.Cases.InvoiceAllocationOutstandingDto": { "type": "object", "properties": { "principal": { "type": "number", "format": "double" }, "interest": { "type": "number", "format": "double" }, "reminderFees": { "type": "number", "format": "double" }, "collectionFees": { "type": "number", "format": "double" } }, "additionalProperties": false, "description": "Additive external-API read model. Per-bucket outstanding on the debt ledger, produced by\nthe payment allocation engine (bucket total minus Ξ£ active stored allocations β€” never re-derived\nfrom a model). Mirrors the internal\n`Debitura.Domain.Model.Receiveables.InvoiceEconomics.EconomicalAllocationOutstanding` shape." }, "Debitura.Web.ExternalApi.Contracts.V1.Cases.InvoiceDto": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid" }, "dateCreated": { "type": "string", "format": "date-time" }, "dateUpdated": { "type": "string", "format": "date-time", "nullable": true }, "reference": { "type": "string", "nullable": true }, "creditorReference": { "type": "string", "nullable": true }, "creditorComments": { "type": "string", "nullable": true }, "claimDescription": { "type": "string", "nullable": true }, "grossAmount": { "type": "number", "format": "double" }, "remainder": { "type": "number", "format": "double" }, "interestFees": { "type": "number", "format": "double" }, "reminderFees": { "type": "number", "format": "double" }, "collectionFees": { "type": "number", "format": "double" }, "totalAddedFees": { "type": "number", "format": "double" }, "currency": { "type": "string", "nullable": true }, "isTestCase": { "type": "boolean" }, "lifecycle": { "type": "string", "nullable": true }, "dueDate": { "type": "string", "format": "date-time" }, "date": { "type": "string", "format": "date-time" }, "dateFinished": { "type": "string", "format": "date-time", "nullable": true }, "dateCollectionStarted": { "type": "string", "format": "date-time", "nullable": true }, "closeCode": { "type": "string", "nullable": true }, "currentEngagementPhase": { "type": "string", "description": "The current phase of the case's engagement: \"Pre-legal\", \"Legal\", or \"Enforcement\".\nA different axis from Debitura.Web.ExternalApi.Contracts.V1.Cases.InvoiceDto.Lifecycle/Debitura.Web.ExternalApi.Contracts.V1.Cases.InvoiceDto.CloseCode β€” an Active case can be\nin any of the three phases.\n \nNull means \"no active engagement\" (e.g. lead / quoting / pre-contract-signing / unassigned, or\na data-consistency gap) β€” this is a distinct third state, NOT a synonym for Pre-legal. Most\ncases legitimately read Pre-legal; phase only leaves Pre-legal on legal/enforcement quote flows.\n \nNot guaranteed to be monotonic: an admin correction can move phase backwards (e.g. Legal back\nto Pre-legal).\n \nPersists after case closure β€” reflects the case's last-known engagement phase, not the current\nLifecycle. Note: this is a different field from a lead quote's own offered phase (the phase a\npartner's quote proposes to work the case at, if this case ever went through a quote flow) β€”\nthis field is the case-level phase of its actual engagement, not a quote's terms.", "nullable": true }, "claimType": { "type": "string", "description": "The type of claim for this case (e.g. \"Unpaid Invoice\", \"Loan Repayment\", \"Breach of Contract\").\nNull if not set.", "nullable": true }, "creditorDivisionId": { "type": "string", "format": "uuid", "nullable": true }, "debtor": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Cases.DebtorDto" }, "collectionPartner": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Cases.CollectionPartnerDto" }, "creditor": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Cases.CreditorDto" }, "bankAccount": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Cases.BankAccountDto" }, "blendedAgeUpliftPoints": { "type": "number", "description": "MULTI-INVOICE AGE BUCKET PRICING\nCalculated blended age uplift percentage points (0-20) for multi-invoice cases.\nShows the additional fee percentage added due to invoice age.\nFormula: ((A12-A24)Γ—10 + A24Γ—20) / Total Principal\nNull for single-invoice cases (age uplift is calculated from due date instead).", "format": "double", "nullable": true }, "preLegalSuccessFee": { "type": "number", "description": "PRE-LEGAL SUCCESS FEE\nThe total pre-legal success fee percentage for this case.\nIncludes base fee + age-based uplift (blended or single-invoice).\nNull if pricing has not been calculated yet or if case is not in pre-legal phase.\nExample: 20.5 represents 20.5% success fee.", "format": "double", "nullable": true }, "solutionUrl": { "type": "string", "description": "When the case is created with allowPendingContracts=true and required contracts are unsigned,\nthis URL points to the signing page. Null when contracts are already signed or not applicable.", "nullable": true, "deprecated": true }, "signingHandoff": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Cases.SigningHandoffDto" }, "exclusivePeriodEndDate": { "type": "string", "description": "The date the exclusive collection period ends (or ended).\nNull if no collection period has been created for this case (e.g. custom-terms cases).\nUse GET /cases/{id}/exclusive-period for the full chain including extensions.", "format": "date-time", "nullable": true }, "disputeStatus": { "type": "string", "description": "Whether the claim is disputed by the debtor.\nReturns the description of Debitura.Domain.Model.Receiveables.Invoices.Enums.ClaimDisputeStatus:\n\"Yes, the claim is disputed\", \"No, the claim is not disputed\", or \"Don't Know\".\nNull when the dispute status has not been set on the case.", "nullable": true }, "validation": { "$ref": "#/components/schemas/Debitura.Domain.Services.CaseValidation.CaseValidationLeanDto" }, "assignedUser": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Cases.AssignedUserDto" }, "allocationOutstanding": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Cases.InvoiceAllocationOutstandingDto" } }, "additionalProperties": false, "description": "V1 Invoice DTO for external partner APIs" }, "Debitura.Web.ExternalApi.Contracts.V1.Cases.JurisdictionDto": { "type": "object", "properties": { "id": { "type": "integer", "description": "Internal jurisdiction identifier.", "format": "int32" }, "name": { "type": "string", "description": "Display name of the jurisdiction (e.g., \"Denmark\", \"United States - California\").", "nullable": true }, "countryAlpha2": { "type": "string", "description": "ISO 3166-1 alpha-2 country code.", "nullable": true }, "stateAlpha2": { "type": "string", "description": "ISO 3166-2 state/region code (only for countries with state-level routing like the US).", "nullable": true } }, "additionalProperties": false, "description": "Geographic jurisdiction information for the case." }, "Debitura.Web.ExternalApi.Contracts.V1.Cases.PricingPreviewDto": { "type": "object", "properties": { "baseSuccessFeePercentage": { "type": "number", "description": "Base success fee percentage before age surcharges.\nThis is the standard rate for cases under 12 months overdue.", "format": "double" }, "ageSurchargePercentage": { "type": "number", "description": "Additional percentage points added for aged invoices.\nCalculated based on invoice age:\n- 12-24 months overdue: +8 percentage points\n- 24+ months overdue: +15 percentage points\n- Multi-invoice with mixed ages: blended rate (0-15 percentage points)", "format": "double" }, "totalSuccessFeePercentage": { "type": "number", "description": "Total success fee percentage (base + age surcharge).\nThis is the percentage of the recovered amount that will be charged as a success fee.", "format": "double" }, "currencyCode": { "type": "string", "description": "ISO 4217 currency code for the case.", "nullable": true }, "pricingSource": { "type": "string", "description": "Which pricing rule determined the fee.\nPossible values: \"Standard agreement\", \"Creditor custom pricing\",\n\"Managing partner custom pricing\", \"Jurisdiction custom pricing\",\n\"Partner custom pricing\", \"Accepted quote\".", "nullable": true }, "pricingSourceDescription": { "type": "string", "description": "Human-readable explanation of why this pricing was applied.\nExample: \"9.5% success fee β€” BD Legal custom collection rates (EU zone, $1,000–$7,999 tier)\"", "nullable": true } }, "additionalProperties": false, "description": "Estimated pricing for the case, including age-based surcharges." }, "Debitura.Web.ExternalApi.Contracts.V1.Cases.Requests.CreateCollectionCaseRequestApiViewModel": { "required": [ "currencyCode" ], "type": "object", "properties": { "currencyCode": { "type": "string", "nullable": true }, "date": { "type": "string", "format": "date-time" }, "dueDate": { "type": "string", "format": "date-time", "nullable": true }, "comments": { "maxLength": 4000, "type": "string", "description": "Optional comments about the case, e.g. payment history or communication context.", "nullable": true }, "claimDescription": { "maxLength": 4000, "type": "string", "description": "Client provided description of the claim", "nullable": true }, "creditorReference": { "maxLength": 50, "type": "string", "nullable": true }, "debtor": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Cases.DebtorDto" }, "creditorDivisionId": { "type": "string", "format": "uuid", "nullable": true }, "amountToRecover": { "type": "number", "description": "The TOTAL amount to recover for this case.\nThis represents the full principal amount across all invoices (if multiple invoices are bundled).\n \nFor multi-invoice cases with different ages, you can optionally provide age breakdown fields\n(AmountToRecoverOver12Months and AmountToRecoverOver24Months) to enable blended age-based pricing.\n \nIf age breakdown fields are omitted, age uplift will be calculated from the invoice due date (single-invoice pricing).", "format": "double" }, "amountToRecoverOver6Months": { "type": "number", "description": "OPTIONAL - MULTI-INVOICE AGE BUCKET PRICING (PRICING ZONE 180-DAY THRESHOLD)\n \nThe portion of AmountToRecover that is more than 6 months (180 days) overdue.\nThis includes amounts that are 12+ and 24+ months overdue.\n \nThis field is optional and can only be provided alongside AmountToRecoverOver12Months\nand AmountToRecoverOver24Months. It enables precise pricing tier selection based on\nthe 180-day threshold. When omitted, the system falls back to deriving the threshold\nfrom AmountToRecoverOver12Months.\n \nValidation rules:\n- Must be ≀ AmountToRecover\n- Must be β‰₯ AmountToRecoverOver12Months", "format": "double", "nullable": true }, "amountToRecoverOver12Months": { "type": "number", "description": "OPTIONAL - MULTI-INVOICE AGE BUCKET PRICING\n \nThe portion of AmountToRecover that is more than 12 months overdue.\nThis includes amounts that are 24+ months overdue.\n \nIf provided, AmountToRecoverOver24Months must also be provided.\nBoth fields must be provided together or both omitted.\n \nUsed to calculate blended age uplift for multi-invoice cases:\n- Amount under 12 months = AmountToRecover - AmountToRecoverOver12Months\n- Amount 12-24 months = AmountToRecoverOver12Months - AmountToRecoverOver24Months\n- Amount over 24 months = AmountToRecoverOver24Months\n \nBlended uplift formula: ((A12-A24)Γ—10 + A24Γ—20) / AmountToRecover\nwhere A12 = AmountToRecoverOver12Months, A24 = AmountToRecoverOver24Months\n \nValidation rules:\n- Must be ≀ AmountToRecover\n- Must be β‰₯ AmountToRecoverOver24Months", "format": "double", "nullable": true }, "amountToRecoverOver24Months": { "type": "number", "description": "OPTIONAL - MULTI-INVOICE AGE BUCKET PRICING\n \nThe portion of AmountToRecover that is more than 24 months overdue.\n \nIf provided, AmountToRecoverOver12Months must also be provided.\nBoth fields must be provided together or both omitted.\n \nUsed to calculate blended age uplift for multi-invoice cases.\nSee AmountToRecoverOver12Months for full details on the calculation.\n \nValidation rules:\n- Must be ≀ AmountToRecoverOver12Months\n- Must be ≀ AmountToRecover", "format": "double", "nullable": true }, "skipDebituraVerification": { "type": "boolean", "description": "This skips the 'Pending verification' for Debitura and puts case straight to partner" }, "skipCreationEmails": { "type": "boolean", "description": "Deprecated β€” this field is accepted for backwards compatibility but is ignored server-side.\nCreation emails are always suppressed; the hourly CasesStarted digest is the single\nnotification channel for all entry points.", "deprecated": true }, "allowPendingContracts": { "type": "boolean", "description": "When true, cases with unsigned contracts (SDCA/POA) are accepted in 'PendingContractSigning'\nstatus instead of being rejected with 422. The case transitions automatically once contracts are signed.\nDefault: false (unsigned contracts return 422)." }, "isTest": { "type": "boolean", "description": "When true, creates a test case that IS persisted to the database but marked as test data.\nTest cases are excluded from production metrics and can be easily filtered or deleted.\nUse this for integration testing and development." }, "tag": { "maxLength": 100, "type": "string", "description": "Optional tag for scoped test data grouping (e.g. \"suite-run-{uuid}\").\nUse this to group test cases created by a single CI pipeline run so they can be\nbulk-deleted via DELETE /test/cases?tag={tag} without affecting parallel runs.\nOnly meaningful when IsTest is true. Max 100 characters.", "nullable": true }, "collectionPartnerId": { "type": "string", "description": "Optional: Specify a collection partner ID to handle this case.\nWhen provided, this partner will be used regardless of lead agent matching rules.\nThe partner must be active and have coverage for the debtor's jurisdiction.", "format": "uuid", "nullable": true }, "assignedUserEmail": { "maxLength": 320, "type": "string", "description": "Optional: Email address of the creditor team member to assign as the case owner.\nWhen provided, email notifications for this case will be sent only to this user\ninstead of all team members.\nMust correspond to an active member of your team.", "format": "email", "nullable": true, "example": "john.doe@example.com" }, "returnUrl": { "maxLength": 2048, "type": "string", "description": "Optional: URL the creditor user should land on after completing any\npending signing chain (SDCA upgrade / PoA / JPA / KYC) on the\nDebitura Creditors app. Embedded, URL-encoded, into\n`BusinessErrorResponseApiDTO.SigningHandoff.CombinedSigningUrl`\n(on 422 with pending signings) and\n`InvoiceDto.SigningHandoff.CombinedSigningUrl` (on 200 when\n`AllowPendingContracts=true` with signings remaining).\n \nMust be an absolute http(s) URL. Values that fail validation\n(relative URLs, non-http schemes, header-injection characters) are\nsilently dropped β€” the combined URL is still emitted but without\nthe returnUrl query parameter, and the Creditors app falls back to\nits own safe in-app default landing.\n \nAdditive. Existing integrations\nthat omit this field see the same behaviour as before.", "nullable": true } }, "additionalProperties": false }, "Debitura.Web.ExternalApi.Contracts.V1.Cases.Requests.PreviewCaseRequestApiViewModel": { "required": [ "amountToRecover", "currencyCode", "debtor" ], "type": "object", "properties": { "amountToRecover": { "type": "number", "description": "The TOTAL amount to recover for this case.\nThis represents the full principal amount across all invoices (if multiple invoices are bundled).\n \nFor multi-invoice cases with different ages, you can optionally provide age breakdown fields\n(AmountToRecoverOver12Months and AmountToRecoverOver24Months) to enable blended age-based pricing.\n \nIf age breakdown fields are omitted, the preview will show base pricing without age surcharge calculation.", "format": "double" }, "currencyCode": { "maxLength": 3, "minLength": 3, "type": "string", "description": "ISO 4217 currency code for the amount (e.g., \"DKK\", \"EUR\", \"USD\")" }, "debtor": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Cases.Requests.PreviewDebtorDto" }, "amountToRecoverOver6Months": { "type": "number", "description": "OPTIONAL - MULTI-INVOICE AGE BUCKET PRICING (PRICING ZONE 180-DAY THRESHOLD)\n \nThe portion of AmountToRecover that is more than 6 months (180 days) overdue.\nThis includes amounts that are 12+ and 24+ months overdue.\n \nThis field is optional and can only be provided alongside AmountToRecoverOver12Months\nand AmountToRecoverOver24Months. It enables precise pricing tier selection based on\nthe 180-day threshold. When omitted, the system falls back to deriving the threshold\nfrom AmountToRecoverOver12Months.\n \nValidation rules:\n- Must be ≀ AmountToRecover\n- Must be β‰₯ AmountToRecoverOver12Months", "format": "double", "nullable": true }, "amountToRecoverOver12Months": { "type": "number", "description": "OPTIONAL - MULTI-INVOICE AGE BUCKET PRICING\n \nThe portion of AmountToRecover that is more than 12 months overdue.\nThis includes amounts that are 24+ months overdue.\n \nIf provided, AmountToRecoverOver24Months must also be provided.\nBoth fields must be provided together or both omitted.\n \nUsed to calculate blended age uplift for multi-invoice cases:\n- Amount under 12 months = AmountToRecover - AmountToRecoverOver12Months\n- Amount 12-24 months = AmountToRecoverOver12Months - AmountToRecoverOver24Months\n- Amount over 24 months = AmountToRecoverOver24Months\n \nBlended uplift formula: ((A12-A24)Γ—10 + A24Γ—20) / AmountToRecover\nwhere A12 = AmountToRecoverOver12Months, A24 = AmountToRecoverOver24Months\n \nValidation rules:\n- Must be ≀ AmountToRecover\n- Must be β‰₯ AmountToRecoverOver24Months", "format": "double", "nullable": true }, "amountToRecoverOver24Months": { "type": "number", "description": "OPTIONAL - MULTI-INVOICE AGE BUCKET PRICING\n \nThe portion of AmountToRecover that is more than 24 months overdue.\n \nIf provided, AmountToRecoverOver12Months must also be provided.\nBoth fields must be provided together or both omitted.\n \nUsed to calculate blended age uplift for multi-invoice cases.\nSee AmountToRecoverOver12Months for full details on the calculation.\n \nValidation rules:\n- Must be ≀ AmountToRecoverOver12Months\n- Must be ≀ AmountToRecover", "format": "double", "nullable": true }, "dueDate": { "type": "string", "description": "Optional invoice due date. Mutually exclusive with age bucket fields.\nIf provided, Debitura computes the age surcharge internally β€” no need to calculate age buckets.\nCannot be a future date.", "format": "date-time", "nullable": true }, "returnUrl": { "maxLength": 2048, "type": "string", "description": "Optional: URL the creditor user should land on after completing any\npending signing chain (SDCA upgrade / PoA / JPA / KYC) on the\nDebitura Creditors app. Embedded, URL-encoded, into\n`PreviewCaseResponseApiViewModel.Result.SigningHandoff.CombinedSigningUrl`\n(when at least one signing-related required action is present) and into\n`BusinessErrorResponseApiDTO.SigningHandoff.CombinedSigningUrl` /\n`InvoiceDto.SigningHandoff.CombinedSigningUrl` on POST `/cases`.\n \nMust be an absolute http(s) URL. Values that fail validation\n(relative URLs, non-http schemes, header-injection characters) are\nsilently dropped β€” the combined URL is still emitted but without\nthe returnUrl query parameter, and the Creditors app falls back to\nits own safe in-app default landing.\n \nAdditive. Existing integrations\nthat omit this field see the same behaviour as before.", "nullable": true } }, "additionalProperties": false, "description": "Request model for previewing case eligibility, partner assignment, and required actions\nbefore actually creating a collection case.\n \nThis endpoint allows you to check:\n- Whether a case would be eligible for collection (partner coverage available)\n- Which partner would be assigned\n- What documents need to be signed (SDCA, Power of Attorney)\n- Estimated pricing with age-based surcharges\n \nUse this to guide users through document signing before final case submission.", "example": { "amountToRecover": 4000, "currencyCode": "EUR", "debtor": { "type": "Company", "countryAlpha2": "PT" }, "dueDate": "2026-04-22" } }, "Debitura.Web.ExternalApi.Contracts.V1.Cases.Requests.PreviewDebtorDto": { "required": [ "countryAlpha2", "type" ], "type": "object", "properties": { "type": { "minLength": 1, "type": "string", "description": "Debtor type. Valid values: \"Company\" or \"Private\"\nThis affects partner selection as different partners may specialize in B2B vs B2C collection." }, "countryAlpha2": { "maxLength": 2, "minLength": 2, "type": "string", "description": "Country code (ISO 3166-1 alpha-2 format, e.g., \"DK\", \"US\", \"PL\")\nUsed to determine jurisdiction and available collection partners." }, "stateAlpha2": { "maxLength": 2, "minLength": 2, "type": "string", "description": "US state code (e.g., \"CA\", \"NY\")\nREQUIRED for United States cases only, as US partner coverage is state-specific.\nOptional for other countries.", "nullable": true } }, "additionalProperties": false, "description": "Simplified debtor information for case preview.\nOnly includes the minimum fields required for partner routing and eligibility checking." }, "Debitura.Web.ExternalApi.Contracts.V1.Cases.SigningHandoffDto": { "type": "object", "properties": { "combinedSigningUrl": { "type": "string", "description": "Single signing entry URL that walks the creditor through every\npending step (SDCA upgrade β†’ PoA β†’ JPA β†’ KYC) on the Creditors app\nand returns to the partner-supplied returnUrl when done.", "nullable": true } }, "additionalProperties": false, "description": "Partner-facing handoff metadata for a creditor's pending signing chain.\nReturned on POST /cases responses (422 with pending-signing errors,\nor 200 with AllowPendingContracts=true when signings remain).\n \nDesigned as an envelope so future fields (expiration, suggested email\ncopy, etc.) can be added without polluting the parent DTO." }, "Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto": { "type": "object", "properties": { "error": { "type": "string", "description": "Short human-readable error label (legacy field β€” preserved for backward compatibility).", "nullable": true }, "message": { "type": "string", "description": "Human-readable error description (legacy field β€” preserved for backward compatibility).", "nullable": true }, "businessErrors": { "type": "array", "items": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Cases.BusinessErrorApiDTO" }, "description": "Canonical structured error array. Consumers should migrate to reading this field.", "nullable": true } }, "additionalProperties": false, "description": "Generic structured error response for API endpoints.\n \nDual-write design: existing fields (Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto.Error / Debitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto.Message etc.)\nare preserved for backward compatibility alongside the canonical\nDebitura.Web.ExternalApi.Contracts.V1.Errors.ApiErrorResponseDto.BusinessErrors array, allowing consumers to migrate at their own pace." }, "Debitura.Web.ReferralPartnerApi.Models.AccessTokens.AccessTokenResponse": { "type": "object", "properties": { "accessToken": { "type": "string", "description": "The JWT bearer token to use in Authorization header.\nFormat: \"Bearer {access_token}\"", "nullable": true }, "expiresIn": { "type": "integer", "description": "Token lifetime in seconds (typically 1800 for 30 minutes).", "format": "int32" }, "creditorId": { "type": "string", "description": "The Debitura creditor ID that this token grants access to.", "format": "uuid" }, "externalTenantId": { "type": "string", "description": "The partner's external tenant ID for reference.", "nullable": true }, "tokenType": { "type": "string", "description": "Token type - always \"Bearer\" for JWT tokens.", "nullable": true } }, "additionalProperties": false, "description": "Response containing a short-lived JWT bearer token for accessing the Customer API." }, "Debitura.Web.ReferralPartnerApi.Models.AccessTokens.CreateAccessTokenRequest": { "required": [ "externalTenantId" ], "type": "object", "properties": { "externalTenantId": { "maxLength": 255, "minLength": 1, "type": "string", "description": "The partner's external identifier for the client/tenant.\nThis must match an active ReferralPartnerClientLink." } }, "additionalProperties": false, "description": "Request to generate a short-lived access token for accessing the Customer API\non behalf of a linked client." }, "Debitura.Web.ReferralPartnerApi.Models.Cases.CaseClientInfo": { "type": "object", "properties": { "externalTenantId": { "type": "string", "description": "Your external tenant ID for this client (the identifier you provided when linking).", "nullable": true }, "creditorId": { "type": "string", "format": "uuid" }, "companyName": { "type": "string", "nullable": true }, "contacts": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Cases.ClientContacts" } }, "additionalProperties": false, "description": "Client (creditor) info with referral-partner-specific ExternalTenantId." }, "Debitura.Web.ReferralPartnerApi.Models.Cases.CaseDebtorInfo": { "type": "object", "properties": { "name": { "type": "string", "description": "Debtor display name (company name, or person name if individual).", "nullable": true }, "country": { "type": "string", "description": "Debtor's country (full name, e.g. \"United Kingdom\", \"Denmark\").", "nullable": true } }, "additionalProperties": false, "description": "Debtor info for the case." }, "Debitura.Web.ReferralPartnerApi.Models.Cases.CaseItem": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid" }, "reference": { "type": "string", "nullable": true }, "creditorReference": { "type": "string", "nullable": true }, "client": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Cases.CaseClientInfo" }, "debtor": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Cases.CaseDebtorInfo" }, "grossAmount": { "type": "number", "format": "double" }, "remainder": { "type": "number", "format": "double" }, "currency": { "type": "string", "nullable": true }, "lifecycle": { "type": "string", "description": "Lifecycle status as human-readable description (e.g. \"Active\", \"Closed\", \"Pending Verification\").\nSame format as InvoiceDto.Lifecycle in the external API contracts.", "nullable": true }, "closeCode": { "type": "string", "description": "Close code description if the case is closed (e.g. \"Paid\", \"Withdrawn by Client\"), null otherwise.", "nullable": true }, "currentEngagementPhase": { "type": "string", "description": "The current phase of the case's engagement: \"Pre-legal\", \"Legal\", or \"Enforcement\". A\ndifferent axis from Debitura.Web.ReferralPartnerApi.Models.Cases.CaseItem.Lifecycle/Debitura.Web.ReferralPartnerApi.Models.Cases.CaseItem.CloseCode β€” an Active case can be\nin any of the three phases.\n \nNull means \"no active engagement\" (e.g. lead / quoting / pre-contract-signing / unassigned,\nor a data-consistency gap) β€” a distinct third state, NOT a synonym for Pre-legal. Most cases\nlegitimately read Pre-legal; phase only leaves Pre-legal on legal/enforcement quote flows.\n \nNot guaranteed to be monotonic (an admin correction can move phase backwards). Persists\nafter case closure β€” reflects the case's last-known engagement phase, not the current\nLifecycle.", "nullable": true }, "dateCreated": { "type": "string", "format": "date-time" }, "dueDate": { "type": "string", "format": "date-time" }, "dateCollectionStarted": { "type": "string", "format": "date-time", "nullable": true }, "dateFinished": { "type": "string", "format": "date-time", "nullable": true }, "validation": { "$ref": "#/components/schemas/Debitura.Domain.Services.CaseValidation.CaseValidationStatusDto" }, "collectionPartner": { "type": "string", "description": "Display name of the collection partner handling this case (e.g. \"Oriel Collections\").\nNull if no collection partner has been assigned yet.", "nullable": true }, "expectedReferralRatePercentage": { "type": "number", "description": "The expected referral fee rate as a percentage (e.g. 70.0 = 70%).\nFor cases with a collection partner that has a per-assignment override, the override is used.\nOtherwise falls back to the referral link's snapshotted rate (frozen at link creation time).\nNull when no collection partner has been assigned yet β€” a rate can only be determined\nonce routing is complete.\nFor realised payouts with frozen rates, see `referralFeePercentageSnapshot` on the\ntransactions endpoint.", "format": "double", "nullable": true } }, "additionalProperties": false, "description": "A debt collection case as seen by a referral partner.\nFollows the same field conventions as InvoiceDto (ExternalApi.Contracts)\nbut scoped to what referral partners need, with ExternalTenantId on Client." }, "Debitura.Web.ReferralPartnerApi.Models.Cases.CasePotentialRevenue": { "type": "object", "properties": { "grossAmountUsd": { "type": "number", "description": "Case gross amount converted to USD.", "format": "double" }, "successFeePercentage": { "type": "number", "description": "Success fee percentage charged by the collection partner (e.g. 9.5).", "format": "double" }, "collectionPartnerRevenueUsd": { "type": "number", "description": "GrossAmountUsd * SuccessFeePercentage / 100.", "format": "double" }, "platformRevenueSharePercentage": { "type": "number", "description": "Debitura's revenue share percentage of the collection fee (e.g. 40.0).", "format": "double" }, "platformRevenueUsd": { "type": "number", "description": "CollectionPartnerRevenueUsd * PlatformRevenueSharePercentage / 100.", "format": "double" }, "referralFeePercentage": { "type": "number", "description": "Referral partner's share percentage of platform revenue (e.g. 50.0).", "format": "double" }, "referralRevenueUsd": { "type": "number", "description": "PlatformRevenueUsd * ReferralFeePercentage / 100.", "format": "double" } }, "additionalProperties": false, "description": "Breakdown of potential revenue if the full case amount is collected.\nAll amounts are in USD; percentages are displayed as whole numbers (e.g. 9.5 = 9.5%)." }, "Debitura.Web.ReferralPartnerApi.Models.Cases.CasesSummary": { "type": "object", "properties": { "totalCases": { "type": "integer", "format": "int32" }, "casesThisMonth": { "type": "integer", "format": "int32" }, "byLifecycle": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Cases.LifecycleBreakdown" } }, "additionalProperties": false }, "Debitura.Web.ReferralPartnerApi.Models.Cases.ClientContacts": { "type": "object", "properties": { "onboardingUser": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Cases.ContactUser" }, "officeEmail": { "type": "string", "description": "The creditor's office email address (company-level contact).", "nullable": true }, "otherUsers": { "type": "array", "items": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Cases.ContactUser" }, "description": "Other users linked to this creditor account (excludes the onboarding user).", "nullable": true } }, "additionalProperties": false, "description": "Contact information for a client, including the original onboarding user,\nthe company office email, and all other users linked to the creditor." }, "Debitura.Web.ReferralPartnerApi.Models.Cases.ContactUser": { "type": "object", "properties": { "email": { "type": "string", "nullable": true }, "name": { "type": "string", "nullable": true } }, "additionalProperties": false, "description": "A user contact associated with a creditor." }, "Debitura.Web.ReferralPartnerApi.Models.Cases.GetCaseDetailResponse": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid" }, "reference": { "type": "string", "nullable": true }, "creditorReference": { "type": "string", "nullable": true }, "client": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Cases.CaseClientInfo" }, "debtor": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Cases.CaseDebtorInfo" }, "grossAmount": { "type": "number", "format": "double" }, "remainder": { "type": "number", "format": "double" }, "currency": { "type": "string", "nullable": true }, "lifecycle": { "type": "string", "nullable": true }, "closeCode": { "type": "string", "nullable": true }, "currentEngagementPhase": { "type": "string", "description": "The current phase of the case's engagement: \"Pre-legal\", \"Legal\", or \"Enforcement\". Null\nmeans no active engagement β€” see Debitura.Web.ReferralPartnerApi.Models.Cases.CaseItem.CurrentEngagementPhase for full\nsemantics (not monotonic, persists after case closure).", "nullable": true }, "dateCreated": { "type": "string", "format": "date-time" }, "dueDate": { "type": "string", "format": "date-time" }, "dateCollectionStarted": { "type": "string", "format": "date-time", "nullable": true }, "dateFinished": { "type": "string", "format": "date-time", "nullable": true }, "validation": { "$ref": "#/components/schemas/Debitura.Domain.Services.CaseValidation.CaseValidationStatusDto" }, "collectionPartner": { "type": "string", "description": "Display name of the collection partner handling this case (e.g. \"Oriel Collections\").\nNull if no collection partner has been assigned yet.", "nullable": true }, "expectedReferralRatePercentage": { "type": "number", "description": "The expected referral fee rate as a percentage (e.g. 70.0 = 70%).\nUses the per-assignment override when set, otherwise the referral link's snapshotted rate\n(frozen at link creation time). Null when no collection partner has been assigned yet.", "format": "double", "nullable": true }, "potentialRevenue": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Cases.CasePotentialRevenue" } }, "additionalProperties": false, "description": "Response model for retrieving a single case with potential revenue breakdown.\nExtends CaseItem fields with revenue data for referral partners." }, "Debitura.Web.ReferralPartnerApi.Models.Cases.GetCasesResponse": { "type": "object", "properties": { "page": { "$ref": "#/components/schemas/Debitura.Domain.Model.Base.PageData" }, "cases": { "type": "array", "items": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Cases.CaseItem" }, "nullable": true }, "summary": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Cases.CasesSummary" } }, "additionalProperties": false, "description": "Response model for listing cases linked to a referral partner" }, "Debitura.Web.ReferralPartnerApi.Models.Cases.LifecycleBreakdown": { "type": "object", "properties": { "active": { "type": "integer", "format": "int32" }, "pending": { "type": "integer", "format": "int32" }, "closed": { "type": "integer", "format": "int32" }, "paused": { "type": "integer", "format": "int32" } }, "additionalProperties": false }, "Debitura.Web.ReferralPartnerApi.Models.Cases.PendingActionDto": { "type": "object", "properties": { "type": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Cases.PendingActionType" }, "collectionPartnerId": { "type": "string", "description": "The collection partner this action is scoped to, when applicable.\nSet for partner-specific actions (PoA, KYC). Null for actions that\nare not partner-scoped (e.g. SDCA upgrade, which is platform-wide).", "format": "uuid", "nullable": true }, "dueDate": { "type": "string", "description": "Optional deadline by which the action must be completed (UTC).\nReserved for orchestrator-generated payloads (the orchestrator\nendpoint), where SDCA-upgrade entries can include their refresh\ndeadline. Always null on the `/cases/preview` endpoint, since\npreview is creditor-less and SDCA-upgrade is not surfaced there.", "format": "date-time", "nullable": true } }, "additionalProperties": false, "description": "A single pending action that may need to be completed before cases\ncan be successfully submitted. Returned as part of the structured\nPendingActions array on the /cases/preview response.\n \nAdditive: this complements (does not replace) the existing\nRequiresKycVerification boolean β€” old API consumers can continue to\nrely on RequiresKycVerification as before." }, "Debitura.Web.ReferralPartnerApi.Models.Cases.PendingActionType": { "enum": [ "SdcaUpgrade", "PoA", "Jpa", "Kyc" ], "type": "string", "description": "Type of action that may need to be completed by the creditor before\n(or as part of) submitting cases via the referral partner API.\nNew values may be added in future API versions β€” clients should treat\nunknown values as informational and not crash.\n \nWire format is LOCKED to NAMED STRING values (e.g. `\"PoA\"`,\n`\"Kyc\"`) via Newtonsoft.Json.Converters.StringEnumConverter. The host serializer\nfor this API is Newtonsoft.Json (`AddNewtonsoftJson` in\n`Program.cs`), so a `System.Text.Json``JsonStringEnumConverter` attribute would be silently ignored β€”\nhence the explicit Newtonsoft converter here.\n \nNumeric values below mirror `Domain.CombinedSigningStep`\n(SdcaUpgrade=1, PoA=2, Jpa=3, Kyc=4, Done=5) by convention, but they\nare an internal implementation detail. Clients MUST consume the string\nnames; the numbers are not part of the public contract.\n \nRenumbering or removing already-released values is forbidden β€” see\n`Debitura.Wiki/engineering/development-philosophy/backend-standards.md`\n(line 102: \"Never renumber or remove released enum values\").\n \nThe System.Text.Json.Serialization.JsonStringEnumConverter attribute is\ndeclared in addition so that consumers (and our own integration tests)\nwho parse responses using `System.Text.Json` can deserialize the\nstring form back into this enum. The Newtonsoft converter is what\nactually controls outbound wire format on this host." }, "Debitura.Web.ReferralPartnerApi.Models.Cases.ReferralPartnerPreviewCaseResponse": { "type": "object", "properties": { "isEligible": { "type": "boolean", "description": "Whether the case is eligible for collection (a partner is available in the requested jurisdiction).\nIf false, check IneligibilityReason for details." }, "ineligibilityReason": { "type": "string", "description": "Explanation of why the case is not eligible (only present when IsEligible = false).\nCommon reasons: \"We don't have an exclusive pre-legal partner in the provided jurisdiction.\"", "nullable": true }, "jurisdiction": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Cases.JurisdictionDto" }, "pricingPreview": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Cases.PricingPreviewDto" }, "requiresKycVerification": { "type": "boolean", "description": "Whether the resolved collection partner requires KYC verification before cases can be submitted.\nWhen true, the creditor must complete KYC verification before case creation.\nUse the case creation endpoint with a creditor ID to determine whether KYC is already on file." }, "pendingActions": { "type": "array", "items": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Cases.PendingActionDto" }, "description": "Structured list of actions the creditor will need to complete before\n(or as part of) submitting cases for the matched collection partner.\nAlways present β€” empty when nothing is pending.\n \nAt preview time the request is creditor-less, so this list reflects the\nmatched partner's hard requirements (e.g. PoA per partner, KYC if the\npartner is configured for it). Creditor-specific items such as SDCA\nupgrade are returned only when the API has creditor context.\n \nAdditive over Debitura.Web.ReferralPartnerApi.Models.Cases.ReferralPartnerPreviewCaseResponse.RequiresKycVerification β€” old clients that\nonly read Debitura.Web.ReferralPartnerApi.Models.Cases.ReferralPartnerPreviewCaseResponse.RequiresKycVerification are unaffected.", "nullable": true }, "combinedSigningUrl": { "type": "string", "description": "Always `null` on `/cases/preview` because preview is creditor-less β€”\nno concrete creditor signing state exists to chain. The structured\nDebitura.Web.ReferralPartnerApi.Models.Cases.ReferralPartnerPreviewCaseResponse.PendingActions array on this response indicates which step types\nthe matched partner will require ahead of onboarding.\n \nThe canonical placement for the combined-signing URL on POST `/cases`\nresponses is the nested `SigningHandoff` envelope (a\n`SigningHandoffDto` on both `BusinessErrorResponseApiDTO` and\n`InvoiceDto`). The combined URL is populated on POST `/cases`\nresponses, where the creditor IS identified:\n422 with at least one signing-related business error\n (`MissingDebtCollectionContract`, `MissingPowerOfAttorney`,\n `MissingKycVerification`) β€” see\n `BusinessErrorResponseApiDTO.SigningHandoff.CombinedSigningUrl`.200 with `AllowPendingContracts=true` when signings\n remain β€” see `InvoiceDto.SigningHandoff.CombinedSigningUrl`.\nBoth POST surfaces use the same Creditors-app\n`/Signing/PendingContracts` entry point and walk the SDCA-upgrade β†’\nPoA β†’ JPA β†’ KYC chain end-to-end.\n \nThis flat `CombinedSigningUrl` field on `/cases/preview` is\npreserved as-is for backward compatibility (it is always null in practice).", "nullable": true } }, "additionalProperties": false, "description": "Response from the Referral Partner pricing preview endpoint.\nReturns eligibility, jurisdiction, estimated success fee pricing, and\nany actions that the creditor will need to complete before cases can\nbe submitted (PoA, KYC, SDCA upgrade)." }, "Debitura.Web.ReferralPartnerApi.Models.Clients.CaseCreationFailure": { "type": "object", "properties": { "caseIndex": { "type": "integer", "description": "Zero-based index of the failed case in the original Cases array.", "format": "int32" }, "creditorReference": { "type": "string", "description": "Creditor reference from the failed case, if provided.\nHelps consumers identify which specific case failed.", "nullable": true }, "errorType": { "type": "string", "description": "Machine-readable error type code for programmatic error handling.\nEnables API consumers to handle different failure scenarios without parsing error messages.\n \n\nPossible values:Debitura.Web.ReferralPartnerApi.Models.Clients.CaseCreationErrorTypes.NoPartnerAvailableNo collection partner available for the debtor's jurisdiction.\nThe debtor is in a country/region where Debitura does not yet have collection partner coverage.\nConsider resubmitting with debtors in supported jurisdictions.Debitura.Web.ReferralPartnerApi.Models.Clients.CaseCreationErrorTypes.ValidationErrorThe request failed field-level validation.\nCheck the Debitura.Web.ReferralPartnerApi.Models.Clients.CaseCreationFailure.ValidationErrors property for detailed field-specific errors.\nCommon causes: missing required fields, invalid formats, business rule violations.Debitura.Web.ReferralPartnerApi.Models.Clients.CaseCreationErrorTypes.DuplicateReferenceThe provided CreditorReference already exists for this creditor or is duplicated in the current request.\nCreditorReference must be unique per creditor.Debitura.Web.ReferralPartnerApi.Models.Clients.CaseCreationErrorTypes.IdempotencyViolationThe client has already been created in a previous API call.\nCases are not created on repeated calls to maintain idempotency.\nThis is informational - the original operation already succeeded.Debitura.Web.ReferralPartnerApi.Models.Clients.CaseCreationErrorTypes.UnexpectedErrorAn unexpected system error occurred during case creation.\nThis is a catch-all for errors not covered by other types.\nContact Debitura support if this error persists.\nNull if the error type cannot be determined or is not applicable.", "nullable": true }, "errorMessage": { "type": "string", "description": "High-level error message explaining why the case creation failed.", "nullable": true }, "validationErrors": { "type": "object", "additionalProperties": { "type": "array", "items": { "type": "string" } }, "description": "Detailed field-level validation errors if the failure was due to validation.\nNull if the failure was due to other reasons (e.g., no partner match).", "nullable": true }, "signingHandoff": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Cases.SigningHandoffDto" } }, "additionalProperties": false, "description": "Represents a failed case creation attempt during multi-case client creation." }, "Debitura.Web.ReferralPartnerApi.Models.Clients.ClientCaseStats": { "type": "object", "properties": { "casesTotal": { "type": "integer", "format": "int32" }, "casesClosed": { "type": "integer", "format": "int32" }, "earningsUsd": { "type": "number", "format": "double" } }, "additionalProperties": false }, "Debitura.Web.ReferralPartnerApi.Models.Clients.ClientCreatedResponse": { "type": "object", "properties": { "externalTenantId": { "type": "string", "nullable": true }, "onboardingDone": { "type": "boolean" }, "onboardingLinks": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Clients.OnboardingLinksDto" }, "client": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Clients.CreditorDto" }, "users": { "type": "array", "items": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Clients.UserDto" }, "nullable": true }, "isAttributedClient": { "type": "boolean" }, "dateLinked": { "type": "string", "format": "date-time" }, "caseStats": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Clients.ClientCaseStats" }, "kycStatus": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Clients.KycStatus" }, "kycVerification": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Clients.KycVerificationDto" }, "caseResults": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Clients.MultiCaseResult" } }, "additionalProperties": false }, "Debitura.Web.ReferralPartnerApi.Models.Clients.ClientDeletableResponse": { "type": "object", "properties": { "isDeletable": { "type": "boolean", "description": "True if the client can be safely deleted." }, "blockers": { "type": "array", "items": { "type": "string" }, "description": "List of reasons why the client cannot be deleted (empty if IsDeletable is true).", "nullable": true } }, "additionalProperties": false, "description": "Response indicating whether a client can be deleted." }, "Debitura.Web.ReferralPartnerApi.Models.Clients.ClientDetailsDto": { "required": [ "country", "name", "supportEmail" ], "type": "object", "properties": { "name": { "minLength": 1, "type": "string" }, "registrationNumber": { "type": "string", "nullable": true }, "address": { "maxLength": 500, "minLength": 0, "type": "string", "nullable": true }, "zipCode": { "maxLength": 20, "minLength": 0, "type": "string", "nullable": true }, "city": { "maxLength": 100, "minLength": 0, "type": "string", "nullable": true }, "state": { "maxLength": 100, "minLength": 0, "type": "string", "nullable": true }, "country": { "minLength": 1, "type": "string" }, "supportEmail": { "minLength": 1, "type": "string", "format": "email" }, "supportPhone": { "type": "string", "nullable": true } }, "additionalProperties": false }, "Debitura.Web.ReferralPartnerApi.Models.Clients.ClientUserDto": { "required": [ "email", "name" ], "type": "object", "properties": { "name": { "minLength": 1, "type": "string" }, "email": { "minLength": 1, "type": "string", "format": "email" }, "isOnboardingUser": { "type": "boolean", "description": "Marks this user as the one going through onboarding.\nDefaults to false. Exactly ONE user must have this set to true." } }, "additionalProperties": false }, "Debitura.Web.ReferralPartnerApi.Models.Clients.ClientsSummary": { "type": "object", "properties": { "totalClients": { "type": "integer", "format": "int32" }, "attributedClients": { "type": "integer", "format": "int32" }, "onboardingComplete": { "type": "integer", "format": "int32" }, "onboardingPending": { "type": "integer", "format": "int32" }, "totalCases": { "type": "integer", "format": "int32" } }, "additionalProperties": false }, "Debitura.Web.ReferralPartnerApi.Models.Clients.ConflictResponse": { "type": "object", "properties": { "type": { "type": "string", "description": "The type of conflict that occurred", "nullable": true }, "message": { "type": "string", "description": "Human-readable description of the conflict", "nullable": true }, "data": { "description": "Additional payload for the conflict. Shape depends on Debitura.Web.ReferralPartnerApi.Models.Clients.ConflictResponse.Type:\n`ClientExistsNeedsLinking` β†’ Debitura.Web.ReferralPartnerApi.Models.Clients.ClientExistsNeedsLinkingResponse (ExternalTenantId + OnboardingLinks.Url only β€” never contains PII).`ClientAlreadyLinkedToAnotherPartner` β†’ Debitura.Web.ReferralPartnerApi.Models.Clients.ClientAlreadyLinkedResponse (ExternalTenantId only β€” never contains PII).Other conflict types may omit this field entirely.", "nullable": true } }, "additionalProperties": false, "description": "Response returned when a conflict occurs during client creation" }, "Debitura.Web.ReferralPartnerApi.Models.Clients.CreateClientRequest": { "required": [ "client", "externalTenantId", "users" ], "type": "object", "properties": { "externalTenantId": { "minLength": 1, "type": "string" }, "client": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Clients.ClientDetailsDto" }, "users": { "minItems": 1, "type": "array", "items": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Clients.ClientUserDto" } }, "cases": { "type": "array", "items": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Cases.Requests.CreateCollectionCaseRequestApiViewModel" }, "description": "Optional: Cases to create alongside the client.\nIf provided, cases will be created with PendingContractSigning status.\nThe onboarding URL will guide the client through contract signing for all required PoAs.\nSupports multi-invoice age bucket pricing fields (AmountToRecoverOver6Months, AmountToRecoverOver12Months, AmountToRecoverOver24Months).", "nullable": true } }, "additionalProperties": false, "example": { "externalTenantId": "tenant-12345", "client": { "name": "Acme Corp", "registrationNumber": "12345678", "address": "123 Business Street", "zipCode": "1000", "city": "Lisbon", "state": "Lisbon", "country": "Portugal", "supportEmail": "billing@acme-corp.com", "supportPhone": "+351 123 456 789" }, "users": [ { "name": "John Doe", "email": "john.doe@acme-corp.com", "isOnboardingUser": true } ], "cases": [ { "currencyCode": "EUR", "amountToRecover": 4000, "date": "2026-02-22", "dueDate": "2026-03-02", "claimDescription": "Custom mobile app development services", "comments": "Outstanding invoice INV 2024 00789 for custom mobile app development delivered 15 Nov 2024; payment 60 days overdue despite two reminders.", "creditorReference": "INV‑2024‑00789", "isTest": false, "debtor": { "type": "Company", "name": "Acme Corp", "contactPerson": "John Doe", "companyRegistrationNumber": "12345678", "address": "123 Business Street", "zipCode": "1000", "city": "Lisbon", "state": "Lisbon", "countryAlpha2": "PT", "email": "billing@acme‑corp.com", "phone": "+351 123 456 789" } } ] } }, "Debitura.Web.ReferralPartnerApi.Models.Clients.CreditorDto": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid" }, "companyName": { "type": "string", "nullable": true }, "officeEmail": { "type": "string", "nullable": true }, "country": { "type": "string", "nullable": true }, "address": { "type": "string", "nullable": true }, "city": { "type": "string", "nullable": true }, "zipCode": { "type": "string", "nullable": true }, "companyRegistrationNumber": { "type": "string", "nullable": true } }, "additionalProperties": false }, "Debitura.Web.ReferralPartnerApi.Models.Clients.GetClientsResponse": { "type": "object", "properties": { "page": { "$ref": "#/components/schemas/Debitura.Domain.Model.Base.PageData" }, "summary": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Clients.ClientsSummary" }, "clients": { "type": "array", "items": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Clients.ClientCreatedResponse" }, "description": "List of linked clients", "nullable": true } }, "additionalProperties": false, "description": "Response model for listing clients linked to a referral partner" }, "Debitura.Web.ReferralPartnerApi.Models.Clients.KycStatus": { "enum": [ "NotRequired", "Pending", "Verified" ], "type": "string", "description": "KYC (Know Your Customer) verification status for a client linked to a referral partner.\nCaptures three distinct states that a simple boolean cannot express.\n \nWire format is LOCKED to snake_case string values (\"not_required\", \"pending\", \"verified\")\nvia Newtonsoft.Json StringEnumConverter with SnakeCaseNamingStrategy. The host serializer\nfor this API is Newtonsoft.Json (AddNewtonsoftJson in Program.cs), so a System.Text.Json\nJsonStringEnumConverter attribute would be silently ignored β€” hence the explicit Newtonsoft\nconverter here.\n \nThe System.Text.Json JsonConverter attribute is declared in addition so that consumers\n(and our own integration tests) who parse responses using System.Text.Json can deserialize\nthe string form back into this enum. The Newtonsoft converter is what actually controls\noutbound wire format on this host." }, "Debitura.Web.ReferralPartnerApi.Models.Clients.KycVerificationDto": { "type": "object", "properties": { "directorFullName": { "type": "string", "nullable": true }, "directorHomeAddress": { "type": "string", "nullable": true }, "directorDateOfBirth": { "type": "string", "format": "date" }, "dateCreated": { "type": "string", "format": "date-time" }, "verificationStatus": { "$ref": "#/components/schemas/Debitura.Domain.Model.Creditors.CreditorKycVerifications.CreditorKycVerificationStatus" }, "verificationStatusUpdatedAt": { "type": "string", "description": "When Debitura.Web.ReferralPartnerApi.Models.Clients.KycVerificationDto.VerificationStatus was last set. Null until set.", "format": "date-time", "nullable": true } }, "additionalProperties": false }, "Debitura.Web.ReferralPartnerApi.Models.Clients.MultiCaseResult": { "type": "object", "properties": { "successfulCases": { "type": "array", "items": { "$ref": "#/components/schemas/Debitura.Web.ExternalApi.Contracts.V1.Cases.InvoiceDto" }, "description": "Cases that were created successfully.\nEach element contains the full case details.", "nullable": true }, "failedCases": { "type": "array", "items": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Clients.CaseCreationFailure" }, "description": "Cases that failed during creation.\nEach element contains error details and the original case index.", "nullable": true } }, "additionalProperties": false, "description": "Result of creating multiple cases during client creation.\nGroups successful and failed case creation attempts." }, "Debitura.Web.ReferralPartnerApi.Models.Clients.OnboardingLinksDto": { "type": "object", "properties": { "url": { "type": "string", "nullable": true } }, "additionalProperties": false }, "Debitura.Web.ReferralPartnerApi.Models.Clients.SubmitKycVerificationRequest": { "required": [ "directorDateOfBirth", "directorFullName", "directorHomeAddress" ], "type": "object", "properties": { "directorFullName": { "maxLength": 500, "minLength": 1, "type": "string" }, "directorHomeAddress": { "maxLength": 1000, "minLength": 1, "type": "string" }, "directorDateOfBirth": { "type": "string", "format": "date" } }, "additionalProperties": false }, "Debitura.Web.ReferralPartnerApi.Models.Clients.UserDto": { "type": "object", "properties": { "id": { "type": "integer", "format": "int32" }, "email": { "type": "string", "nullable": true }, "firstName": { "type": "string", "nullable": true }, "lastName": { "type": "string", "nullable": true } }, "additionalProperties": false }, "Debitura.Web.ReferralPartnerApi.Models.Coverages.CoverageItemApiDTO": { "type": "object", "properties": { "jurisdictionId": { "type": "integer", "format": "int32" }, "jurisdiction": { "type": "string", "nullable": true }, "country": { "type": "string", "nullable": true }, "countryId": { "type": "integer", "format": "int32" }, "countryAlpha2": { "type": "string", "nullable": true }, "usStateAlpha2": { "type": "string", "nullable": true }, "partners": { "type": "array", "items": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Coverages.PartnerCoverageApiDTO" }, "nullable": true } }, "additionalProperties": false }, "Debitura.Web.ReferralPartnerApi.Models.Coverages.PartnerCoverageApiDTO": { "type": "object", "properties": { "partnerId": { "type": "string", "format": "uuid" }, "partnerName": { "type": "string", "nullable": true }, "conditions": { "type": "string", "description": "Human-readable description of when this partner applies.\nExamples: \"All cases\", \"B2B cases only\", \"Amount β‰₯ €1,000\"", "nullable": true } }, "additionalProperties": false }, "Debitura.Web.ReferralPartnerApi.Models.ReferralPartners.FilterOptionCarveoutPartner": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid" }, "name": { "type": "string", "nullable": true } }, "additionalProperties": false }, "Debitura.Web.ReferralPartnerApi.Models.ReferralPartners.FilterOptionCountry": { "type": "object", "properties": { "id": { "type": "integer", "format": "int32" }, "name": { "type": "string", "nullable": true } }, "additionalProperties": false }, "Debitura.Web.ReferralPartnerApi.Models.ReferralPartners.GetFilterOptionsResponse": { "type": "object", "properties": { "countries": { "type": "array", "items": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.ReferralPartners.FilterOptionCountry" }, "description": "Distinct debtor countries from the referral partner's case history, sorted by name.", "nullable": true }, "carveoutPartners": { "type": "array", "items": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.ReferralPartners.FilterOptionCarveoutPartner" }, "description": "Collection partners from the referral partner's active JurisdictionPricingZone records, sorted by name.", "nullable": true } }, "additionalProperties": false, "description": "Response model for the filter-options endpoint, providing distinct filter values\navailable for the authenticated referral partner's cases and earnings." }, "Debitura.Web.ReferralPartnerApi.Models.ReferralPartners.ReferralPartnerResponse": { "type": "object", "properties": { "id": { "type": "string", "description": "Unique identifier for the referral partner.", "format": "uuid" }, "companyName": { "type": "string", "description": "Company name of the referral partner.", "nullable": true }, "shortName": { "type": "string", "description": "Short name of the referral partner.", "nullable": true }, "contactEmail": { "type": "string", "description": "Contact email for the referral partner.", "nullable": true }, "externalSystemId": { "type": "string", "description": "External system identifier for the partner.", "nullable": true }, "referralFeePercentage": { "type": "number", "description": "Percentage of Debitura's earnings that will be paid as referral fee.", "format": "double" }, "isActive": { "type": "boolean", "description": "Whether the partner is currently active." }, "isPublicDemo": { "type": "boolean", "description": "When true, this partner is used for public onboarding demos and may have demo-specific behaviour." }, "logoUrl": { "type": "string", "description": "URL to the referral partner's logo image.", "nullable": true }, "backgroundColorCode": { "type": "string", "description": "Background color code for custom styling (e.g., \"#FFFFFF\").", "nullable": true }, "fontColor": { "type": "string", "description": "Font color code for custom styling (e.g., \"#000000\").", "nullable": true }, "fontFamily": { "type": "string", "description": "Font family for custom styling (e.g., \"Arial, sans-serif\").", "nullable": true }, "invoicingTriggerMode": { "$ref": "#/components/schemas/Debitura.Domain.Model.ReferralPartners.Enums.InvoicingTriggerMode" } }, "additionalProperties": false, "description": "Response containing referral partner information including styling configuration." }, "Debitura.Web.ReferralPartnerApi.Models.Reporting.CaseInfo": { "type": "object", "properties": { "invoiceId": { "type": "string", "format": "uuid" }, "caseReference": { "type": "string", "nullable": true }, "debtorName": { "type": "string", "nullable": true }, "originalAmount": { "type": "number", "format": "double" }, "currency": { "type": "string", "nullable": true } }, "additionalProperties": false }, "Debitura.Web.ReferralPartnerApi.Models.Reporting.ClientInfo": { "type": "object", "properties": { "externalTenantId": { "type": "string", "nullable": true }, "creditorId": { "type": "string", "format": "uuid" }, "companyName": { "type": "string", "nullable": true } }, "additionalProperties": false }, "Debitura.Web.ReferralPartnerApi.Models.Reporting.EarningsInfo": { "type": "object", "properties": { "currency": { "type": "string", "description": "Currency of the original transaction", "nullable": true }, "debituraRevenue": { "type": "number", "format": "double" }, "debituraRevenueUsd": { "type": "number", "format": "double" }, "referralFeePercentage": { "type": "number", "format": "double" }, "referralFeeAmount": { "type": "number", "format": "double" }, "referralFeeAmountUsd": { "type": "number", "format": "double" }, "isEstimate": { "type": "boolean", "description": "True if the referral fee amount is an estimate (CommissionPaymentStatus != Paid).\nWhen true, the final amount may change based on FX rates." } }, "additionalProperties": false }, "Debitura.Web.ReferralPartnerApi.Models.Reporting.PaymentInfo": { "type": "object", "properties": { "amount": { "type": "number", "format": "double" }, "currency": { "type": "string", "nullable": true }, "paymentDate": { "type": "string", "format": "date-time" } }, "additionalProperties": false }, "Debitura.Web.ReferralPartnerApi.Models.Reporting.RecognitionInfo": { "type": "object", "properties": { "isRecognized": { "type": "boolean", "description": "Whether revenue has been recognized (PlatformInvoicingStatus == PaymentReceived)" }, "referralFeeRecognizedUsd": { "type": "number", "description": "Recognized referral fee amount in USD (0 if not yet recognized)", "format": "double" } }, "additionalProperties": false }, "Debitura.Web.ReferralPartnerApi.Models.Reporting.RevenueBreakdown": { "type": "object", "properties": { "pendingReferralFeeUsd": { "type": "number", "description": "Stage 1: Pending β€” CommissionPaymentStatus=Unpaid/Credited, PlatformInvoicingStatus=NotInvoiced,\nand ReferralInvoicingStatus=null/Pending (excludes payouts already invoiced/paid to the referral\npartner via a commission clawback after settlement β€” see Stage 5/6).\nFee is speculative. Depends on the client paying the collection partner. Amount may change.", "format": "double" }, "pendingCount": { "type": "integer", "format": "int32" }, "confirmedPendingInvoiceReferralFeeUsd": { "type": "number", "description": "Stage 2: Confirmed, awaiting Debitura invoice β€” CommissionPaymentStatus=Paid, PlatformInvoicingStatus=NotInvoiced,\nand ReferralInvoicingStatus=null/Pending (excludes payouts already invoiced/paid to the referral\npartner β€” see Stage 5/6).\nFee is confirmed. Debitura will invoice the collection partner on the next billing cycle (8th of month).", "format": "double" }, "confirmedPendingInvoiceCount": { "type": "integer", "format": "int32" }, "awaitingCollectionPartnerPaymentReferralFeeUsd": { "type": "number", "description": "Stage 3: Awaiting collection partner payment β€” PlatformInvoicingStatus=InvoiceIssued and\nReferralInvoicingStatus=null/Pending (excludes payouts already invoiced/paid to the referral\npartner β€” see Stage 5/6).\nDebitura has invoiced the collection partner. Payment expected within 30 days.", "format": "double" }, "awaitingCollectionPartnerPaymentCount": { "type": "integer", "format": "int32" }, "readyToInvoiceDebituraReferralFeeUsd": { "type": "number", "description": "Stage 4: Ready to invoice Debitura β€” PlatformInvoicingStatus=PaymentReceived and ReferralInvoicingStatus=null/Pending.\nCollection partner has paid Debitura. Referral partner can now invoice Debitura.", "format": "double" }, "readyToInvoiceDebituraCount": { "type": "integer", "format": "int32" }, "awaitingDebituraPaymentReferralFeeUsd": { "type": "number", "description": "Stage 5: Awaiting Debitura payment β€” ReferralInvoicingStatus=Invoiced. NOT gated on\nPlatformInvoicingStatus: that tracks Debitura's own invoicing cycle with the collection partner,\nan independent axis from the referral partner's invoicing state (ConfirmedPipeline partners can\nbe invoiced/paid before Debitura's own PlatformInvoicingStatus reaches PaymentReceived).\nReferral partner has invoiced Debitura. Payment expected within 20 business days.\nDisputed amounts are excluded β€” see Debitura.Web.ReferralPartnerApi.Models.Reporting.RevenueBreakdown.DisputedReferralFeeUsd.", "format": "double" }, "awaitingDebituraPaymentCount": { "type": "integer", "format": "int32" }, "paidReferralFeeUsd": { "type": "number", "description": "Stage 6: Paid β€” ReferralInvoicingStatus=Paid. NOT gated on PlatformInvoicingStatus β€” see Stage 5.\nDebitura has paid the referral partner.", "format": "double" }, "paidCount": { "type": "integer", "format": "int32" }, "disputedReferralFeeUsd": { "type": "number", "description": "Disputed β€” ReferralInvoicingStatus=Disputed. NOT gated on PlatformInvoicingStatus β€” see Stage 5.\nDeliberately excluded from every other bucket (including \"ready to invoice\" / \"awaiting payment\"\ntotals): per business rules, disputed referral fees must be shown separately, not folded\ninto a \"payment expected\" lifecycle stage, since the amount may still be reduced, corrected, or\nreverted.", "format": "double" }, "disputedCount": { "type": "integer", "format": "int32" } }, "additionalProperties": false }, "Debitura.Web.ReferralPartnerApi.Models.Reporting.StatusInfo": { "type": "object", "properties": { "commissionPaymentStatus": { "type": "string", "description": "Commission payment status: \"Unpaid\" | \"Paid\" | \"Credited\"\nTracks whether Debitura has received the collection partner's commission.\nPaid = fee confirmed and received by Debitura.", "nullable": true }, "platformInvoicingStatus": { "type": "string", "description": "Platform invoicing status: \"NotInvoiced\" | \"InvoiceIssued\" | \"PaymentReceived\" | \"InvoiceCredited\"\nTracks Debitura's invoicing lifecycle with the collection partner.", "nullable": true }, "referralInvoicingStatus": { "type": "string", "description": "Referral invoicing status: \"Pending\" | \"Invoiced\" | \"Paid\" | \"Disputed\"\nTracks the referral partner's invoicing with Debitura. Set only via manual DB operation β€”\nno application code path writes anything but \"Pending\" (at payout creation).", "nullable": true } }, "additionalProperties": false }, "Debitura.Web.ReferralPartnerApi.Models.Reporting.TransactionItem": { "type": "object", "properties": { "transactionId": { "type": "string", "format": "uuid" }, "date": { "type": "string", "format": "date-time" }, "client": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Reporting.ClientInfo" }, "case": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Reporting.CaseInfo" }, "payment": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Reporting.PaymentInfo" }, "earnings": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Reporting.EarningsInfo" }, "recognition": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Reporting.RecognitionInfo" }, "status": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Reporting.StatusInfo" } }, "additionalProperties": false }, "Debitura.Web.ReferralPartnerApi.Models.Reporting.TransactionRevenueStage": { "enum": [ 0, 1, 2, 3, 4, 5, 6 ], "type": "integer", "description": "The 7-stage revenue lifecycle used by Debitura.Web.ReferralPartnerApi.Models.Reporting.RevenueBreakdown β€” one\nvalue per bucket, in the same order/naming as the summary. Used by Debitura.Web.ReferralPartnerApi.Models.Reporting.GetTransactionsRequest.RevenueStages\nto request the row-list for a given tab/bucket.\n \nUnlike the raw Debitura.Web.ReferralPartnerApi.Models.Reporting.GetTransactionsRequest.CommissionPaymentStatuses/\nDebitura.Web.ReferralPartnerApi.Models.Reporting.GetTransactionsRequest.PlatformInvoicingStatuses/Debitura.Web.ReferralPartnerApi.Models.Reporting.GetTransactionsRequest.ReferralInvoicingStatuses\nfilters (which AND together independently), this filter reproduces the exact per-stage predicate the\nsummary aggregation uses to compute each bucket β€” including the ConfirmedPipeline fold:\nfor partners in ConfirmedPipeline mode, requesting Debitura.Web.ReferralPartnerApi.Models.Reporting.TransactionRevenueStage.ReadyToInvoiceDebitura also matches the\nfolded Debitura.Web.ReferralPartnerApi.Models.Reporting.TransactionRevenueStage.ConfirmedPendingInvoice/Debitura.Web.ReferralPartnerApi.Models.Reporting.TransactionRevenueStage.AwaitingCollectionPartnerPayment confirmed\nsubset, and requesting Debitura.Web.ReferralPartnerApi.Models.Reporting.TransactionRevenueStage.ConfirmedPendingInvoice/Debitura.Web.ReferralPartnerApi.Models.Reporting.TransactionRevenueStage.AwaitingCollectionPartnerPayment\nexcludes that subset β€” so a transaction row appears under exactly one stage, matching the summary badges\none-for-one. No-op difference for partners not in ConfirmedPipeline mode.", "format": "int32" }, "Debitura.Web.ReferralPartnerApi.Models.Reporting.TransactionsResponse": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Reporting.TransactionItem" }, "nullable": true }, "page": { "$ref": "#/components/schemas/Debitura.Domain.Model.Base.PageData" }, "summary": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Reporting.TransactionsSummary" } }, "additionalProperties": false, "description": "Response model for transactions list" }, "Debitura.Web.ReferralPartnerApi.Models.Reporting.TransactionsSummary": { "type": "object", "properties": { "revenue": { "$ref": "#/components/schemas/Debitura.Web.ReferralPartnerApi.Models.Reporting.RevenueBreakdown" }, "totalDebituraRevenueUsd": { "type": "number", "description": "Total Debitura revenue across all transactions for reference", "format": "double" } }, "additionalProperties": false }, "Debitura.Web.ReferralPartnerApi.Models.Webhooks.TriggerTestWebhookRequest": { "required": [ "eventType" ], "type": "object", "properties": { "eventType": { "minLength": 1, "type": "string", "description": "The webhook event type to trigger (e.g. \"case.updated\", \"client.linked\")" }, "caseId": { "type": "string", "description": "Required for case.created, case.updated, and case.closed events", "format": "uuid", "nullable": true }, "externalTenantId": { "type": "string", "description": "Required for client.* events (client.linked, client.link_declined, client.onboarding.*)", "nullable": true }, "oldLifecycle": { "type": "string", "description": "Optional override for case.updated: the \"from\" lifecycle (defaults to current case lifecycle)", "nullable": true }, "newLifecycle": { "type": "string", "description": "Optional override for case.updated: the \"to\" lifecycle (defaults to \"Closed\")", "nullable": true }, "closeCode": { "type": "string", "description": "Optional override for case.closed: the close code (defaults to \"Paid\")", "nullable": true }, "closeComment": { "type": "string", "description": "Optional override for case.closed: a close comment", "nullable": true } }, "additionalProperties": false }, "Debitura.Web.ReferralPartnerApi.Models.Webhooks.TriggerTestWebhookResponse": { "type": "object", "properties": { "eventType": { "type": "string", "nullable": true }, "enqueuedCount": { "type": "integer", "format": "int32" }, "message": { "type": "string", "nullable": true } }, "additionalProperties": false } }, "securitySchemes": { "ApiKey": { "type": "apiKey", "description": "Referral Partner API Key (use XApiKey header)", "name": "XApiKey", "in": "header" } } }, "security": [ { "ApiKey": [ ] } ], "tags": [ { "name": "Cases", "description": "Cases" }, { "name": "Clients", "description": "Clients" }, { "name": "Coverage", "description": "Coverage" }, { "name": "FilterOptions", "description": "Referral Partners" }, { "name": "OAuth" }, { "name": "PreviewCases", "description": "Cases" }, { "name": "ReferralPartners", "description": "Referral Partners" }, { "name": "Reporting", "description": "Reporting" }, { "name": "Webhooks" } ], "externalDocs": { "description": "Debitura developer documentation", "url": "https://docs.debitura.com" } }