openapi: 3.2.0 info: title: Compabase Persons API version: 1.0.0 description: '### Introduction Versioned JSON API for Polish company data: KRS search and full profiles, CEIDG (sole proprietors) by NIP, financial statements and document inventory, peer statistics, company connections, news/UGC, Warsaw Stock Exchange (GPW) listings, and watchlist management.' servers: - url: https://compabase.com/api/v1 description: Full URL tags: - name: Persons paths: /persons/search: get: tags: - Persons summary: Search persons by name description: 'Searches for natural persons by name (first name, last name, or both). Returns a deduplicated list of matching persons with their `person_id` key and the number of companies they are linked to. Use the returned `person_id` with `GET /persons/{personId}/connections` to fetch full connection details. Identification is restricted to name-based queries (first name, last name, or both). Protected data, including PESEL and exact birth dates, is never exposed. To assist with identification, every result includes a `birth_year` (integer). **Result capping:** internally the search scans up to 2 000 matching link rows before aggregation. For very common names the response may include a `note` field indicating the result set was truncated; use a more specific query to narrow results.' security: - ApiKeyAuth: [] - BearerAuth: [] parameters: - name: q in: query required: true schema: type: string minLength: 2 description: 'Name substring to search for (case-insensitive). Must be at least **2 characters**. Matched against the stored display name using `ILIKE %q%`. ' example: Kowalski - name: limit in: query schema: type: integer default: 20 minimum: 1 maximum: 50 description: Maximum number of persons to return. Capped at **50**. responses: '200': description: List of matching persons. content: application/json: schema: type: object required: - data - total properties: data: type: array items: $ref: '#/components/schemas/PersonSearchItem' total: type: integer description: Number of distinct persons found (before `limit` slicing). note: type: string nullable: true description: Present when the internal scan limit was reached and results may be incomplete. example: data: - person_id: 033e6964-179b-4039-86a2-0e0590c56918 display_name: Krzysztof Mateusz Kowalski birth_year: 1985 company_count: 3 - person_id: 0063e9c1-265f-47d4-a3ad-6cb698869f7a display_name: Sebastian Piotr Kowalski birth_year: null company_count: 2 - person_id: 048bd9e8-8b0e-446f-8b36-e60f518d3abe display_name: Henry Kowalski birth_year: 1972 company_count: 1 total: 3 '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '429': $ref: '#/components/responses/TooManyRequests' operationId: getPersonsSearch x-operation-id-source: derived /persons/{personId}/connections: get: tags: - Persons summary: Company connections for a person description: 'Returns all companies linked to the given person together with the relationship type and role label for each link. Use `GET /persons/search` to resolve a name to a `person_id` first.' security: - ApiKeyAuth: [] - BearerAuth: [] parameters: - name: personId in: path required: true schema: type: string format: uuid description: UUID of the person; obtained from `GET /persons/search`. example: 033e6964-179b-4039-86a2-0e0590c56918 responses: '200': description: Person connections payload. content: application/json: schema: $ref: '#/components/schemas/PersonConnectionsResponse' example: person_id: 033e6964-179b-4039-86a2-0e0590c56918 companies: - entity_id: 1a2b3c4d-0000-0000-0000-000000000001 registry_number: '0000123456' company_name: Example Company Ltd. relationships: - kind: management role: President of the Management Board - entity_id: 1a2b3c4d-0000-0000-0000-000000000002 registry_number: '0000654321' company_name: Second Company Ltd. relationships: - kind: ownership role: null '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/TooManyRequests' operationId: getPersonsByPersonIdConnections x-operation-id-source: derived components: responses: BadRequest: description: Invalid request parameters. content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' examples: invalidKrs: summary: Invalid KRS value value: statusCode: 400 statusMessage: Invalid krs message: Invalid krs data: error: code: INVALID_KRS message: After normalization, KRS must contain exactly 10 digits. details: parameter: krs invalidCursor: summary: Invalid cursor format value: statusCode: 400 statusMessage: Invalid cursor message: Invalid cursor data: error: code: INVALID_CURSOR message: Cursor must be a valid UUID. details: parameter: cursor invalidRange: summary: Invalid numeric range value: statusCode: 400 statusMessage: Invalid range message: Invalid range data: error: code: INVALID_RANGE message: revenue_min cannot be greater than revenue_max. details: parameter: revenue_min,revenue_max NotFound: description: Resource not found. content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' example: statusCode: 404 statusMessage: Not Found message: Not Found data: error: code: NOT_FOUND message: Company not found. Unauthorized: description: Missing, invalid, or revoked API key. content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' example: statusCode: 401 statusMessage: Unauthorized message: Unauthorized data: message: Missing or invalid API key. TooManyRequests: description: Monthly quota exceeded for this API key. content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' example: statusCode: 429 statusMessage: Too Many Requests message: Too Many Requests data: error: code: QUOTA_EXCEEDED message: Monthly quota exceeded for this API key. schemas: PersonConnectionsResponse: type: object required: - person_id - companies properties: person_id: type: string format: uuid companies: type: array items: type: object required: - entity_id - relationships properties: entity_id: type: string format: uuid registry_number: type: string nullable: true description: KRS number (10 digits), if available. company_name: type: string nullable: true relationships: type: array items: type: object required: - kind - role properties: kind: type: string description: Relationship type (e.g. `management`, `ownership`). role: type: string nullable: true description: Role label (e.g. `PREZES ZARZĄDU`), if available. ErrorResponse: type: object required: - statusCode - statusMessage - message properties: statusCode: type: integer description: HTTP status code. statusMessage: type: string description: HTTP status text. message: type: string description: Short error summary (same as statusMessage for most errors). data: type: object description: Domain error payload set by the handler. properties: message: type: string description: Human-readable message (used by 401 responses). error: type: object description: Structured domain error (used by 400/404/429 responses). properties: code: type: string description: Machine-readable domain error code. enum: - INVALID_KRS - INVALID_NIP - INVALID_CURSOR - INVALID_RANGE - INVALID_PARAMETER - CONFLICTING_PARAMETERS - INVALID_BOOLEAN - INVALID_KEYWORDS - INVALID_API_KEY - UNAUTHORIZED - NOT_FOUND - QUOTA_EXCEEDED message: type: string details: type: object additionalProperties: true PersonSearchItem: type: object required: - person_id - display_name - birth_year - company_count properties: person_id: type: string format: uuid description: Stable UUID key for this person. Use with `GET /persons/{personId}/connections`. display_name: type: string nullable: true description: Full display name of the person. birth_year: type: integer nullable: true description: Year of birth when known (derived from registry data; full birth date is not exposed). `null` if unavailable. example: 1985 company_count: type: integer description: Number of distinct companies this person is linked to. securitySchemes: ApiKeyAuth: type: apiKey in: header name: X-API-Key BearerAuth: type: http scheme: bearer