API Reference

The ExtractVibe API lets you extract comprehensive brand kits from any website programmatically. All endpoints are served from https://extractvibe.com/api.

Base URL

https://extractvibe.com/api

Quick start

Extract a brand kit in three steps: start an extraction, poll for completion, then fetch the result.

Quick start
# 1. Start extraction
JOB=$(curl -s -X POST https://extractvibe.com/api/extract \
  -H "Content-Type: application/json" \
  -H "x-api-key: ev_your_api_key_here" \
  -d '{"url": "https://stripe.com"}')

JOB_ID=$(echo $JOB | jq -r '.jobId')

# 2. Poll until complete (typically 15-25 seconds)
curl -s https://extractvibe.com/api/extract/$JOB_ID \
  -H "x-api-key: ev_your_api_key_here"

# 3. Get the brand kit
curl -s https://extractvibe.com/api/extract/$JOB_ID/result \
  -H "x-api-key: ev_your_api_key_here" | jq .

Authentication

ExtractVibe supports two authentication methods: session cookies and API keys. Session cookies are set automatically when you sign in through the web interface. API keys are designed for programmatic access and server-to-server integrations.

To authenticate with an API key, include it in the `x-api-key` header of your request. API keys use the `ev_` prefix and can be created and managed from your dashboard or via the API keys endpoints.

Some endpoints work without authentication (marked as "optional" or "none"). Anonymous requests are subject to stricter rate limits. Authenticated requests receive higher limits based on your plan tier.

Never expose your API key in client-side code. Use environment variables on your server and proxy requests if you need to call the API from a browser.

Session cookie

Browser (session)
# Session cookies are set automatically after sign-in.
# Include credentials in browser requests:
fetch("/api/credits", { credentials: "include" });

API key

Server (API key)
curl https://extractvibe.com/api/credits \
  -H "x-api-key: ev_your_api_key_here"

Rate Limits

All endpoints are rate limited. Limits vary by authentication tier. Rate limit information is included in response headers: X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset.

TierReadsWritesWindow
Anonymous30 req/min3 req/day60s / 24h
Free60 req/min10 req/min60s
Starter180 req/min30 req/min60s
Pro600 req/min60 req/min60s

Error Codes

The API uses standard HTTP status codes. All error responses include a JSON body with an error field describing the problem.

StatusNameDescription
400Bad RequestThe request body is malformed or missing required fields. Check the endpoint documentation for required parameters.
401UnauthorizedAuthentication is required but was not provided, or the provided credentials are invalid.
402Payment RequiredYour credit balance is zero. Upgrade your plan or wait for the monthly reset.
404Not FoundThe requested resource does not exist. The job ID, API key, or brand domain was not found.
429Too Many RequestsYou have exceeded the rate limit for your tier. Check the X-RateLimit-Reset header for when you can retry.
500Internal Server ErrorAn unexpected error occurred. If this persists, please open an issue on GitHub.

Error response format

429 Too Many Requests
{
  "error": "Rate limit exceeded",
  "limit": 30,
  "retryAfter": 45
}

Endpoints

Complete reference for all 12 API endpoints. Each endpoint includes authentication requirements, rate limits, request/response schemas, and code examples in cURL, JavaScript, and Python.

GET
/api/health

Health check

Returns the API status, version, and current timestamp. Use this to verify connectivity before making other calls.

Auth: none
Rate limit: None

Responses

200API is healthy
json
{
  "ok": true,
  "version": "0.1.0",
  "timestamp": 1742342400000
}

Examples

bash
curl https://extractvibe.com/api/health
POST
/api/extract

Start extraction

Starts a brand extraction job for the given URL. Returns a job ID that you can use to poll for status and retrieve results. Each extraction costs 1 credit for authenticated users. Anonymous users get 3 free extractions per day.

Auth: optional
Rate limit: Varies by tier (anon: 3/day, free: 10/min, starter: 30/min, pro: 60/min)

Request body

JSON object with a `url` field. The URL can include or omit the protocol -- `https://` will be prepended automatically if missing.

application/json
{
  "url": "https://stripe.com"
}

Responses

202Extraction job created
json
{
  "jobId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "domain": "stripe.com"
}
400Invalid or missing URL
json
{
  "error": "Missing required field: url"
}
402No credits remaining
json
{
  "error": "No credits remaining. Upgrade your plan or wait for monthly reset."
}
429Rate limit exceeded
json
{
  "error": "Rate limit exceeded",
  "limit": 3,
  "retryAfter": 72000
}

Examples

bash
curl -X POST https://extractvibe.com/api/extract \
  -H "Content-Type: application/json" \
  -H "x-api-key: ev_your_api_key_here" \
  -d '{"url": "https://stripe.com"}'
GET
/api/extract/:jobId

Poll job status

Check the current status of an extraction job. The status field will be one of: `queued`, `running`, `complete`, or `errored`. Anyone with the job ID can poll status.

Auth: optional
Rate limit: Read tier (anon: 30/min, free: 60/min, starter: 180/min, pro: 600/min)

Path parameters

jobIdThe UUID returned from POST /api/extract

Responses

200Job status retrieved
json
{
  "jobId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "status": {
    "status": "running",
    "error": null,
    "output": null
  }
}
200Job completed
json
{
  "jobId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "status": {
    "status": "complete",
    "error": null,
    "output": {
      "domain": "stripe.com",
      "cached": true
    }
  }
}
404Job not found
json
{
  "error": "Job not found"
}

Examples

bash
curl https://extractvibe.com/api/extract/a1b2c3d4-e5f6-7890-abcd-ef1234567890 \
  -H "x-api-key: ev_your_api_key_here"
GET
/api/extract/:jobId/result

Get extraction result

Retrieve the full brand kit result for a completed extraction job. Returns the complete brand analysis including colors, typography, voice, personality, and rules. Results are cached in KV for fast retrieval.

Auth: optional
Rate limit: Read tier

Path parameters

jobIdThe UUID returned from POST /api/extract

Responses

200Brand kit result
json
{
  "meta": {
    "domain": "stripe.com",
    "url": "https://stripe.com",
    "extractedAt": "2026-03-18T12:00:00Z",
    "durationMs": 18420,
    "schemaVersion": "v1"
  },
  "colors": {
    "primary": "#635BFF",
    "secondary": "#0A2540",
    "accent": "#00D4AA",
    "background": "#FFFFFF",
    "palette": [
      {
        "hex": "#635BFF",
        "role": "primary",
        "name": "Stripe Purple"
      },
      {
        "hex": "#0A2540",
        "role": "secondary",
        "name": "Ink"
      },
      {
        "hex": "#00D4AA",
        "role": "accent",
        "name": "Cyan"
      },
      {
        "hex": "#425466",
        "role": "muted",
        "name": "Slate"
      },
      {
        "hex": "#F6F9FC",
        "role": "background",
        "name": "Off White"
      }
    ]
  },
  "typography": {
    "headings": {
      "family": "Sohne",
      "weight": "600",
      "style": "normal"
    },
    "body": {
      "family": "Sohne",
      "weight": "400",
      "style": "normal"
    },
    "mono": {
      "family": "Sohne Mono",
      "weight": "400",
      "style": "normal"
    },
    "scale": [
      14,
      16,
      20,
      24,
      32,
      48,
      64
    ]
  },
  "voice": {
    "tone": "confident, technical, approachable",
    "personality": [
      "innovative",
      "reliable",
      "developer-friendly"
    ],
    "writingStyle": "Clear and concise with technical precision. Uses active voice and addresses the reader directly.",
    "samplePhrases": [
      "Financial infrastructure for the internet",
      "Start building with Stripe",
      "Payments built for developers"
    ]
  },
  "logos": [
    {
      "url": "https://extractvibe-assets.r2.dev/stripe.com/logo-primary.svg",
      "type": "svg",
      "variant": "primary",
      "width": 120,
      "height": 50
    }
  ],
  "vibeScore": 92,
  "tags": [
    "premium",
    "developer-first",
    "polished",
    "enterprise"
  ]
}
404Result not ready or not found
json
{
  "error": "Result not found or still processing"
}

Examples

bash
curl https://extractvibe.com/api/extract/a1b2c3d4-e5f6-7890-abcd-ef1234567890/result \
  -H "x-api-key: ev_your_api_key_here"
GET
/api/brand/:domain

Get brand by domain

Retrieve a cached brand kit by domain name. This is a public endpoint that returns the most recent extraction result for a given domain. If the domain has not been extracted yet, returns 404.

Auth: optional
Rate limit: Read tier

Path parameters

domainThe domain name without protocol or www prefix (e.g., `stripe.com`)

Responses

200Cached brand kit
json
{
  "meta": {
    "domain": "stripe.com",
    "url": "https://stripe.com",
    "extractedAt": "2026-03-18T12:00:00Z",
    "durationMs": 18420,
    "schemaVersion": "v1"
  },
  "colors": {
    "primary": "#635BFF",
    "secondary": "#0A2540",
    "accent": "#00D4AA",
    "background": "#FFFFFF",
    "palette": [
      {
        "hex": "#635BFF",
        "role": "primary",
        "name": "Stripe Purple"
      }
    ]
  },
  "typography": {
    "headings": {
      "family": "Sohne",
      "weight": "600"
    },
    "body": {
      "family": "Sohne",
      "weight": "400"
    }
  },
  "voice": {
    "tone": "confident, technical, approachable",
    "personality": [
      "innovative",
      "reliable",
      "developer-friendly"
    ]
  },
  "vibeScore": 92,
  "tags": [
    "premium",
    "developer-first",
    "polished"
  ]
}
404Brand not found
json
{
  "error": "Brand not found. Extract it first."
}

Examples

bash
curl https://extractvibe.com/api/brand/stripe.com
GET
/api/extract/history

List extraction history

Returns the 50 most recent extraction jobs for the authenticated user, ordered by creation date descending. Each entry includes the job ID, domain, status, and timing information.

Auth: required
Rate limit: Read tier

Responses

200List of extractions
json
{
  "extractions": [
    {
      "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "domain": "stripe.com",
      "url": "https://stripe.com",
      "status": "complete",
      "durationMs": 18420,
      "createdAt": "2026-03-18T12:00:00Z",
      "completedAt": "2026-03-18T12:00:18Z"
    },
    {
      "id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
      "domain": "linear.app",
      "url": "https://linear.app",
      "status": "complete",
      "durationMs": 15230,
      "createdAt": "2026-03-17T09:30:00Z",
      "completedAt": "2026-03-17T09:30:15Z"
    }
  ]
}
401Not authenticated
json
{
  "error": "Unauthorized"
}

Examples

bash
curl https://extractvibe.com/api/extract/history \
  -H "x-api-key: ev_your_api_key_here"
GET
/api/extract/:jobId/export/:format

Export brand kit

Download a brand kit in various formats. Supported formats: `json` (full brand kit), `css` (CSS custom properties), `tailwind` (Tailwind CSS theme), `markdown` (human-readable report), and `tokens` (W3C design tokens). Returns the file as a download attachment.

Auth: required
Rate limit: Read tier

Path parameters

jobIdThe UUID of a completed extraction job
formatExport format: `json`, `css`, `tailwind`, `markdown`, or `tokens`

Responses

200File download (Content-Disposition: attachment)
json
/* stripe.com — extracted by ExtractVibe */
:root {
  --brand-primary: #635BFF;
  --brand-secondary: #0A2540;
  --brand-accent: #00D4AA;
  --brand-background: #FFFFFF;
  --brand-muted: #425466;
  --font-heading: "Sohne", sans-serif;
  --font-body: "Sohne", sans-serif;
  --font-mono: "Sohne Mono", monospace;
}
400Invalid format
json
{
  "error": "Invalid format. Use: json, css, tailwind, markdown, tokens"
}
404Result not found
json
{
  "error": "Result not found"
}

Examples

bash
# Download as CSS variables
curl -o stripe-variables.css \
  https://extractvibe.com/api/extract/a1b2c3d4-e5f6-7890-abcd-ef1234567890/export/css \
  -H "x-api-key: ev_your_api_key_here"

# Download as Tailwind theme
curl -o stripe-tailwind.css \
  https://extractvibe.com/api/extract/a1b2c3d4-e5f6-7890-abcd-ef1234567890/export/tailwind \
  -H "x-api-key: ev_your_api_key_here"
GET
/api/credits

Get credit balance

Returns the current credit balance and plan for the authenticated user. Free accounts start with 50 credits that reset monthly.

Auth: required
Rate limit: Read tier

Responses

200Credit balance
json
{
  "credits": 47,
  "plan": "free"
}
401Not authenticated
json
{
  "error": "Unauthorized"
}

Examples

bash
curl https://extractvibe.com/api/credits \
  -H "x-api-key: ev_your_api_key_here"
POST
/api/keys

Create API key

Creates a new API key for the authenticated user. The full key is returned only once in the response -- store it securely. Keys use the `ev_` prefix followed by 48 hex characters.

Auth: required
Rate limit: Write tier

Request body

Optional JSON object with a `name` field for the key. Defaults to "Default" if omitted.

application/json
{
  "name": "Production server"
}

Responses

201API key created
json
{
  "id": "c3d4e5f6-a7b8-9012-cdef-234567890123",
  "name": "Production server",
  "key": "ev_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4"
}
401Not authenticated
json
{
  "error": "Unauthorized"
}

Examples

bash
curl -X POST https://extractvibe.com/api/keys \
  -H "Content-Type: application/json" \
  -H "x-api-key: ev_your_existing_key" \
  -d '{"name": "Production server"}'
GET
/api/keys

List API keys

Returns all active API keys for the authenticated user. Keys are listed by creation date descending. The full key value is not returned -- only the ID, name, and timestamps.

Auth: required
Rate limit: Read tier

Responses

200List of API keys
json
{
  "keys": [
    {
      "id": "c3d4e5f6-a7b8-9012-cdef-234567890123",
      "name": "Production server",
      "createdAt": "2026-03-15T10:00:00Z",
      "lastUsedAt": "2026-03-18T14:30:00Z"
    },
    {
      "id": "d4e5f6a7-b8c9-0123-defa-345678901234",
      "name": "Development",
      "createdAt": "2026-03-10T08:00:00Z",
      "lastUsedAt": null
    }
  ]
}
401Not authenticated
json
{
  "error": "Unauthorized"
}

Examples

bash
curl https://extractvibe.com/api/keys \
  -H "x-api-key: ev_your_api_key_here"
DELETE
/api/keys/:id

Revoke API key

Permanently deletes an API key. The key will immediately stop working for any requests. This action cannot be undone.

Auth: required
Rate limit: Write tier

Path parameters

idThe UUID of the API key to revoke

Responses

200Key revoked
json
{
  "ok": true
}
404Key not found
json
{
  "error": "Key not found"
}
401Not authenticated
json
{
  "error": "Unauthorized"
}

Examples

bash
curl -X DELETE https://extractvibe.com/api/keys/c3d4e5f6-a7b8-9012-cdef-234567890123 \
  -H "x-api-key: ev_your_api_key_here"
GET
/api/openapi.json

OpenAPI specification

Returns the OpenAPI 3.1 specification for the ExtractVibe API. Use this to generate client libraries, import into Postman, or integrate with any OpenAPI-compatible tooling.

Auth: none
Rate limit: None

Responses

200OpenAPI 3.1 JSON spec
json
{
  "openapi": "3.1.0",
  "info": {
    "title": "ExtractVibe API",
    "version": "0.1.0",
    "description": "Brand intelligence extraction API"
  },
  "servers": [
    {
      "url": "https://extractvibe.com"
    }
  ],
  "paths": {
    "...": "Full endpoint definitions"
  }
}

Examples

bash
# Download the OpenAPI spec
curl -o openapi.json https://extractvibe.com/api/openapi.json

# Import into Postman or generate a client
npx openapi-typescript openapi.json -o types.ts