{"openapi":"3.1.0","info":{"title":"Nordic Devhouse API","version":"1.0.0","summary":"Create and observe maintained web-data jobs.","description":"The canonical contract for Nordic Devhouse REST API v1. SDKs and the documentation reference are generated and tested against this document.","contact":{"name":"Nordic Devhouse SDK Maintainers","email":"sdk@nordicdevhouse.com","url":"https://github.com/X42NORDIC/nordic-devhouse-sdk"},"license":{"name":"MIT","identifier":"MIT","url":"https://opensource.org/license/mit"}},"jsonSchemaDialect":"https://json-schema.org/draft/2020-12/schema","servers":[{"url":"https://api.nordicdevhouse.com/v1","description":"Production"}],"tags":[{"name":"Scraping","description":"Create validated web-data jobs."},{"name":"Jobs","description":"Observe durable asynchronous work."},{"name":"Datasets","description":"Create versioned dataset exports."},{"name":"Observability","description":"Inspect fake API request metrics and traces."}],"security":[{"bearerAuth":[]}],"webhooks":{"scrapeCompleted":{"post":{"operationId":"receiveScrapeCompletedWebhook","summary":"Scraping job completed","description":"Sent to a configured endpoint. Verify Nordic-Signature against the unmodified request body before parsing JSON.","parameters":[{"$ref":"#/components/parameters/NordicSignature"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEvent"}}}},"responses":{"200":{"description":"Event acknowledged"}}}}},"paths":{"/scrape":{"parameters":[{"$ref":"#/components/parameters/ApiVersion"}],"post":{"operationId":"createScrapeJob","summary":"Create a scraping job","description":"Creates one idempotent scraping job. The response is asynchronous; use the returned job ID or a verified webhook to observe completion.","tags":["Scraping"],"parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScrapeRequest"},"example":{"url":"https://example.com/products","formats":["json"],"metadata":{"import_id":"catalog-2026-08-11"}}}}},"responses":{"202":{"description":"Job accepted","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"},"X-Trace-Id":{"$ref":"#/components/headers/TraceId"},"X-API-Version":{"$ref":"#/components/headers/ApiVersion"},"X-Supported-API-Versions":{"$ref":"#/components/headers/SupportedApiVersions"},"X-Request-Duration-Ms":{"$ref":"#/components/headers/RequestDurationMs"},"Retry-After":{"$ref":"#/components/headers/RetryAfter"},"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-Quota-Limit":{"$ref":"#/components/headers/QuotaLimit"},"X-Quota-Remaining":{"$ref":"#/components/headers/QuotaRemaining"},"X-Quota-Reset":{"$ref":"#/components/headers/QuotaReset"},"X-Credit-Limit":{"$ref":"#/components/headers/CreditLimit"},"X-Credit-Remaining":{"$ref":"#/components/headers/CreditRemaining"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Job"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/AuthenticationError"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}},"x-error-codes":{"400":["validation_error"],"401":["authentication_error"],"429":["rate_limited"],"500":["server_error"]}}},"/jobs":{"parameters":[{"$ref":"#/components/parameters/ApiVersion"}],"get":{"operationId":"listJobs","summary":"List jobs","description":"Returns jobs in reverse creation order with cursor pagination.","tags":["Jobs"],"parameters":[{"$ref":"#/components/parameters/Cursor"},{"$ref":"#/components/parameters/Limit"},{"name":"status","in":"query","required":false,"schema":{"$ref":"#/components/schemas/JobStatus"}}],"responses":{"200":{"description":"Job page","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"},"X-Trace-Id":{"$ref":"#/components/headers/TraceId"},"X-API-Version":{"$ref":"#/components/headers/ApiVersion"},"X-Supported-API-Versions":{"$ref":"#/components/headers/SupportedApiVersions"},"X-Request-Duration-Ms":{"$ref":"#/components/headers/RequestDurationMs"},"Retry-After":{"$ref":"#/components/headers/RetryAfter"},"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-Quota-Limit":{"$ref":"#/components/headers/QuotaLimit"},"X-Quota-Remaining":{"$ref":"#/components/headers/QuotaRemaining"},"X-Quota-Reset":{"$ref":"#/components/headers/QuotaReset"},"X-Credit-Limit":{"$ref":"#/components/headers/CreditLimit"},"X-Credit-Remaining":{"$ref":"#/components/headers/CreditRemaining"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobPage"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/AuthenticationError"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}},"x-error-codes":{"400":["validation_error"],"401":["authentication_error"],"429":["rate_limited"],"500":["server_error"]}}},"/jobs/{job_id}":{"parameters":[{"$ref":"#/components/parameters/ApiVersion"}],"get":{"operationId":"getJob","summary":"Get a job","description":"Returns the current state and, when completed, the validated result.","tags":["Jobs"],"parameters":[{"$ref":"#/components/parameters/JobId"}],"responses":{"200":{"description":"Current job","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"},"X-Trace-Id":{"$ref":"#/components/headers/TraceId"},"X-API-Version":{"$ref":"#/components/headers/ApiVersion"},"X-Supported-API-Versions":{"$ref":"#/components/headers/SupportedApiVersions"},"X-Request-Duration-Ms":{"$ref":"#/components/headers/RequestDurationMs"},"Retry-After":{"$ref":"#/components/headers/RetryAfter"},"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-Quota-Limit":{"$ref":"#/components/headers/QuotaLimit"},"X-Quota-Remaining":{"$ref":"#/components/headers/QuotaRemaining"},"X-Quota-Reset":{"$ref":"#/components/headers/QuotaReset"},"X-Credit-Limit":{"$ref":"#/components/headers/CreditLimit"},"X-Credit-Remaining":{"$ref":"#/components/headers/CreditRemaining"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Job"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/AuthenticationError"},"404":{"$ref":"#/components/responses/NotFoundError"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}},"x-error-codes":{"400":["validation_error"],"401":["authentication_error"],"404":["not_found"],"429":["rate_limited"],"500":["server_error"]}},"delete":{"operationId":"cancelJob","summary":"Cancel a job","description":"Cancels queued or running work. Completed, failed, and already canceled jobs are returned unchanged.","tags":["Jobs"],"parameters":[{"$ref":"#/components/parameters/JobId"}],"responses":{"200":{"description":"Canceled or already terminal job","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"},"X-Trace-Id":{"$ref":"#/components/headers/TraceId"},"X-API-Version":{"$ref":"#/components/headers/ApiVersion"},"X-Supported-API-Versions":{"$ref":"#/components/headers/SupportedApiVersions"},"X-Request-Duration-Ms":{"$ref":"#/components/headers/RequestDurationMs"},"Retry-After":{"$ref":"#/components/headers/RetryAfter"},"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-Quota-Limit":{"$ref":"#/components/headers/QuotaLimit"},"X-Quota-Remaining":{"$ref":"#/components/headers/QuotaRemaining"},"X-Quota-Reset":{"$ref":"#/components/headers/QuotaReset"},"X-Credit-Limit":{"$ref":"#/components/headers/CreditLimit"},"X-Credit-Remaining":{"$ref":"#/components/headers/CreditRemaining"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Job"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/AuthenticationError"},"404":{"$ref":"#/components/responses/NotFoundError"},"409":{"$ref":"#/components/responses/ConflictError"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}},"x-error-codes":{"400":["validation_error"],"401":["authentication_error"],"404":["not_found"],"409":["job_not_ready"],"429":["rate_limited"],"500":["server_error"]}}},"/jobs/{job_id}/stream":{"parameters":[{"$ref":"#/components/parameters/ApiVersion"}],"get":{"operationId":"streamJobData","summary":"Stream completed job data","description":"Returns one JSON record per line using application/x-ndjson after the job has completed.","tags":["Jobs"],"parameters":[{"$ref":"#/components/parameters/JobId"}],"responses":{"200":{"description":"NDJSON result stream","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"},"X-Trace-Id":{"$ref":"#/components/headers/TraceId"},"X-API-Version":{"$ref":"#/components/headers/ApiVersion"},"X-Supported-API-Versions":{"$ref":"#/components/headers/SupportedApiVersions"},"X-Request-Duration-Ms":{"$ref":"#/components/headers/RequestDurationMs"},"Retry-After":{"$ref":"#/components/headers/RetryAfter"},"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-Quota-Limit":{"$ref":"#/components/headers/QuotaLimit"},"X-Quota-Remaining":{"$ref":"#/components/headers/QuotaRemaining"},"X-Quota-Reset":{"$ref":"#/components/headers/QuotaReset"},"X-Credit-Limit":{"$ref":"#/components/headers/CreditLimit"},"X-Credit-Remaining":{"$ref":"#/components/headers/CreditRemaining"}},"content":{"application/x-ndjson":{"schema":{"type":"string"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/AuthenticationError"},"404":{"$ref":"#/components/responses/NotFoundError"},"409":{"$ref":"#/components/responses/ConflictError"},"410":{"$ref":"#/components/responses/ExpiredError"},"413":{"$ref":"#/components/responses/ResponseTooLarge"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}},"x-error-codes":{"400":["validation_error"],"401":["authentication_error"],"404":["not_found"],"409":["job_not_ready"],"410":["resource_expired"],"413":["response_too_large"],"429":["rate_limited"],"500":["server_error"]}}},"/events":{"parameters":[{"$ref":"#/components/parameters/ApiVersion"}],"get":{"operationId":"listEvents","summary":"List delivery events","description":"Returns signed webhook-worthy events in cursor-paginated order.","tags":["Jobs"],"parameters":[{"$ref":"#/components/parameters/Cursor"},{"$ref":"#/components/parameters/Limit"},{"name":"type","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Event page","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"},"X-Trace-Id":{"$ref":"#/components/headers/TraceId"},"X-API-Version":{"$ref":"#/components/headers/ApiVersion"},"X-Supported-API-Versions":{"$ref":"#/components/headers/SupportedApiVersions"},"X-Request-Duration-Ms":{"$ref":"#/components/headers/RequestDurationMs"},"Retry-After":{"$ref":"#/components/headers/RetryAfter"},"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-Quota-Limit":{"$ref":"#/components/headers/QuotaLimit"},"X-Quota-Remaining":{"$ref":"#/components/headers/QuotaRemaining"},"X-Quota-Reset":{"$ref":"#/components/headers/QuotaReset"},"X-Credit-Limit":{"$ref":"#/components/headers/CreditLimit"},"X-Credit-Remaining":{"$ref":"#/components/headers/CreditRemaining"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventPage"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/AuthenticationError"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}},"x-error-codes":{"400":["validation_error"],"401":["authentication_error"],"429":["rate_limited"],"500":["server_error"]}}},"/webhooks/deliveries":{"parameters":[{"$ref":"#/components/parameters/ApiVersion"}],"get":{"operationId":"listWebhookDeliveries","summary":"List webhook deliveries","description":"Returns delivery attempts and dead-letter state for local or test webhook endpoints.","tags":["Jobs"],"parameters":[{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["pending","delivered","dead_letter"]}}],"responses":{"200":{"description":"Webhook delivery list","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"},"X-Trace-Id":{"$ref":"#/components/headers/TraceId"},"X-API-Version":{"$ref":"#/components/headers/ApiVersion"},"X-Supported-API-Versions":{"$ref":"#/components/headers/SupportedApiVersions"},"X-Request-Duration-Ms":{"$ref":"#/components/headers/RequestDurationMs"},"Retry-After":{"$ref":"#/components/headers/RetryAfter"},"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-Quota-Limit":{"$ref":"#/components/headers/QuotaLimit"},"X-Quota-Remaining":{"$ref":"#/components/headers/QuotaRemaining"},"X-Quota-Reset":{"$ref":"#/components/headers/QuotaReset"},"X-Credit-Limit":{"$ref":"#/components/headers/CreditLimit"},"X-Credit-Remaining":{"$ref":"#/components/headers/CreditRemaining"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/WebhookDelivery"}}}}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/AuthenticationError"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}},"x-error-codes":{"400":["validation_error"],"401":["authentication_error"],"429":["rate_limited"],"500":["server_error"]}}},"/observability/metrics":{"parameters":[{"$ref":"#/components/parameters/ApiVersion"}],"get":{"operationId":"getObservabilityMetrics","summary":"Read API metrics","description":"Returns in-process request counters and durations for the fake API runtime.","tags":["Observability"],"responses":{"200":{"description":"Metrics snapshot","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"},"X-Trace-Id":{"$ref":"#/components/headers/TraceId"},"X-API-Version":{"$ref":"#/components/headers/ApiVersion"},"X-Supported-API-Versions":{"$ref":"#/components/headers/SupportedApiVersions"},"X-Request-Duration-Ms":{"$ref":"#/components/headers/RequestDurationMs"},"Retry-After":{"$ref":"#/components/headers/RetryAfter"},"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-Quota-Limit":{"$ref":"#/components/headers/QuotaLimit"},"X-Quota-Remaining":{"$ref":"#/components/headers/QuotaRemaining"},"X-Quota-Reset":{"$ref":"#/components/headers/QuotaReset"},"X-Credit-Limit":{"$ref":"#/components/headers/CreditLimit"},"X-Credit-Remaining":{"$ref":"#/components/headers/CreditRemaining"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MetricsSnapshot"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/AuthenticationError"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}},"x-error-codes":{"400":["validation_error"],"401":["authentication_error"],"429":["rate_limited"],"500":["server_error"]}}},"/datasets/{dataset_id}":{"parameters":[{"$ref":"#/components/parameters/ApiVersion"}],"get":{"operationId":"getDataset","summary":"Get a materialized dataset","description":"Returns the immutable dataset created by a completed scrape job.","tags":["Datasets"],"parameters":[{"$ref":"#/components/parameters/DatasetId"}],"responses":{"200":{"description":"Materialized dataset","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"},"X-Trace-Id":{"$ref":"#/components/headers/TraceId"},"X-API-Version":{"$ref":"#/components/headers/ApiVersion"},"X-Supported-API-Versions":{"$ref":"#/components/headers/SupportedApiVersions"},"X-Request-Duration-Ms":{"$ref":"#/components/headers/RequestDurationMs"},"Retry-After":{"$ref":"#/components/headers/RetryAfter"},"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-Quota-Limit":{"$ref":"#/components/headers/QuotaLimit"},"X-Quota-Remaining":{"$ref":"#/components/headers/QuotaRemaining"},"X-Quota-Reset":{"$ref":"#/components/headers/QuotaReset"},"X-Credit-Limit":{"$ref":"#/components/headers/CreditLimit"},"X-Credit-Remaining":{"$ref":"#/components/headers/CreditRemaining"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Dataset"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/AuthenticationError"},"404":{"$ref":"#/components/responses/NotFoundError"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}},"x-error-codes":{"400":["validation_error"],"401":["authentication_error"],"404":["not_found"],"429":["rate_limited"],"500":["server_error"]}}},"/datasets/{dataset_id}/exports":{"parameters":[{"$ref":"#/components/parameters/ApiVersion"}],"post":{"operationId":"createDatasetExport","summary":"Create a dataset export","description":"Creates an immutable export from a dataset version.","tags":["Datasets"],"parameters":[{"$ref":"#/components/parameters/DatasetId"},{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DatasetExportRequest"},"example":{"format":"json","mode":"snapshot"}}}},"responses":{"202":{"description":"Export accepted","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"},"X-Trace-Id":{"$ref":"#/components/headers/TraceId"},"X-API-Version":{"$ref":"#/components/headers/ApiVersion"},"X-Supported-API-Versions":{"$ref":"#/components/headers/SupportedApiVersions"},"X-Request-Duration-Ms":{"$ref":"#/components/headers/RequestDurationMs"},"Retry-After":{"$ref":"#/components/headers/RetryAfter"},"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-Quota-Limit":{"$ref":"#/components/headers/QuotaLimit"},"X-Quota-Remaining":{"$ref":"#/components/headers/QuotaRemaining"},"X-Quota-Reset":{"$ref":"#/components/headers/QuotaReset"},"X-Credit-Limit":{"$ref":"#/components/headers/CreditLimit"},"X-Credit-Remaining":{"$ref":"#/components/headers/CreditRemaining"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DatasetExport"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/AuthenticationError"},"404":{"$ref":"#/components/responses/NotFoundError"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}},"x-error-codes":{"400":["validation_error"],"401":["authentication_error"],"404":["not_found"],"429":["rate_limited"],"500":["server_error"]}}},"/datasets/{dataset_id}/exports/{export_id}":{"parameters":[{"$ref":"#/components/parameters/ApiVersion"}],"get":{"operationId":"getDatasetExport","summary":"Get a dataset export","description":"Returns export state and a short-lived download URL when ready.","tags":["Datasets"],"parameters":[{"$ref":"#/components/parameters/DatasetId"},{"$ref":"#/components/parameters/ExportId"}],"responses":{"200":{"description":"Current export","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"},"X-Trace-Id":{"$ref":"#/components/headers/TraceId"},"X-API-Version":{"$ref":"#/components/headers/ApiVersion"},"X-Supported-API-Versions":{"$ref":"#/components/headers/SupportedApiVersions"},"X-Request-Duration-Ms":{"$ref":"#/components/headers/RequestDurationMs"},"Retry-After":{"$ref":"#/components/headers/RetryAfter"},"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-Quota-Limit":{"$ref":"#/components/headers/QuotaLimit"},"X-Quota-Remaining":{"$ref":"#/components/headers/QuotaRemaining"},"X-Quota-Reset":{"$ref":"#/components/headers/QuotaReset"},"X-Credit-Limit":{"$ref":"#/components/headers/CreditLimit"},"X-Credit-Remaining":{"$ref":"#/components/headers/CreditRemaining"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DatasetExport"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/AuthenticationError"},"404":{"$ref":"#/components/responses/NotFoundError"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}},"x-error-codes":{"400":["validation_error"],"401":["authentication_error"],"404":["not_found"],"429":["rate_limited"],"500":["server_error"]}}},"/downloads/{export_id}":{"parameters":[{"$ref":"#/components/parameters/ApiVersion"}],"get":{"operationId":"downloadDatasetExport","summary":"Download a completed dataset export","description":"Streams the completed export as JSON, CSV, or opaque Parquet bytes. Download URLs expire independently from export metadata.","tags":["Datasets"],"parameters":[{"$ref":"#/components/parameters/ExportDownloadId"}],"responses":{"200":{"description":"Export bytes","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"},"X-Trace-Id":{"$ref":"#/components/headers/TraceId"},"X-API-Version":{"$ref":"#/components/headers/ApiVersion"},"X-Supported-API-Versions":{"$ref":"#/components/headers/SupportedApiVersions"},"X-Request-Duration-Ms":{"$ref":"#/components/headers/RequestDurationMs"},"Retry-After":{"$ref":"#/components/headers/RetryAfter"},"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-Quota-Limit":{"$ref":"#/components/headers/QuotaLimit"},"X-Quota-Remaining":{"$ref":"#/components/headers/QuotaRemaining"},"X-Quota-Reset":{"$ref":"#/components/headers/QuotaReset"},"X-Credit-Limit":{"$ref":"#/components/headers/CreditLimit"},"X-Credit-Remaining":{"$ref":"#/components/headers/CreditRemaining"}},"content":{"application/json":{"schema":{"type":"array","items":{"type":"object","additionalProperties":true}}},"text/csv":{"schema":{"type":"string"}},"application/octet-stream":{"schema":{"type":"string","format":"binary"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/AuthenticationError"},"404":{"$ref":"#/components/responses/NotFoundError"},"409":{"$ref":"#/components/responses/ConflictError"},"410":{"$ref":"#/components/responses/ExpiredError"},"413":{"$ref":"#/components/responses/ResponseTooLarge"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}},"x-error-codes":{"400":["validation_error"],"401":["authentication_error"],"404":["not_found"],"409":["idempotency_conflict"],"410":["download_expired"],"413":["response_too_large"],"429":["rate_limited"],"500":["server_error"]}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"Nordic Devhouse API key","description":"Server-side, environment-bound API key with explicit scopes, optional resource bindings, daily quotas, IP allowlists, rotation policy, and a per-key rate limit. Keys may expire, require rotation, or be revoked. Never expose one to browser or mobile application code."}},"parameters":{"JobId":{"name":"job_id","in":"path","required":true,"schema":{"type":"string","pattern":"^job_[A-Za-z0-9_]+$"}},"DatasetId":{"name":"dataset_id","in":"path","required":true,"schema":{"type":"string","pattern":"^ds_[A-Za-z0-9_]+$"}},"ExportId":{"name":"export_id","in":"path","required":true,"schema":{"type":"string","pattern":"^exp_[A-Za-z0-9_]+$"}},"IdempotencyKey":{"name":"Idempotency-Key","in":"header","required":false,"description":"Stable key reused for retries of one logical create operation.","schema":{"type":"string","minLength":8,"maxLength":255}},"ApiVersion":{"name":"Api-Version","in":"header","required":false,"description":"Requested API contract version. Aliases v1 and 1.0 are accepted for 1.0.0.","schema":{"type":"string","default":"1.0.0","example":"1.0.0"}},"NordicSignature":{"name":"Nordic-Signature","in":"header","required":true,"schema":{"type":"string"}},"Cursor":{"name":"cursor","in":"query","required":false,"schema":{"type":"string"}},"Limit":{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":25}},"ExportDownloadId":{"name":"export_id","in":"path","required":true,"description":"Dataset export identifier.","schema":{"type":"string","pattern":"^exp_[A-Za-z0-9_]+$"}}},"headers":{"RequestId":{"description":"Stable identifier for support and tracing.","schema":{"type":"string","pattern":"^req_[A-Za-z0-9_]+$"}},"RetryAfter":{"description":"Seconds until the caller should retry.","schema":{"type":"integer","minimum":1}},"ApiVersion":{"description":"API contract version used for the response.","schema":{"type":"string","example":"1.0.0"}},"TraceId":{"description":"Trace identifier for distributed tracing.","schema":{"type":"string","pattern":"^[0-9a-f]{32}$"}},"SupportedApiVersions":{"description":"Comma-separated API versions accepted by the server.","schema":{"type":"string","example":"1.0.0"}},"RequestDurationMs":{"description":"Server processing time in milliseconds.","schema":{"type":"integer","minimum":0}},"RateLimitLimit":{"description":"Request limit for the current rate window.","schema":{"type":"integer","minimum":0}},"RateLimitRemaining":{"description":"Requests remaining in the current rate window.","schema":{"type":"integer","minimum":0}},"QuotaLimit":{"description":"Usage quota for the current quota window.","schema":{"type":"integer","minimum":0}},"QuotaRemaining":{"description":"Usage quota remaining in the current quota window.","schema":{"type":"integer","minimum":0}},"QuotaReset":{"description":"RFC 3339 timestamp when the current quota window resets.","schema":{"type":"string","format":"date-time"}},"CreditLimit":{"description":"Monthly credit allowance.","schema":{"type":"integer","minimum":0}},"CreditRemaining":{"description":"Monthly credits remaining.","schema":{"type":"integer","minimum":0}}},"responses":{"ValidationError":{"description":"Request validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"},"X-Trace-Id":{"$ref":"#/components/headers/TraceId"},"X-API-Version":{"$ref":"#/components/headers/ApiVersion"},"X-Supported-API-Versions":{"$ref":"#/components/headers/SupportedApiVersions"},"X-Request-Duration-Ms":{"$ref":"#/components/headers/RequestDurationMs"},"Retry-After":{"$ref":"#/components/headers/RetryAfter"},"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-Quota-Limit":{"$ref":"#/components/headers/QuotaLimit"},"X-Quota-Remaining":{"$ref":"#/components/headers/QuotaRemaining"},"X-Quota-Reset":{"$ref":"#/components/headers/QuotaReset"},"X-Credit-Limit":{"$ref":"#/components/headers/CreditLimit"},"X-Credit-Remaining":{"$ref":"#/components/headers/CreditRemaining"}}},"AuthenticationError":{"description":"Credentials are missing or invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"},"X-Trace-Id":{"$ref":"#/components/headers/TraceId"},"X-API-Version":{"$ref":"#/components/headers/ApiVersion"},"X-Supported-API-Versions":{"$ref":"#/components/headers/SupportedApiVersions"},"X-Request-Duration-Ms":{"$ref":"#/components/headers/RequestDurationMs"},"Retry-After":{"$ref":"#/components/headers/RetryAfter"},"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-Quota-Limit":{"$ref":"#/components/headers/QuotaLimit"},"X-Quota-Remaining":{"$ref":"#/components/headers/QuotaRemaining"},"X-Quota-Reset":{"$ref":"#/components/headers/QuotaReset"},"X-Credit-Limit":{"$ref":"#/components/headers/CreditLimit"},"X-Credit-Remaining":{"$ref":"#/components/headers/CreditRemaining"}}},"NotFoundError":{"description":"Resource was not found in the authenticated workspace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"},"X-Trace-Id":{"$ref":"#/components/headers/TraceId"},"X-API-Version":{"$ref":"#/components/headers/ApiVersion"},"X-Supported-API-Versions":{"$ref":"#/components/headers/SupportedApiVersions"},"X-Request-Duration-Ms":{"$ref":"#/components/headers/RequestDurationMs"},"Retry-After":{"$ref":"#/components/headers/RetryAfter"},"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-Quota-Limit":{"$ref":"#/components/headers/QuotaLimit"},"X-Quota-Remaining":{"$ref":"#/components/headers/QuotaRemaining"},"X-Quota-Reset":{"$ref":"#/components/headers/QuotaReset"},"X-Credit-Limit":{"$ref":"#/components/headers/CreditLimit"},"X-Credit-Remaining":{"$ref":"#/components/headers/CreditRemaining"}}},"RateLimitError":{"description":"Request rate exceeded","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"},"X-Trace-Id":{"$ref":"#/components/headers/TraceId"},"X-API-Version":{"$ref":"#/components/headers/ApiVersion"},"X-Supported-API-Versions":{"$ref":"#/components/headers/SupportedApiVersions"},"X-Request-Duration-Ms":{"$ref":"#/components/headers/RequestDurationMs"},"Retry-After":{"$ref":"#/components/headers/RetryAfter"},"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-Quota-Limit":{"$ref":"#/components/headers/QuotaLimit"},"X-Quota-Remaining":{"$ref":"#/components/headers/QuotaRemaining"},"X-Quota-Reset":{"$ref":"#/components/headers/QuotaReset"},"X-Credit-Limit":{"$ref":"#/components/headers/CreditLimit"},"X-Credit-Remaining":{"$ref":"#/components/headers/CreditRemaining"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"ConflictError":{"description":"The resource cannot complete this operation in its current state","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"},"X-Trace-Id":{"$ref":"#/components/headers/TraceId"},"X-API-Version":{"$ref":"#/components/headers/ApiVersion"},"X-Supported-API-Versions":{"$ref":"#/components/headers/SupportedApiVersions"},"X-Request-Duration-Ms":{"$ref":"#/components/headers/RequestDurationMs"},"Retry-After":{"$ref":"#/components/headers/RetryAfter"},"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-Quota-Limit":{"$ref":"#/components/headers/QuotaLimit"},"X-Quota-Remaining":{"$ref":"#/components/headers/QuotaRemaining"},"X-Quota-Reset":{"$ref":"#/components/headers/QuotaReset"},"X-Credit-Limit":{"$ref":"#/components/headers/CreditLimit"},"X-Credit-Remaining":{"$ref":"#/components/headers/CreditRemaining"}}},"ExpiredError":{"description":"The resource or download has expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"},"X-Trace-Id":{"$ref":"#/components/headers/TraceId"},"X-API-Version":{"$ref":"#/components/headers/ApiVersion"},"X-Supported-API-Versions":{"$ref":"#/components/headers/SupportedApiVersions"},"X-Request-Duration-Ms":{"$ref":"#/components/headers/RequestDurationMs"},"Retry-After":{"$ref":"#/components/headers/RetryAfter"},"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-Quota-Limit":{"$ref":"#/components/headers/QuotaLimit"},"X-Quota-Remaining":{"$ref":"#/components/headers/QuotaRemaining"},"X-Quota-Reset":{"$ref":"#/components/headers/QuotaReset"},"X-Credit-Limit":{"$ref":"#/components/headers/CreditLimit"},"X-Credit-Remaining":{"$ref":"#/components/headers/CreditRemaining"}}},"ResponseTooLarge":{"description":"Response exceeds the supported SDK byte limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"},"X-Trace-Id":{"$ref":"#/components/headers/TraceId"},"X-API-Version":{"$ref":"#/components/headers/ApiVersion"},"X-Supported-API-Versions":{"$ref":"#/components/headers/SupportedApiVersions"},"X-Request-Duration-Ms":{"$ref":"#/components/headers/RequestDurationMs"},"Retry-After":{"$ref":"#/components/headers/RetryAfter"},"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-Quota-Limit":{"$ref":"#/components/headers/QuotaLimit"},"X-Quota-Remaining":{"$ref":"#/components/headers/QuotaRemaining"},"X-Quota-Reset":{"$ref":"#/components/headers/QuotaReset"},"X-Credit-Limit":{"$ref":"#/components/headers/CreditLimit"},"X-Credit-Remaining":{"$ref":"#/components/headers/CreditRemaining"}}},"ServerError":{"description":"Temporary server failure","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"},"X-Trace-Id":{"$ref":"#/components/headers/TraceId"},"X-API-Version":{"$ref":"#/components/headers/ApiVersion"},"X-Supported-API-Versions":{"$ref":"#/components/headers/SupportedApiVersions"},"X-Request-Duration-Ms":{"$ref":"#/components/headers/RequestDurationMs"},"Retry-After":{"$ref":"#/components/headers/RetryAfter"},"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-Quota-Limit":{"$ref":"#/components/headers/QuotaLimit"},"X-Quota-Remaining":{"$ref":"#/components/headers/QuotaRemaining"},"X-Quota-Reset":{"$ref":"#/components/headers/QuotaReset"},"X-Credit-Limit":{"$ref":"#/components/headers/CreditLimit"},"X-Credit-Remaining":{"$ref":"#/components/headers/CreditRemaining"}}}},"schemas":{"ScrapeRequest":{"type":"object","additionalProperties":false,"required":["url","formats"],"properties":{"url":{"type":"string","format":"uri","pattern":"^https://"},"formats":{"type":"array","minItems":1,"uniqueItems":true,"items":{"type":"string","enum":["json","csv","html"]}},"webhook_url":{"type":"string","format":"uri","pattern":"^https://"},"metadata":{"type":"object","additionalProperties":{"type":["string","number","boolean","null"]},"maxProperties":20}}},"JobStatus":{"type":"string","enum":["queued","running","completed","failed","canceled"]},"Job":{"type":"object","required":["id","status","created_at","request_id"],"properties":{"id":{"type":"string","pattern":"^job_[A-Za-z0-9_]+$"},"status":{"$ref":"#/components/schemas/JobStatus"},"created_at":{"type":"string","format":"date-time"},"completed_at":{"type":["string","null"],"format":"date-time"},"retention_expires_at":{"type":["string","null"],"format":"date-time"},"request_id":{"type":"string","pattern":"^req_[A-Za-z0-9_]+$"},"records":{"type":"integer","minimum":0,"default":0},"dataset_id":{"type":["string","null"],"pattern":"^ds_[A-Za-z0-9_]+$","description":"Dataset materialized from a completed scrape job."},"data":{"oneOf":[{"title":"JobDataArray","type":"array","items":{}},{"title":"JobDataObject","type":"object","additionalProperties":true}],"nullable":true},"warnings":{"type":"array","items":{"type":"string"}},"last_event_id":{"type":["string","null"],"pattern":"^evt_[A-Za-z0-9_]+$"},"metadata":{"type":"object","additionalProperties":true}}},"JobPage":{"type":"object","required":["data","has_more"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Job"}},"next_cursor":{"type":["string","null"]},"has_more":{"type":"boolean"}}},"Event":{"type":"object","required":["id","type","created_at","data"],"properties":{"id":{"type":"string","pattern":"^evt_[A-Za-z0-9_]+$"},"type":{"type":"string","enum":["scrape.completed","scrape.failed","scrape.canceled","dataset.ready","dataset.failed","realtime.change"]},"created_at":{"type":"string","format":"date-time"},"data":{"type":"object","additionalProperties":true}}},"EventPage":{"type":"object","required":["data","has_more"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Event"}},"next_cursor":{"type":["string","null"]},"has_more":{"type":"boolean"}}},"WebhookDelivery":{"type":"object","required":["id","event_id","endpoint","status","attempts"],"properties":{"id":{"type":"string","pattern":"^whd_[A-Za-z0-9_]+$"},"event_id":{"type":"string","pattern":"^evt_[A-Za-z0-9_]+$"},"endpoint":{"type":"string","format":"uri"},"status":{"type":"string","enum":["pending","delivered","dead_letter"]},"attempts":{"type":"integer","minimum":0},"next_attempt_at":{"type":["string","null"],"format":"date-time"},"delivered_at":{"type":["string","null"],"format":"date-time"},"last_error":{"type":["string","null"]}}},"Dataset":{"type":"object","additionalProperties":false,"required":["id","name","version","records"],"properties":{"id":{"type":"string","pattern":"^ds_[A-Za-z0-9_]+$"},"name":{"type":"string"},"version":{"type":"string"},"records":{"type":"integer","minimum":0},"source_job_id":{"type":["string","null"],"pattern":"^job_[A-Za-z0-9_]+$"}}},"DatasetExportRequest":{"type":"object","additionalProperties":false,"required":["format"],"properties":{"format":{"type":"string","enum":["json","csv","parquet"]},"mode":{"type":"string","enum":["snapshot","changes"],"default":"snapshot"},"version":{"type":"string"}}},"DatasetExport":{"type":"object","required":["id","dataset_id","status","format","created_at","request_id"],"properties":{"id":{"type":"string","pattern":"^exp_[A-Za-z0-9_]+$"},"dataset_id":{"type":"string","pattern":"^ds_[A-Za-z0-9_]+$"},"status":{"type":"string","enum":["queued","running","completed","failed"]},"format":{"type":"string","enum":["json","csv","parquet"]},"created_at":{"type":"string","format":"date-time"},"completed_at":{"type":["string","null"],"format":"date-time"},"download_url":{"type":["string","null"],"format":"uri"},"expires_at":{"type":["string","null"],"format":"date-time"},"request_id":{"type":"string","pattern":"^req_[A-Za-z0-9_]+$"}}},"MetricsSnapshot":{"type":"object","additionalProperties":{"type":"object","required":["requests","errors","statuses","durationMs"],"properties":{"requests":{"type":"integer","minimum":0},"errors":{"type":"integer","minimum":0},"statuses":{"type":"object","additionalProperties":{"type":"integer","minimum":0}},"durationMs":{"type":"number","minimum":0}}}},"WebhookEvent":{"type":"object","required":["id","type","created_at","data"],"properties":{"id":{"type":"string","pattern":"^evt_[A-Za-z0-9_]+$"},"type":{"type":"string","enum":["scrape.completed","scrape.failed","scrape.canceled","dataset.ready","dataset.failed","realtime.change"]},"created_at":{"type":"string","format":"date-time"},"data":{"type":"object","additionalProperties":true}}},"ErrorEnvelope":{"type":"object","required":["error"],"properties":{"error":{"$ref":"#/components/schemas/Error"}}},"Error":{"type":"object","required":["code","message","request_id","category","retryable"],"properties":{"code":{"type":"string","examples":["rate_limited"],"enum":["unsupported_api_version","authentication_error","invalid_api_key","api_key_revoked","api_key_expired","rotation_overlap_expired","rotation_required","environment_mismatch","scope_missing","resource_scope_missing","ip_not_allowed","credential_quarantined","validation_error","not_found","idempotency_conflict","rate_limited","quota_exceeded","server_error","timeout","resource_expired","export_not_ready","download_expired","job_not_ready","invalid_signature","replayed_event","response_too_large"]},"message":{"type":"string","examples":["Too many requests"]},"request_id":{"type":"string","pattern":"^req_[A-Za-z0-9_]+$"},"category":{"type":"string","enum":["auth","input","resource","throttle","upstream","transport","state","webhook","versioning","server"]},"retryable":{"type":"boolean"},"retry_after":{"type":["integer","null"],"minimum":1,"description":"Delay in seconds before a retry may be attempted."},"issues":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}}