Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,13 @@ className="border-[var(--border)] bg-[var(--card)] text-[var(--foreground)]"

## API Route Handlers

When implementing a new API route, ask the user whether it should be part of the public API. If yes:

1. Add the request/response Zod schemas to `packages/web/src/openapi/publicApiSchemas.ts`, calling `.openapi('SchemaName')` on each schema to register it with a name.
2. Register the route in `packages/web/src/openapi/publicApiDocument.ts` using `registry.registerPath(...)`, assigning it to the appropriate tag.
3. Add the endpoint to the relevant group in the `API Reference` tab of `docs/docs.json`.
4. Regenerate the OpenAPI spec by running `yarn workspace @sourcebot/web openapi:generate`.

Route handlers should validate inputs using Zod schemas.

**Query parameters** (GET requests):
Expand Down
32 changes: 20 additions & 12 deletions docs/api-reference/sourcebot-public.openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,8 @@
"description": "System health and version endpoints."
},
{
"name": "User Management (EE)",
"description": "User management endpoints. Requires the `org-management` entitlement and OWNER role."
},
{
"name": "Audit (EE)",
"description": "Audit log endpoints. Requires the `audit` entitlement and OWNER role."
"name": "Enterprise (EE)",
"description": "Enterprise endpoints for user management and audit logging."
}
],
"security": [
Expand Down Expand Up @@ -1100,13 +1096,13 @@
"bearerToken": {
"type": "http",
"scheme": "bearer",
"description": "Send either a Sourcebot API key (`sbk_...`) or, on EE instances with OAuth enabled, an OAuth access token (`sboa_...`) in the Authorization header."
"description": "Bearer authentication header of the form `Bearer <token>`, where `<token>` is your API key."
},
"apiKeyHeader": {
"type": "apiKey",
"in": "header",
"name": "X-Sourcebot-Api-Key",
"description": "Send a Sourcebot API key (`sbk_...`) in the X-Sourcebot-Api-Key header."
"description": "Header of the form `X-Sourcebot-Api-Key: <token>`, where `<token>` is your API key."
}
}
},
Expand Down Expand Up @@ -1828,10 +1824,13 @@
"get": {
"operationId": "getUser",
"tags": [
"User Management (EE)"
"Enterprise (EE)"
],
"summary": "Get a user",
"description": "Fetches profile details for a single organization member by `userId`. Only organization owners can access this endpoint.",
"x-mint": {
"content": "<Note>\nThis API is only available with an active Enterprise license. Please add your [license key](/docs/license-key) to activate it.\n</Note>"
},
"parameters": [
{
"schema": {
Expand Down Expand Up @@ -1900,10 +1899,13 @@
"delete": {
"operationId": "deleteUser",
"tags": [
"User Management (EE)"
"Enterprise (EE)"
],
"summary": "Delete a user",
"description": "Permanently deletes a user and all associated records. Only organization owners can delete other users.",
"x-mint": {
"content": "<Note>\nThis API is only available with an active Enterprise license. Please add your [license key](/docs/license-key) to activate it.\n</Note>"
},
"parameters": [
{
"schema": {
Expand Down Expand Up @@ -1974,10 +1976,13 @@
"get": {
"operationId": "listUsers",
"tags": [
"User Management (EE)"
"Enterprise (EE)"
],
"summary": "List users",
"description": "Returns all members of the organization. Only organization owners can access this endpoint.",
"x-mint": {
"content": "<Note>\nThis API is only available with an active Enterprise license. Please add your [license key](/docs/license-key) to activate it.\n</Note>"
},
"responses": {
"200": {
"description": "List of organization members.",
Expand Down Expand Up @@ -2016,10 +2021,13 @@
"get": {
"operationId": "listAuditRecords",
"tags": [
"Audit (EE)"
"Enterprise (EE)"
],
"summary": "List audit records",
"description": "Returns a paginated list of audit log entries. Only organization owners can access this endpoint.",
"x-mint": {
"content": "<Note>\nThis API is only available with an active Enterprise license. Please add your [license key](/docs/license-key) to activate it.\n</Note>"
},
"parameters": [
{
"schema": {
Expand Down
7 changes: 7 additions & 0 deletions docs/docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,13 @@
"icon": "code",
"openapi": "api-reference/sourcebot-public.openapi.json",
"groups": [
{
"group": "Overview",
"icon": "book-open",
"pages": [
"docs/api-reference/authentication"
]
},
{
"group": "Search & Navigation",
"icon": "magnifying-glass",
Expand Down
34 changes: 34 additions & 0 deletions docs/docs/api-reference/authentication.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
---
title: "Authentication"
---

To securely access and interact with Sourcebot’s API, authentication is required. Users must generate an API Key, which will be used to authenticate requests.

<Note>
If [anonymous access](/docs/configuration/auth/access-settings#anonymous-access) is enabled, some endpoints will be accessible without a API key.
</Note>

## Creating an API key

Navigate to **Settings → API Keys** and click **Create API Key**. Copy the value - it is only shown once.

<Frame>
<img src="/images/mcp_api_key_settings.png" alt="API Keys page in Sourcebot Settings" />
</Frame>

## Using an API key

Pass your API key as a Bearer token in the `Authorization` header on every request.

```bash
Authorization: Bearer <your-api-key>
```

For example, to call the `/api/search` endpoint:

```bash
curl -X POST https://your-sourcebot-instance.com/api/search \
-H "Authorization: Bearer <your-api-key>" \
-H "Content-Type: application/json" \
-d '{"query": "hello world", "matches": 10}'
```
35 changes: 26 additions & 9 deletions packages/web/src/openapi/publicApiDocument.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,13 @@ const searchTag = { name: 'Search & Navigation', description: 'Code search and s
const reposTag = { name: 'Repositories', description: 'Repository listing and metadata endpoints.' };
const gitTag = { name: 'Git', description: 'Git history, diff, and file content endpoints.' };
const systemTag = { name: 'System', description: 'System health and version endpoints.' };
const eeUserManagementTag = { name: 'User Management (EE)', description: 'User management endpoints. Requires the `org-management` entitlement and OWNER role.' };
const eeAuditTag = { name: 'Audit (EE)', description: 'Audit log endpoints. Requires the `audit` entitlement and OWNER role.' };
const eeTag = { name: 'Enterprise (EE)', description: 'Enterprise endpoints for user management and audit logging.' };

const EE_LICENSE_KEY_NOTE = dedent`
<Note>
This API is only available with an active Enterprise license. Please add your [license key](/docs/license-key) to activate it.
</Note>
`;

const publicFileTreeNodeSchema: SchemaObject = {
type: 'object',
Expand Down Expand Up @@ -67,13 +72,13 @@ const securitySchemes: Record<keyof typeof securitySchemeNames, SecuritySchemeOb
[securitySchemeNames.bearerToken]: {
type: 'http',
scheme: 'bearer',
description: 'Send either a Sourcebot API key (`sbk_...`) or, on EE instances with OAuth enabled, an OAuth access token (`sboa_...`) in the Authorization header.',
description: 'Bearer authentication header of the form `Bearer <token>`, where `<token>` is your API key.',
},
[securitySchemeNames.apiKeyHeader]: {
type: 'apiKey',
in: 'header',
name: 'X-Sourcebot-Api-Key',
description: 'Send a Sourcebot API key (`sbk_...`) in the X-Sourcebot-Api-Key header.',
description: 'Header of the form `X-Sourcebot-Api-Key: <token>`, where `<token>` is your API key.',
},
};

Expand Down Expand Up @@ -339,7 +344,7 @@ export function createPublicOpenApiDocument(version: string) {
method: 'get',
path: '/api/ee/user',
operationId: 'getUser',
tags: [eeUserManagementTag.name],
tags: [eeTag.name],
summary: 'Get a user',
description: 'Fetches profile details for a single organization member by `userId`. Only organization owners can access this endpoint.',
request: {
Expand All @@ -357,13 +362,16 @@ export function createPublicOpenApiDocument(version: string) {
404: errorJson('User not found.'),
500: errorJson('Unexpected failure.'),
},
'x-mint': {
content: EE_LICENSE_KEY_NOTE,
},
});

registry.registerPath({
method: 'delete',
path: '/api/ee/user',
operationId: 'deleteUser',
tags: [eeUserManagementTag.name],
tags: [eeTag.name],
summary: 'Delete a user',
description: 'Permanently deletes a user and all associated records. Only organization owners can delete other users.',
request: {
Expand All @@ -381,13 +389,16 @@ export function createPublicOpenApiDocument(version: string) {
404: errorJson('User not found.'),
500: errorJson('Unexpected failure.'),
},
'x-mint': {
content: EE_LICENSE_KEY_NOTE,
},
});

registry.registerPath({
method: 'get',
path: '/api/ee/users',
operationId: 'listUsers',
tags: [eeUserManagementTag.name],
tags: [eeTag.name],
summary: 'List users',
description: 'Returns all members of the organization. Only organization owners can access this endpoint.',
responses: {
Expand All @@ -398,14 +409,17 @@ export function createPublicOpenApiDocument(version: string) {
403: errorJson('Insufficient permissions or entitlement not enabled.'),
500: errorJson('Unexpected failure.'),
},
'x-mint': {
content: EE_LICENSE_KEY_NOTE,
},
});

// EE: Audit
registry.registerPath({
method: 'get',
path: '/api/ee/audit',
operationId: 'listAuditRecords',
tags: [eeAuditTag.name],
tags: [eeTag.name],
summary: 'List audit records',
description: 'Returns a paginated list of audit log entries. Only organization owners can access this endpoint.',
request: {
Expand All @@ -430,6 +444,9 @@ export function createPublicOpenApiDocument(version: string) {
403: errorJson('Insufficient permissions or entitlement not enabled.'),
500: errorJson('Unexpected failure.'),
},
'x-mint': {
content: EE_LICENSE_KEY_NOTE,
},
});

const generator = new OpenApiGeneratorV3(registry.definitions);
Expand All @@ -441,7 +458,7 @@ export function createPublicOpenApiDocument(version: string) {
version,
description: 'OpenAPI description for the public Sourcebot REST endpoints used for search, repository listing, and file browsing. Authentication is instance-dependent: API keys are the standard integration mechanism, OAuth bearer tokens are EE-only, and some instances may allow anonymous access.',
},
tags: [searchTag, reposTag, gitTag, systemTag, eeUserManagementTag, eeAuditTag],
tags: [searchTag, reposTag, gitTag, systemTag, eeTag],
security: [
{ [securitySchemeNames.bearerToken]: [] },
{ [securitySchemeNames.apiKeyHeader]: [] },
Expand Down
Loading