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