OpenAPI contract
The canonical REST API 1.0.0 contract is an OpenAPI 3.1.0 document. The reference, contract tests, and SDK implementations consume the same source.
Endpoints
| Method | Path | Purpose | Success |
|---|---|---|---|
| POST | /v1/scrape | Create a scraping job | 202 |
| GET | /v1/jobs | List jobs | 200 |
| GET | /v1/jobs/{job_id} | Get a job | 200 |
| DELETE | /v1/jobs/{job_id} | Cancel a job | 200 |
| GET | /v1/jobs/{job_id}/stream | Stream completed job data | 200 |
| GET | /v1/events | List delivery events | 200 |
| GET | /v1/webhooks/deliveries | List webhook deliveries | 200 |
| GET | /v1/observability/metrics | Read API metrics | 200 |
| GET | /v1/datasets/{dataset_id} | Get a materialized dataset | 200 |
| POST | /v1/datasets/{dataset_id}/exports | Create a dataset export | 202 |
| GET | /v1/datasets/{dataset_id}/exports/{export_id} | Get a dataset export | 200 |
| GET | /v1/downloads/{export_id} | Download a completed dataset export | 200 |
Scrape request fields
| Field | Type | Required |
|---|---|---|
| url | string | yes |
| formats | string[] | yes |
| webhook_url | string | no |
| metadata | object | no |
Request examples
curl -X POST https://api.nordicdevhouse.com/v1/scrape \\
-H "Authorization: Bearer api_live_••••••••" \\n -H "Content-Type: application/json" \\n -H "Idempotency-Key: docs-example-001" \\
-d '{
"url": "https://example.com/products",
"formats": [
"json"
],
"metadata": {
"import_id": "catalog-2026-08-11"
}
}'const result = await ndh.request({
method: 'POST',
path: '/v1/scrape',
body: { url: "https://example.com/products", formats: ["json"], metadata: { import_id: "catalog-2026-08-11" } }
});result = ndh.request(
method="POST",
path="/v1/scrape",
body={
"url": "https://example.com/products",
"formats": [
"json"
],
"metadata": {
"import_id": "catalog-2026-08-11"
}
}
)Job response object
| Field | Type | Required |
|---|---|---|
| id | string | yes |
| status | JobStatus | yes |
| created_at | string | yes |
| completed_at | string | null | no |
| retention_expires_at | string | null | no |
| request_id | string | yes |
| records | integer | no |
| dataset_id | string | null | no |
| data | object | no |
| warnings | array | no |
| last_event_id | string | null | no |
| metadata | object | no |
Create a scraping job details
POST /v1/scrapeSandboxCreates one idempotent scraping job. The response is asynchronous; use the returned job ID or a verified webhook to observe completion.
202 Job accepted
""400
{
"error": {
"code": "request_failed",
"message": "Request failed with HTTP 400",
"request_id": "req_example"
}
}Generated from the status contract401
{
"error": {
"code": "unauthorized",
"message": "Request failed with HTTP 401",
"request_id": "req_example"
}
}Generated from the status contract429
{
"error": {
"code": "rate_limited",
"message": "Request failed with HTTP 429",
"request_id": "req_example"
}
}Generated from the status contract500
{
"error": {
"code": "server_error",
"message": "Request failed with HTTP 500",
"request_id": "req_example"
}
}Generated from the status contractcurl -X POST https://api.nordicdevhouse.com/v1/scrape \\
-H "Authorization: Bearer api_live_••••••••" \\n -H "Content-Type: application/json" \\n -H "Idempotency-Key: docs-example-001" \\
-d '{
"url": "https://example.com/products",
"formats": [
"json"
],
"metadata": {
"import_id": "catalog-2026-08-11"
}
}'const result = await ndh.request({
method: 'POST',
path: '/v1/scrape',
body: { url: "https://example.com/products", formats: ["json"], metadata: { import_id: "catalog-2026-08-11" } }
});result = ndh.request(
method="POST",
path="/v1/scrape",
body={
"url": "https://example.com/products",
"formats": [
"json"
],
"metadata": {
"import_id": "catalog-2026-08-11"
}
}
)List jobs details
GET /v1/jobsSandboxReturns jobs in reverse creation order with cursor pagination.
200 Job page
""400
{
"error": {
"code": "request_failed",
"message": "Request failed with HTTP 400",
"request_id": "req_example"
}
}Generated from the status contract401
{
"error": {
"code": "unauthorized",
"message": "Request failed with HTTP 401",
"request_id": "req_example"
}
}Generated from the status contract429
{
"error": {
"code": "rate_limited",
"message": "Request failed with HTTP 429",
"request_id": "req_example"
}
}Generated from the status contract500
{
"error": {
"code": "server_error",
"message": "Request failed with HTTP 500",
"request_id": "req_example"
}
}Generated from the status contractGet a job details
GET /v1/jobs/{job_id}SandboxReturns the current state and, when completed, the validated result.
200 Current job
""400
{
"error": {
"code": "request_failed",
"message": "Request failed with HTTP 400",
"request_id": "req_example"
}
}Generated from the status contract401
{
"error": {
"code": "unauthorized",
"message": "Request failed with HTTP 401",
"request_id": "req_example"
}
}Generated from the status contract404
{
"error": {
"code": "not_found",
"message": "Request failed with HTTP 404",
"request_id": "req_example"
}
}Generated from the status contract429
{
"error": {
"code": "rate_limited",
"message": "Request failed with HTTP 429",
"request_id": "req_example"
}
}Generated from the status contract500
{
"error": {
"code": "server_error",
"message": "Request failed with HTTP 500",
"request_id": "req_example"
}
}Generated from the status contractCancel a job details
DELETE /v1/jobs/{job_id}SandboxCancels queued or running work. Completed, failed, and already canceled jobs are returned unchanged.
200 Canceled or already terminal job
""400
{
"error": {
"code": "request_failed",
"message": "Request failed with HTTP 400",
"request_id": "req_example"
}
}Generated from the status contract401
{
"error": {
"code": "unauthorized",
"message": "Request failed with HTTP 401",
"request_id": "req_example"
}
}Generated from the status contract404
{
"error": {
"code": "not_found",
"message": "Request failed with HTTP 404",
"request_id": "req_example"
}
}Generated from the status contract409
{
"error": {
"code": "conflict",
"message": "Request failed with HTTP 409",
"request_id": "req_example"
}
}Generated from the status contract429
{
"error": {
"code": "rate_limited",
"message": "Request failed with HTTP 429",
"request_id": "req_example"
}
}Generated from the status contract500
{
"error": {
"code": "server_error",
"message": "Request failed with HTTP 500",
"request_id": "req_example"
}
}Generated from the status contractStream completed job data details
GET /v1/jobs/{job_id}/streamSandboxReturns one JSON record per line using application/x-ndjson after the job has completed.
200 NDJSON result stream
""400
{
"error": {
"code": "request_failed",
"message": "Request failed with HTTP 400",
"request_id": "req_example"
}
}Generated from the status contract401
{
"error": {
"code": "unauthorized",
"message": "Request failed with HTTP 401",
"request_id": "req_example"
}
}Generated from the status contract404
{
"error": {
"code": "not_found",
"message": "Request failed with HTTP 404",
"request_id": "req_example"
}
}Generated from the status contract409
{
"error": {
"code": "conflict",
"message": "Request failed with HTTP 409",
"request_id": "req_example"
}
}Generated from the status contract410
{
"error": {
"code": "request_failed",
"message": "Request failed with HTTP 410",
"request_id": "req_example"
}
}Generated from the status contract413
{
"error": {
"code": "request_failed",
"message": "Request failed with HTTP 413",
"request_id": "req_example"
}
}Generated from the status contract429
{
"error": {
"code": "rate_limited",
"message": "Request failed with HTTP 429",
"request_id": "req_example"
}
}Generated from the status contract500
{
"error": {
"code": "server_error",
"message": "Request failed with HTTP 500",
"request_id": "req_example"
}
}Generated from the status contractList delivery events details
GET /v1/eventsSandboxReturns signed webhook-worthy events in cursor-paginated order.
200 Event page
""400
{
"error": {
"code": "request_failed",
"message": "Request failed with HTTP 400",
"request_id": "req_example"
}
}Generated from the status contract401
{
"error": {
"code": "unauthorized",
"message": "Request failed with HTTP 401",
"request_id": "req_example"
}
}Generated from the status contract429
{
"error": {
"code": "rate_limited",
"message": "Request failed with HTTP 429",
"request_id": "req_example"
}
}Generated from the status contract500
{
"error": {
"code": "server_error",
"message": "Request failed with HTTP 500",
"request_id": "req_example"
}
}Generated from the status contractList webhook deliveries details
GET /v1/webhooks/deliveriesSandboxReturns delivery attempts and dead-letter state for local or test webhook endpoints.
200 Webhook delivery list
{
"data": []
}400
{
"error": {
"code": "request_failed",
"message": "Request failed with HTTP 400",
"request_id": "req_example"
}
}Generated from the status contract401
{
"error": {
"code": "unauthorized",
"message": "Request failed with HTTP 401",
"request_id": "req_example"
}
}Generated from the status contract429
{
"error": {
"code": "rate_limited",
"message": "Request failed with HTTP 429",
"request_id": "req_example"
}
}Generated from the status contract500
{
"error": {
"code": "server_error",
"message": "Request failed with HTTP 500",
"request_id": "req_example"
}
}Generated from the status contractRead API metrics details
GET /v1/observability/metricsSandboxReturns in-process request counters and durations for the fake API runtime.
200 Metrics snapshot
""400
{
"error": {
"code": "request_failed",
"message": "Request failed with HTTP 400",
"request_id": "req_example"
}
}Generated from the status contract401
{
"error": {
"code": "unauthorized",
"message": "Request failed with HTTP 401",
"request_id": "req_example"
}
}Generated from the status contract429
{
"error": {
"code": "rate_limited",
"message": "Request failed with HTTP 429",
"request_id": "req_example"
}
}Generated from the status contract500
{
"error": {
"code": "server_error",
"message": "Request failed with HTTP 500",
"request_id": "req_example"
}
}Generated from the status contractGet a materialized dataset details
GET /v1/datasets/{dataset_id}SandboxReturns the immutable dataset created by a completed scrape job.
200 Materialized dataset
""400
{
"error": {
"code": "request_failed",
"message": "Request failed with HTTP 400",
"request_id": "req_example"
}
}Generated from the status contract401
{
"error": {
"code": "unauthorized",
"message": "Request failed with HTTP 401",
"request_id": "req_example"
}
}Generated from the status contract404
{
"error": {
"code": "not_found",
"message": "Request failed with HTTP 404",
"request_id": "req_example"
}
}Generated from the status contract429
{
"error": {
"code": "rate_limited",
"message": "Request failed with HTTP 429",
"request_id": "req_example"
}
}Generated from the status contract500
{
"error": {
"code": "server_error",
"message": "Request failed with HTTP 500",
"request_id": "req_example"
}
}Generated from the status contractCreate a dataset export details
POST /v1/datasets/{dataset_id}/exportsSandboxCreates an immutable export from a dataset version.
202 Export accepted
""400
{
"error": {
"code": "request_failed",
"message": "Request failed with HTTP 400",
"request_id": "req_example"
}
}Generated from the status contract401
{
"error": {
"code": "unauthorized",
"message": "Request failed with HTTP 401",
"request_id": "req_example"
}
}Generated from the status contract404
{
"error": {
"code": "not_found",
"message": "Request failed with HTTP 404",
"request_id": "req_example"
}
}Generated from the status contract429
{
"error": {
"code": "rate_limited",
"message": "Request failed with HTTP 429",
"request_id": "req_example"
}
}Generated from the status contract500
{
"error": {
"code": "server_error",
"message": "Request failed with HTTP 500",
"request_id": "req_example"
}
}Generated from the status contractcurl -X POST https://api.nordicdevhouse.com/v1/datasets/{dataset_id}/exports \\
-H "Authorization: Bearer api_live_••••••••" \\n -H "Content-Type: application/json" \\n -H "Idempotency-Key: docs-example-001" \\
-d '{
"format": "json",
"mode": "snapshot"
}'const result = await ndh.request({
method: 'POST',
path: '/v1/datasets/{dataset_id}/exports',
body: { format: "json", mode: "snapshot" }
});result = ndh.request(
method="POST",
path="/v1/datasets/{dataset_id}/exports",
body={
"format": "json",
"mode": "snapshot"
}
)Get a dataset export details
GET /v1/datasets/{dataset_id}/exports/{export_id}SandboxReturns export state and a short-lived download URL when ready.
200 Current export
""400
{
"error": {
"code": "request_failed",
"message": "Request failed with HTTP 400",
"request_id": "req_example"
}
}Generated from the status contract401
{
"error": {
"code": "unauthorized",
"message": "Request failed with HTTP 401",
"request_id": "req_example"
}
}Generated from the status contract404
{
"error": {
"code": "not_found",
"message": "Request failed with HTTP 404",
"request_id": "req_example"
}
}Generated from the status contract429
{
"error": {
"code": "rate_limited",
"message": "Request failed with HTTP 429",
"request_id": "req_example"
}
}Generated from the status contract500
{
"error": {
"code": "server_error",
"message": "Request failed with HTTP 500",
"request_id": "req_example"
}
}Generated from the status contractDownload a completed dataset export details
GET /v1/downloads/{export_id}SandboxStreams the completed export as JSON, CSV, or opaque Parquet bytes. Download URLs expire independently from export metadata.
200 Export bytes
[]400
{
"error": {
"code": "request_failed",
"message": "Request failed with HTTP 400",
"request_id": "req_example"
}
}Generated from the status contract401
{
"error": {
"code": "unauthorized",
"message": "Request failed with HTTP 401",
"request_id": "req_example"
}
}Generated from the status contract404
{
"error": {
"code": "not_found",
"message": "Request failed with HTTP 404",
"request_id": "req_example"
}
}Generated from the status contract409
{
"error": {
"code": "conflict",
"message": "Request failed with HTTP 409",
"request_id": "req_example"
}
}Generated from the status contract410
{
"error": {
"code": "request_failed",
"message": "Request failed with HTTP 410",
"request_id": "req_example"
}
}Generated from the status contract413
{
"error": {
"code": "request_failed",
"message": "Request failed with HTTP 413",
"request_id": "req_example"
}
}Generated from the status contract429
{
"error": {
"code": "rate_limited",
"message": "Request failed with HTTP 429",
"request_id": "req_example"
}
}Generated from the status contract500
{
"error": {
"code": "server_error",
"message": "Request failed with HTTP 500",
"request_id": "req_example"
}
}Generated from the status contract