sourcely/developers
SOURCELY API PREVIEW

Errors & recovery

Distinguish rejected requests, failed searches, and features still planned for production.

Implemented error mapping

HTTP / outcomeCode or shapeMeaningYour next step
401error.code: "invalid_api_key"The API key is missing, invalid, revoked, or expired.Send a valid dashboard key. No search is created.
402error.code: "insufficient_balance"Your credit balance cannot cover this search's estimated_cost.Top up or reduce the requested work. No search is created and nothing is deducted.
404error.code: "job_not_found"No retained record for this account, or the ID belongs to another account.Verify the ID and key. The result may have expired after one hour, been deleted, or been lost.
409error.code: "search_conflict"The search is already running or its state changed during a write.Read the known search ID; do not duplicate work automatically.
503error.code: "cache_unavailable"Redis could not confirm a read or write.Retry GET with backoff when the ID is known; POST outcomes may be uncertain.
429error.code: "rate_limit_exceeded"This API key exceeded its per-minute or per-hour limit.Wait for the Retry-After header, then retry the same request. No search is created.
503error.code: "service_unavailable"API key verification or rate limiting could not be completed.Retry later. No search is created.
422error.code: "invalid_webhook_url"webhook_url is not a public http(s) URL.Send a public URL, or omit it and poll. No search is created.
422detail: [...]Invalid JSON, an unknown field, or a value outside the request schema.Correct the fields identified in detail[].loc.
202 creation, then 200 polling with status: "failed"Failed SearchResultSearch execution failed, exceeded its execution timeout, or its worker stopped with a recorded failure.Treat the search as failed; do not interpret HTTP 200 as successful retrieval.

Insufficient balance

Creating a search returns 402 when the account cannot cover estimated_cost. Branch on error.code. The message states the reason. details.estimated_cost is the price that was compared. details.credits_remaining is your remaining credit balance.

402 · insufficient_balance
{
  "error": {
    "code": "insufficient_balance",
    "message": "Prepaid balance is below the estimated cost of this search.",
    "details": {
      "estimated_cost": 0.165,
      "credits_remaining": 0.04
    }
  }
}

No search is created and nothing is charged. Add credits on the API and MCP page in Sourcely, or turn on automatic top-up, then send the request again. A cheaper request, such as enrichment: "none", also has a lower estimate.

Not found

Example · not_found
{
  "error": {
    "code": "job_not_found",
    "message": "Job src_missing was not found.",
    "details": null
  }
}

Cache unavailable

503 · cache_unavailable
{
  "error": {
    "code": "cache_unavailable",
    "message": "Search storage is temporarily unavailable.",
    "details": null
  }
}

A confirmed admission failure before the Redis transaction executes prevents provider execution. A lost acknowledgement or transaction command failure can leave an uncertain outcome; a completion write failure can occur after providers ran. Neither case is automatically retried by the API. If you have the search ID, retry GET with bounded backoff. Without an ID, repeating POST may start duplicate work; request-level idempotency is still planned. A failed search is reported with actual_cost 0. A completed search is reported at its calculated cost. A create whose estimate is above the credit balance returns 402 and does not start a search.

Validation

For example, max_claims: 0 is outside the accepted range. The validation envelope differs from the custom API error envelope:

422 · validation error
{
  "detail": [
    {
      "loc": ["body", "max_claims"],
      "msg": "Input should be greater than or equal to 1",
      "type": "greater_than_equal",
      "input": 0,
      "ctx": { "ge": 1 }
    }
  ]
}

Additional details and message text can vary. Branch on the status and structured fields, rather than matching the full message. Validation responses can include the invalid input; avoid recording submitted text or credentials in application logs.

Failed job

Example · failed
{
  "job_id": "src_example",
  "status": "failed",
  "result_type": "search",
  "document": null,
  "claims": null,
  "sources": {},
  "usage": {
    "currency": "USD",
    "estimated_cost": 0.005,
    "actual_cost": 0,
    "discount_percent": 0,
    "balance_after": null
  },
  "metadata": null
}

The current SearchResult has no job-level error field. A failed claim may have its own error, but stored job-level error details are not exposed yet.

Empty results versus failures

A completed search may contain no sources. Current provider adapters also catch upstream failures and return empty lists, so the preview cannot always distinguish no matches from an exhausted provider failure. Clear provider-failure classification is planned.

Planned production errors

The following are design targets, not currently enforced responses for the initial pair of endpoints:

HTTPProposed codePlanned actionPlanned balance effect
403account_disabledContact support.No deduction.
409idempotency_conflictRestore the original request for that key.No extra deduction.
410search_expiredThe retained result has expired, when a tombstone confirms this.No automatic rerun or deduction.
429concurrency_limit_exceededToo many searches are already running for this key.Back off according to Retry-After. Rejected work consumes nothing.
Failed jobupstream_error / search_timeout / internal_errorInspect the recorded terminal outcome.Release the hold or refund that failed operation.

Safe recovery and balance

A dropped connection is not proof that a search failed. Recover an existing search ID when available. In the planned prepaid model, service failures release or refund the affected operation; successful work is not charged again when retrieved. Wallet accounting and automatic refunds are not implemented in the current API.

On this page