Orpheus Docs Get an API key

API documentation

Send a URL and your proxy. Orpheus detects the anti-bot challenge, clears it, and returns the page — with a session you can reuse for the next requests.

Base URL https://orpheus-api.lapetiteagora.fr

Quick start

  1. Sign in to the console and create an API key in the API keys tab. Copy it: it is shown only once.
  2. Have a sticky residential or ISP proxy ready (one exit IP kept for at least 10 minutes).
  3. Call POST /v1/fetch with the URL and the proxy.
curl -X POST https://orpheus-api.lapetiteagora.fr/v1/fetch \
  -H "Authorization: Bearer $LPA_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://www.example.com/",
    "proxy": "http://user:pass@proxy.example:8080"
  }'

Set a client timeout of about 70 seconds: clearing a challenge can take a few seconds, sometimes more.

Authentication

Every request carries your API key in the Authorization header:

HTTP
Authorization: Bearer lpa_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Keys are created and revoked in the console. Treat them like passwords: keep them server-side, never in a browser or a public repository. A revoked key, or a suspended account, gets 401 invalid_key immediately.

Fetch a page

POST/v1/fetch

Request body (JSON)

FieldTypeDescription
urlrequiredstringThe page to fetch, http or https.
proxystringRequired to start a session. http://user:pass@host:port, https://… or socks5://…. Omit it (or send the same value) when you pass a session_id.
session_idstringReuse a session returned by a previous call. See Sessions.
methodstringGET (default), POST, PUT, PATCH, DELETE, HEAD or OPTIONS.
headersobjectExtra request headers, as {"Name": "value"} strings. The browser headers (User-Agent, client hints…) are already set.
bodystringRequest body for POST/PUT/PATCH.
body_encodingstringtext (default) or base64 for a binary body.
cookiesobject · arrayCookies to add to the session before the request. See Cookies.
presetstringBrowser fingerprint, set when the session is created. Default chrome-latest-windows (keep it unless you know why).

Response

The API answers 200 as soon as the target site answered — whatever the site's own status. Read the site's status in status.

200 OK
{
  "status": 200,
  "headers": { "content-type": ["text/html; charset=utf-8"] },
  "body": "<!doctype html>…",
  "encoding": "text",
  "url": "https://www.example.com/",
  "session_id": "s_Ij4oudr1bYPzUA8U3sdlACAf",
  "solved": ["datadome"],
  "cookies": [{ "name": "datadome", "value": "…", "domain": ".example.com", "path": "/" }],
  "elapsed_ms": 2343
}
FieldDescription
statusHTTP status returned by the target site.
headersResponse headers; each value is a list of strings.
body · encodingThe page. encoding is text (UTF-8) or base64 for binary content (images, PDF…).
urlFinal URL, after redirects.
session_idSend it back to keep the same identity. Also returned with most errors.
solvedProtections cleared during this call: akamai, datadome, incapsula, kasada, cloudflare, ticketmaster. Empty when nothing had to be solved.
cookiesAll cookies of the session after the call.
elapsed_msTime spent on our side, including solving.

Sessions

Anti-bot cookies are bound to the browser identity that obtained them: IP, fingerprint, cookie jar. A session keeps that identity for you, so a challenge cleared once stays cleared.

  • The first call (with a proxy, without session_id) creates a session and returns its session_id.
  • Send that session_id on the next calls: same proxy, same fingerprint, same cookies. Later pages usually come back in a few hundred milliseconds, with solved: [].
  • A session expires after 30 minutes without requests. Each request extends it.
  • A session keeps its proxy for life. Sending a different proxy with a session_id returns 409 proxy_mismatch: start a new session instead.
  • One request at a time per session. A second concurrent request waits up to 10 seconds, then gets 409 session_busy. To go faster, run several sessions in parallel, each with its own proxy.
import os, requests

API = "https://orpheus-api.lapetiteagora.fr/v1/fetch"
HEADERS = {"Authorization": f"Bearer {os.environ['LPA_KEY']}"}

def fetch(**payload):
    r = requests.post(API, headers=HEADERS, json=payload, timeout=70)
    data = r.json()
    if r.status_code != 200:
        raise RuntimeError(data["error"])
    return data

# 1. Home page first: creates the session and clears the challenge
home = fetch(url="https://www.shop.example/", proxy="http://user:pass@proxy.example:8080")

# 2. Then the product page, on the same identity
product = fetch(
    url="https://www.shop.example/product/42",
    session_id=home["session_id"],
    headers={"Referer": "https://www.shop.example/"},
)
print(product["status"], product["solved"])

Cookies

Start a session with cookies you already have (a login, a cart, a consent choice), or add some later. They are stored in the session and sent on every following request until the site replaces them.

Simple form

An object {"name": "value"}. Cookies are set on the host of the url.

JSON
{
  "url": "https://www.shop.example/cart",
  "proxy": "http://user:pass@proxy.example:8080",
  "cookies": { "cart_id": "42", "lang": "fr" }
}

Detailed form

A list of objects, to choose the domain (e.g. .shop.example for every subdomain) or the path (default /).

JSON
{
  "url": "https://www.shop.example/",
  "session_id": "s_…",
  "cookies": [
    { "name": "auth", "value": "eyJ…", "domain": ".shop.example", "path": "/" }
  ]
}
  • Up to 50 cookies per request, 4,096 characters per value, no ; or line breaks in values.
  • A cookie with the same name, domain and path replaces the previous one.
  • Every response returns the session's cookies in cookies, so you can reuse them elsewhere.
  • Cookie values are never written to your request logs.
!

Anti-bot cookies are tied to an identity. A datadome or cf_clearance cookie obtained from another IP or browser will usually be rejected. Let Orpheus obtain them in the session instead.

Errors

Errors use a non-200 status and the same shape. When a session exists, its session_id is included.

422
{
  "error": { "code": "proxy_blocked", "message": "…" },
  "session_id": "s_…"
}
StatusCodeWhat to do
400invalid_requestFix the request: missing url, missing proxy for a new session, invalid field, private or unreachable address.
401invalid_keyMissing, wrong or revoked key, or suspended account.
402quota_exceededMonthly quota reached. It resets on the 1st (UTC).
404session_not_foundThe session expired (30 min idle) or was closed. Start a new one.
409proxy_mismatchA session keeps its proxy. Start a new session for another proxy.
409session_busyAnother request is using this session. Wait, or use another session.
413response_too_largeThe page is larger than 5 MB.
422proxy_blockedThe site blocked this IP. Change proxy and start a new session.
429too_many_concurrentToo many requests in flight for your account. Retry when one finishes.
502challenge_failedThe challenge could not be cleared. Retry once; if it persists, change proxy.
502solver_error · transport_errorTemporary solver or network issue (often the proxy). Retry with a short delay.
504timeoutNo answer in time. Retry; the session stays usable.
500internal_errorOur side. Retry, and tell us if it persists.
✓

Retry rule of thumb: retry 429, 502, 504 and 500 with a short backoff. Never retry 422 on the same session: switch proxy.

Limits

LimitValue
Monthly requests (beta)20,000 per account, reset on the 1st (UTC). Every call to /v1/fetch that reaches the site counts, even if solving then fails; calls refused upfront (400, 401, 402, 404, 409, 429) don't.
Concurrent requests5 per account by default (see your Account tab).
Time per requestAbout 55 seconds, solving included.
Response size5 MB of page content.
Session lifetime30 minutes after the last request.
Cookies50 per request, 4,096 characters per value.

Usage, solved challenges and your last requests are in the console.

Other endpoints

GET/v1/usage

Requests used this month, your quota, and the daily breakdown for the last 30 days (requests, successes, errors, bytes, solves by protection).

curl
curl -s https://orpheus-api.lapetiteagora.fr/v1/usage -H "Authorization: Bearer $LPA_KEY"
DELETE/v1/sessions/{session_id}

Closes a session right away (otherwise it expires on its own). Returns {"deleted": true}, or 404 if it no longer exists.

curl
curl -s -X DELETE https://orpheus-api.lapetiteagora.fr/v1/sessions/s_… -H "Authorization: Bearer $LPA_KEY"

Best practices

  • Sticky proxies only. A rotating proxy changes IP between requests and invalidates the cookies you just obtained. Aim for sessions of 10 minutes or more.
  • One session per identity. Reuse it for every page of a flow; open more sessions (with more proxies) to scale.
  • Browse naturally. Load the home or category page first, then the product page with a Referer header. Direct hits on deep pages get flagged more often.
  • Don't hammer one session. Clear the challenge with one request, then go on; avoid bursts from the same IP.
  • On proxy_blocked, drop the session and its proxy for a while; a burned IP stays burned.
  • Respect the sites you access. You are responsible for following their terms and the laws that apply to you.