sourcely/developers
SOURCELY API PREVIEW

Get started

Create a search, fetch its results, and list the sources in a few lines of code.

Before you start

In Sourcely, open API and MCP, add credits, and create an API key. Save it as the SOURCELY_API_KEY environment variable. These examples run real searches against https://api.sourcely.net and use your credits (Credits and pricing).

Send your text with explicit options. enrichment: "none" skips analysis and citation_formats: [] skips citation formatting, which keeps the first search fast and cheap.

Terminal
curl -X POST https://api.sourcely.net/search \
  -H "Authorization: Bearer $SOURCELY_API_KEY" \
  -H 'Content-Type: application/json' \
  --data '{"text":"How do urban green spaces affect mental health?","mode":"quick","enrichment":"none","granularity":["document"],"citation_formats":[]}'

The API answers 202 Accepted with a job_id and the status queued. The search runs in the background; you read the result in the next step.

Example acceptance response
{ "job_id": "src_example", "status": "queued" }

2. Get the results

Request the search by its job_id (not a source ID):

Terminal
curl https://api.sourcely.net/search/src_example \
  -H "Authorization: Bearer $SOURCELY_API_KEY"

Replace src_example with your job_id. Repeat the request until status is completed or failed. A 200 response can still describe a failed search, so always check status (search states).

3. Put it together

This script creates a search, polls until it finishes, and prints each source. Details live in the sources map; document.source_ids gives their order.

Requires httpx
import os
import time
import httpx

api_base_url = "https://api.sourcely.net"
api_key = os.environ["SOURCELY_API_KEY"]
headers = {"Authorization": f"Bearer {api_key}"}
search_request = {
    "text": "How do urban green spaces affect mental health?",
    "mode": "quick",
    "enrichment": "none",
    "citation_formats": [],
}

with httpx.Client(timeout=180) as client:
    response = client.post(f"{api_base_url}/search", headers=headers, json=search_request)
    response.raise_for_status()
    job_id = response.json()["job_id"]

    for attempt in range(60):
        response = client.get(f"{api_base_url}/search/{job_id}", headers=headers)
        response.raise_for_status()
        search_result = response.json()
        if search_result["status"] == "failed":
            raise RuntimeError("Search failed; inspect the error guide.")
        if search_result["status"] == "completed":
            break
        time.sleep(2)
    else:
        raise TimeoutError(f"Search still pending; keep job_id {job_id}")

    document = search_result.get("document") or {}
    for source_id in document.get("source_ids", []):
        source = search_result["sources"][source_id]
        print(source["title"], source["url"])

Timeouts

The timeouts and the 2-second polling interval are example client limits, not service guarantees. A client timeout does not mean the search failed: keep the job_id and check it again. Creating a search is not idempotent, so don't retry a timed-out POST blindly.

On this page