openapi: 3.1.0 info: title: 'finder API documentation' description: 'Website-scoped search and document indexing service powered by Typesense.' version: 1.0.0 servers: - url: 'https://finder.app.solidpixels.com' tags: - name: Search description: 'Full-text search operations.' - name: Documents description: 'Document indexing and management.' - name: Collections description: 'Collection metadata and information.' components: securitySchemes: default: type: http scheme: bearer description: 'Use a JWT (Bearer token) for authentication.' schemas: CollectionInfo: type: object properties: name: type: string num_documents: type: integer created_at: type: integer CollectionInfoResponse: type: object properties: success: const: true data: $ref: '#/components/schemas/CollectionInfo' message: type: string required: - success - data DeleteResult: type: object properties: id: type: string collection: type: string DeleteResultResponse: type: object properties: success: const: true data: $ref: '#/components/schemas/DeleteResult' message: type: string required: - success - data Document: type: object properties: id: type: string fields: type: object properties: name: type: string description: type: string price: type: integer account_id: type: string DocumentResponse: type: object properties: success: const: true data: $ref: '#/components/schemas/Document' message: type: string required: - success - data EntityIndex: type: object properties: collection: type: string exists: type: boolean schema: type: object nullable: true additionalProperties: true documents: type: array items: type: object additionalProperties: true state: type: object nullable: true additionalProperties: true required: - collection - exists - schema - documents EntityIndexResponse: type: object properties: success: const: true data: $ref: '#/components/schemas/EntityIndex' message: type: string required: - success - data Error: type: object properties: success: type: boolean message: type: string errors: type: object required: - success - message IndexDocumentsRequest: type: object properties: documents: type: array description: 'Array of documents to index.' items: type: string required: - documents IndexResult: type: object properties: indexed: type: integer total: type: integer collection: type: string results: type: array items: type: object properties: success: type: boolean id: type: string IndexResultResponse: type: object properties: success: const: true data: $ref: '#/components/schemas/IndexResult' message: type: string required: - success - data SearchEntitiesRequest: type: object properties: collection: type: string description: 'Entity collection name.' q: type: string description: 'Search query string.' filter_by: type: string description: 'Typesense filter expression.' query_by: type: string description: 'Comma-separated fields to search.' page: type: integer description: 'Page number.' per_page: type: integer description: 'Results per page (max 250).' exact_field: type: string description: 'Declared identifier or hostname field for exact matching.' exact_values: type: array description: 'One or two exact values.' items: type: string required: - collection - q - query_by SearchResult: type: object properties: hits: type: array items: type: object properties: document: type: object properties: id: type: string name: type: string description: type: string price: type: integer highlights: type: array items: type: object properties: field: type: string snippet: type: string text_match: type: number total: type: integer per_page: type: integer current_page: type: integer last_page: type: integer search_time_ms: type: integer SearchResultResponse: type: object properties: success: const: true data: $ref: '#/components/schemas/SearchResult' message: type: string required: - success - data ValidationError: type: object properties: success: type: boolean message: type: string errors: type: object required: - success - message - errors responses: Forbidden: description: Forbidden. content: application/json: schema: $ref: '#/components/schemas/Error' InternalServerError: description: 'Internal server error.' content: application/json: schema: $ref: '#/components/schemas/Error' NotFound: description: 'Not found.' content: application/json: schema: $ref: '#/components/schemas/Error' Unauthenticated: description: Unauthenticated. content: application/json: schema: $ref: '#/components/schemas/Error' ValidationFailed: description: 'Validation failed.' content: application/json: schema: $ref: '#/components/schemas/ValidationError' security: - default: [] paths: /api/v1/search: get: summary: 'Search documents' operationId: getApiV1Search description: 'Full-text search across indexed documents.' parameters: - in: query name: q description: 'Search query string.' required: true schema: type: string description: 'Search query string.' examples: - laptop - in: query name: per_page description: 'Results per page (max 250).' required: false schema: type: integer description: 'Results per page (max 250).' examples: - 10 - in: query name: page description: 'Page number.' required: false schema: type: integer description: 'Page number.' examples: - 1 - in: query name: sort_by description: 'Sort field and direction.' required: false schema: type: string description: 'Sort field and direction.' examples: - 'indexed_at:desc' - in: query name: filter_by description: 'Typesense filter expression.' required: false schema: type: string description: 'Typesense filter expression.' examples: - 'category:=electronics' responses: 200: description: 'Search results with pagination.' content: application/json: schema: $ref: '#/components/schemas/SearchResultResponse' example: success: true data: hits: - document: id: cc656455-2d38-3250-9c6f-5797c7051fc6 name: 'et saepe unde' description: 'Iure quos explicabo eaque dolores vel cupiditate.' price: 580 highlights: - field: name snippet: 'enim' text_match: 0.16 - document: id: 2ffbe34b-4d13-3982-90f7-53735211fb93 name: 'veniam aspernatur neque' description: 'Et officia vel quo corrupti debitis quia.' price: 366 highlights: - field: name snippet: 'inventore' text_match: 0.67 total: 42 per_page: 10 current_page: 1 last_page: 5 search_time_ms: 5 401: $ref: '#/components/responses/Unauthenticated' 403: $ref: '#/components/responses/Forbidden' 422: $ref: '#/components/responses/ValidationFailed' 500: $ref: '#/components/responses/InternalServerError' tags: - Search /api/v1/entities/search: post: summary: 'Search entities' operationId: postApiV1EntitiesSearch description: 'Search an internal entity collection and return matching IDs.' parameters: [] responses: 200: description: '' content: application/json: schema: type: object properties: success: type: boolean examples: - true message: type: string examples: - 'Search completed' data: type: object properties: ids: type: array items: type: string examples: - - '42' found: type: integer examples: - 1 examples: - success: true message: 'Search completed' data: ids: - '42' found: 1 401: $ref: '#/components/responses/Unauthenticated' 403: $ref: '#/components/responses/Forbidden' 422: $ref: '#/components/responses/ValidationFailed' 500: $ref: '#/components/responses/InternalServerError' 503: description: '' content: application/json: schema: type: object properties: success: type: boolean examples: - false message: type: string examples: - 'Search service unavailable.' examples: - success: false message: 'Search service unavailable.' tags: - Search requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/SearchEntitiesRequest' /api/v1/documents: post: summary: 'Index documents' operationId: postApiV1Documents description: 'Bulk index documents into the website collection.' parameters: [] responses: 201: description: '' content: application/json: schema: $ref: '#/components/schemas/IndexResultResponse' example: success: true data: indexed: 2 total: 2 collection: web_gzu16lymnbzh results: - success: true id: 882e5ae5-4a15-385b-9a9b-d64f080b8a91 - success: true id: 39efed0f-2acf-38b7-b073-301fc9f1283a message: 'Documents indexed successfully' 401: $ref: '#/components/responses/Unauthenticated' 403: $ref: '#/components/responses/Forbidden' 422: $ref: '#/components/responses/ValidationFailed' 500: $ref: '#/components/responses/InternalServerError' 502: description: 'When some import outcomes cannot be verified. Accepted rows remain indexed.' content: application/json: schema: type: object properties: success: type: boolean examples: - false message: type: string examples: - 'Document import outcomes could not be verified' data: type: object properties: indexed: type: integer examples: - 1 total: type: integer examples: - 2 collection: type: string examples: - web_example results: type: array items: type: object properties: success: type: boolean examples: - true examples: - - success: true - success: false code: 502 error: 'Import outcome is unknown' examples: - success: false message: 'Document import outcomes could not be verified' data: indexed: 1 total: 2 collection: web_example results: - success: true - success: false code: 502 error: 'Import outcome is unknown' tags: - Documents requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/IndexDocumentsRequest' '/api/v1/documents/{id}': get: summary: 'Get document' operationId: getApiV1DocumentsById description: 'Retrieve a single document by ID.' parameters: [] responses: 200: description: 'Document data.' content: application/json: schema: $ref: '#/components/schemas/DocumentResponse' example: success: true data: id: cc656455-2d38-3250-9c6f-5797c7051fc6 fields: name: 'et saepe unde' description: 'Iure quos explicabo eaque dolores vel cupiditate.' price: 580 account_id: acc_yw7hikcnvqf9 401: $ref: '#/components/responses/Unauthenticated' 403: $ref: '#/components/responses/Forbidden' 404: $ref: '#/components/responses/NotFound' 500: $ref: '#/components/responses/InternalServerError' tags: - Documents delete: summary: 'Delete document' operationId: deleteApiV1DocumentsById description: 'Remove a document from the collection.' parameters: [] responses: 200: description: '' content: application/json: schema: $ref: '#/components/schemas/DeleteResultResponse' example: success: true data: id: cc656455-2d38-3250-9c6f-5797c7051fc6 collection: web_u16lymnbzhqm message: 'Document deleted successfully' 401: $ref: '#/components/responses/Unauthenticated' 403: $ref: '#/components/responses/Forbidden' 404: $ref: '#/components/responses/NotFound' 500: $ref: '#/components/responses/InternalServerError' tags: - Documents parameters: - in: path name: id description: 'Document ID.' required: true schema: type: string examples: - doc-123 /api/v1/collection/info: get: summary: 'Get collection info' operationId: getApiV1CollectionInfo description: 'Retrieve metadata about the website collection.' parameters: [] responses: 200: description: 'Collection metadata.' content: application/json: schema: $ref: '#/components/schemas/CollectionInfoResponse' example: success: true data: name: web_gzu16lymnbzh num_documents: 8366 created_at: 1767225600 401: $ref: '#/components/responses/Unauthenticated' 403: $ref: '#/components/responses/Forbidden' 500: $ref: '#/components/responses/InternalServerError' tags: - Collections '/api/v1/entities/{collection}/index': get: summary: 'Inspect an entity index' operationId: getApiV1EntitiesByCollectionIndex description: 'Return schema and documents for source parity checks.' parameters: [] responses: 200: description: '' content: application/json: schema: $ref: '#/components/schemas/EntityIndexResponse' example: success: true data: collection: solidpixels_websites exists: true schema: name: solidpixels_websites fields: - name: name type: string optional: true facet: false - name: domain type: string optional: true facet: true - name: prefixed_id type: string optional: true facet: true - name: indexed_at type: int64 optional: true num_documents: 1 documents: - id: '1' name: Example domain: example.test prefixed_id: web_example state: component: solidpixels resource: websites profile_hash: e069d18f772a06e16693f20a87a38546171f8587f3d4ec2215a569ee158cf126 descriptor: fields: - name - domain public_id: prefixed_id hostname: domain key_type: int ready: true control_revision: 3 rebuild_revision: 1 watermark: 3 rejected_through: 0 message: 'Entity index inspected' 401: $ref: '#/components/responses/Unauthenticated' 403: $ref: '#/components/responses/Forbidden' 404: $ref: '#/components/responses/NotFound' 409: description: '' content: application/json: schema: type: object properties: success: type: boolean examples: - false message: type: string examples: - 'Search schema is incompatible.' examples: - success: false message: 'Search schema is incompatible.' 500: $ref: '#/components/responses/InternalServerError' 502: description: '' content: application/json: schema: type: object properties: success: type: boolean examples: - false message: type: string examples: - 'Invalid search response.' examples: - success: false message: 'Invalid search response.' 503: description: '' content: application/json: schema: type: object properties: success: type: boolean examples: - false message: type: string examples: - 'Search service unavailable.' examples: - success: false message: 'Search service unavailable.' tags: - Collections parameters: - in: path name: collection description: 'Component-owned resource collection.' required: true schema: type: string examples: - solidpixels_websites