API reference

Documentation

Integrate semantic search, AI answers, and site indexing.

Base URLhttps://api.surge-search.com

Overview

All API routes live under /v1. Successful responses wrap payloads in { "data": … }. Errors return { "errors": [{ status, title, code }] }.

There are three access levels:

  • API key: search, answer, and index from your app or server
  • Cognito JWT: dashboard management (projects, keys, jobs, analytics)
  • Unauthenticated: demo leads, claim, signup, and signin

Authentication

Send your API key as x-surge-api-key: <key> or Authorization: Bearer <key>.

PrefixUseEndpoints
pk_live_…Browser, mobile, React SDK/v1/search, /v1/answer
sk_live_…Server-side onlyAll public endpoints including /v1/index

Publishable keys are rate-limited per IP (60 search / 20 answer requests per minute). Secret keys are subject to your plan quota only.

Management routes require a Cognito ID token: Authorization: Bearer <idToken>. The JWT must include custom:tenantId matching the tenantId in the path.

Answer

POST/v1/answer

API key (pk_ or sk_)

AI-generated answer with cited sources from your indexed content.

Request body

{
  "question": "How long is the free trial?",
  "projectId": "optional",
  "mode": "default"
}

mode is "default" or "fact_check" (stricter grounding).

Response 200

{
  "data": {
    "question": "How long is the free trial?",
    "answer": "The free trial lasts 14 days… [1]",
    "sources": [
      { "url": "…", "title": "Pricing", "excerpt": "…" }
    ]
  }
}

Index

POST/v1/index

Secret API key (sk_) only

Queue a crawl and vector index for a URL. Creates a project if needed.

Request body

{
  "url": "https://example.com",
  "projectId": "optional"
}

Response 202

{
  "data": {
    "jobId": "01J…",
    "projectId": "01J…",
    "status": "queued"
  }
}

Projects

Manage indexed sites for your tenant. All routes require a Cognito JWT.

GET/v1/tenants/{tenantId}/projects

Cognito JWT

List all projects.

{
  "data": [
    {
      "projectId": "01J…",
      "name": "example.com",
      "url": "https://example.com",
      "indexStatus": "idle",
      "pageCount": 42,
      "lastIndexedAt": "2026-05-28T12:00:00.000Z"
    }
  ]
}
POST/v1/tenants/{tenantId}/projects

Cognito JWT

{ "url": "https://example.com", "name": "optional" }

Returns 201 with the created project.

POST/v1/tenants/{tenantId}/projects/{projectId}/reindex

Cognito JWT

Queue a full re-index. Returns 202 with jobId.

DELETE/v1/tenants/{tenantId}/projects/{projectId}

Cognito JWT

Delete project and purge vectors. Idempotent if already removed.

Jobs

GET/v1/tenants/{tenantId}/jobs

Cognito JWT

List recent index jobs.

GET/v1/tenants/{tenantId}/jobs/{jobId}

Cognito JWT

Get a single job. Status: queued, running, completed, or failed.

{
  "data": {
    "jobId": "01J…",
    "projectId": "01J…",
    "url": "https://example.com",
    "status": "completed",
    "pagesIndexed": 120,
    "createdAt": "…",
    "completedAt": "…"
  }
}

API keys

GET/v1/tenants/{tenantId}/api-keys

Cognito JWT

List keys (prefix only; raw secret is never returned again).

POST/v1/tenants/{tenantId}/api-keys

Cognito JWT

{
  "name": "Production",
  "type": "publishable"
}

type is "publishable" or "secret". Response 201 includes the full key once. Store it securely.

DELETE/v1/tenants/{tenantId}/api-keys/{apiKeyId}

Cognito JWT

Revoke a key immediately.

Analytics

GET/v1/tenants/{tenantId}/analytics/queries

Cognito JWT

Query analytics from the last ~500 searches and answers.

{
  "data": {
    "totalQueries": 42,
    "zeroResultRate": 0.12,
    "topQueries": [
      { "query": "pricing", "count": 5, "zeroResults": 0 }
    ],
    "zeroResultQueries": [
      { "query": "enterprise sso", "count": 3, "zeroResults": 3 }
    ]
  }
}

Usage

GET/v1/tenants/{tenantId}/usage

Cognito JWT

Current billing period usage and plan limits.

{
  "data": {
    "period": "2026-05",
    "plan": "starter",
    "usage": { "queries": 120, "answers": 30, "pagesIndexed": 450 },
    "limits": {
      "maxQueriesPerMonth": 1000,
      "maxIndexedPages": 1000,
      "maxSites": 3
    }
  }
}

Billing: POST …/billing/checkout with { "plan": "starter" | "plus" | "scale" } returns a Stripe Checkout URL. POST …/billing/portal opens the customer portal.

Errors

StatusCodeMeaning
400bad_requestInvalid request body or parameters
401unauthorizedMissing or invalid API key / JWT
403forbiddenWrong key type, suspended tenant, or wrong tenant
404not_foundResource does not exist
409conflictDuplicate (e.g. email already registered)
429quota_exceededRate limit or plan quota exceeded
500internalServer error