openapi: 3.0.3 info: title: 'LegalCity API Documentation' description: 'Complete RESTful API for LegalCity debt recovery and legal services management' version: 1.0.0 servers: - url: 'https://apiv2-sandbox.legalcity.fr' tags: - name: 'API System & Health' description: "\nSystem status and API information endpoints." - name: 'Authentication & User Sessions' description: "\nEndpoints for handling user authentication, registration, and session management." - name: 'Recovery Management' description: "\nComplete API for managing debt recovery cases with support for both amicable recovery\nand legal injunction procedures. Includes CRUD operations, statistics, and injunction transfers.\nAll business rules and validation are configurable through the system settings." - name: 'Company Management' description: "\nAPIs for managing company information including customers and debtors" - name: 'Invoice Management' description: "\nAPIs for managing invoices related to debt recovery cases" - name: 'Document Management' description: "\nAPIs for managing documents related to recovery cases including correspondence,\nlegal documents, invoices, and file attachments. Use GET /api/docs/file-types\nto retrieve available document types before creating or filtering documents." - name: 'Comment Management' description: "\nAPIs for managing comments on recovery cases including internal notes,\ncommunications, and case updates with advanced visibility controls.\n\n**Visibility System**:\n- `visibleToUser`: Internal team visibility\n- `visibleToDebtor`: Debtor can see this comment\n- `visibleToBailiff`: Bailiff/legal representative access\n- `isRead`: Read/validation status tracking\n\n**Use Cases**:\n- Internal case notes and updates\n- Client communications log\n- Legal procedure documentation\n- Status change notifications" - name: 'Protected Invoice Management' description: "\nEndpoints for managing protected invoices. These endpoints handle\nsecure invoice information storage and retrieval for client billing." - name: 'Scoring Management' description: "\nEndpoints for managing credit scoring, solvency reports, and company surveillance.\nThese endpoints handle ordering and monitoring of financial assessments." components: securitySchemes: default: type: http scheme: bearer description: '' security: - default: [] paths: /api/health: get: summary: 'Health Check' operationId: healthCheck description: "Returns the current status of the API service and server timestamp.\nUse this endpoint to verify that the API is running and accessible." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: status: ok timestamp: '2025-10-31T14:30:00.000000Z' version: '2.0' properties: status: type: string example: ok timestamp: type: string example: '2025-10-31T14:30:00.000000Z' version: type: string example: '2.0' tags: - 'API System & Health' security: [] /api/info: get: summary: 'API Information' operationId: aPIInformation description: "Provides comprehensive information about the LegalCity API including\navailable endpoints, authentication details, and documentation links.\nThis endpoint is useful for API discovery and integration setup.\n\n**Features**:\n- API version and metadata\n- Documentation and collection URLs\n- Authentication endpoints\n- Main resource endpoints\n- OpenAPI specification access\n\n**Use Cases**:\n- API client initialization\n- Documentation discovery\n- Integration testing\n- Development environment setup" parameters: [] responses: 200: description: '' content: text/plain: schema: type: string example: "{\n \"api_name\": \"LegalCity Recovery API\",\n \"version\": \"2.0\",\n \"description\": \"Comprehensive API for legal debt recovery management\",\n \"documentation\": \"https://apiv2-sandbox.legalcity.fr/docs\",\n \"postman_collection\": \"https://apiv2-sandbox.legalcity.fr/docs/collection.json\",\n \"openapi_spec\": \"https://apiv2-sandbox.legalcity.fr/docs/openapi.yaml\",\n \"auth\": {\n \"type\": \"Bearer Token (OAuth2)\",\n \"login_endpoint\": \"https://apiv2-sandbox.legalcity.fr/api/auth/login\",\n \"register_endpoint\": \"https://apiv2-sandbox.legalcity.fr/api/auth/register\",\n \"logout_endpoint\": \"https://apiv2-sandbox.legalcity.fr/api/auth/logout\",\n \"me_endpoint\": \"https://apiv2-sandbox.legalcity.fr/api/auth/me\"\n },\n \"endpoints\": {\n \"auth\": \"https://apiv2-sandbox.legalcity.fr/api/auth\",\n \"recoveries\": \"https://apiv2-sandbox.legalcity.fr/api/recoveries\",\n \"companies\": \"https://apiv2-sandbox.legalcity.fr/api/recoveries/{recoveryId}/companies\",\n \"documents\": \"https://apiv2-sandbox.legalcity.fr/api/recoveries/{recoveryId}/docs\",\n \"invoices\": \"https://apiv2-sandbox.legalcity.fr/api/recoveries/{recoveryId}/invoices\",\n \"comments\": \"https://apiv2-sandbox.legalcity.fr/api/recoveries/{recoveryId}/comments\",\n \"protected_invoices\": \"https://apiv2-sandbox.legalcity.fr/api/protected-invoices\",\n \"scoring\": \"https://apiv2-sandbox.legalcity.fr/api/scoring\",\n \"health\": \"https://apiv2-sandbox.legalcity.fr/api/health\"\n },\n \"features\": {\n \"recovery_management\": \"Complete debt recovery case management\",\n \"company_tracking\": \"Customer and debtor information management\",\n \"document_upload\": \"Secure document storage and retrieval\",\n \"invoice_tracking\": \"Invoice management with payment status\",\n \"comment_system\": \"Internal and external communication tracking\",\n \"protected_invoices\": \"Secure invoice storage with tracking codes\",\n \"scoring_services\": \"Credit scoring and solvency reports\"\n },\n \"supported_formats\": {\n \"response_format\": \"JSON\",\n \"authentication\": \"Bearer Token (OAuth2)\",\n \"file_uploads\": \"PDF, DOC, DOCX, XLS, XLSX, JPG, PNG, GIF (max 10MB)\",\n \"date_format\": \"YYYY-MM-DD\",\n \"datetime_format\": \"ISO 8601 (YYYY-MM-DDTHH:mm:ss.sssZ)\"\n },\n \"rate_limits\": {\n \"login_attempts\": \"5 per minute per IP\",\n \"api_requests\": \"1000 per hour per user\",\n \"file_uploads\": \"50 per hour per user\"\n },\n \"contact\": {\n \"support\": \"amine@legalcity.fr\",\n \"documentation\": \"https://apiv2-sandbox.legalcity.fr/docs\",\n }\n}" tags: - 'API System & Health' security: [] '/api/{fallbackPlaceholder}': get: summary: 'Not Found Handler' operationId: notFoundHandler description: "Catches all undefined API routes and returns a standardized 404 error response.\nThis ensures consistent error formatting across the API." parameters: [] responses: 404: description: '' content: application/json: schema: type: object example: success: false message: 'API endpoint not found' properties: success: type: boolean example: false message: type: string example: 'API endpoint not found' tags: - 'API System & Health' security: [] parameters: - in: path name: fallbackPlaceholder description: '' example: '|{+-0p' required: true schema: type: string /api/auth/login: post: summary: Login operationId: login description: "Authenticate a user using their email and API key credentials.\nReturns an access token (Bearer) required for authorized API requests.\n\nUse this endpoint to obtain a valid authentication token before accessing\nany protected routes within the LegalCity API.\n\n**Rate Limiting**: This endpoint is limited to 5 attempts per minute per IP address.\nAfter 5 failed attempts, wait 1 minute before trying again." parameters: [] responses: 200: description: '' content: text/plain: schema: type: string example: "{\n \"success\": true,\n \"data\": {\n \"user\": {\n \"id\": 1,\n \"first_name\": \"John\",\n \"last_name\": \"Doe\",\n \"email\": \"john@example.com\",\n \"entreprise\": \"Company SARL\",\n \"can_register\": true,\n },\n \"token\": \"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9...\",\n \"token_type\": \"Bearer\"\n },\n \"message\": \"Login successful\"\n}" 401: description: '' content: application/json: schema: type: object example: success: false message: 'Invalid credentials provided' properties: success: type: boolean example: false message: type: string example: 'Invalid credentials provided' 403: description: '' content: application/json: schema: type: object example: success: false message: 'You do not have permission to access this resource.' properties: success: type: boolean example: false message: type: string example: 'You do not have permission to access this resource.' 422: description: '' content: application/json: schema: type: object example: success: false message: 'Validation failed.' errors: email: - 'The email field is required.' key: - 'The key field is required.' properties: success: type: boolean example: false message: type: string example: 'Validation failed.' errors: type: object properties: email: type: array example: - 'The email field is required.' items: type: string key: type: array example: - 'The key field is required.' items: type: string 429: description: '' content: application/json: schema: type: object example: success: false message: 'Too Many Attempts. Please wait 60 seconds before trying again.' properties: success: type: boolean example: false message: type: string example: 'Too Many Attempts. Please wait 60 seconds before trying again.' 500: description: '' content: application/json: schema: type: object example: success: false message: 'Authentication failed' properties: success: type: boolean example: false message: type: string example: 'Authentication failed' tags: - 'Authentication & User Sessions' requestBody: required: true content: application/json: schema: type: object properties: email: type: string description: "The user's registered email address." example: john@example.com nullable: false key: type: string description: "The user's unique API key." example: 06572215-cb86-4ca2-b6b1-2ba6ceb1e8a5 nullable: false required: - email - key security: [] /api/auth/register: post: summary: 'User Registration' operationId: userRegistration description: "Create a new user account or update existing user with API access.\nRequires an authenticated user with \"can_register\" permission.\n\n**Important**: This endpoint returns API credentials (api_key and auth_secret)\nfor newly registered users. Store these securely as they won't be shown again." parameters: [] responses: 200: description: '' content: text/plain: schema: type: string example: "{\n \"success\": true,\n \"data\": {\n \"user\": {\n \"id\": 1,\n \"first_name\": \"John\",\n \"last_name\": \"Doe\",\n \"email\": \"john@example.com\",\n \"entreprise\": \"Company SARL\",\n \"can_register\": false,\n \"api_key\": \"06572215-cb86-4ca2-b6b1-2ba6ceb1e8a5\",\n \"auth_secret\": \"uuid-secret-string\",\n }\n },\n \"message\": \"User already exists with API access\"\n}" 201: description: '' content: text/plain: schema: type: string example: "{\n \"success\": true,\n \"data\": {\n \"user\": {\n \"id\": 1,\n \"first_name\": \"John\",\n \"last_name\": \"Doe\",\n \"email\": \"john@example.com\",\n \"entreprise\": \"Company SARL\",\n \"can_register\": false,\n \"api_key\": \"06572215-cb86-4ca2-b6b1-2ba6ceb1e8a5\",\n \"auth_secret\": \"uuid-secret-string\",\n }\n },\n \"message\": \"User registered successfully\"\n}" 403: description: '' content: application/json: schema: type: object example: success: false message: 'You do not have permission to access this resource.' properties: success: type: boolean example: false message: type: string example: 'You do not have permission to access this resource.' 422: description: '' content: application/json: schema: type: object example: success: false message: 'Validation failed' errors: email: - 'The email field is required.' first_name: - 'The first name field is required.' properties: success: type: boolean example: false message: type: string example: 'Validation failed' errors: type: object properties: email: type: array example: - 'The email field is required.' items: type: string first_name: type: array example: - 'The first name field is required.' items: type: string tags: - 'Authentication & User Sessions' requestBody: required: true content: application/json: schema: type: object properties: first_name: type: string description: "The user's first name." example: John nullable: false last_name: type: string description: "The user's last name." example: Doe nullable: false email: type: string description: "The user's email address." example: john@example.com nullable: false entreprise: type: string description: 'Company name.' example: 'Company SARL' nullable: false siren: type: string description: 'Company SIREN number.' example: '123456789' nullable: false address: type: string description: 'Company address.' example: '123 Main St' nullable: false city: type: string description: City. example: Paris nullable: false postal: type: string description: 'Postal code.' example: '75001' nullable: false phone: type: string description: 'Phone number.' example: '+33123456789' nullable: false metadata: type: object description: 'optional Additional JSON metadata for future use.' example: custom_field: value preferences: theme: dark nullable: false properties: { } required: - first_name - last_name - email - entreprise - siren - address - city - postal - phone /api/auth/logout: post: summary: Logout operationId: logout description: "Revoke the current user's access token and invalidate the session.\nAfter logout, the provided Bearer token will no longer be valid for API requests.\n\n**Note**: Once logged out, you'll need to call the login endpoint again\nto obtain a new access token." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: success: true message: 'Logout successful' properties: success: type: boolean example: true message: type: string example: 'Logout successful' 401: description: '' content: application/json: schema: type: object example: success: false message: 'User not authenticated' properties: success: type: boolean example: false message: type: string example: 'User not authenticated' tags: - 'Authentication & User Sessions' /api/auth/refresh: post: summary: 'Refresh Token' operationId: refreshToken description: "Refresh the current access token by revoking the old one and issuing a new one.\nUse this endpoint to obtain a fresh token without requiring the user to login again.\n\n**Important**: After calling this endpoint, use the new token for all subsequent requests.\nThe old token will be immediately revoked and no longer valid.\n\n**Rate Limiting**: Limited to 10 attempts per minute to prevent abuse." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: success: true data: token: eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9... token_type: Bearer message: 'Token refreshed successfully' properties: success: type: boolean example: true data: type: object properties: token: type: string example: eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9... token_type: type: string example: Bearer message: type: string example: 'Token refreshed successfully' 401: description: '' content: application/json: schema: type: object example: success: false message: 'User not authenticated' properties: success: type: boolean example: false message: type: string example: 'User not authenticated' 500: description: '' content: application/json: schema: type: object example: success: false message: 'Token refresh failed' properties: success: type: boolean example: false message: type: string example: 'Token refresh failed' tags: - 'Authentication & User Sessions' /api/auth/me: get: summary: 'Get Authenticated User' operationId: getAuthenticatedUser description: "Retrieve the currently authenticated user's profile information including\nAPI access status and registration permissions.\n\nUse this endpoint to verify your authentication status and get current user details." parameters: [] responses: 200: description: '' content: text/plain: schema: type: string example: "{\n \"success\": true,\n \"data\": {\n \"id\": 1,\n \"first_name\": \"John\",\n \"last_name\": \"Doe\",\n \"email\": \"john@example.com\",\n \"entreprise\": \"Company SARL\",\n \"can_register\": true,\n },\n \"message\": \"User retrieved successfully\"\n}" 401: description: '' content: application/json: schema: type: object example: success: false message: Unauthenticated properties: success: type: boolean example: false message: type: string example: Unauthenticated tags: - 'Authentication & User Sessions' /api/recoveries/complete: post: summary: 'Create Complete Recovery Case' operationId: createCompleteRecoveryCase description: "Create a complete recovery case with customer, debtor companies, and invoices in a single request.\nThis endpoint combines the functionality of creating a recovery case, customer company, debtor company,\nand multiple invoices in one atomic transaction.\n\n**Workflow:**\n1. Creates the recovery case with all financial parameters\n2. Creates customer company (creditor) and associates it with recovery\n3. Creates debtor company and associates it with recovery\n4. Creates all provided invoices and associates them with recovery\n5. Updates recovery totals based on invoice amounts\n\n**Important Notes:**\n- All operations are performed in a database transaction (atomic operation)\n- If any step fails, all changes are rolled back automatically\n- Customer and debtor companies are mandatory\n- Invoices are optional: you can send 0, 1, or multiple invoices in an array\n- Each invoice must have a unique invoice_number\n\n**Invoice Array Examples:**\n```json\n// No invoices\n\"invoices\": []\n\n// Single invoice\n\"invoices\": [\n {\"invoice_number\": \"INV-001\", \"invoice_date\": \"2025-10-20\", \"invoice_amount\": 1500.00}\n]\n\n// Multiple invoices\n\"invoices\": [\n {\"invoice_number\": \"INV-001\", \"invoice_date\": \"2025-10-20\", \"invoice_amount\": 1500.00},\n {\"invoice_number\": \"INV-002\", \"invoice_date\": \"2025-10-21\", \"invoice_amount\": 2000.00, \"invoice_part_paid\": true, \"invoice_part_paid_amount\": 500.00},\n {\"invoice_number\": \"INV-003\", \"invoice_date\": \"2025-10-22\", \"invoice_amount\": 800.00}\n]\n```" parameters: [] responses: 201: description: '' content: application/json: schema: type: object example: success: true data: recovery: id: 25 recovery_reference: REC-XYZ123 recovery_service_object: 'Web development services' recovery_last_status: 1 recovery_due_date: '2025-12-31' amount: '3000.00' amount_torecover: '3000.00' user_id: 1 created_at: '2025-12-07T10:30:00.000000Z' customer: id: 15 company_name: 'ABC Corp' company_legalrep_firstname: John company_legalrep_lastname: Doe company_email: john@abc.com debtor: id: 16 company_name: 'XYZ Ltd' company_legalrep_firstname: Jane company_legalrep_lastname: Smith company_email: jane@xyz.com invoices: - id: 42 invoice_number: INV-2025-001 invoice_amount: '1500.00' invoice_date: '2025-10-20' remaining_amount: '1500.00' - id: 43 invoice_number: INV-2025-002 invoice_amount: '1500.00' invoice_date: '2025-10-21' remaining_amount: '1500.00' summary: total_invoices: 2 total_amount: '3000.00' total_remaining: '3000.00' message: 'Complete recovery case created successfully' properties: success: type: boolean example: true data: type: object properties: recovery: type: object properties: id: type: integer example: 25 recovery_reference: type: string example: REC-XYZ123 recovery_service_object: type: string example: 'Web development services' recovery_last_status: type: integer example: 1 recovery_due_date: type: string example: '2025-12-31' amount: type: string example: '3000.00' amount_torecover: type: string example: '3000.00' user_id: type: integer example: 1 created_at: type: string example: '2025-12-07T10:30:00.000000Z' customer: type: object properties: id: type: integer example: 15 company_name: type: string example: 'ABC Corp' company_legalrep_firstname: type: string example: John company_legalrep_lastname: type: string example: Doe company_email: type: string example: john@abc.com debtor: type: object properties: id: type: integer example: 16 company_name: type: string example: 'XYZ Ltd' company_legalrep_firstname: type: string example: Jane company_legalrep_lastname: type: string example: Smith company_email: type: string example: jane@xyz.com invoices: type: array example: - id: 42 invoice_number: INV-2025-001 invoice_amount: '1500.00' invoice_date: '2025-10-20' remaining_amount: '1500.00' - id: 43 invoice_number: INV-2025-002 invoice_amount: '1500.00' invoice_date: '2025-10-21' remaining_amount: '1500.00' items: type: object properties: id: type: integer example: 42 invoice_number: type: string example: INV-2025-001 invoice_amount: type: string example: '1500.00' invoice_date: type: string example: '2025-10-20' remaining_amount: type: string example: '1500.00' summary: type: object properties: total_invoices: type: integer example: 2 total_amount: type: string example: '3000.00' total_remaining: type: string example: '3000.00' message: type: string example: 'Complete recovery case created successfully' 422: description: '' content: application/json: schema: type: object example: success: false message: 'Validation failed' errors: recovery.recovery_service_object: - 'The recovery service object field is required.' customer.company_legalrep_firstname: - 'The customer legal representative first name is required.' debtor.company_legalrep_lastname: - 'The debtor legal representative last name is required.' invoices.0.invoice_number: - 'The invoice number field is required.' properties: success: type: boolean example: false message: type: string example: 'Validation failed' errors: type: object properties: recovery.recovery_service_object: type: array example: - 'The recovery service object field is required.' items: type: string customer.company_legalrep_firstname: type: array example: - 'The customer legal representative first name is required.' items: type: string debtor.company_legalrep_lastname: type: array example: - 'The debtor legal representative last name is required.' items: type: string invoices.0.invoice_number: type: array example: - 'The invoice number field is required.' items: type: string 500: description: '' content: application/json: schema: type: object example: success: false message: 'Failed to create complete recovery case' properties: success: type: boolean example: false message: type: string example: 'Failed to create complete recovery case' tags: - 'Recovery Management' requestBody: required: true content: application/json: schema: type: object properties: recovery: type: object description: 'Recovery case information' example: [] nullable: false properties: recovery_service_object: type: string description: 'Description of the service or product.' example: 'Web development services' nullable: false recovery_due_date: type: date description: 'Payment due date.' example: '2025-12-31' nullable: false recovery_late_interest: type: boolean description: 'optional Apply late payment interest. Default: false.' example: true nullable: false recovery_interest_rate: type: string description: 'optional Interest rate type (yes/no).' example: 'yes' nullable: false recovery_interest_rate_percent: type: numeric description: "optional Interest rate percentage (0-100). Required if recovery_interest_rate is 'yes'." example: '5.50' nullable: false recovery_penalty: type: boolean description: 'optional Apply penalty. Default: false.' example: true nullable: false recovery_penalty_type: type: string description: 'optional Penalty type (montant/pourcent). Required if recovery_penalty is true.' example: montant nullable: false recovery_penalty_amount: type: numeric description: "optional Penalty fixed amount. Required if penalty_type is 'montant'." example: '150.00' nullable: false recovery_penalty_percent: type: numeric description: "optional Penalty percentage. Required if penalty_type is 'pourcent'." example: '10.00' nullable: false recovery_raison_notpaid: type: integer description: 'optional Reason code for non-payment.' example: 1 nullable: false recovery_observations: type: string description: 'optional Additional observations.' example: 'Client experiencing financial difficulties' nullable: false type: type: integer description: 'optional Recovery type (1=amicable, 2=injunction). Default: 1.' example: 1 nullable: false assign_to_me: type: boolean description: 'optional Assign case to authenticated user. Default: true.' example: true nullable: false required: - recovery_service_object - recovery_due_date customer: type: object description: 'Customer (creditor) company information' example: [] nullable: false properties: company_type: type: string description: 'optional Company type (particular, commercial, freelance, liberal, civil, association).' example: commercial nullable: false company_legal_form: type: string description: 'optional Legal form (SAS, SARL, SA, SNC, GIE). Required for commercial/civil/association.' example: SARL nullable: false company_siren: type: string description: 'optional SIREN number. Required for commercial/civil/association.' example: '123456789' nullable: false company_name: type: string description: 'optional Company name. Required for commercial/civil/association.' example: 'ABC Corp' nullable: false company_legalrep_firstname: type: string description: 'Legal representative first name.' example: John nullable: false company_legalrep_lastname: type: string description: 'Legal representative last name.' example: Doe nullable: false company_legalrep_gender: type: string description: 'optional Gender (M, Mme).' example: M nullable: false company_legalrep_quality: type: integer description: 'optional Representative quality/position.' example: 1 nullable: false company_address: type: string description: 'optional Full address.' example: '123 Main St' nullable: false company_city: type: string description: 'optional City.' example: Paris nullable: false company_postal: type: string description: 'optional Postal code.' example: '75001' nullable: false company_country: type: string description: 'optional Country.' example: France nullable: false company_email: type: email description: 'optional Email address.' example: john@abc.com nullable: false company_phone: type: string description: 'optional Phone number.' example: '+33123456789' nullable: false required: - company_legalrep_firstname - company_legalrep_lastname debtor: type: object description: 'Debtor company information (same fields as customer)' example: [] nullable: false properties: company_type: type: string description: 'optional Company type.' example: commercial nullable: false company_legal_form: type: string description: 'optional Legal form.' example: SAS nullable: false company_siren: type: string description: 'optional SIREN number.' example: '987654321' nullable: false company_name: type: string description: 'optional Company name.' example: 'XYZ Ltd' nullable: false company_legalrep_firstname: type: string description: 'Legal representative first name.' example: Jane nullable: false company_legalrep_lastname: type: string description: 'Legal representative last name.' example: Smith nullable: false company_legalrep_gender: type: string description: 'optional Gender.' example: Mme nullable: false company_address: type: string description: 'optional Full address.' example: '456 Oak Ave' nullable: false company_city: type: string description: 'optional City.' example: Lyon nullable: false company_postal: type: string description: 'optional Postal code.' example: '69001' nullable: false company_country: type: string description: 'optional Country.' example: France nullable: false company_email: type: email description: 'optional Email address.' example: jane@xyz.com nullable: false company_phone: type: string description: 'optional Phone number.' example: '+33987654321' nullable: false required: - company_legalrep_firstname - company_legalrep_lastname invoices: type: array description: 'optional Array of invoice objects (0 or more)' example: - architecto items: type: string required: - recovery - customer - debtor /api/recoveries: get: summary: 'List Recovery Cases' operationId: listRecoveryCases description: "Retrieve a paginated list of debt recovery cases for the authenticated user with\nadvanced filtering, sorting, and search capabilities. Supports both amicable recovery\nand injunction procedures with comprehensive status tracking." parameters: - in: query name: status description: "optional Filter by recovery status group. Available groups:
\n• **1** = Dossier Créé
\n• **2** = Relance 1
\n• **3** = Relance 2
" example: 1 required: false schema: type: integer description: "optional Filter by recovery status group. Available groups:
\n• **1** = Dossier Créé
\n• **2** = Relance 1
\n• **3** = Relance 2
" example: 1 nullable: false - in: query name: search description: 'optional Search across multiple fields including reference, debtor name, debtor company name, and customer company name.' example: John required: false schema: type: string description: 'optional Search across multiple fields including reference, debtor name, debtor company name, and customer company name.' example: John nullable: false - in: query name: sort_by description: "optional Sort by recovery field. Available fields:
\n• **id** - Recovery ID
\n• **recovery_reference** - Recovery reference
\n• **recovery_service_object** - Service description
\n• **recovery_last_status** - Status ID
\n• **recovery_due_date** - Due date
\n• **amount** - Total amount
\n• **amount_torecover** - Amount to recover
\n• **user_id** - Assigned user ID
\n• **created_at** - Creation date
\n• **updated_at** - Last update date
\n• **debtor_name** - Debtor name
\n• **debtor_company** - Debtor company name
\n• **customer_company** - Customer company name
\nDefaults to created_at." example: recovery_reference required: false schema: type: string description: "optional Sort by recovery field. Available fields:
\n• **id** - Recovery ID
\n• **recovery_reference** - Recovery reference
\n• **recovery_service_object** - Service description
\n• **recovery_last_status** - Status ID
\n• **recovery_due_date** - Due date
\n• **amount** - Total amount
\n• **amount_torecover** - Amount to recover
\n• **user_id** - Assigned user ID
\n• **created_at** - Creation date
\n• **updated_at** - Last update date
\n• **debtor_name** - Debtor name
\n• **debtor_company** - Debtor company name
\n• **customer_company** - Customer company name
\nDefaults to created_at." example: recovery_reference nullable: false - in: query name: sort_order description: 'optional Sort order (asc/desc). Defaults to desc.' example: asc required: false schema: type: string description: 'optional Sort order (asc/desc). Defaults to desc.' example: asc nullable: false - in: query name: per_page description: 'optional Items per page (max configurable limit). Defaults to configured value.' example: 20 required: false schema: type: integer description: 'optional Items per page (max configurable limit). Defaults to configured value.' example: 20 nullable: false - in: query name: page description: 'optional Page number for pagination. Defaults to 1.' example: 1 required: false schema: type: integer description: 'optional Page number for pagination. Defaults to 1.' example: 1 nullable: false responses: 200: description: '' content: application/json: schema: type: object example: success: true data: recoveries: - id: 1 recovery_reference: REC-ABC123 debtor_name: 'John Doe' debtor_company: 'Example Corp' customer_company: 'LegalCity SARL' amount: '1500.00' amount_torecover: '1500.00' recovery_last_status: 1 recovery_due_date: '2025-11-20' created_at: '2025-10-20T10:30:00.000000Z' updated_at: '2025-10-20T10:30:00.000000Z' status: id: 1 name: 'Dossier Créé' description: 'Recovery case created and awaiting processing' user: id: 1 first_name: John last_name: Doe invoices_count: 2 comments_count: 5 pagination: current_page: 1 per_page: 15 total: 50 last_page: 4 from: 1 to: 15 has_more_pages: true filters_applied: status: 1 search: null sort_by: created_at sort_order: desc message: 'Recoveries retrieved successfully. Total: 50 recoveries found.' properties: success: type: boolean example: true data: type: object properties: recoveries: type: array example: - id: 1 recovery_reference: REC-ABC123 debtor_name: 'John Doe' debtor_company: 'Example Corp' customer_company: 'LegalCity SARL' amount: '1500.00' amount_torecover: '1500.00' recovery_last_status: 1 recovery_due_date: '2025-11-20' created_at: '2025-10-20T10:30:00.000000Z' updated_at: '2025-10-20T10:30:00.000000Z' status: id: 1 name: 'Dossier Créé' description: 'Recovery case created and awaiting processing' user: id: 1 first_name: John last_name: Doe invoices_count: 2 comments_count: 5 items: type: object properties: id: type: integer example: 1 recovery_reference: type: string example: REC-ABC123 debtor_name: type: string example: 'John Doe' debtor_company: type: string example: 'Example Corp' customer_company: type: string example: 'LegalCity SARL' amount: type: string example: '1500.00' amount_torecover: type: string example: '1500.00' recovery_last_status: type: integer example: 1 recovery_due_date: type: string example: '2025-11-20' created_at: type: string example: '2025-10-20T10:30:00.000000Z' updated_at: type: string example: '2025-10-20T10:30:00.000000Z' status: type: object properties: id: type: integer example: 1 name: type: string example: 'Dossier Créé' description: type: string example: 'Recovery case created and awaiting processing' user: type: object properties: id: type: integer example: 1 first_name: type: string example: John last_name: type: string example: Doe invoices_count: type: integer example: 2 comments_count: type: integer example: 5 pagination: type: object properties: current_page: type: integer example: 1 per_page: type: integer example: 15 total: type: integer example: 50 last_page: type: integer example: 4 from: type: integer example: 1 to: type: integer example: 15 has_more_pages: type: boolean example: true filters_applied: type: object properties: status: type: integer example: 1 search: type: string example: null sort_by: type: string example: created_at sort_order: type: string example: desc message: type: string example: 'Recoveries retrieved successfully. Total: 50 recoveries found.' 401: description: '' content: application/json: schema: type: object example: success: false message: Unauthenticated properties: success: type: boolean example: false message: type: string example: Unauthenticated 422: description: '' content: application/json: schema: type: object example: success: false message: 'Validation failed' errors: status: - 'The selected status filter is invalid.' sort_by: - 'The selected sort field is invalid.' per_page: - 'The per page field must be between 1 and 100.' properties: success: type: boolean example: false message: type: string example: 'Validation failed' errors: type: object properties: status: type: array example: - 'The selected status filter is invalid.' items: type: string sort_by: type: array example: - 'The selected sort field is invalid.' items: type: string per_page: type: array example: - 'The per page field must be between 1 and 100.' items: type: string tags: - 'Recovery Management' post: summary: '' operationId: postApiRecoveries description: '' parameters: [] responses: { } tags: - 'Recovery Management' security: [] '/api/recoveries/{id}': get: summary: 'Get Recovery Case Details' operationId: getRecoveryCaseDetails description: "Retrieve comprehensive details of a specific recovery case including all related entities:\ncompanies, invoices, documents, comments, status history, payments, and debts.\nIncludes ownership verification for security." parameters: [] responses: 200: description: '' content: text/plain: schema: type: string example: "{\n \"success\": true,\n \"data\": {\n \"id\": 15,\n \"recovery_reference\": \"REC-ABC123\",\n \"recovery_status\": 2,\n \"amount\": \"1500.00\",\n \"amount_torecover\": \"1500.00\",\n \"user\": {...},\n \"customer\": {...},\n \"debtor\": {...},\n \"status\": {...},\n \"statusHistory\": [...],\n \"invoices\": [...],\n \"docs\": [...],\n \"comments\": [...],\n \"acomptes\": [...],\n \"dettes\": [...],\n \"all_docs\": [...]\n },\n \"message\": \"Recovery retrieved successfully\"\n}" 403: description: '' content: application/json: schema: type: object example: success: false message: 'Unauthorized access to this recovery' properties: success: type: boolean example: false message: type: string example: 'Unauthorized access to this recovery' 404: description: '' content: application/json: schema: type: object example: success: false message: 'Recovery not found' properties: success: type: boolean example: false message: type: string example: 'Recovery not found' tags: - 'Recovery Management' put: summary: 'Update Recovery Case' operationId: updateRecoveryCase description: "Update an existing recovery case with new information. Uses configurable validation rules\nfor updates and maintains data integrity. Only the recovery owner can modify the case." parameters: [] responses: 200: description: '' content: text/plain: schema: type: string example: "{\n \"success\": true,\n \"data\": {\n \"id\": 15,\n \"recovery_reference\": \"REC-ABC123\",\n \"recovery_service_object\": \"Updated web development services\",\n \"updated_at\": \"2025-10-23T15:30:00.000000Z\",\n \"user\": {...},\n \"customer\": {...},\n \"debtor\": {...},\n \"status\": {...}\n },\n \"message\": \"Recovery updated successfully\"\n}" 403: description: '' content: application/json: schema: oneOf: - description: '' type: object example: success: false message: 'Unauthorized access to this recovery' properties: success: type: boolean example: false message: type: string example: 'Unauthorized access to this recovery' - description: '' type: object example: success: false message: 'Recovery cannot be modified. Only recoveries with status 1 or 2 can be updated.' properties: success: type: boolean example: false message: type: string example: 'Recovery cannot be modified. Only recoveries with status 1 or 2 can be updated.' 404: description: '' content: application/json: schema: type: object example: success: false message: 'Recovery not found' properties: success: type: boolean example: false message: type: string example: 'Recovery not found' 422: description: '' content: application/json: schema: type: object example: success: false message: 'Validation failed' errors: recovery_interest_rate_percent: - 'The interest rate must be between 0 and 100.' properties: success: type: boolean example: false message: type: string example: 'Validation failed' errors: type: object properties: recovery_interest_rate_percent: type: array example: - 'The interest rate must be between 0 and 100.' items: type: string tags: - 'Recovery Management' requestBody: required: false content: application/json: schema: type: object properties: type: type: integer description: "optional Recovery type. Available options:
\n• **1** = Amicable recovery
\n• **2** = Injunction procedure
" example: 1 nullable: false recovery_service_object: type: string description: 'optional Updated description of services/products.' example: 'Updated web development services' nullable: false recovery_raison_notpaid: type: integer description: "optional Updated reason for non-payment. Available options:
\n• **0** = Other
\n• **1** = Bad payer
\n• **2** = Temporary financial difficulties
\n• **3** = Major financial difficulties
\n• **4** = Service poorly performed
\n• **5** = Service partially carried out
\n• **6** = Service never requested
\n• **7** = None
\n• **8** = Other
" example: 3 nullable: false recovery_observations: type: string description: 'optional Updated additional observations.' example: 'Latest client communication' nullable: false recovery_due_date: type: date description: 'optional Updated due date for payment.' example: '2026-01-31' nullable: false recovery_late_interest: type: boolean description: 'optional Updated late interest setting. When false, recovery_interest_rate and recovery_interest_rate_percent must be null.' example: true nullable: false recovery_interest_rate: type: string description: "optional Updated interest rate type (required when recovery_late_interest is true). Available options:
\n• **no** = No interest rate
\n• **yes** = Custom rate (requires recovery_interest_rate_percent)
\n• **yes 3** = Legal rate (3x)
\nMust be null when recovery_late_interest is false." example: 'yes' nullable: false recovery_interest_rate_percent: type: numeric description: 'optional Updated interest rate percentage (0-100). Required when recovery_interest_rate is "yes", otherwise must be null.' example: '6.0' nullable: false recovery_penalty: type: boolean description: 'optional Updated penalty setting. When false, recovery_penalty_type, recovery_penalty_amount and recovery_penalty_percent must be null.' example: false nullable: false recovery_penalty_type: type: string description: "optional Updated penalty calculation type (required when recovery_penalty is true). Available options:
\n• **amount** = Fixed amount (requires recovery_penalty_amount)
\n• **percent** = Percentage (requires recovery_penalty_percent)
\nMust be null when recovery_penalty is false." example: amount nullable: false recovery_penalty_amount: type: numeric description: 'optional Updated fixed penalty amount. Required when recovery_penalty_type is "amount", otherwise must be null.' example: '150.00' nullable: false recovery_penalty_percent: type: numeric description: 'optional Updated penalty percentage (0-100). Required when recovery_penalty_type is "percent", otherwise must be null.' example: '12.0' nullable: false delete: summary: 'Delete Recovery Case' operationId: deleteRecoveryCase description: "Permanently delete a recovery case from the system. This action is irreversible and\nwill cascade delete all related entities including companies, invoices, comments,\nand status history. Only the recovery owner can delete the case." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: success: true message: 'Recovery deleted successfully' properties: success: type: boolean example: true message: type: string example: 'Recovery deleted successfully' 403: description: '' content: application/json: schema: oneOf: - description: '' type: object example: success: false message: 'Unauthorized access to this recovery' properties: success: type: boolean example: false message: type: string example: 'Unauthorized access to this recovery' - description: '' type: object example: success: false message: 'Recovery cannot be modified. Only recoveries with status 1 or 2 can be updated.' properties: success: type: boolean example: false message: type: string example: 'Recovery cannot be modified. Only recoveries with status 1 or 2 can be updated.' 404: description: '' content: application/json: schema: type: object example: success: false message: 'Recovery not found' properties: success: type: boolean example: false message: type: string example: 'Recovery not found' tags: - 'Recovery Management' parameters: - in: path name: id description: 'The ID of the recovery case.' example: '15' required: true schema: type: string '/api/recoveries/{recovery}/injonction-transfer': post: summary: 'Transfer Recovery to Injunction Procedure' operationId: transferRecoveryToInjunctionProcedure description: "Transform an amicable recovery case into a legal injunction procedure (\"injonction de payer\").\nThis endpoint validates eligibility requirements and handles the complete transfer process\nincluding entity duplication, specialized configuration, and legal procedure tracking.\nSupports both national and European injunction procedures based on debtor country and business rules.\n\n**Eligibility Requirements:**\n- Recovery must be owned by authenticated user\n- Recovery status must be between 3 and 908 (configured range)\n- No existing injunction link (injonction_id must be null)\n- Debtor must be in allowed countries (configurable list)\n- Must have eligible products/services or proper access configuration\n- Validates order details and product eligibility\n\n**Process Flow:**\n1. Validates ownership (404 if not found, 403 if unauthorized)\n2. Validates eligibility requirements (status, debtor country, product eligibility)\n3. Creates new injunction recovery with specialized configuration\n4. Duplicates customer and debtor companies with data integrity\n5. Copies unpaid/partially paid invoices only\n6. Duplicates all recovery comments with visibility settings\n7. Creates initial status history record\n8. Links original recovery to new injunction case\n9. Generates payment URLs and references" parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: success: true data: id: 45 reference: REC-INJC1234 type: 'INJONCTION DE PAYER' assign_to_me: true customer_ref: CUST-ABC123 debtor_ref: DEBT-DEF456 url_pay: 'https://api.legalcity.fr/injonction/INJC1234KEY' message: 'Recovery successfully transferred to injunction procedure' properties: success: type: boolean example: true data: type: object properties: id: type: integer example: 45 reference: type: string example: REC-INJC1234 type: type: string example: 'INJONCTION DE PAYER' assign_to_me: type: boolean example: true customer_ref: type: string example: CUST-ABC123 debtor_ref: type: string example: DEBT-DEF456 url_pay: type: string example: 'https://api.legalcity.fr/injonction/INJC1234KEY' message: type: string example: 'Recovery successfully transferred to injunction procedure' 403: description: '' content: application/json: schema: oneOf: - description: '' type: object example: success: false message: 'Unauthorized access to this recovery' properties: success: type: boolean example: false message: type: string example: 'Unauthorized access to this recovery' - description: '' type: object example: success: false message: 'This recovery is not eligible for injunction transfer' properties: success: type: boolean example: false message: type: string example: 'This recovery is not eligible for injunction transfer' 404: description: '' content: application/json: schema: type: object example: success: false message: 'Recovery not found' properties: success: type: boolean example: false message: type: string example: 'Recovery not found' 500: description: '' content: application/json: schema: type: object example: success: false message: 'An error occurred during injunction transfer' properties: success: type: boolean example: false message: type: string example: 'An error occurred during injunction transfer' tags: - 'Recovery Management' parameters: - in: path name: recovery description: 'The ID of the recovery case to transfer to injunction.' example: 15 required: true schema: type: integer '/api/recoveries/{recoveryId}/companies': get: summary: 'List Companies' operationId: listCompanies description: 'Get a paginated list of companies for a specific recovery case with optional filtering and search.' parameters: - in: query name: search description: 'optional Search in company name, firstname, lastname, email, phone, or SIREN.' example: LegalCity required: false schema: type: string description: 'optional Search in company name, firstname, lastname, email, phone, or SIREN.' example: LegalCity nullable: false - in: query name: relation_type description: 'optional Filter by relation type in recovery (customer, debtor).' example: customer required: false schema: type: string description: 'optional Filter by relation type in recovery (customer, debtor).' example: customer nullable: false - in: query name: sort_by description: 'optional Sort by field. Defaults to company_legalrep_lastname.' example: company_name required: false schema: type: string description: 'optional Sort by field. Defaults to company_legalrep_lastname.' example: company_name nullable: false - in: query name: sort_order description: 'optional Sort order (asc/desc). Defaults to asc.' example: desc required: false schema: type: string description: 'optional Sort order (asc/desc). Defaults to asc.' example: desc nullable: false - in: query name: per_page description: 'optional Items per page (max 100). Defaults to 15.' example: 20 required: false schema: type: integer description: 'optional Items per page (max 100). Defaults to 15.' example: 20 nullable: false - in: query name: page description: 'optional Page number. Defaults to 1.' example: 1 required: false schema: type: integer description: 'optional Page number. Defaults to 1.' example: 1 nullable: false responses: 200: description: '' content: text/plain: schema: type: string example: "{\n \"success\": true,\n \"data\": {\n \"companies\": [\n {\n \"id\": 1,\n \"company_type\": \"commercial\",\n \"company_legal_form\": \"SARL\",\n \"company_siren\": \"123456789\",\n \"company_name\": \"LegalCity SARL\",\n \"company_legalrep_gender\": \"M\",\n \"company_legalrep_firstname\": \"John\",\n \"company_legalrep_lastname\": \"Doe\",\n \"company_address\": \"123 Avenue des Champs\",\n \"company_city\": \"Paris\",\n \"company_postal\": \"75008\",\n \"company_country\": \"France\",\n \"company_email\": \"contact@legalcity.com\",\n \"company_phone\": \"+33123456789\",\n }\n ],\n \"pagination\": {\n \"current_page\": 1,\n \"per_page\": 15,\n \"total\": 25,\n \"last_page\": 2,\n \"from\": 1,\n \"to\": 15,\n \"has_more_pages\": true\n },\n \"filters_applied\": {\n \"search\": \"LegalCity\",\n \"relation_type\": \"customer\",\n \"sort_by\": \"company_legalrep_lastname\",\n \"sort_order\": \"asc\"\n }\n },\n \"message\": \"Companies retrieved successfully\"\n}" 401: description: '' content: application/json: schema: type: object example: success: false message: Unauthenticated properties: success: type: boolean example: false message: type: string example: Unauthenticated 404: description: '' content: application/json: schema: type: object example: success: false message: 'Recovery case not found' properties: success: type: boolean example: false message: type: string example: 'Recovery case not found' 422: description: '' content: application/json: schema: type: object example: success: false message: 'Validation failed' errors: per_page: - 'The per page field must be between 1 and 100.' relation_type: - 'The relation type must be either customer or debtor.' properties: success: type: boolean example: false message: type: string example: 'Validation failed' errors: type: object properties: per_page: type: array example: - 'The per page field must be between 1 and 100.' items: type: string relation_type: type: array example: - 'The relation type must be either customer or debtor.' items: type: string tags: - 'Company Management' post: summary: 'Create Company for Recovery' operationId: createCompanyForRecovery description: "Create a new company that MUST be associated with the specified recovery case.\nEach recovery can have exactly 2 companies: 1 customer (creditor) and 1 debtor." parameters: [] responses: 201: description: '' content: text/plain: schema: type: string example: "{\n \"success\": true,\n \"data\": {\n \"id\": 10,\n \"company_type\": \"commercial\",\n \"company_legal_form\": \"SARL\",\n \"company_siren\": \"123456789\",\n \"company_name\": \"LegalCity SARL\",\n \"company_legalrep_gender\": \"M\",\n \"company_legalrep_firstname\": \"John\",\n \"company_legalrep_lastname\": \"Doe\",\n \"company_address\": \"123 Avenue des Champs\",\n \"company_city\": \"Paris\",\n \"company_postal\": \"75008\",\n \"company_country\": \"France\",\n \"company_email\": \"contact@legalcity.com\",\n \"company_phone\": \"+33123456789\",\n },\n \"message\": \"Company created and associated with recovery successfully\"\n}" 403: description: '' content: application/json: schema: oneOf: - description: '' type: object example: success: false message: 'Unauthorized access to this recovery' properties: success: type: boolean example: false message: type: string example: 'Unauthorized access to this recovery' - description: '' type: object example: success: false message: 'Recovery cannot be modified. Only recoveries with status 1 or 2 can be updated.' properties: success: type: boolean example: false message: type: string example: 'Recovery cannot be modified. Only recoveries with status 1 or 2 can be updated.' 404: description: '' content: application/json: schema: type: object example: success: false message: 'Recovery not found' properties: success: type: boolean example: false message: type: string example: 'Recovery not found' 422: description: '' content: application/json: schema: type: object example: success: false message: 'Validation failed' errors: relation_type: - 'The relation type field is required.' company_legalrep_firstname: - 'The company legalrep firstname field is required.' company_name: - 'The company name field is required when company type is commercial.' properties: success: type: boolean example: false message: type: string example: 'Validation failed' errors: type: object properties: relation_type: type: array example: - 'The relation type field is required.' items: type: string company_legalrep_firstname: type: array example: - 'The company legalrep firstname field is required.' items: type: string company_name: type: array example: - 'The company name field is required when company type is commercial.' items: type: string 500: description: '' content: application/json: schema: type: object example: success: false message: 'Failed to create company: This recovery case already has a customer. Each recovery can have only one customer and one debtor.' properties: success: type: boolean example: false message: type: string example: 'Failed to create company: This recovery case already has a customer. Each recovery can have only one customer and one debtor.' tags: - 'Company Management' requestBody: required: true content: application/json: schema: type: object properties: relation_type: type: string description: 'Type of relation (customer=creditor, debtor=debtor).' example: customer nullable: false company_type: type: string description: 'optional Company type (particular, commercial, freelance, liberal, civil, association). Can be null.' example: commercial nullable: false company_legal_form: type: string description: 'optional Legal form (SAS, SARL, SA, SNC, GIE). Required when company_type is commercial/civil/association, null otherwise.' example: SARL nullable: false company_siren: type: string description: 'optional SIREN number. Required when company_type is commercial/civil/association, optional for freelance, null for others.' example: '123456789' nullable: false company_name: type: string description: 'optional Company name. Required when company_type is commercial/civil/association, null otherwise.' example: 'Example Corp' nullable: false company_legalrep_firstname: type: string description: 'Legal representative first name.' example: John nullable: false company_legalrep_lastname: type: string description: 'Legal representative last name.' example: Doe nullable: false company_legalrep_gender: type: string description: 'optional Legal representative gender (M, Mme). Can be null.' example: M nullable: false company_legalrep_quality: type: integer description: 'optional Legal representative quality. For SAS/SA/GIE: 1=Président, 2=Directeur Général, 5=Autre. For SARL/SNC: 3=Gérant, 4=Co-Gérant, 5=Autre. Can be null.' example: 1 nullable: false company_legalrep_quality_other: type: string description: 'optional Description when quality=5 (Autre). Required when quality=5, null otherwise.' example: Fondateur nullable: false company_freelance_type: type: string description: 'optional Freelance type (trader, artisan). Only allowed when company_type is freelance, null otherwise.' example: trader nullable: false company_address: type: string description: 'optional Full address.' example: '123 Main Street' nullable: false company_city: type: string description: 'optional City.' example: Paris nullable: false company_postal: type: string description: 'optional Postal code.' example: '75001' nullable: false company_country: type: string description: 'optional Country.' example: France nullable: false company_email: type: email description: 'optional Email address.' example: john@example.com nullable: false company_phone: type: string description: 'optional Phone number.' example: '+33123456789' nullable: false required: - relation_type - company_legalrep_firstname - company_legalrep_lastname parameters: - in: path name: recoveryId description: 'ID of the recovery case.' example: 5 required: true schema: type: integer '/api/recoveries/{recoveryId}/companies/{companyId}': get: summary: 'Display the specified company.' operationId: displayTheSpecifiedCompany description: '' parameters: [] responses: 200: description: '' content: text/plain: schema: type: string example: "{\n \"success\": true,\n \"data\": {\n \"id\": 10,\n \"company_type\": \"commercial\",\n \"company_legal_form\": \"SARL\",\n \"company_siren\": \"123456789\",\n \"company_name\": \"Example Corp\",\n \"company_legalrep_gender\": \"M\",\n \"company_legalrep_firstname\": \"John\",\n \"company_legalrep_lastname\": \"Doe\",\n \"company_address\": \"123 Main Street\",\n \"company_city\": \"Paris\",\n \"company_postal\": \"75001\",\n \"company_country\": \"France\",\n \"company_email\": \"contact@example.com\",\n \"company_phone\": \"+33123456789\",\n },\n \"message\": \"Company retrieved successfully\"\n}" 404: description: '' content: application/json: schema: oneOf: - description: '' type: object example: success: false message: 'Company not found' properties: success: type: boolean example: false message: type: string example: 'Company not found' - description: '' type: object example: success: false message: 'Recovery case not found' properties: success: type: boolean example: false message: type: string example: 'Recovery case not found' tags: - 'Company Management' put: summary: 'Update the specified company.' operationId: updateTheSpecifiedCompany description: '' parameters: [] responses: 200: description: '' content: text/plain: schema: type: string example: "{\n \"success\": true,\n \"data\": {\n \"id\": 10,\n \"company_type\": \"commercial\",\n \"company_legal_form\": \"SARL\",\n \"company_siren\": \"123456789\",\n \"company_name\": \"Updated Corp Name\",\n \"company_legalrep_gender\": \"M\",\n \"company_legalrep_firstname\": \"John\",\n \"company_legalrep_lastname\": \"Doe\",\n \"company_address\": \"123 Main Street\",\n \"company_city\": \"Paris\",\n \"company_postal\": \"75001\",\n \"company_country\": \"France\",\n \"company_email\": \"updated@example.com\",\n \"company_phone\": \"+33123456789\",\n },\n \"message\": \"Company updated successfully\"\n}" 403: description: '' content: application/json: schema: type: object example: success: false message: 'Recovery cannot be modified. Only recoveries with status 1 or 2 can be updated.' properties: success: type: boolean example: false message: type: string example: 'Recovery cannot be modified. Only recoveries with status 1 or 2 can be updated.' 404: description: '' content: application/json: schema: oneOf: - description: '' type: object example: success: false message: 'Company not found' properties: success: type: boolean example: false message: type: string example: 'Company not found' - description: '' type: object example: success: false message: 'Recovery case not found' properties: success: type: boolean example: false message: type: string example: 'Recovery case not found' 422: description: '' content: application/json: schema: type: object example: success: false message: 'Validation failed' errors: company_email: - 'The company email must be a valid email address.' properties: success: type: boolean example: false message: type: string example: 'Validation failed' errors: type: object properties: company_email: type: array example: - 'The company email must be a valid email address.' items: type: string tags: - 'Company Management' requestBody: required: false content: application/json: schema: type: object properties: company_type: type: string description: 'optional Company type (particular, commercial, freelance, liberal, civil, association).' example: commercial nullable: false company_legal_form: type: string description: 'optional Legal form (SAS, SARL, SA, SNC, GIE).' example: SARL nullable: false company_siren: type: string description: 'optional SIREN number.' example: '123456789' nullable: false company_name: type: string description: 'optional Company name.' example: 'Updated Corp Name' nullable: false company_legalrep_firstname: type: string description: 'optional Legal representative first name.' example: John nullable: false company_legalrep_lastname: type: string description: 'optional Legal representative last name.' example: Doe nullable: false company_legalrep_gender: type: string description: 'optional Legal representative gender (M, Mme).' example: M nullable: false company_legalrep_quality: type: integer description: 'optional Legal representative quality.' example: 1 nullable: false company_legalrep_quality_other: type: string description: 'optional Description when quality=5 (Autre).' example: Fondateur nullable: false company_legalrep_birthday: type: date description: 'optional Legal representative birthday.' example: '1980-05-15' nullable: false company_legalrep_birthday_city: type: string description: 'optional Legal representative birth city.' example: Paris nullable: false company_legalrep_nationality: type: string description: 'optional Legal representative nationality.' example: French nullable: false company_legalrep_profession: type: string description: 'optional Legal representative profession.' example: Engineer nullable: false company_freelance_type: type: string description: 'optional Freelance type (trader, artisan).' example: trader nullable: false company_address: type: string description: 'optional Full address.' example: '123 Main Street' nullable: false company_city: type: string description: 'optional City.' example: Paris nullable: false company_postal: type: string description: 'optional Postal code.' example: '75001' nullable: false company_country: type: string description: 'optional Country.' example: France nullable: false company_state: type: string description: 'optional State/Region.' example: Île-de-France nullable: false company_email: type: email description: 'optional Email address.' example: updated@example.com nullable: false company_phone: type: string description: 'optional Phone number.' example: '+33123456789' nullable: false company_activity: type: string description: 'optional Company activity description.' example: 'Software Development' nullable: false delete: summary: 'Remove the specified company.' operationId: removeTheSpecifiedCompany description: '' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: success: true message: 'Company removed from recovery successfully' properties: success: type: boolean example: true message: type: string example: 'Company removed from recovery successfully' 403: description: '' content: application/json: schema: type: object example: success: false message: 'Recovery cannot be modified. Only recoveries with status 1 or 2 can be updated.' properties: success: type: boolean example: false message: type: string example: 'Recovery cannot be modified. Only recoveries with status 1 or 2 can be updated.' 404: description: '' content: application/json: schema: oneOf: - description: '' type: object example: success: false message: 'Company not found' properties: success: type: boolean example: false message: type: string example: 'Company not found' - description: '' type: object example: success: false message: 'Recovery case not found' properties: success: type: boolean example: false message: type: string example: 'Recovery case not found' 500: description: '' content: application/json: schema: type: object example: success: false message: 'Failed to delete company: Cannot delete this company - recovery would be incomplete' properties: success: type: boolean example: false message: type: string example: 'Failed to delete company: Cannot delete this company - recovery would be incomplete' tags: - 'Company Management' parameters: - in: path name: recoveryId description: 'ID of the recovery case.' example: 5 required: true schema: type: integer - in: path name: companyId description: 'ID of the company.' example: 10 required: true schema: type: integer '/api/companies/type/{type}': get: summary: 'Get Companies by Type' operationId: getCompaniesByType description: "Retrieve companies filtered by their relationship type (customer, debtor, or both)\nfor the authenticated user." parameters: [] responses: 200: description: '' content: text/plain: schema: type: string example: "{\n \"success\": true,\n \"data\": [\n {\n \"id\": 10,\n \"company_type\": \"commercial\",\n \"company_legal_form\": \"SARL\",\n \"company_siren\": \"123456789\",\n \"company_name\": \"Example Corp\",\n \"company_legalrep_gender\": \"Mme\",\n \"company_legalrep_firstname\": \"Jane\",\n \"company_legalrep_lastname\": \"Smith\",\n \"company_address\": \"456 Rue de la Paix\",\n \"company_city\": \"Lyon\",\n \"company_postal\": \"69001\",\n \"company_country\": \"France\",\n \"company_email\": \"contact@example.com\",\n \"company_phone\": \"+33987654321\",\n }\n ],\n \"message\": \"Companies of type 'customer' retrieved successfully\"\n}" 400: description: '' content: application/json: schema: type: object example: success: false message: 'Invalid type. Must be customer, debtor, or both' properties: success: type: boolean example: false message: type: string example: 'Invalid type. Must be customer, debtor, or both' 401: description: '' content: application/json: schema: type: object example: success: false message: Unauthenticated properties: success: type: boolean example: false message: type: string example: Unauthenticated tags: - 'Company Management' parameters: - in: path name: type description: 'The type of companies to filter (customer, debtor, or both).' example: customer required: true schema: type: string '/api/recoveries/{recoveryId}/invoices': get: summary: 'List Invoices' operationId: listInvoices description: 'Get a paginated list of invoices for the authenticated user with advanced filtering options.' parameters: - in: query name: is_part_paid description: 'optional Filter by partial payment status.' example: false required: false schema: type: boolean description: 'optional Filter by partial payment status.' example: false nullable: false - in: query name: search description: 'optional Search in invoice number, reference, or description.' example: INV-2025 required: false schema: type: string description: 'optional Search in invoice number, reference, or description.' example: INV-2025 nullable: false - in: query name: date_from description: 'date optional Filter invoices from this date.' example: '2025-01-01' required: false schema: type: string description: 'date optional Filter invoices from this date.' example: '2025-01-01' nullable: false - in: query name: date_to description: 'date optional Filter invoices until this date.' example: '2025-12-31' required: false schema: type: string description: 'date optional Filter invoices until this date.' example: '2025-12-31' nullable: false - in: query name: sort_by description: 'optional Sort by field. Defaults to invoice_date.' example: invoice_amount required: false schema: type: string description: 'optional Sort by field. Defaults to invoice_date.' example: invoice_amount nullable: false - in: query name: sort_order description: 'optional Sort order (asc/desc). Defaults to desc.' example: asc required: false schema: type: string description: 'optional Sort order (asc/desc). Defaults to desc.' example: asc nullable: false - in: query name: per_page description: 'optional Items per page (max 100). Defaults to 15.' example: 20 required: false schema: type: integer description: 'optional Items per page (max 100). Defaults to 15.' example: 20 nullable: false - in: query name: page description: 'optional Page number. Defaults to 1.' example: 1 required: false schema: type: integer description: 'optional Page number. Defaults to 1.' example: 1 nullable: false responses: 200: description: '' content: application/json: schema: type: object example: success: true data: invoices: - id: 1 recovery_id: 5 invoice_amount: '1500.00' invoice_number: INV-2025-001 invoice_date: '2025-10-20' invoice_due_date: '2025-11-20' invoice_part_paid: false invoice_part_paid_amount: null remaining_amount: '1500.00' api_invoice_id: CLIENT-REF-001 is_paid: false days_overdue: 5 recovery: id: 5 recovery_reference: REC-ABC123 debtor_name: 'John Doe' recovery_last_status: 1 pagination: current_page: 1 per_page: 15 total: 45 last_page: 3 from: 1 to: 15 has_more_pages: true summary: total_amount: '67500.00' total_paid: '15000.00' total_remaining: '52500.00' partially_paid_count: 8 overdue_count: 12 filters_applied: is_part_paid: false search: INV-2025 date_from: '2025-01-01' date_to: '2025-12-31' sort_by: invoice_date sort_order: desc message: 'Invoices retrieved successfully. Total: 45 invoices found.' properties: success: type: boolean example: true data: type: object properties: invoices: type: array example: - id: 1 recovery_id: 5 invoice_amount: '1500.00' invoice_number: INV-2025-001 invoice_date: '2025-10-20' invoice_due_date: '2025-11-20' invoice_part_paid: false invoice_part_paid_amount: null remaining_amount: '1500.00' api_invoice_id: CLIENT-REF-001 is_paid: false days_overdue: 5 recovery: id: 5 recovery_reference: REC-ABC123 debtor_name: 'John Doe' recovery_last_status: 1 items: type: object properties: id: type: integer example: 1 recovery_id: type: integer example: 5 invoice_amount: type: string example: '1500.00' invoice_number: type: string example: INV-2025-001 invoice_date: type: string example: '2025-10-20' invoice_due_date: type: string example: '2025-11-20' invoice_part_paid: type: boolean example: false invoice_part_paid_amount: type: string example: null remaining_amount: type: string example: '1500.00' api_invoice_id: type: string example: CLIENT-REF-001 is_paid: type: boolean example: false days_overdue: type: integer example: 5 recovery: type: object properties: id: type: integer example: 5 recovery_reference: type: string example: REC-ABC123 debtor_name: type: string example: 'John Doe' recovery_last_status: type: integer example: 1 pagination: type: object properties: current_page: type: integer example: 1 per_page: type: integer example: 15 total: type: integer example: 45 last_page: type: integer example: 3 from: type: integer example: 1 to: type: integer example: 15 has_more_pages: type: boolean example: true summary: type: object properties: total_amount: type: string example: '67500.00' total_paid: type: string example: '15000.00' total_remaining: type: string example: '52500.00' partially_paid_count: type: integer example: 8 overdue_count: type: integer example: 12 filters_applied: type: object properties: is_part_paid: type: boolean example: false search: type: string example: INV-2025 date_from: type: string example: '2025-01-01' date_to: type: string example: '2025-12-31' sort_by: type: string example: invoice_date sort_order: type: string example: desc message: type: string example: 'Invoices retrieved successfully. Total: 45 invoices found.' 401: description: '' content: application/json: schema: type: object example: success: false message: Unauthenticated properties: success: type: boolean example: false message: type: string example: Unauthenticated 404: description: '' content: application/json: schema: type: object example: success: false message: 'Recovery case not found' properties: success: type: boolean example: false message: type: string example: 'Recovery case not found' 422: description: '' content: application/json: schema: type: object example: success: false message: 'Validation failed' errors: date_from: - 'The date from field must be a valid date.' date_to: - 'The date to field must be a valid date after date from.' per_page: - 'The per page field must be between 1 and 100.' properties: success: type: boolean example: false message: type: string example: 'Validation failed' errors: type: object properties: date_from: type: array example: - 'The date from field must be a valid date.' items: type: string date_to: type: array example: - 'The date to field must be a valid date after date from.' items: type: string per_page: type: array example: - 'The per page field must be between 1 and 100.' items: type: string tags: - 'Invoice Management' post: summary: 'Create Invoice' operationId: createInvoice description: 'Create a new invoice associated with a recovery case including all financial details.' parameters: [] responses: 201: description: '' content: application/json: schema: type: object example: success: true data: id: 15 recovery_id: 5 invoice_amount: '1500.00' invoice_number: INV-2025-001 invoice_date: '2025-10-20' invoice_due_date: '2025-11-20' invoice_part_paid: false invoice_part_paid_amount: null remaining_amount: '1500.00' api_invoice_id: CLIENT-REF-123 is_paid: false days_overdue: 0 recovery: id: 5 recovery_reference: REC-ABC123 debtor_name: 'John Doe' debtor_company: 'Example Corp' message: 'Invoice created successfully' properties: success: type: boolean example: true data: type: object properties: id: type: integer example: 15 recovery_id: type: integer example: 5 invoice_amount: type: string example: '1500.00' invoice_number: type: string example: INV-2025-001 invoice_date: type: string example: '2025-10-20' invoice_due_date: type: string example: '2025-11-20' invoice_part_paid: type: boolean example: false invoice_part_paid_amount: type: string example: null remaining_amount: type: string example: '1500.00' api_invoice_id: type: string example: CLIENT-REF-123 is_paid: type: boolean example: false days_overdue: type: integer example: 0 recovery: type: object properties: id: type: integer example: 5 recovery_reference: type: string example: REC-ABC123 debtor_name: type: string example: 'John Doe' debtor_company: type: string example: 'Example Corp' message: type: string example: 'Invoice created successfully' 403: description: '' content: application/json: schema: type: object example: success: false message: 'Recovery cannot be modified. Only recoveries with status 1 or 2 can be updated.' properties: success: type: boolean example: false message: type: string example: 'Recovery cannot be modified. Only recoveries with status 1 or 2 can be updated.' 404: description: '' content: application/json: schema: type: object example: success: false message: 'Recovery case not found' properties: success: type: boolean example: false message: type: string example: 'Recovery case not found' 422: description: '' content: application/json: schema: type: object example: success: false message: 'Validation failed' errors: recovery_id: - 'The recovery id field is required.' invoice_number: - 'The invoice number field is required.' invoice_amount: - 'The invoice amount field is required.' properties: success: type: boolean example: false message: type: string example: 'Validation failed' errors: type: object properties: recovery_id: type: array example: - 'The recovery id field is required.' items: type: string invoice_number: type: array example: - 'The invoice number field is required.' items: type: string invoice_amount: type: array example: - 'The invoice amount field is required.' items: type: string tags: - 'Invoice Management' requestBody: required: true content: application/json: schema: type: object properties: invoice_number: type: string description: 'Unique invoice number.' example: INV-2025-001 nullable: false invoice_date: type: date description: 'Invoice issue date.' example: '2025-10-20' nullable: false invoice_due_date: type: date description: 'optional Payment due date (must be after invoice date).' example: '2025-11-20' nullable: false invoice_amount: type: numeric description: 'Invoice amount.' example: '1500.00' nullable: false invoice_part_paid: type: boolean description: 'optional Partial payment status.' example: false nullable: false invoice_part_paid_amount: type: numeric description: 'optional Partial payment amount.' example: '500.00' nullable: false api_invoice_id: type: string description: 'optional Internal client reference.' example: CLIENT-REF-123 nullable: false required: - invoice_number - invoice_date - invoice_amount parameters: - in: path name: recoveryId description: 'ID of the recovery case.' example: 5 required: true schema: type: integer '/api/recoveries/{recoveryId}/invoices/{invoiceId}': get: summary: 'Show Invoice' operationId: showInvoice description: 'Retrieve detailed information about a specific invoice including recovery case details and financial breakdown.' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: success: true data: id: 5 recovery_id: 3 invoice_amount: '1500.00' invoice_number: INV-2025-001 invoice_date: '2025-10-20' invoice_due_date: '2025-11-20' invoice_part_paid: false invoice_part_paid_amount: null remaining_amount: '1500.00' api_invoice_id: null is_paid: false days_overdue: 5 recovery: id: 3 recovery_reference: REC-ABC123 debtor_name: 'John Doe' debtor_company: 'Example Corp' case_status: active message: 'Invoice retrieved successfully' properties: success: type: boolean example: true data: type: object properties: id: type: integer example: 5 recovery_id: type: integer example: 3 invoice_amount: type: string example: '1500.00' invoice_number: type: string example: INV-2025-001 invoice_date: type: string example: '2025-10-20' invoice_due_date: type: string example: '2025-11-20' invoice_part_paid: type: boolean example: false invoice_part_paid_amount: type: string example: null remaining_amount: type: string example: '1500.00' api_invoice_id: type: string example: null is_paid: type: boolean example: false days_overdue: type: integer example: 5 recovery: type: object properties: id: type: integer example: 3 recovery_reference: type: string example: REC-ABC123 debtor_name: type: string example: 'John Doe' debtor_company: type: string example: 'Example Corp' case_status: type: string example: active message: type: string example: 'Invoice retrieved successfully' 404: description: '' content: application/json: schema: type: object example: success: false message: 'Invoice not found' properties: success: type: boolean example: false message: type: string example: 'Invoice not found' tags: - 'Invoice Management' put: summary: 'Update Invoice' operationId: updateInvoice description: 'Update invoice details including financial information, payment status, and related recovery case data.' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: success: true data: id: 5 recovery_id: 5 invoice_amount: '1600.00' invoice_number: INV-2025-001-UPDATED invoice_date: '2025-10-20' invoice_due_date: '2025-11-20' invoice_part_paid: true invoice_part_paid_amount: '800.00' remaining_amount: '800.00' api_invoice_id: CLIENT-REF-123-UPD is_paid: false days_overdue: 0 recovery: id: 5 recovery_reference: REC-ABC123 debtor_name: 'John Doe' debtor_company: 'Example Corp' message: 'Invoice updated successfully' properties: success: type: boolean example: true data: type: object properties: id: type: integer example: 5 recovery_id: type: integer example: 5 invoice_amount: type: string example: '1600.00' invoice_number: type: string example: INV-2025-001-UPDATED invoice_date: type: string example: '2025-10-20' invoice_due_date: type: string example: '2025-11-20' invoice_part_paid: type: boolean example: true invoice_part_paid_amount: type: string example: '800.00' remaining_amount: type: string example: '800.00' api_invoice_id: type: string example: CLIENT-REF-123-UPD is_paid: type: boolean example: false days_overdue: type: integer example: 0 recovery: type: object properties: id: type: integer example: 5 recovery_reference: type: string example: REC-ABC123 debtor_name: type: string example: 'John Doe' debtor_company: type: string example: 'Example Corp' message: type: string example: 'Invoice updated successfully' 403: description: '' content: application/json: schema: type: object example: success: false message: 'Recovery cannot be modified. Only recoveries with status 1 or 2 can be updated.' properties: success: type: boolean example: false message: type: string example: 'Recovery cannot be modified. Only recoveries with status 1 or 2 can be updated.' 404: description: '' content: application/json: schema: oneOf: - description: '' type: object example: success: false message: 'Invoice not found' properties: success: type: boolean example: false message: type: string example: 'Invoice not found' - description: '' type: object example: success: false message: 'Recovery case not found' properties: success: type: boolean example: false message: type: string example: 'Recovery case not found' 422: description: '' content: application/json: schema: type: object example: success: false message: 'Validation failed' errors: invoice_due_date: - 'The invoice due date must be after the invoice date.' invoice_part_paid_amount: - 'The partial payment amount cannot exceed the invoice amount.' properties: success: type: boolean example: false message: type: string example: 'Validation failed' errors: type: object properties: invoice_due_date: type: array example: - 'The invoice due date must be after the invoice date.' items: type: string invoice_part_paid_amount: type: array example: - 'The partial payment amount cannot exceed the invoice amount.' items: type: string tags: - 'Invoice Management' requestBody: required: false content: application/json: schema: type: object properties: invoice_number: type: string description: 'optional Unique invoice number.' example: INV-2025-001-UPDATED nullable: false invoice_date: type: date description: 'optional Invoice issue date.' example: '2025-10-20' nullable: false invoice_due_date: type: date description: 'optional Payment due date (must be after invoice date).' example: '2025-11-20' nullable: false invoice_amount: type: numeric description: 'optional Invoice amount.' example: '1600.00' nullable: false invoice_part_paid: type: boolean description: 'optional Partial payment status.' example: true nullable: false invoice_part_paid_amount: type: numeric description: 'optional Partial payment amount.' example: '800.00' nullable: false api_invoice_id: type: string description: 'optional Internal client reference.' example: CLIENT-REF-123-UPD nullable: false delete: summary: 'Delete Invoice' operationId: deleteInvoice description: 'Permanently delete an invoice from the system. This action cannot be undone.' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: success: true message: 'Invoice deleted successfully' properties: success: type: boolean example: true message: type: string example: 'Invoice deleted successfully' 403: description: '' content: application/json: schema: type: object example: success: false message: 'Recovery cannot be modified. Only recoveries with status 1 or 2 can be updated.' properties: success: type: boolean example: false message: type: string example: 'Recovery cannot be modified. Only recoveries with status 1 or 2 can be updated.' 404: description: '' content: application/json: schema: oneOf: - description: '' type: object example: success: false message: 'Invoice not found' properties: success: type: boolean example: false message: type: string example: 'Invoice not found' - description: '' type: object example: success: false message: 'Recovery case not found' properties: success: type: boolean example: false message: type: string example: 'Recovery case not found' tags: - 'Invoice Management' parameters: - in: path name: recoveryId description: 'ID of the recovery case.' example: 5 required: true schema: type: integer - in: path name: invoiceId description: 'ID of the invoice.' example: 5 required: true schema: type: integer /api/docs/file-types: get: summary: 'Get File Types' operationId: getFileTypes description: "Retrieve all active file types available for documents.\nUse this endpoint before creating documents to ensure you're using valid file type IDs.\n\n**Supported File Types**: PDF, DOC, DOCX, XLS, XLSX, JPG, PNG, GIF\n**Maximum File Size**: 10MB per file\n**Security**: All files are scanned for malware and validated for content type" parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: success: true data: - id: 1 type: Facture position: 1 active: true description: 'Invoice or billing document' - id: 2 type: Courrier position: 2 active: true description: 'General correspondence' - id: 3 type: LRAR position: 3 active: true description: 'Registered mail with acknowledgment of receipt' message: 'Active file types retrieved successfully' properties: success: type: boolean example: true data: type: array example: - id: 1 type: Facture position: 1 active: true description: 'Invoice or billing document' - id: 2 type: Courrier position: 2 active: true description: 'General correspondence' - id: 3 type: LRAR position: 3 active: true description: 'Registered mail with acknowledgment of receipt' items: type: object properties: id: type: integer example: 1 type: type: string example: Facture position: type: integer example: 1 active: type: boolean example: true description: type: string example: 'Invoice or billing document' message: type: string example: 'Active file types retrieved successfully' 401: description: '' content: application/json: schema: type: object example: success: false message: Unauthenticated properties: success: type: boolean example: false message: type: string example: Unauthenticated tags: - 'Document Management' '/api/recoveries/{recoveryId}/docs': get: summary: 'List Documents' operationId: listDocuments description: 'Get all documents for a specific recovery case with filtering and pagination.' parameters: - in: query name: search description: 'Search in document filename.' example: contrat required: false schema: type: string description: 'Search in document filename.' example: contrat nullable: false - in: query name: invoice_id description: 'Filter documents by invoice ID.' example: 3 required: false schema: type: integer description: 'Filter documents by invoice ID.' example: 3 nullable: false - in: query name: file_type description: 'Filter by file type ID (use GET /api/docs/file-types to get available types).' example: 1 required: false schema: type: integer description: 'Filter by file type ID (use GET /api/docs/file-types to get available types).' example: 1 nullable: false - in: query name: sort_by description: 'Sort field (recovery_id, file_type, invoice_id, file_created_at).' example: file_created_at required: false schema: type: string description: 'Sort field (recovery_id, file_type, invoice_id, file_created_at).' example: file_created_at nullable: false - in: query name: sort_order description: 'Sort direction (asc, desc).' example: desc required: false schema: type: string description: 'Sort direction (asc, desc).' example: desc nullable: false - in: query name: per_page description: 'Items per page (max 100).' example: 15 required: false schema: type: integer description: 'Items per page (max 100).' example: 15 nullable: false - in: query name: page description: 'Page number for pagination.' example: 1 required: false schema: type: integer description: 'Page number for pagination.' example: 1 nullable: false responses: 200: description: '' content: application/json: schema: type: object example: success: true data: documents: - id: 1 recovery_id: 5 invoice_id: 3 adminUserId: 1 fileId: 10 fileTypeId: 1 visibleToUser: true visibleToDebtor: false visibleToBailiff: false visibleToOIP: false isSigned: false created_at: '2025-10-19T15:30:00.000000Z' updated_at: '2025-10-20T10:30:00.000000Z' recovery: id: 5 recovery_reference: REC-ABC123 debtor_name: 'John Doe' debtor_company: 'Example Corp' invoice: id: 3 invoice_number: INV-2025-001 amount_ttc: '1500.00' file: id: 10 filename: document.pdf mime: application/pdf file_type_info: id: 1 type: 'Mise en demeure' pagination: current_page: 1 per_page: 15 total: 42 last_page: 3 from: 1 to: 15 has_more_pages: true message: 'Documents retrieved successfully' properties: success: type: boolean example: true data: type: object properties: documents: type: array example: - id: 1 recovery_id: 5 invoice_id: 3 adminUserId: 1 fileId: 10 fileTypeId: 1 visibleToUser: true visibleToDebtor: false visibleToBailiff: false visibleToOIP: false isSigned: false created_at: '2025-10-19T15:30:00.000000Z' updated_at: '2025-10-20T10:30:00.000000Z' recovery: id: 5 recovery_reference: REC-ABC123 debtor_name: 'John Doe' debtor_company: 'Example Corp' invoice: id: 3 invoice_number: INV-2025-001 amount_ttc: '1500.00' file: id: 10 filename: document.pdf mime: application/pdf file_type_info: id: 1 type: 'Mise en demeure' items: type: object properties: id: type: integer example: 1 recovery_id: type: integer example: 5 invoice_id: type: integer example: 3 adminUserId: type: integer example: 1 fileId: type: integer example: 10 fileTypeId: type: integer example: 1 visibleToUser: type: boolean example: true visibleToDebtor: type: boolean example: false visibleToBailiff: type: boolean example: false visibleToOIP: type: boolean example: false isSigned: type: boolean example: false created_at: type: string example: '2025-10-19T15:30:00.000000Z' updated_at: type: string example: '2025-10-20T10:30:00.000000Z' recovery: type: object properties: id: type: integer example: 5 recovery_reference: type: string example: REC-ABC123 debtor_name: type: string example: 'John Doe' debtor_company: type: string example: 'Example Corp' invoice: type: object properties: id: type: integer example: 3 invoice_number: type: string example: INV-2025-001 amount_ttc: type: string example: '1500.00' file: type: object properties: id: type: integer example: 10 filename: type: string example: document.pdf mime: type: string example: application/pdf file_type_info: type: object properties: id: type: integer example: 1 type: type: string example: 'Mise en demeure' pagination: type: object properties: current_page: type: integer example: 1 per_page: type: integer example: 15 total: type: integer example: 42 last_page: type: integer example: 3 from: type: integer example: 1 to: type: integer example: 15 has_more_pages: type: boolean example: true message: type: string example: 'Documents retrieved successfully' 401: description: '' content: application/json: schema: type: object example: success: false message: Unauthenticated properties: success: type: boolean example: false message: type: string example: Unauthenticated 404: description: '' content: application/json: schema: type: object example: success: false message: 'Recovery case not found' properties: success: type: boolean example: false message: type: string example: 'Recovery case not found' tags: - 'Document Management' post: summary: 'Create Document' operationId: createDocument description: 'Store a new document with file upload for a specific recovery case.' parameters: [] responses: 201: description: '' content: application/json: schema: type: object example: success: true data: id: 1 recovery_id: 5 invoice_id: 3 adminUserId: 1 fileId: 10 fileTypeId: 1 visibleToUser: true visibleToDebtor: false visibleToBailiff: false visibleToOIP: false isSigned: false created_at: '2025-10-19T15:30:00.000000Z' updated_at: '2025-10-20T10:30:00.000000Z' recovery: id: 5 recovery_reference: REC-ABC123 debtor_name: 'John Doe' debtor_company: 'Example Corp' invoice: id: 3 invoice_number: INV-2025-001 amount_ttc: '1500.00' file: id: 10 filename: document.pdf mime: application/pdf file_type_info: id: 1 type: 'Mise en demeure' message: 'Document uploaded successfully' properties: success: type: boolean example: true data: type: object properties: id: type: integer example: 1 recovery_id: type: integer example: 5 invoice_id: type: integer example: 3 adminUserId: type: integer example: 1 fileId: type: integer example: 10 fileTypeId: type: integer example: 1 visibleToUser: type: boolean example: true visibleToDebtor: type: boolean example: false visibleToBailiff: type: boolean example: false visibleToOIP: type: boolean example: false isSigned: type: boolean example: false created_at: type: string example: '2025-10-19T15:30:00.000000Z' updated_at: type: string example: '2025-10-20T10:30:00.000000Z' recovery: type: object properties: id: type: integer example: 5 recovery_reference: type: string example: REC-ABC123 debtor_name: type: string example: 'John Doe' debtor_company: type: string example: 'Example Corp' invoice: type: object properties: id: type: integer example: 3 invoice_number: type: string example: INV-2025-001 amount_ttc: type: string example: '1500.00' file: type: object properties: id: type: integer example: 10 filename: type: string example: document.pdf mime: type: string example: application/pdf file_type_info: type: object properties: id: type: integer example: 1 type: type: string example: 'Mise en demeure' message: type: string example: 'Document uploaded successfully' 400: description: '' content: application/json: schema: type: object example: success: false message: 'Failed to process file' properties: success: type: boolean example: false message: type: string example: 'Failed to process file' 401: description: '' content: application/json: schema: type: object example: success: false message: Unauthenticated properties: success: type: boolean example: false message: type: string example: Unauthenticated 404: description: '' content: application/json: schema: oneOf: - description: 'Recovery not found' type: object example: success: false message: 'Recovery case not found' properties: success: type: boolean example: false message: type: string example: 'Recovery case not found' - description: 'Invoice not found' type: object example: success: false message: 'Invoice not found or does not belong to this recovery' properties: success: type: boolean example: false message: type: string example: 'Invoice not found or does not belong to this recovery' 422: description: '' content: application/json: schema: type: object example: success: false message: 'Validation failed' errors: name: - 'The name field is required.' pathinfo: - 'The pathinfo field is required when file is not present.' properties: success: type: boolean example: false message: type: string example: 'Validation failed' errors: type: object properties: name: type: array example: - 'The name field is required.' items: type: string pathinfo: type: array example: - 'The pathinfo field is required when file is not present.' items: type: string 500: description: '' content: application/json: schema: type: object example: success: false message: 'Failed to upload document' properties: success: type: boolean example: false message: type: string example: 'Failed to upload document' tags: - 'Document Management' requestBody: required: true content: application/json: schema: type: object properties: name: type: string description: 'Document name that will be used as filename.' example: 'Mise en demeure #1' nullable: false pathinfo: type: string description: 'URL to download the document from (legacy API compatibility).' example: 'https://example.com/document.pdf' nullable: false invoice_id: type: integer description: 'ID of the associated invoice.' example: 3 nullable: false file_type: type: integer description: 'Document type identifier (use GET /api/docs/file-types to get available types).' example: 1 nullable: false required: - name - pathinfo parameters: - in: path name: recoveryId description: 'ID of the recovery case.' example: 5 required: true schema: type: integer '/api/recoveries/{recoveryId}/docs/{docId}': get: summary: 'Show Document' operationId: showDocument description: 'Get detailed document information for a specific recovery case.' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: success: true data: id: 1 recovery_id: 5 invoice_id: 3 adminUserId: 1 fileId: 10 fileTypeId: 1 visibleToUser: true visibleToDebtor: false visibleToBailiff: false visibleToOIP: false isSigned: false created_at: '2025-10-19T15:30:00.000000Z' updated_at: '2025-10-20T10:30:00.000000Z' recovery: id: 5 recovery_reference: REC-ABC123 debtor_name: 'John Doe' debtor_company: 'Example Corp' invoice: id: 3 invoice_number: INV-2025-001 amount_ttc: '1500.00' file: id: 10 filename: document.pdf mime: application/pdf file_type_info: id: 1 type: 'Mise en demeure' message: 'Document retrieved successfully' properties: success: type: boolean example: true data: type: object properties: id: type: integer example: 1 recovery_id: type: integer example: 5 invoice_id: type: integer example: 3 adminUserId: type: integer example: 1 fileId: type: integer example: 10 fileTypeId: type: integer example: 1 visibleToUser: type: boolean example: true visibleToDebtor: type: boolean example: false visibleToBailiff: type: boolean example: false visibleToOIP: type: boolean example: false isSigned: type: boolean example: false created_at: type: string example: '2025-10-19T15:30:00.000000Z' updated_at: type: string example: '2025-10-20T10:30:00.000000Z' recovery: type: object properties: id: type: integer example: 5 recovery_reference: type: string example: REC-ABC123 debtor_name: type: string example: 'John Doe' debtor_company: type: string example: 'Example Corp' invoice: type: object properties: id: type: integer example: 3 invoice_number: type: string example: INV-2025-001 amount_ttc: type: string example: '1500.00' file: type: object properties: id: type: integer example: 10 filename: type: string example: document.pdf mime: type: string example: application/pdf file_type_info: type: object properties: id: type: integer example: 1 type: type: string example: 'Mise en demeure' message: type: string example: 'Document retrieved successfully' 401: description: '' content: application/json: schema: type: object example: success: false message: Unauthenticated properties: success: type: boolean example: false message: type: string example: Unauthenticated 403: description: '' content: application/json: schema: type: object example: success: false message: 'Unauthorized access to this document' properties: success: type: boolean example: false message: type: string example: 'Unauthorized access to this document' 404: description: '' content: application/json: schema: oneOf: - description: 'Recovery not found' type: object example: success: false message: 'Recovery case not found' properties: success: type: boolean example: false message: type: string example: 'Recovery case not found' - description: 'Document not found' type: object example: success: false message: 'Document not found' properties: success: type: boolean example: false message: type: string example: 'Document not found' tags: - 'Document Management' delete: summary: 'Delete Document' operationId: deleteDocument description: 'Remove document from a specific recovery case.' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: success: true message: 'Document deleted successfully' properties: success: type: boolean example: true message: type: string example: 'Document deleted successfully' 400: description: '' content: application/json: schema: type: object example: success: false message: 'Cannot delete document with pending signature requests' properties: success: type: boolean example: false message: type: string example: 'Cannot delete document with pending signature requests' 401: description: '' content: application/json: schema: type: object example: success: false message: Unauthenticated properties: success: type: boolean example: false message: type: string example: Unauthenticated 403: description: '' content: application/json: schema: type: object example: success: false message: 'Unauthorized access to this document' properties: success: type: boolean example: false message: type: string example: 'Unauthorized access to this document' 404: description: '' content: application/json: schema: oneOf: - description: 'Recovery not found' type: object example: success: false message: 'Recovery case not found' properties: success: type: boolean example: false message: type: string example: 'Recovery case not found' - description: 'Document not found' type: object example: success: false message: 'Document not found' properties: success: type: boolean example: false message: type: string example: 'Document not found' tags: - 'Document Management' parameters: - in: path name: recoveryId description: 'ID of the recovery case.' example: 5 required: true schema: type: integer - in: path name: docId description: 'ID of the document.' example: 123 required: true schema: type: integer '/api/recoveries/{recoveryId}/docs/{docId}/download': get: summary: 'Download Document File' operationId: downloadDocumentFile description: "Download the actual file for a specific document with secure access control.\nFiles are served with proper security headers and content type validation.\n\n**Security Features**:\n- User ownership verification\n- Document access permissions check\n- File existence validation\n- Secure file serving with proper headers\n- Content-Type header protection\n\n**File Serving**:\n- Files are served with secure file response handling\n- Original filename is preserved\n- Proper MIME type detection\n- Download logging for audit purposes" parameters: [] responses: 200: description: '' content: application/json: schema: type: string example: 'File download with proper headers and content-disposition' 401: description: '' content: application/json: schema: type: object example: success: false message: Unauthenticated properties: success: type: boolean example: false message: type: string example: Unauthenticated 403: description: '' content: application/json: schema: oneOf: - description: Unauthorized type: object example: success: false message: 'Unauthorized access to this document' properties: success: type: boolean example: false message: type: string example: 'Unauthorized access to this document' - description: 'Not implemented' type: object example: success: false message: 'This endpoint is not yet implemented. Feature under development.' properties: success: type: boolean example: false message: type: string example: 'This endpoint is not yet implemented. Feature under development.' 404: description: '' content: application/json: schema: oneOf: - description: 'Recovery not found' type: object example: success: false message: 'Recovery case not found' properties: success: type: boolean example: false message: type: string example: 'Recovery case not found' - description: 'Document not found' type: object example: success: false message: 'Document not found' properties: success: type: boolean example: false message: type: string example: 'Document not found' - description: 'File not found' type: object example: success: false message: 'File not found' properties: success: type: boolean example: false message: type: string example: 'File not found' 500: description: '' content: application/json: schema: type: object example: success: false message: 'File could not be accessed' properties: success: type: boolean example: false message: type: string example: 'File could not be accessed' tags: - 'Document Management' parameters: - in: path name: recoveryId description: 'ID of the recovery case.' example: 5 required: true schema: type: integer - in: path name: docId description: 'ID of the document.' example: 123 required: true schema: type: integer '/api/recoveries/{recoveryId}/comments': get: summary: 'List Comments' operationId: listComments description: "Get all comments for a specific recovery case with visibility filtering and access control.\nComments are automatically filtered based on user permissions and visibility settings.\n\n**Visibility Rules**:\n- All users see comments where `visibleToUser = true`\n- Debtors only see comments where `visibleToDebtor = true`\n- Bailiffs see comments where `visibleToBailiff = true`\n- Admin users can see all comments regardless of visibility" parameters: - in: query name: per_page description: 'optional Items per page (max 100). Defaults to 15.' example: 20 required: false schema: type: integer description: 'optional Items per page (max 100). Defaults to 15.' example: 20 nullable: false - in: query name: page description: 'optional Page number. Defaults to 1.' example: 1 required: false schema: type: integer description: 'optional Page number. Defaults to 1.' example: 1 nullable: false - in: query name: visibility description: 'enum optional Filter by visibility level (user, debtor, bailiff, all).' example: user required: false schema: type: string description: 'enum optional Filter by visibility level (user, debtor, bailiff, all).' example: user nullable: false - in: query name: unread_only description: 'optional Show only unread comments.' example: true required: false schema: type: boolean description: 'optional Show only unread comments.' example: true nullable: false responses: 200: description: '' content: application/json: schema: type: object example: success: true data: comments: - id: 1 recovery_id: 1 user_id: 1 comment: 'Client contacted by phone - no response received' visibleToUser: true visibleToDebtor: false visibleToBailiff: true isRead: false created_at: '2025-10-20T10:30:00.000000Z' updated_at: '2025-10-20T10:30:00.000000Z' - id: 2 recovery_id: 1 user_id: 1 comment: 'Payment plan proposal sent to debtor' visibleToUser: true visibleToDebtor: true visibleToBailiff: false isRead: true created_at: '2025-10-21T14:15:00.000000Z' updated_at: '2025-10-21T14:15:00.000000Z' pagination: current_page: 1 per_page: 20 total: 189 last_page: 10 from: 1 to: 20 has_more_pages: true summary: total_comments: 189 unread_count: 45 visible_to_debtor: 23 visible_to_bailiff: 67 message: 'Comments retrieved successfully. Total: 189 comments found.' properties: success: type: boolean example: true data: type: object properties: comments: type: array example: - id: 1 recovery_id: 1 user_id: 1 comment: 'Client contacted by phone - no response received' visibleToUser: true visibleToDebtor: false visibleToBailiff: true isRead: false created_at: '2025-10-20T10:30:00.000000Z' updated_at: '2025-10-20T10:30:00.000000Z' - id: 2 recovery_id: 1 user_id: 1 comment: 'Payment plan proposal sent to debtor' visibleToUser: true visibleToDebtor: true visibleToBailiff: false isRead: true created_at: '2025-10-21T14:15:00.000000Z' updated_at: '2025-10-21T14:15:00.000000Z' items: type: object properties: id: type: integer example: 1 recovery_id: type: integer example: 1 user_id: type: integer example: 1 comment: type: string example: 'Client contacted by phone - no response received' visibleToUser: type: boolean example: true visibleToDebtor: type: boolean example: false visibleToBailiff: type: boolean example: true isRead: type: boolean example: false created_at: type: string example: '2025-10-20T10:30:00.000000Z' updated_at: type: string example: '2025-10-20T10:30:00.000000Z' pagination: type: object properties: current_page: type: integer example: 1 per_page: type: integer example: 20 total: type: integer example: 189 last_page: type: integer example: 10 from: type: integer example: 1 to: type: integer example: 20 has_more_pages: type: boolean example: true summary: type: object properties: total_comments: type: integer example: 189 unread_count: type: integer example: 45 visible_to_debtor: type: integer example: 23 visible_to_bailiff: type: integer example: 67 message: type: string example: 'Comments retrieved successfully. Total: 189 comments found.' 401: description: '' content: application/json: schema: type: object example: success: false message: Unauthenticated properties: success: type: boolean example: false message: type: string example: Unauthenticated 404: description: '' content: application/json: schema: type: object example: success: false message: 'Recovery case not found' properties: success: type: boolean example: false message: type: string example: 'Recovery case not found' tags: - 'Comment Management' post: summary: 'Create Comment' operationId: createComment description: 'Add a new comment to a recovery case with specified visibility settings.' parameters: [] responses: 201: description: '' content: application/json: schema: type: object example: success: true data: id: 1 recovery_id: 1 user_id: 1 comment: 'Client contacted by phone - no response' visibleToUser: true visibleToDebtor: false visibleToBailiff: true isRead: false created_at: '2025-10-20T10:30:00.000000Z' updated_at: '2025-10-20T10:30:00.000000Z' message: 'Comment created successfully' properties: success: type: boolean example: true data: type: object properties: id: type: integer example: 1 recovery_id: type: integer example: 1 user_id: type: integer example: 1 comment: type: string example: 'Client contacted by phone - no response' visibleToUser: type: boolean example: true visibleToDebtor: type: boolean example: false visibleToBailiff: type: boolean example: true isRead: type: boolean example: false created_at: type: string example: '2025-10-20T10:30:00.000000Z' updated_at: type: string example: '2025-10-20T10:30:00.000000Z' message: type: string example: 'Comment created successfully' 404: description: '' content: application/json: schema: type: object example: success: false message: 'Recovery case not found' properties: success: type: boolean example: false message: type: string example: 'Recovery case not found' 422: description: '' content: application/json: schema: type: object example: success: false message: 'Validation failed' errors: comment: - 'The comment field is required.' - 'The comment contains potentially dangerous HTML tags.' - 'The comment contains too much HTML markup.' properties: success: type: boolean example: false message: type: string example: 'Validation failed' errors: type: object properties: comment: type: array example: - 'The comment field is required.' - 'The comment contains potentially dangerous HTML tags.' - 'The comment contains too much HTML markup.' items: type: string tags: - 'Comment Management' requestBody: required: true content: application/json: schema: type: object properties: comment: type: string description: 'The comment text (HTML allowed with restrictions). Allowed HTML tags: p, br, strong, b, em, i, u, ul, ol, li, h1-h6, blockquote, a. No JavaScript or dangerous attributes allowed.' example: '

Client contacted by phone - no response

' nullable: false required: - comment parameters: - in: path name: recoveryId description: 'The recovery case ID.' example: 1 required: true schema: type: integer '/api/recoveries/{recoveryId}/comments/{commentId}': get: summary: 'Show Comment' operationId: showComment description: 'Get details of a specific comment.' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: success: true data: id: 1 recovery_id: 1 user_id: 1 comment: 'Client contacted by phone - no response' visibleToUser: true visibleToDebtor: false visibleToBailiff: true isRead: false created_at: '2025-10-20T10:30:00.000000Z' updated_at: '2025-10-20T10:30:00.000000Z' message: 'Comment retrieved successfully' properties: success: type: boolean example: true data: type: object properties: id: type: integer example: 1 recovery_id: type: integer example: 1 user_id: type: integer example: 1 comment: type: string example: 'Client contacted by phone - no response' visibleToUser: type: boolean example: true visibleToDebtor: type: boolean example: false visibleToBailiff: type: boolean example: true isRead: type: boolean example: false created_at: type: string example: '2025-10-20T10:30:00.000000Z' updated_at: type: string example: '2025-10-20T10:30:00.000000Z' message: type: string example: 'Comment retrieved successfully' 404: description: '' content: application/json: schema: oneOf: - description: 'Recovery not found' type: object example: success: false message: 'Recovery case not found' properties: success: type: boolean example: false message: type: string example: 'Recovery case not found' - description: 'Comment not found' type: object example: success: false message: 'Comment not found' properties: success: type: boolean example: false message: type: string example: 'Comment not found' tags: - 'Comment Management' put: summary: 'Update Comment' operationId: updateComment description: 'Update an existing comment with new content or visibility settings.' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: success: true data: id: 1 recovery_id: 1 user_id: 1 comment: 'Client contacted by phone - answered this time' visibleToUser: true visibleToDebtor: false visibleToBailiff: true isRead: false created_at: '2025-10-20T10:30:00.000000Z' updated_at: '2025-10-20T10:30:00.000000Z' message: 'Comment updated successfully' properties: success: type: boolean example: true data: type: object properties: id: type: integer example: 1 recovery_id: type: integer example: 1 user_id: type: integer example: 1 comment: type: string example: 'Client contacted by phone - answered this time' visibleToUser: type: boolean example: true visibleToDebtor: type: boolean example: false visibleToBailiff: type: boolean example: true isRead: type: boolean example: false created_at: type: string example: '2025-10-20T10:30:00.000000Z' updated_at: type: string example: '2025-10-20T10:30:00.000000Z' message: type: string example: 'Comment updated successfully' 403: description: '' content: application/json: schema: type: object example: success: false message: 'Cannot update comment that is visible to debtor/bailiff or has been read' properties: success: type: boolean example: false message: type: string example: 'Cannot update comment that is visible to debtor/bailiff or has been read' 404: description: '' content: application/json: schema: type: object example: success: false message: 'Comment not found' properties: success: type: boolean example: false message: type: string example: 'Comment not found' 422: description: '' content: application/json: schema: type: object example: success: false message: 'Validation failed' errors: comment: - 'The comment must not be greater than 2000 characters.' - 'The comment contains potentially dangerous HTML tags.' - 'The comment contains too much HTML markup.' properties: success: type: boolean example: false message: type: string example: 'Validation failed' errors: type: object properties: comment: type: array example: - 'The comment must not be greater than 2000 characters.' - 'The comment contains potentially dangerous HTML tags.' - 'The comment contains too much HTML markup.' items: type: string tags: - 'Comment Management' requestBody: required: false content: application/json: schema: type: object properties: comment: type: string description: 'optional The updated comment text (HTML allowed with restrictions). Allowed HTML tags: p, br, strong, b, em, i, u, ul, ol, li, h1-h6, blockquote, a. No JavaScript or dangerous attributes allowed.' example: '

Client contacted by phone - answered this time

' nullable: false delete: summary: 'Delete Comment' operationId: deleteComment description: 'Remove a comment from the recovery case.' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: success: true message: 'Comment deleted successfully' properties: success: type: boolean example: true message: type: string example: 'Comment deleted successfully' 403: description: '' content: application/json: schema: type: object example: success: false message: 'Cannot delete comment that is visible to debtor/bailiff or has been read' properties: success: type: boolean example: false message: type: string example: 'Cannot delete comment that is visible to debtor/bailiff or has been read' 404: description: '' content: application/json: schema: oneOf: - description: 'Recovery not found' type: object example: success: false message: 'Recovery case not found' properties: success: type: boolean example: false message: type: string example: 'Recovery case not found' - description: 'Comment not found' type: object example: success: false message: 'Comment not found' properties: success: type: boolean example: false message: type: string example: 'Comment not found' tags: - 'Comment Management' parameters: - in: path name: recoveryId description: 'The recovery case ID.' example: 1 required: true schema: type: integer - in: path name: commentId description: 'The comment ID.' example: 1 required: true schema: type: integer /api/protected-invoices: get: summary: 'List Protected Invoices' operationId: listProtectedInvoices description: 'Retrieves a paginated list of protected invoices with optional filters.' parameters: - in: query name: search description: 'optional Search in invoice numbers and descriptions.' example: INV-2024 required: false schema: type: string description: 'optional Search in invoice numbers and descriptions.' example: INV-2024 nullable: false - in: query name: status description: 'optional Filter by invoice status (pending, paid, cancelled).' example: pending required: false schema: type: string description: 'optional Filter by invoice status (pending, paid, cancelled).' example: pending nullable: false - in: query name: siren description: 'optional Filter by client SIREN.' example: '123456789' required: false schema: type: string description: 'optional Filter by client SIREN.' example: '123456789' nullable: false - in: query name: sort_by description: 'optional Sort by field. Defaults to due_date.' example: invoice_number required: false schema: type: string description: 'optional Sort by field. Defaults to due_date.' example: invoice_number nullable: false - in: query name: sort_order description: 'optional Sort order (asc/desc). Defaults to desc.' example: asc required: false schema: type: string description: 'optional Sort order (asc/desc). Defaults to desc.' example: asc nullable: false - in: query name: per_page description: 'optional Items per page (max 100). Defaults to 15.' example: 20 required: false schema: type: integer description: 'optional Items per page (max 100). Defaults to 15.' example: 20 nullable: false - in: query name: page description: 'optional Page number. Defaults to 1.' example: 1 required: false schema: type: integer description: 'optional Page number. Defaults to 1.' example: 1 nullable: false responses: 200: description: '' content: application/json: schema: type: object example: success: true data: protected_invoices: - id: 1 api_invoice_id: INV-202405252001 tracking_code: fyn_INV-202405252001 siren: '123456789' invoice_number: INV-2024-001 due_date: '2024-12-31' amount: '1500.50' currency: EUR status: pending status_label: 'À payer' formatted_amount: '1500.50 EUR' is_overdue: false is_paid: false created_at: '2024-10-31T21:15:00.000000Z' updated_at: '2024-10-31T21:15:00.000000Z' pagination: current_page: 1 per_page: 15 total: 1 last_page: 1 from: 1 to: 1 has_more_pages: false message: 'Protected invoices retrieved successfully' properties: success: type: boolean example: true data: type: object properties: protected_invoices: type: array example: - id: 1 api_invoice_id: INV-202405252001 tracking_code: fyn_INV-202405252001 siren: '123456789' invoice_number: INV-2024-001 due_date: '2024-12-31' amount: '1500.50' currency: EUR status: pending status_label: 'À payer' formatted_amount: '1500.50 EUR' is_overdue: false is_paid: false created_at: '2024-10-31T21:15:00.000000Z' updated_at: '2024-10-31T21:15:00.000000Z' items: type: object properties: id: type: integer example: 1 api_invoice_id: type: string example: INV-202405252001 tracking_code: type: string example: fyn_INV-202405252001 siren: type: string example: '123456789' invoice_number: type: string example: INV-2024-001 due_date: type: string example: '2024-12-31' amount: type: string example: '1500.50' currency: type: string example: EUR status: type: string example: pending status_label: type: string example: 'À payer' formatted_amount: type: string example: '1500.50 EUR' is_overdue: type: boolean example: false is_paid: type: boolean example: false created_at: type: string example: '2024-10-31T21:15:00.000000Z' updated_at: type: string example: '2024-10-31T21:15:00.000000Z' pagination: type: object properties: current_page: type: integer example: 1 per_page: type: integer example: 15 total: type: integer example: 1 last_page: type: integer example: 1 from: type: integer example: 1 to: type: integer example: 1 has_more_pages: type: boolean example: false message: type: string example: 'Protected invoices retrieved successfully' 401: description: '' content: application/json: schema: type: object example: success: false message: Unauthenticated properties: success: type: boolean example: false message: type: string example: Unauthenticated tags: - 'Protected Invoice Management' post: summary: 'Store Protected Invoice' operationId: storeProtectedInvoice description: "Creates a new protected invoice with automatic tracking code generation.\nThe tracking code is automatically generated with the prefix \"fyn_\" followed by a unique identifier." parameters: [] responses: 201: description: '' content: application/json: schema: type: object example: success: true data: id: 1 api_invoice_id: INV-202405252001 tracking_code: fyn_INV-202405252001 siren: '123456789' invoice_number: INV-2024-001 due_date: '2024-12-31' amount: '1500.50' currency: EUR status: pending status_label: 'À payer' description: 'Services rendered for January 2024' formatted_amount: '1500.50 EUR' is_overdue: false is_paid: false created_at: '2024-10-31T21:15:00.000000Z' updated_at: '2024-10-31T21:15:00.000000Z' message: 'Protected invoice created successfully' properties: success: type: boolean example: true data: type: object properties: id: type: integer example: 1 api_invoice_id: type: string example: INV-202405252001 tracking_code: type: string example: fyn_INV-202405252001 siren: type: string example: '123456789' invoice_number: type: string example: INV-2024-001 due_date: type: string example: '2024-12-31' amount: type: string example: '1500.50' currency: type: string example: EUR status: type: string example: pending status_label: type: string example: 'À payer' description: type: string example: 'Services rendered for January 2024' formatted_amount: type: string example: '1500.50 EUR' is_overdue: type: boolean example: false is_paid: type: boolean example: false created_at: type: string example: '2024-10-31T21:15:00.000000Z' updated_at: type: string example: '2024-10-31T21:15:00.000000Z' message: type: string example: 'Protected invoice created successfully' 401: description: '' content: application/json: schema: type: object example: success: false message: Unauthenticated properties: success: type: boolean example: false message: type: string example: Unauthenticated 422: description: '' content: application/json: schema: type: object example: success: false message: 'Validation failed' errors: api_invoice_id: - 'An invoice with this API ID already exists for your account.' siren: - 'The siren must be exactly 9 characters.' properties: success: type: boolean example: false message: type: string example: 'Validation failed' errors: type: object properties: api_invoice_id: type: array example: - 'An invoice with this API ID already exists for your account.' items: type: string siren: type: array example: - 'The siren must be exactly 9 characters.' items: type: string tags: - 'Protected Invoice Management' requestBody: required: true content: application/json: schema: type: object properties: api_invoice_id: type: string description: 'Unique invoice identifier for your system.' example: INV-202405252001 nullable: false siren: type: string description: 'Client SIREN (9 digits).' example: '123456789' nullable: false invoice_number: type: string description: 'Invoice number (free-form).' example: INV-2024-001 nullable: false due_date: type: date description: 'Invoice due date (format: YYYY-MM-DD).' example: '2024-12-31' nullable: false amount: type: decimal description: 'Invoice amount.' example: '1500.50' nullable: false currency: type: string description: 'optional Invoice currency (EUR, USD, GBP). Defaults to EUR.' example: EUR nullable: false status: type: string description: 'optional Initial status (pending, paid, cancelled). Defaults to pending.' example: pending nullable: false description: type: string description: 'optional Invoice description.' example: 'Services rendered for January 2024' nullable: false required: - api_invoice_id - siren - invoice_number - due_date - amount '/api/protected-invoices/{id}': get: summary: 'Show Protected Invoice' operationId: showProtectedInvoice description: 'Retrieves details of a specific protected invoice by its ID.' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: success: true data: id: 1 api_invoice_id: INV-202405252001 tracking_code: fyn_INV-202405252001 siren: '123456789' invoice_number: INV-2024-001 due_date: '2024-12-31' amount: '1500.50' currency: EUR status: pending status_label: 'À payer' description: 'Services rendered for January 2024' formatted_amount: '1500.50 EUR' is_overdue: false is_paid: false created_at: '2024-10-31T21:15:00.000000Z' updated_at: '2024-10-31T21:15:00.000000Z' message: 'Protected invoice retrieved successfully' properties: success: type: boolean example: true data: type: object properties: id: type: integer example: 1 api_invoice_id: type: string example: INV-202405252001 tracking_code: type: string example: fyn_INV-202405252001 siren: type: string example: '123456789' invoice_number: type: string example: INV-2024-001 due_date: type: string example: '2024-12-31' amount: type: string example: '1500.50' currency: type: string example: EUR status: type: string example: pending status_label: type: string example: 'À payer' description: type: string example: 'Services rendered for January 2024' formatted_amount: type: string example: '1500.50 EUR' is_overdue: type: boolean example: false is_paid: type: boolean example: false created_at: type: string example: '2024-10-31T21:15:00.000000Z' updated_at: type: string example: '2024-10-31T21:15:00.000000Z' message: type: string example: 'Protected invoice retrieved successfully' 401: description: '' content: application/json: schema: type: object example: success: false message: Unauthenticated properties: success: type: boolean example: false message: type: string example: Unauthenticated 404: description: '' content: application/json: schema: type: object example: success: false message: 'Protected invoice not found' properties: success: type: boolean example: false message: type: string example: 'Protected invoice not found' tags: - 'Protected Invoice Management' put: summary: 'Update Protected Invoice Status' operationId: updateProtectedInvoiceStatus description: "Updates the status of a protected invoice. This automatically updates the timestamp.\nOnly the status can be modified after creation." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: success: true data: id: 1 api_invoice_id: INV-202405252001 tracking_code: fyn_INV-202405252001 siren: '123456789' invoice_number: INV-2024-001 due_date: '2024-12-31' amount: '1500.50' currency: EUR status: paid status_label: Payée formatted_amount: '1500.50 EUR' is_overdue: false is_paid: true created_at: '2024-10-31T21:15:00.000000Z' updated_at: '2024-10-31T21:30:00.000000Z' message: 'Protected invoice status updated successfully' properties: success: type: boolean example: true data: type: object properties: id: type: integer example: 1 api_invoice_id: type: string example: INV-202405252001 tracking_code: type: string example: fyn_INV-202405252001 siren: type: string example: '123456789' invoice_number: type: string example: INV-2024-001 due_date: type: string example: '2024-12-31' amount: type: string example: '1500.50' currency: type: string example: EUR status: type: string example: paid status_label: type: string example: Payée formatted_amount: type: string example: '1500.50 EUR' is_overdue: type: boolean example: false is_paid: type: boolean example: true created_at: type: string example: '2024-10-31T21:15:00.000000Z' updated_at: type: string example: '2024-10-31T21:30:00.000000Z' message: type: string example: 'Protected invoice status updated successfully' 401: description: '' content: application/json: schema: type: object example: success: false message: Unauthenticated properties: success: type: boolean example: false message: type: string example: Unauthenticated 404: description: '' content: application/json: schema: type: object example: success: false message: 'Protected invoice not found' properties: success: type: boolean example: false message: type: string example: 'Protected invoice not found' 422: description: '' content: application/json: schema: type: object example: success: false message: 'Validation failed' errors: status: - 'Status must be one of: pending, paid, cancelled.' properties: success: type: boolean example: false message: type: string example: 'Validation failed' errors: type: object properties: status: type: array example: - 'Status must be one of: pending, paid, cancelled.' items: type: string tags: - 'Protected Invoice Management' requestBody: required: true content: application/json: schema: type: object properties: status: type: string description: 'New status (pending, paid, cancelled).' example: '"paid"' nullable: false required: - status parameters: - in: path name: id description: 'The protected invoice ID.' example: 1 required: true schema: type: integer '/api/protected-invoices/api/{apiInvoiceId}': get: summary: 'Get Protected Invoice by API Invoice ID' operationId: getProtectedInvoiceByAPIInvoiceID description: 'Retrieves a protected invoice using its unique API invoice ID.' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: success: true data: id: 1 api_invoice_id: INV-202405252001 tracking_code: fyn_INV-202405252001 siren: '123456789' invoice_number: INV-2024-001 due_date: '2024-12-31' amount: '1500.50' currency: EUR status: pending status_label: 'À payer' description: 'Services rendered for January 2024' formatted_amount: '1500.50 EUR' is_overdue: false is_paid: false created_at: '2024-10-31T21:15:00.000000Z' updated_at: '2024-10-31T21:15:00.000000Z' message: 'Protected invoice found' properties: success: type: boolean example: true data: type: object properties: id: type: integer example: 1 api_invoice_id: type: string example: INV-202405252001 tracking_code: type: string example: fyn_INV-202405252001 siren: type: string example: '123456789' invoice_number: type: string example: INV-2024-001 due_date: type: string example: '2024-12-31' amount: type: string example: '1500.50' currency: type: string example: EUR status: type: string example: pending status_label: type: string example: 'À payer' description: type: string example: 'Services rendered for January 2024' formatted_amount: type: string example: '1500.50 EUR' is_overdue: type: boolean example: false is_paid: type: boolean example: false created_at: type: string example: '2024-10-31T21:15:00.000000Z' updated_at: type: string example: '2024-10-31T21:15:00.000000Z' message: type: string example: 'Protected invoice found' 401: description: '' content: application/json: schema: type: object example: success: false message: Unauthenticated properties: success: type: boolean example: false message: type: string example: Unauthenticated 404: description: '' content: application/json: schema: type: object example: success: false message: 'Protected invoice not found with this API invoice ID' properties: success: type: boolean example: false message: type: string example: 'Protected invoice not found with this API invoice ID' tags: - 'Protected Invoice Management' parameters: - in: path name: apiInvoiceId description: 'The API invoice ID.' example: INV-202405252001 required: true schema: type: string /api/scoring/order: post: summary: 'Order Scoring Report' operationId: orderScoringReport description: "Orders a solvency report and/or surveillance for a company.\nThis endpoint allows ordering both services simultaneously or individually." parameters: [] responses: 201: description: '' content: application/json: schema: type: object example: success: true data: order_id: SCR-2024-001 services: - solvency_report - surveillance status: pending estimated_delivery: '2024-01-17T10:00:00.000000Z' message: 'Scoring order placed successfully' properties: success: type: boolean example: true data: type: object properties: order_id: type: string example: SCR-2024-001 services: type: array example: - solvency_report - surveillance items: type: string status: type: string example: pending estimated_delivery: type: string example: '2024-01-17T10:00:00.000000Z' message: type: string example: 'Scoring order placed successfully' 401: description: '' content: application/json: schema: type: object example: success: false message: Unauthenticated properties: success: type: boolean example: false message: type: string example: Unauthenticated 403: description: '' content: application/json: schema: type: object example: success: false message: 'This endpoint is not yet implemented. Feature under development.' properties: success: type: boolean example: false message: type: string example: 'This endpoint is not yet implemented. Feature under development.' tags: - 'Scoring Management' requestBody: required: true content: application/json: schema: type: object properties: company_id: type: integer description: 'The target company identifier.' example: 123 nullable: false company_name: type: string description: 'The company name.' example: '"ACME Corporation"' nullable: false company_siret: type: string description: 'The company SIRET number.' example: '"12345678901234"' nullable: false services: type: array description: 'Array of requested services.' example: - solvency_report - surveillance items: type: string report_type: type: string description: 'The type of solvency report (if applicable).' example: '"standard"' nullable: false surveillance_duration: type: integer description: 'Duration in months for surveillance (if applicable).' example: 12 nullable: false priority: type: string description: 'The processing priority.' example: '"standard"' nullable: false required: - company_id - company_name - services /api/scoring/tokens: get: summary: 'Check Available Tokens' operationId: checkAvailableTokens description: "Returns the number of remaining tokens available for ordering reports and surveillance.\nThis endpoint helps users monitor their consumption and remaining credits." parameters: [] responses: 200: description: '' content: application/json: schema: oneOf: - description: '' type: object example: success: true data: remaining_tokens: 75 message: 'Token information retrieved successfully' properties: success: type: boolean example: true data: type: object properties: remaining_tokens: type: integer example: 75 message: type: string example: 'Token information retrieved successfully' - description: '' type: object example: success: true data: remaining_tokens: 0 message: 'No tokens available' properties: success: type: boolean example: true data: type: object properties: remaining_tokens: type: integer example: 0 message: type: string example: 'No tokens available' 401: description: '' content: application/json: schema: type: object example: success: false message: Unauthenticated properties: success: type: boolean example: false message: type: string example: Unauthenticated tags: - 'Scoring Management' /api/scoring/orders: get: summary: 'List Scoring Orders' operationId: listScoringOrders description: 'Retrieves a list of scoring orders for the authenticated user.' parameters: - in: query name: status description: 'Filter by order status.' example: completed required: false schema: type: string description: 'Filter by order status.' example: completed nullable: false - in: query name: service_type description: 'Filter by service type.' example: solvency_report required: false schema: type: string description: 'Filter by service type.' example: solvency_report nullable: false - in: query name: per_page description: 'Number of items per page.' example: 15 required: false schema: type: integer description: 'Number of items per page.' example: 15 nullable: false - in: query name: page description: 'The page number for pagination.' example: 1 required: false schema: type: integer description: 'The page number for pagination.' example: 1 nullable: false responses: 200: description: '' content: application/json: schema: type: object example: success: true data: scoring_orders: [] pagination: current_page: 1 per_page: 15 total: 0 last_page: 1 from: null to: null message: 'Scoring orders retrieved successfully' properties: success: type: boolean example: true data: type: object properties: scoring_orders: type: array example: [] pagination: type: object properties: current_page: type: integer example: 1 per_page: type: integer example: 15 total: type: integer example: 0 last_page: type: integer example: 1 from: type: string example: null to: type: string example: null message: type: string example: 'Scoring orders retrieved successfully' 401: description: '' content: application/json: schema: type: object example: success: false message: Unauthenticated properties: success: type: boolean example: false message: type: string example: Unauthenticated 403: description: '' content: application/json: schema: type: object example: success: false message: 'This endpoint is not yet implemented. Feature under development.' properties: success: type: boolean example: false message: type: string example: 'This endpoint is not yet implemented. Feature under development.' tags: - 'Scoring Management' '/api/scoring/orders/{orderId}': get: summary: 'Show Scoring Order' operationId: showScoringOrder description: 'Retrieves details of a specific scoring order including results if available.' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: success: true data: order_id: SCR-2024-001 company_name: 'ACME Corporation' services: - solvency_report status: completed results: solvency_score: 85 risk_level: low message: 'Scoring order retrieved successfully' properties: success: type: boolean example: true data: type: object properties: order_id: type: string example: SCR-2024-001 company_name: type: string example: 'ACME Corporation' services: type: array example: - solvency_report items: type: string status: type: string example: completed results: type: object properties: solvency_score: type: integer example: 85 risk_level: type: string example: low message: type: string example: 'Scoring order retrieved successfully' 401: description: '' content: application/json: schema: type: object example: success: false message: Unauthenticated properties: success: type: boolean example: false message: type: string example: Unauthenticated 403: description: '' content: application/json: schema: type: object example: success: false message: 'This endpoint is not yet implemented. Feature under development.' properties: success: type: boolean example: false message: type: string example: 'This endpoint is not yet implemented. Feature under development.' 404: description: '' content: application/json: schema: type: object example: success: false message: 'Scoring order not found' properties: success: type: boolean example: false message: type: string example: 'Scoring order not found' tags: - 'Scoring Management' parameters: - in: path name: orderId description: 'The scoring order ID.' example: SCR-2024-001 required: true schema: type: string