Every endpoint, straight from the API
All paths are relative to https://api.pandorlabs.com/v1. New here? Start with the quickstart.
Scrapers
The catalogue of scrapers. Each one declares the parameters it accepts as a JSON Schema, so a client can build a request without guessing. A scraper in live mode is run on demand with your own parameters; one in dataset mode is refreshed on a schedule (refreshEveryMinutes) and is bought as a dataset download instead of run. Each scraper's own parameters are documented in the scraper directory.
/v1/scrapersList scrapers
Every scraper the key can run, with the parameters each one accepts.
Query parameters
categorystringoptionalKeep one category only.
searchstringoptionalMatch against the id, name, description and tags.
curl "https://api.pandorlabs.com/v1/scrapers" \ -H "Authorization: Bearer $PANDORLABS_KEY"{ "data": [ { "id": "reddit", "name": "Reddit", "description": "Posts from the subreddits and keywords you name.", "category": "social_media", "tags": [ "reddit", "posts" ], "mode": "live", "parameters": [ { "name": "subreddits", "label": "Subreddits", "type": "stringList", "description": "Names only, without the r/ prefix.", "default": [ "forhire" ] } ], "inputSchema": { "type": "object", "additionalProperties": false, "properties": { "subreddits": { "type": "array", "items": { "type": "string" }, "title": "Subreddits", "default": [ "forhire" ] } } }, "exampleInput": { "subreddits": [ "forhire" ] }, "lastRunAt": "2026-09-30T08:00:00.000Z" } ]}/v1/scrapers/{scraperId}Describe a scraper
One scraper in full: its parameters, the JSON Schema of its input, and the fields its rows carry.
Path parameters
scraperIdstringrequiredScraper id, from GET /scrapers.
curl "https://api.pandorlabs.com/v1/scrapers/{scraperId}" \ -H "Authorization: Bearer $PANDORLABS_KEY"{ "id": "reddit", "name": "Reddit", "description": "Posts from the subreddits and keywords you name.", "category": "social_media", "tags": [ "reddit", "posts" ], "mode": "live", "parameters": [ { "name": "subreddits", "label": "Subreddits", "type": "stringList", "description": "Names only, without the r/ prefix.", "default": [ "forhire" ] } ], "inputSchema": { "type": "object", "additionalProperties": false, "properties": { "subreddits": { "type": "array", "items": { "type": "string" }, "title": "Subreddits", "default": [ "forhire" ] } } }, "exampleInput": { "subreddits": [ "forhire" ] }, "lastRunAt": "2026-09-30T08:00:00.000Z", "rowCount": 48210, "fields": [ { "name": "title", "type": "string", "coverage": 1 } ], "related": []}Runs
One execution of a scraper with your own parameters. Runs are asynchronous: start one, poll its status, and read its rows once it has finished. A finished run is billed 2 credits per 100 rows it collected.
/v1/scrapers/{scraperId}/runsStart a run
Queue a run and return immediately. Parameters you leave out keep the value the scraper is configured with; unknown or mistyped ones are rejected with a 400 that names each problem. If you already have a run of this scraper with the same input that is still in flight, or that finished within maxAgeMinutes, that run is returned instead of starting another. Only scrapers in live mode can be run; a dataset-mode scraper answers 409 and is downloaded instead. Needs a positive credit balance, otherwise 402.
Path parameters
scraperIdstringrequiredScraper id, from GET /scrapers.
Body
inputobjectoptionalParameters for this run, matching the inputSchema of the scraper.
maxAgeMinutesintegeroptionalReuse your own finished run with the same input if it completed within this many minutes (at most 1440). 0 only reuses a run still in flight.
Default
10
curl -X POST "https://api.pandorlabs.com/v1/scrapers/{scraperId}/runs" \ -H "Authorization: Bearer $PANDORLABS_KEY" \ -H "Content-Type: application/json" \ -d '{ "input": {}, "maxAgeMinutes": 10 }'{ "id": "66f2c1a9e4b0a7d3c9f01234", "scraperId": "reddit", "status": "queued", "input": { "subreddits": [ "webdev" ], "timeFilter": "week" }, "rowCount": 0, "createdAt": "2026-09-30T09:12:04.000Z", "startedAt": "2026-09-30T09:12:05.000Z", "billing": { "status": "pending", "credits": 4 }, "links": { "self": "/v1/runs/66f2c1a9e4b0a7d3c9f01234", "rows": "/v1/runs/66f2c1a9e4b0a7d3c9f01234/rows", "download": "/v1/datasets/reddit/downloads" }}/v1/runsList your runs
Runs started with any key of your account, newest first.
Query parameters
pageintegeroptionalPage number, starting at 1.
Default
1limitintegeroptionalRows per page, up to 100.
Default
20scraperIdstringoptionalKeep the runs of one scraper only.
statusstringoptionalKeep runs in one status only.
One of
queuedrunningcompletedfailedcancelled
curl "https://api.pandorlabs.com/v1/runs?page=1&limit=20" \ -H "Authorization: Bearer $PANDORLABS_KEY"{ "data": [ { "id": "66f2c1a9e4b0a7d3c9f01234", "scraperId": "reddit", "status": "running", "input": { "subreddits": [ "webdev" ], "timeFilter": "week" }, "rowCount": 128, "createdAt": "2026-09-30T09:12:04.000Z", "startedAt": "2026-09-30T09:12:05.000Z", "billing": { "status": "pending", "credits": 4 }, "links": { "self": "/v1/runs/66f2c1a9e4b0a7d3c9f01234", "rows": "/v1/runs/66f2c1a9e4b0a7d3c9f01234/rows", "download": "/v1/datasets/reddit/downloads" } } ], "page": 1, "limit": 20, "total": 1, "hasNext": false}/v1/runs/{runId}Get a run
Status, row count so far, timings and billing of one run. Poll this until the status is completed, failed or cancelled; the run is billed at that point.
Path parameters
runIdstringrequiredRun id, returned when the run was started.
curl "https://api.pandorlabs.com/v1/runs/{runId}" \ -H "Authorization: Bearer $PANDORLABS_KEY"{ "id": "66f2c1a9e4b0a7d3c9f01234", "scraperId": "reddit", "status": "running", "input": { "subreddits": [ "webdev" ], "timeFilter": "week" }, "rowCount": 128, "createdAt": "2026-09-30T09:12:04.000Z", "startedAt": "2026-09-30T09:12:05.000Z", "billing": { "status": "pending", "credits": 4 }, "links": { "self": "/v1/runs/66f2c1a9e4b0a7d3c9f01234", "rows": "/v1/runs/66f2c1a9e4b0a7d3c9f01234/rows", "download": "/v1/datasets/reddit/downloads" }}/v1/runs/{runId}/rowsRead the rows of a run
Only the rows this run collected. Available once the run has finished and is paid: 409 while it is queued or running, 402 while the balance cannot cover it.
Path parameters
runIdstringrequiredRun id, returned when the run was started.
Query parameters
pageintegeroptionalPage number, starting at 1.
Default
1limitintegeroptionalRows per page, up to 1000.
Default
100
curl "https://api.pandorlabs.com/v1/runs/{runId}/rows?page=1&limit=100" \ -H "Authorization: Bearer $PANDORLABS_KEY"{ "run": "66f2c1a9e4b0a7d3c9f01234", "status": "completed", "data": [ { "title": "Looking for a developer to rebuild our storefront", "subreddit": "forhire", "score": 42, "created_at": "2026-09-30T07:41:10.000Z" } ], "page": 1, "limit": 100, "total": 128, "hasNext": true}/v1/runs/{runId}/cancelCancel a run
Stop a queued or running run. The rows it already collected are billed and stay readable.
Path parameters
runIdstringrequiredRun id, returned when the run was started.
curl -X POST "https://api.pandorlabs.com/v1/runs/{runId}/cancel" \ -H "Authorization: Bearer $PANDORLABS_KEY"{ "id": "66f2c1a9e4b0a7d3c9f01234", "scraperId": "reddit", "status": "cancelled", "input": { "subreddits": [ "webdev" ], "timeFilter": "week" }, "rowCount": 128, "createdAt": "2026-09-30T09:12:04.000Z", "startedAt": "2026-09-30T09:12:05.000Z", "billing": { "status": "pending", "credits": 4 }, "links": { "self": "/v1/runs/66f2c1a9e4b0a7d3c9f01234", "rows": "/v1/runs/66f2c1a9e4b0a7d3c9f01234/rows", "download": "/v1/datasets/reddit/downloads" }}Dataset downloads
A whole dataset as one file, paid in credits: 1 per 100 rows when the stored data is recent enough, 2 per 100 rows when the scraper has to be re-run first.
/v1/datasets/{datasetId}/downloadsDownload a dataset
Buy the whole dataset as a file. When the last successful run is within maxAgeHours the stored rows are charged at the cached rate and the download is ready at once. Otherwise the scraper is re-run with its configured settings, the download stays refreshing until that run completes, and the rows the dataset then holds are charged at the live rate, so the credits in the response are an estimate until the download is ready. A failed refresh charges nothing. Answers 402 when the balance cannot cover the quote.
Path parameters
datasetIdstringrequiredDataset id. It is the id of the scraper that fills it.
Body
maxAgeHoursintegeroptionalOldest data you accept, in hours. 0 always re-runs the scraper.
Default
24formatstringoptionalFile format.
Default
csvOne ofcsvjsonl
curl -X POST "https://api.pandorlabs.com/v1/datasets/{datasetId}/downloads" \ -H "Authorization: Bearer $PANDORLABS_KEY" \ -H "Content-Type: application/json" \ -d '{ "maxAgeHours": 24, "format": "csv" }'{ "id": "66f2c3d1e4b0a7d3c9f05678", "datasetId": "reddit", "status": "ready", "freshness": "cached", "format": "csv", "maxAgeHours": 24, "rowCount": 48210, "credits": 483, "createdAt": "2026-09-30T09:12:04.000Z", "readyAt": "2026-09-30T09:12:04.000Z", "expiresAt": "2026-10-01T09:12:04.000Z", "links": { "self": "/v1/downloads/66f2c3d1e4b0a7d3c9f05678", "file": "/v1/downloads/66f2c3d1e4b0a7d3c9f05678/file" }}/v1/downloadsList your downloads
Downloads of your account, newest first.
Query parameters
pageintegeroptionalPage number, starting at 1.
Default
1limitintegeroptionalRows per page, up to 100.
Default
20
curl "https://api.pandorlabs.com/v1/downloads?page=1&limit=20" \ -H "Authorization: Bearer $PANDORLABS_KEY"{ "data": [ { "id": "66f2c3d1e4b0a7d3c9f05678", "datasetId": "reddit", "status": "ready", "freshness": "cached", "format": "csv", "maxAgeHours": 24, "rowCount": 48210, "credits": 483, "createdAt": "2026-09-30T09:12:04.000Z", "readyAt": "2026-09-30T09:12:04.000Z", "expiresAt": "2026-10-01T09:12:04.000Z", "links": { "self": "/v1/downloads/66f2c3d1e4b0a7d3c9f05678", "file": "/v1/downloads/66f2c3d1e4b0a7d3c9f05678/file" } } ], "page": 1, "limit": 20, "total": 1, "hasNext": false}/v1/downloads/{downloadId}Get a download
Status and price of one download. Poll this until the status is ready; a download waiting on credits is charged again on each call.
Path parameters
downloadIdstringrequiredDownload id, returned when the download was created.
curl "https://api.pandorlabs.com/v1/downloads/{downloadId}" \ -H "Authorization: Bearer $PANDORLABS_KEY"{ "id": "66f2c3d1e4b0a7d3c9f05678", "datasetId": "reddit", "status": "ready", "freshness": "cached", "format": "csv", "maxAgeHours": 24, "rowCount": 48210, "credits": 483, "createdAt": "2026-09-30T09:12:04.000Z", "readyAt": "2026-09-30T09:12:04.000Z", "expiresAt": "2026-10-01T09:12:04.000Z", "links": { "self": "/v1/downloads/66f2c3d1e4b0a7d3c9f05678", "file": "/v1/downloads/66f2c3d1e4b0a7d3c9f05678/file" }}/v1/downloads/{downloadId}/fileFetch the file
The dataset as CSV or JSONL. A paid download can be fetched any number of times for 24 hours. Answers 409 while it is refreshing or when it failed, 402 while it waits on credits, 410 once it expired.
Path parameters
downloadIdstringrequiredDownload id, returned when the download was created.
curl "https://api.pandorlabs.com/v1/downloads/{downloadId}/file" \ -H "Authorization: Bearer $PANDORLABS_KEY"Datasets
Everything a scraper has ever collected. A scraper and its dataset share one id. List and describe datasets here; the rows themselves are delivered as a paid download.
/v1/datasetsList datasets
Every dataset you can read, with its row count.
Takes no parameters.
curl "https://api.pandorlabs.com/v1/datasets" \ -H "Authorization: Bearer $PANDORLABS_KEY"{ "data": [ { "id": "reddit", "name": "Reddit", "description": "Posts from the subreddits and keywords you name.", "category": "social_media", "rowCount": 48210, "tags": [ "reddit", "posts" ], "updatedAt": "2026-09-30T08:00:00.000Z" } ]}/v1/datasets/{datasetId}Describe a dataset
One dataset and its columns. Rows have no declared schema, so the fields are discovered from a sample, with the share of rows that carry each one.
Path parameters
datasetIdstringrequiredDataset id. It is the id of the scraper that fills it.
curl "https://api.pandorlabs.com/v1/datasets/{datasetId}" \ -H "Authorization: Bearer $PANDORLABS_KEY"{ "id": "reddit", "name": "Reddit", "description": "Posts from the subreddits and keywords you name.", "category": "social_media", "rowCount": 48210, "tags": [ "reddit", "posts" ], "updatedAt": "2026-09-30T08:00:00.000Z", "fields": [ { "name": "title", "type": "string", "coverage": 1 } ]}Lookups
Fetch individual profiles on demand, from cache or live, paid in credits.
/v1/lookups/pricingLookup pricing
Credits per result for each platform, cached and live.
Takes no parameters.
curl "https://api.pandorlabs.com/v1/lookups/pricing" \ -H "Authorization: Bearer $PANDORLABS_KEY"/v1/lookups/{platform}Look up profiles
Fetch up to 100 profiles in one call. Spends credits from your balance.
Path parameters
platformstringrequiredPlatform to look up on.
One of
linkedin
Body
targetsstring[]requiredProfile URLs or handles, 1 to 100 of them.
freshnessstringoptionalcached answers from stored profiles; live fetches each one now.
One of
cachedlive
curl -X POST "https://api.pandorlabs.com/v1/lookups/{platform}" \ -H "Authorization: Bearer $PANDORLABS_KEY" \ -H "Content-Type: application/json" \ -d '{ "targets": [], "freshness": "cached" }'/v1/creditsCredit balance
Your balance and recent cached versus live usage.
Takes no parameters.
curl "https://api.pandorlabs.com/v1/credits" \ -H "Authorization: Bearer $PANDORLABS_KEY"Vector sync
Push a dataset into Pinecone or Qdrant as embedded chunks and keep it in sync.
/v1/vector-destinationsList vector destinations
Your Pinecone and Qdrant destinations.
Takes no parameters.
curl "https://api.pandorlabs.com/v1/vector-destinations" \ -H "Authorization: Bearer $PANDORLABS_KEY"/v1/vector-destinationsCreate a vector destination
Connect a dataset to a vector database.
Body
namestringrequiredLabel for the destination.
providerstringrequiredVector database.
One of
pineconeqdrantendpointstringrequiredIndex host or cluster URL.
apiKeystringrequiredCredential for the vector database. Stored encrypted.
datasetIdstringrequiredDataset to push.
collectionstringoptionalQdrant collection name.
namespacestringoptionalPinecone namespace.
filtersstring[]optionalfield:operator:value clauses narrowing the rows to push.
textFieldsstring[]optionalFields to embed.
metadataFieldsstring[]optionalFields to store beside each vector.
autoSyncbooleanoptionalSync again whenever the dataset is refreshed.
curl -X POST "https://api.pandorlabs.com/v1/vector-destinations" \ -H "Authorization: Bearer $PANDORLABS_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "name", "provider": "pinecone", "endpoint": "endpoint", "apiKey": "apiKey", "datasetId": "datasetId", "collection": "collection", "namespace": "namespace", "filters": [], "textFields": [], "metadataFields": [], "autoSync": false }'/v1/vector-destinations/{id}Get a vector destination
One destination and its settings.
Path parameters
idstringrequiredVector destination id (UUID).
curl "https://api.pandorlabs.com/v1/vector-destinations/{id}" \ -H "Authorization: Bearer $PANDORLABS_KEY"/v1/vector-destinations/{id}Update a vector destination
Change any of the fields accepted on creation. Fields left out keep their value.
Path parameters
idstringrequiredVector destination id (UUID).
curl -X PATCH "https://api.pandorlabs.com/v1/vector-destinations/{id}" \ -H "Authorization: Bearer $PANDORLABS_KEY"/v1/vector-destinations/{id}Delete a vector destination
Remove the destination. Vectors already pushed are kept.
Path parameters
idstringrequiredVector destination id (UUID).
curl -X DELETE "https://api.pandorlabs.com/v1/vector-destinations/{id}" \ -H "Authorization: Bearer $PANDORLABS_KEY"/v1/vector-destinations/{id}/syncsList syncs
Past syncs of one destination.
Path parameters
idstringrequiredVector destination id (UUID).
curl "https://api.pandorlabs.com/v1/vector-destinations/{id}/syncs" \ -H "Authorization: Bearer $PANDORLABS_KEY"/v1/vector-destinations/{id}/syncsStart a sync
Chunk, embed and upsert the dataset now.
Path parameters
idstringrequiredVector destination id (UUID).
curl -X POST "https://api.pandorlabs.com/v1/vector-destinations/{id}/syncs" \ -H "Authorization: Bearer $PANDORLABS_KEY"/v1/vector-syncs/{id}Get a sync
Progress of one sync.
Path parameters
idstringrequiredSync id (UUID).
curl "https://api.pandorlabs.com/v1/vector-syncs/{id}" \ -H "Authorization: Bearer $PANDORLABS_KEY"Previews
Render the site behind a URL as a PNG screenshot.
/v1/previewRender a preview
A PNG screenshot of the site behind a URL.
Body
urlstringrequiredhttp or https URL to render.
fullPagebooleanoptionalCapture the whole page rather than the viewport.
widthintegeroptionalViewport width, 320 to 2560.
heightintegeroptionalViewport height, 240 to 4000.
maxAgeSecondsintegeroptionalAccept a cached render no older than this.
filenamestringoptionalName of the downloaded file, without the extension.
curl -X POST "https://api.pandorlabs.com/v1/preview" \ -H "Authorization: Bearer $PANDORLABS_KEY" \ -H "Content-Type: application/json" \ -d '{ "url": "url", "fullPage": false, "width": 0, "height": 0, "maxAgeSeconds": 0, "filename": "filename" }'Account
What the presented key can do, and the machine-readable spec.
/v1/Inspect the key
The scopes and rate limit of the presented key, and the endpoints it can reach.
Takes no parameters.
curl "https://api.pandorlabs.com/v1/" \ -H "Authorization: Bearer $PANDORLABS_KEY"/v1/openapi.jsonOpenAPI document
This API as an OpenAPI 3.1 document, generated from the live scraper catalogue with one typed operation per scraper. No key needed.
Takes no parameters.
curl "https://api.pandorlabs.com/v1/openapi.json"