Skip to main content

Docs / API Error Reference

API Error Reference

Every Foglift API error response includes a machine-readable code field, a docs_url linking to the relevant section below, and a request_id for support correlation.

Response shape

All error responses follow this structure. The details field is present only when the error includes additional context (field validation failures, brand lists, etc.). Every response also includes a Link header (RFC 5988) pointing to this page, and an x-request-id header.

Standard error response
{
  "error": "Human-readable error message.",
  "code": "error_code_snake_case",
  "docs_url": "https://foglift.io/docs/api-errors#error_code_snake_case",
  "request_id": "req_...",
  "details": {}  // optional
}

HTTP headers:
  Link: <https://foglift.io/docs/api-errors#error_code_snake_case>; rel="help"
  x-request-id: req_...

cannot_delete_last_brand

400

Default message

Cannot remove your only brand. Create a new one first.

What triggers it

You called DELETE on your only remaining brand. Every account must have at least one brand.

How to recover

Create a new brand via POST /api/v1/brands before deleting the existing one.

Example request
curl -X DELETE https://foglift.io/api/v1/brands/8f4c2a10-6c2f-4b2e-b2a1-4c5e7f8a9b10 \
  -H "Authorization: Bearer sk_fog_..."
Example response
{
  "error": "Cannot remove your only brand. Create a new one first.",
  "code": "cannot_delete_last_brand",
  "docs_url": "https://foglift.io/docs/api-errors#cannot_delete_last_brand",
  "request_id": "req_m3k7x9..."
}

Related: /docs#rest-api

feature_gated

403

Default message

This feature is not available on your current plan.

What triggers it

You exceeded a per-plan usage limit — for example the brand limit, API key limit, or scheduled-scan limit for your plan. Plan-gated features (batch scans, sitemap scans, team seats, query fanouts) return 402 payment_required instead; this code covers limit-class gates where the feature itself is available but capped.

How to recover

Upgrade your plan at /dashboard/settings or /pricing for higher limits, or remove unused resources (brands, keys) to free up capacity. The details field reports your limit and current usage when available.

Example request
curl -X POST https://foglift.io/api/v1/brands \
  -H "Authorization: Bearer sk_fog_..." \
  -H "Content-Type: application/json" \
  -d '{"url": "https://newbrand.com"}'
Example response
{
  "error": "Your Launch plan allows up to 3 brands. Upgrade to add more.",
  "code": "feature_gated",
  "docs_url": "https://foglift.io/docs/api-errors#feature_gated",
  "request_id": "req_p8r2v5...",
  "details": {
    "limit": 3,
    "used": 3
  }
}

Related: /pricing, /docs#rate-limits

forbidden

403

Default message

You do not have permission to access this resource.

What triggers it

Your authenticated session or API key does not have permission to access the requested resource. This can happen when you try to access another account's data or a restricted admin endpoint.

How to recover

Verify that the API key belongs to the account that owns the resource. If you are using session-based auth, confirm you are logged in to the correct account.

Example request
curl https://foglift.io/api/v1/brands/8f4c2a10-6c2f-4b2e-b2a1-4c5e7f8a9b10 \
  -H "Authorization: Bearer sk_fog_..."
Example response
{
  "error": "You do not have permission to access this resource.",
  "code": "forbidden",
  "docs_url": "https://foglift.io/docs/api-errors#forbidden",
  "request_id": "req_j4n1w8..."
}

Related: /docs#rate-limits

idempotency_key_conflict

409

Default message

A request with this idempotency key has already been processed.

What triggers it

You sent a POST request with an Idempotency-Key header that matches a previously completed request. The original response is returned instead of processing a duplicate.

How to recover

If you intended a new request, generate a fresh idempotency key (a UUID works well). If you are retrying a failed request, use the same key to get the original response safely.

Example request
curl -X POST https://foglift.io/api/v1/ai-visibility \
  -H "Authorization: Bearer sk_fog_..." \
  -H "Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000" \
  -H "Content-Type: application/json" \
  -d '{"prompts": ["best SEO tool"]}'
Example response
{
  "error": "A request with this idempotency key has already been processed.",
  "code": "idempotency_key_conflict",
  "docs_url": "https://foglift.io/docs/api-errors#idempotency_key_conflict",
  "request_id": "req_q5s3t7..."
}

Related: /docs#ai-visibility-api

insufficient_tokens

402

Default message

Insufficient token balance for this operation.

What triggers it

Your monthly AI Visibility token balance cannot cover this request. Each AI engine query costs tokens at different rates: Gemini (1), ChatGPT (3), AI Overview (3), Claude (5), Perplexity (5).

How to recover

Wait for your token balance to reset at the start of your next billing cycle. Alternatively, upgrade your plan for a higher monthly token allowance, or disable expensive engines via POST /api/v1/models to stretch your remaining budget.

Example request
curl -X POST https://foglift.io/api/v1/ai-visibility \
  -H "Authorization: Bearer sk_fog_..." \
  -H "Content-Type: application/json" \
  -d '{"prompts": ["best AI search tool"], "models": ["chatgpt","claude"]}'
Example response
{
  "error": "Insufficient token balance for this operation.",
  "code": "insufficient_tokens",
  "docs_url": "https://foglift.io/docs/api-errors#insufficient_tokens",
  "request_id": "req_a9c4d2..."
}

Related: /pricing, /docs/ai-assistant-setup

internal_error

500

Default message

An internal error occurred. Please try again or contact support.

What triggers it

An unexpected server-side failure. This is not caused by your request payload or authentication.

How to recover

Retry the request after a short delay (start with 1 second, then back off exponentially). If the error persists across multiple retries, contact support@foglift.io with the request_id from the response.

Example request
curl https://foglift.io/api/v1/scan?url=https://example.com \
  -H "Authorization: Bearer sk_fog_..."
Example response
{
  "error": "An internal error occurred. Please try again or contact support.",
  "code": "internal_error",
  "docs_url": "https://foglift.io/docs/api-errors#internal_error",
  "request_id": "req_f7h2k9..."
}

Related: /docs#rest-api

invalid_api_key

401

Default message

The provided API key is invalid or has been revoked.

What triggers it

The API key in your Authorization header (or X-API-Key header) does not match any active key. The key may have been deleted, rotated, or typed incorrectly.

How to recover

Generate a new API key at /dashboard/settings. API keys use the sk_fog_ prefix. Make sure you are passing the full key, not a truncated version.

Example request
curl https://foglift.io/api/v1/scan?url=https://example.com \
  -H "Authorization: Bearer sk_fog_INVALID"
Example response
{
  "error": "The provided API key is invalid or has been revoked.",
  "code": "invalid_api_key",
  "docs_url": "https://foglift.io/docs/api-errors#invalid_api_key",
  "request_id": "req_b3e6g1..."
}

Related: /docs#rate-limits, /dashboard/settings

invalid_payload

400

Default message

The request body is invalid or malformed.

What triggers it

The JSON body of your request could not be parsed, or the top-level structure does not match the expected schema. Common causes: missing Content-Type header, trailing commas in JSON, or sending form-encoded data instead of JSON.

How to recover

Confirm your request includes Content-Type: application/json and the body is valid JSON. Use a JSON linter to check for syntax errors.

Example request
curl -X POST https://foglift.io/api/v1/prompts \
  -H "Authorization: Bearer sk_fog_..." \
  -H "Content-Type: application/json" \
  -d '{invalid json}'
Example response
{
  "error": "The request body is invalid or malformed.",
  "code": "invalid_payload",
  "docs_url": "https://foglift.io/docs/api-errors#invalid_payload",
  "request_id": "req_c4f7h2..."
}

Related: /docs#rest-api

payment_required

402

Default message

Payment is required before this resource can be accessed.

What triggers it

Two triggers share this code. (1) Plan gate: you called a feature your current plan does not include — batch scans, sitemap scans, team seats, query fanouts, Win Rate, watched pages, knowledge bases, or Ask Foglift. These responses carry a details payload identifying the feature and the minimum plan that unlocks it. (2) Unpaid checkout: you attempted to retrieve a paid resource, such as a full scan report, before the checkout session was paid or completed.

How to recover

For plan gates, branch on details.feature and details.required_plan — upgrade at details.upgrade_url to unlock the feature. For unpaid checkout, complete payment and retry with the paid checkout session ID. If payment succeeded but the error persists, contact support with the request_id.

Example request
curl -X POST https://foglift.io/api/v1/scan/batch \
  -H "Authorization: Bearer sk_fog_..." \
  -H "Content-Type: application/json" \
  -d '{"urls": ["https://a.com", "https://b.com"]}'
Example response
{
  "error": "Batch scanning requires a Launch plan or higher.",
  "code": "payment_required",
  "docs_url": "https://foglift.io/docs/api-errors#payment_required",
  "request_id": "req_p2q5r8...",
  "details": {
    "feature": "batch_scan",
    "required_plan": "launch",
    "upgrade_url": "https://foglift.io/pricing"
  }
}

Related: /pricing, /docs#rest-api

missing_workspace_id

400

Default message

brand_id is required for this endpoint.

What triggers it

You called an endpoint that operates on a specific brand, but did not include the brand_id parameter. This only occurs on accounts with multiple brands where the system cannot infer which brand you mean.

How to recover

Include brand_id as a query parameter or in the request body. workspace_id is accepted as a legacy alias. Get your brand IDs from GET /api/v1/brands or from /dashboard/developer.

Example request
curl https://foglift.io/api/v1/ai-visibility/results \
  -H "Authorization: Bearer sk_fog_..."
Example response
{
  "error": "brand_id is required for this endpoint.",
  "code": "missing_workspace_id",
  "docs_url": "https://foglift.io/docs/api-errors#missing_workspace_id",
  "request_id": "req_d5g8j3..."
}

Related: /docs#ai-visibility-api

multi_brand_disambiguation_required

400

Default message

Account has multiple brands. Pass brand_id to disambiguate.

What triggers it

Your account has more than one brand and the endpoint needs to know which one to target. Unlike missing_workspace_id, this error includes a list of your available brands in the details field to help you pick the right one.

How to recover

Choose the correct brand_id from the brands array in the error response, then resend your request with that ID. workspace_id is accepted as a legacy alias.

Example request
curl -X POST https://foglift.io/api/v1/ai-visibility \
  -H "Authorization: Bearer sk_fog_..." \
  -H "Content-Type: application/json" \
  -d '{"prompts": ["best AI tool"]}'
Example response
{
  "error": "Account has multiple brands. Pass brand_id to disambiguate.",
  "code": "multi_brand_disambiguation_required",
  "docs_url": "https://foglift.io/docs/api-errors#multi_brand_disambiguation_required",
  "request_id": "req_e6h9k4...",
  "details": {
    "brands": [
      { "id": "8f4c2a10-6c2f-4b2e-b2a1-4c5e7f8a9b10", "name": "Brand A", "domain": "branda.com" },
      { "id": "1f2e3d4c-5b6a-4789-8abc-0def12345678", "name": "Brand B", "domain": "brandb.com" }
    ]
  }
}

Related: /docs#ai-visibility-api, /docs#mcp-server

not_found

404

Default message

The requested resource was not found.

What triggers it

The endpoint path is valid but the specific resource (brand, prompt, scan result) does not exist. The resource may have been deleted or the ID may be incorrect.

How to recover

Verify the resource ID. For brands, use GET /api/v1/brands to list your current brands. For prompts, use GET /api/v1/prompts to list active prompts.

Example request
curl https://foglift.io/api/v1/brands/00000000-0000-4000-8000-000000000000 \
  -H "Authorization: Bearer sk_fog_..."
Example response
{
  "error": "The requested resource was not found.",
  "code": "not_found",
  "docs_url": "https://foglift.io/docs/api-errors#not_found",
  "request_id": "req_g7j0m5..."
}

Related: /docs#rest-api

prompt_already_exists

409

Default message

This prompt already exists for the brand.

What triggers it

You attempted to add a prompt that is already being tracked for the target brand. Prompt text is compared case-insensitively after trimming whitespace.

How to recover

Check your existing prompts with GET /api/v1/prompts?brand_id=... before adding. workspace_id is accepted as a legacy alias. If you want to re-run the prompt, use POST /api/v1/ai-visibility instead of creating a duplicate.

Example request
curl -X POST https://foglift.io/api/v1/prompts \
  -H "Authorization: Bearer sk_fog_..." \
  -H "Content-Type: application/json" \
  -d '{"prompt": "best AI search tool", "brand_id": "8f4c2a10-6c2f-4b2e-b2a1-4c5e7f8a9b10"}'
Example response
{
  "error": "This prompt already exists for the brand.",
  "code": "prompt_already_exists",
  "docs_url": "https://foglift.io/docs/api-errors#prompt_already_exists",
  "request_id": "req_h8k1n6..."
}

Related: /docs#ai-visibility-api

rate_limited

429

Default message

Too many requests. Please retry after the rate limit window resets.

What triggers it

You have exceeded your daily scan quota or monthly request limit. Limits vary by plan: Free (10/day, 100/month), Launch (50/day, 1,000/month), Growth (200/day, 5,000/month), Enterprise (1,000/day, 25,000/month).

How to recover

Wait for the rate limit window to reset at 00:00 UTC (daily limits) or at the start of your billing cycle (monthly limits). Cache scan results in your application to avoid duplicate requests. Upgrade your plan for higher limits.

Example request
curl https://foglift.io/api/v1/scan?url=https://example.com \
  -H "Authorization: Bearer sk_fog_..."
Example response
{
  "error": "Too many requests. Please retry after the rate limit window resets.",
  "code": "rate_limited",
  "docs_url": "https://foglift.io/docs/api-errors#rate_limited",
  "request_id": "req_i9l2o7..."
}

Related: /pricing, /docs#rate-limits

service_unavailable

503

Default message

Foglift is temporarily unavailable. Please retry shortly.

What triggers it

Foglift is temporarily overloaded, a required provider is unavailable, or a route is missing required server-side configuration.

How to recover

Retry after the Retry-After header when present, then back off exponentially. If the issue persists, contact support with the request_id.

Example request
curl -X POST https://foglift.io/api/scan \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com"}'
Example response
{
  "error": "Foglift is temporarily unavailable. Please retry shortly.",
  "code": "service_unavailable",
  "docs_url": "https://foglift.io/docs/api-errors#service_unavailable",
  "request_id": "req_s3t6u9..."
}

Related: /docs#rest-api

unauthenticated

401

Default message

Authentication required. Provide a valid session or API key (Authorization: Bearer sk_fog_...).

What triggers it

The request did not include an API key or session cookie. Most Foglift API endpoints require authentication. The unauthenticated GET /api/v1/scan endpoint (up to 10 scans/day by IP) is the main exception.

How to recover

Add an Authorization header with your API key: Authorization: Bearer sk_fog_.... Generate a key at /dashboard/settings. The CLI and MCP server handle this automatically when configured.

Example request
curl https://foglift.io/api/v1/ai-visibility/results
Example response
{
  "error": "Authentication required. Provide a valid session or API key (Authorization: Bearer sk_fog_...).",
  "code": "unauthenticated",
  "docs_url": "https://foglift.io/docs/api-errors#unauthenticated",
  "request_id": "req_k0m3p8..."
}

Related: /docs#rate-limits, /dashboard/settings

validation_failed

400

Default message

One or more fields failed validation.

What triggers it

The request body is valid JSON but one or more field values do not pass validation rules. The details field lists which fields failed and why.

How to recover

Check the details object in the error response for specific field-level messages. Fix the invalid fields and retry.

Example request
curl -X POST https://foglift.io/api/v1/prompts \
  -H "Authorization: Bearer sk_fog_..." \
  -H "Content-Type: application/json" \
  -d '{"prompt": "", "brand_id": "8f4c2a10-6c2f-4b2e-b2a1-4c5e7f8a9b10"}'
Example response
{
  "error": "One or more fields failed validation.",
  "code": "validation_failed",
  "docs_url": "https://foglift.io/docs/api-errors#validation_failed",
  "request_id": "req_l1n4q9...",
  "details": {
    "fields": {
      "prompt": "Prompt text is required and must be between 3 and 500 characters."
    }
  }
}

Related: /docs#rest-api

workspace_access_denied

403

Default message

Workspace not found or access denied.

What triggers it

The brand_id you provided does not exist or does not belong to your account. This is distinct from forbidden, which covers general permission failures. This error is specific to brand-scoped endpoints.

How to recover

List your brands with GET /api/v1/brands and use a valid brand_id from that list. workspace_id is accepted as a legacy alias. If you recently deleted the brand, it is no longer accessible.

Example request
curl https://foglift.io/api/v1/prompts?brand_id=00000000-0000-4000-8000-000000000000 \
  -H "Authorization: Bearer sk_fog_..."
Example response
{
  "error": "Workspace not found or access denied.",
  "code": "workspace_access_denied",
  "docs_url": "https://foglift.io/docs/api-errors#workspace_access_denied",
  "request_id": "req_n2o5r0..."
}

Related: /docs#rest-api

Need help?

If you receive an error that is not listed here, or if an error persists after following the recovery steps, email support@foglift.io with the request_id from the error response. The request ID lets us locate the exact server-side log entry for your failed call.

Back to Documentation