API Reference

The Bittlebits REST API lets you programmatically score pages, retrieve rewrite suggestions, and poll for results. All endpoints are available at https://bittlebits.ai/api/v1/.


Authentication

All requests require an API key. Pass it as one of the following headers:

Authorization: YOUR_API_KEY
X-API-Key: YOUR_API_KEY

Generate or rotate your key from Settings → API Key in the Bittlebits dashboard. Requests without a valid key return 401 Unauthorized.


Score

Score a page against Bittlebits' GEO metrics. Each metric is rated 0–10.

POST /v1/score

Submit a URL for scoring. Parameters are passed as query strings.

Rate limit: 100 requests/hour per IP.

POST /v1/score?url=https://example.com/page
ParameterTypeRequiredDescription
urlstringone of url / url_idThe page URL to score
url_idnumberone of url / url_idA previously submitted URL by its Bittlebits ID
link_userbooleannoAssociate this URL with your account (default: true)

Example Code

const res = await fetch('https://bittlebits.ai/api/v1/score?url=https://example.com/page', {
  method: 'POST',
  headers: { 'X-API-Key': YOUR_API_KEY },
});

const data = await res.json();
// { status: 'submitted', url_id: 42, created: true }
import requests

res = requests.post(
    'https://bittlebits.ai/api/v1/score',
    params={'url': 'https://example.com/page'},
    headers={'X-API-Key': YOUR_API_KEY},
)

data = res.json()
# { 'status': 'submitted', 'url_id': 42, 'created': True }

Response 200 OK

{
  "status": "submitted",
  "url_id": 42,
  "created": true
}

created: true means the URL is new and must be scraped before scoring. created: false means the URL was already known and scoring has been queued directly. In either case, poll GET /v1/score for the result.


GET /v1/score

Retrieve the latest score for a URL. Parameters are passed as query strings.

Rate limit: 5 requests/second per IP.

GET /v1/score?url_id=42
X-API-Key: YOUR_API_KEY
ParameterTypeRequiredDescription
url_idnumberone of url_id / urlThe Bittlebits URL ID
urlstringone of url_id / urlThe page URL

Response — ready 200 OK

{
  "url_id": 42,
  "metrics": {
    "citation_readiness": 8.2,
    "content_depth": 6.5,
    "entity_clarity": 7.1
  }
}

Response — pending 202 Accepted

{
  "status": "pending",
  "task_id": "abc123",
  "url_id": 42
}

Poll at a 2-second interval until you receive 200 OK. See Polling.


Rewrite

Retrieve GEO rewrite suggestions for a page.

POST /v1/rewrite

Queue a rewrite for a URL. Same parameters and response shape as POST /v1/score.

POST /v1/rewrite?url_id=42
X-API-Key: YOUR_API_KEY

Example:

const res = await fetch('https://bittlebits.ai/api/v1/rewrite?url=https://example.com/page', {
  method: 'POST',
  headers: { 'X-API-Key': YOUR_API_KEY },
});

const data = await res.json();
// { status: 'submitted', url_id: 42, created: true }

GET /v1/rewrite

Retrieve rewrite suggestions for a URL. Parameters are passed as query strings.

Rate limit: 5 requests/second per IP.

GET /v1/rewrite?url_id=42
X-API-Key: YOUR_API_KEY
ParameterTypeRequiredDescription
url_idnumberone of url_id / urlThe Bittlebits URL ID
urlstringone of url_id / urlThe page URL

Response — ready 200 OK

{
  "url_id": 42,
  "parsed_html": "# Original page content...",
  "suggestions": [
    {
      "stable_id": "hero-h1",
      "current_text": "Welcome to our site",
      "suggested_text": "The leading platform for X",
      "rationale": "More specific entity signal for AI citation",
      "is_addition": false
    }
  ]
}

Response — pending 202 Accepted

{
  "status": "pending",
  "task_id": "abc123",
  "url_id": 42
}

Polling

Scoring and rewriting are async. A 202 Accepted response means the task is queued or running — poll the GET endpoint until you receive 200 OK.

Recommended interval: 2 seconds. Most operations complete within 30–60 seconds.

async function pollUntilReady(urlId) {
  for (let i = 0; i < 30; i++) {
    const res = await fetch(`https://bittlebits.ai/api/v1/score?url_id=${urlId}`, {
      headers: { 'X-API-Key': YOUR_API_KEY },
    });

    const data = await res.json();
    if (res.status === 200) return data;
    if (res.status !== 202) throw new Error(data.error);

    await new Promise(r => setTimeout(r, 2000));
  }
  throw new Error('Timed out waiting for score');
}
import time
import requests

def poll_until_ready(url_id):
    for _ in range(30):
        res = requests.get(
            'https://bittlebits.ai/api/v1/score',
            params={'url_id': url_id},
            headers={'X-API-Key': YOUR_API_KEY},
        )
        if res.status_code == 200:
            return res.json()
        if res.status_code != 202:
            raise RuntimeError(res.json().get('error', res.text))
        time.sleep(2)
    raise TimeoutError('Timed out waiting for score')

Do not retry with a new POST while a task is already pending for the same URL.


Errors

All error responses follow the same shape:

{
  "error": "Human-readable description of the error"
}
StatusMeaning
200 SuccessThe request was successful and the data was returned
202 Accepted / PollThe request was accepted and the response is processing. Poll the api endpoint until 200
400 Bad RequestMissing or invalid parameters (e.g. neither url nor url_id provided)
401 UnauthorizedMissing or invalid API key
404 Not FoundThe requested url_id does not exist, or no task has been submitted for it yet
410 GoneThe task was revoked — resubmit with POST
429 Too Many RequestsRate limit exceeded — back off and retry
500 Internal Server ErrorSomething went wrong on our end
504 Gateway TimeoutThe task timed out — resubmit with POST