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).
1. Create a search
Send your text with explicit options. enrichment: "none" skips analysis and citation_formats: [] skips citation formatting, which keeps the first search fast and cheap.
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.
{ "job_id": "src_example", "status": "queued" }2. Get the results
Request the search by its job_id (not a source ID):
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.
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.