Build with the nData API
Submit asynchronous extraction and transcription jobs, poll for results, and inspect workspace usage. Signed-in API jobs are real processing requests when accepted; availability depends on the configured processor and source.
Quickstart
Create a key in API keys, then set NDATA_SOURCE_URL to a permitted public supported post URL and submit it with a unique idempotency key. The server returns a job ID immediately. Poll that job for its status and result.
processing_mode: live. The anonymous playground is static browser sample data and never submits a job. Runtime availability and supported sources depend on deployment settings.export NDATA_API_KEY='YOUR_SERVER_SIDE_API_KEY'
export NDATA_SOURCE_URL='PASTE_A_PUBLIC_SUPPORTED_POST_URL_YOU_ARE_ALLOWED_TO_USE'
submission=$(curl --fail-with-body -sS -X POST https://api.ndata.io/v1/extractions \
-H "x-api-key: $NDATA_API_KEY" \
-H "Idempotency-Key: replace-with-a-unique-request-id" \
-H "Content-Type: application/json" \
--data "$(jq -n --arg url "$NDATA_SOURCE_URL" --arg prompt "Summarize the key points" '{url:$url,prompt:$prompt}')")
printf '%s\n' "$submission" | jq '{id,status,credits_reserved}'Set NDATA_SOURCE_URL to one public post you are allowed to access. This shell example uses jq. The idempotency key must be new for each new request; reuse the same key to recover an uncertain submission.
job_id=$(printf '%s\n' "$submission" | jq -r '.id')
sleep 10
curl --fail-with-body -sS https://api.ndata.io/v1/extractions/"$job_id" \
-H "x-api-key: $NDATA_API_KEY" | jq '{status,result,error}'Wait at least 10 seconds between reads in this example. Poll again if the status is still queued or running, and honor a longer Retry-After response. A successful POST confirms acceptance only, not completion.
Authentication
Send an API key in the x-api-key header. Keys belong to one workspace and have fixed scopes. Do not expose server keys in browser code or mobile apps.
x-api-keyRequiredAPI key created from the console. Revoked, expired, or invalid keys return 401.
Idempotency-KeyRequired on POSTUnique per workspace across both resources and portal submissions. Reusing a key with a different payload returns 409.
Create an extraction
Submit a job to POST /v1/extractions. A successful submission returns 202 Accepted with the job record and a Location header.
/v1/extractionsextractions:writeRequest body
urlstringProvide a public post URL. New API jobs are handled by the private processor when configured; available sources depend on deployment settings.
promptstring · optionalGuidance or a question about the post and media. The default limit is 4,000 Unicode characters and 16,384 UTF-8 bytes; see Prompt rules. A question adds an answer alongside the other default fields. A custom output schema or template controls the entire response shape.
outputobject · optionalOmit for the platform default JSON preset: source metadata, summary, key_points, answer, and optional keywords, findings, and limitations. Findings classify supported details by type: entity, claim, date, quantity, instruction (one complete procedure), quote, link, on_screen_text, key_moment, or other. An instruction finding preserves the complete ordered procedure, including steps, materials, amounts, conditions, and warnings. Use {"format":"json","schema":{...}} for a bounded custom JSON Schema, or {"format":"markdown","template":"..."} for a separate best-effort Markdown template. A template is required for final Markdown output; omitting output selects the default JSON preset.
Accepted job
{
"id": "c04802ed-42af-4f80-92e2-7c1a9c5e83db",
"status": "queued",
"type": "extraction",
"options": {"prompt": null, "output": {"format": "json"}},
"url": "$NDATA_SOURCE_URL",
"credits_reserved": 5,
"credits_charged": 0,
"created_at": "2026-10-24T10:30:00Z",
"started_at": null,
"completed_at": null,
"duration_ms": null,
"media_duration_seconds": null,
"result": null,
"error": null,
"processing_mode": "live"
}Completed default result
The result below is a static YouTube fixture, not a response to the submitted URL. The URL is shown as a placeholder. Historical simulated jobs retain this result shape and its simulation marker.
{
"simulated": true,
"message": "Sample data only. No source content was fetched or processed.",
"format": "json",
"schema_version": "youtube.post.v2",
"output": {
"platform": "youtube",
"url": "$NDATA_SOURCE_URL",
"author": {"name": null, "handle": null, "url": null},
"text": null,
"media": [],
"summary": "Static sample summary. It is not derived from the entered URL.",
"key_points": ["Static sample key point."],
"answer": null,
"keywords": [],
"findings": [],
"limitations": []
}
}Prompt rules
An extraction prompt is optional plain text that focuses a question or guides extraction. Its default limits are 4,000 Unicode code points and 16,384 UTF-8 bytes. Both limits can be configured by the server and are published in GET /v1/openapi.json as x-ndata-prompt-policy. The signed-in playground loads those effective limits before submission; the public playground uses these documented defaults.
Limits count the raw prompt before trimming outer whitespace. Tabs, line feeds and carriage returns are allowed. NUL, other C0 controls, C1 controls and DEL are rejected. Blank or whitespace-only text is invalid when a prompt is supplied. In the playground, leaving the editor exactly empty omits the optional prompt. Outer whitespace is trimmed before storage; inner spaces and line breaks are preserved.
Prompts may use any language, emoji and ZWJ sequences, right-to-left text, JSON, code, URLs and instruction-like phrases. There is no keyword blacklist. Prompts are text guidance and are never executed as code. The source content and selected output mode/schema remain authoritative: a prompt cannot request another output format, override system rules or cause unsupported facts to be invented.
Optional output fields may be omitted when evidence is missing, nullable fields may be null when their schema permits it, and arrays may be empty. Required unsupported facts can cause processing to fail rather than be fabricated. API jobs process the submitted source through the configured runner. The anonymous sample playground remains static and does not respond to the prompt.
Custom JSON Schema
Custom JSON output uses a bounded subset of Draft 2020-12. The schema document must be an object, and its root output can be an object, array, string, number, integer, boolean or null. nData checks the value at result.output; service-owned job fields are outside the schema. The signed-in playground loads the effective limits from GET /v1/openapi.json. The public playground uses the documented defaults below and never needs a backend.
{
"type": "object",
"properties": {
"answer": {
"type": ["string", "null"],
"description": "Answer the supplied question using the post."
},
"products": {
"type": "array",
"maxItems": 5,
"items": {
"type": "object",
"properties": {
"name": {"type": "string"},
"price": {"type": ["number", "null"], "minimum": 0}
},
"required": ["name", "price"],
"additionalProperties": false
}
}
},
"required": ["answer", "products"],
"additionalProperties": false
}Supported rules
Use a single type or one nullable pair such as ["string", "null"]. A root may also use a local reference to a typed schema. Objects require a properties map and additionalProperties: false. Optional required names must be unique and declared in properties. Arrays require one typed items schema. enum and const contain scalar JSON values that match the declared type and bounds. $defs and nonrecursive local JSON Pointer $ref values may point only to schema positions in this document. A description is field guidance, not an override for system rules; one is limited to 256 characters, with 4,096 characters total.
Supported keywords: type, properties, required, additionalProperties, items, minItems, maxItems, minLength, maxLength, minimum, maximum, exclusiveMinimum, exclusiveMaximum, enum, const, $defs, $ref and description. Optional $schema is allowed only at the root and must select Draft 2020-12.
Other keywords are rejected, including pattern, format, patternProperties, uniqueItems, multipleOf, anyOf, oneOf, allOf, conditional keywords, tuple validation, identifiers and dynamic references. A property named pattern, $ref or __proto__ is ordinary output data and is allowed.
Documented default limits
Byte size is compact serialized UTF-8 JSON size, not the number of characters, spaces in the editor or model tokens. The root object or array has output depth one. A root object containing an array of objects has output depth three. Output depth follows references; the separate structural limit bounds schema document nesting.
max_bytes16,384 bytesCompact UTF-8 schemamax_nodes5,000Structural and expanded nodesmax_depth8Output object/array depthmax_properties200Expanded output propertiesproperty_name_max_chars128Characters per property namedescription_max_chars256Characters per descriptiondescriptions_max_chars4,096Total description charactersenum_max_values100Values per enumstructural_max_depth64Schema JSON nestingmax_items100Largest explicit array count boundmax_string_length8,000Largest explicit string boundgrammar_max_work100,000Expanded grammar allowanceLimits are configurable on the server. The authenticated playground uses the effective OpenAPI policy; if it cannot load that metadata, it blocks custom-schema submission and offers a retry. Public defaults are documented fallback values, not a claim about a remote server's current configuration.
Evidence and missing values
An optional property may be omitted. A nullable property may be null if its other constraints permit null. An array may be empty if allowed. Required facts must be supported by source evidence. If evidence cannot satisfy a required field or a count such as minItems: 5, processing reports a failure and releases the reservation. The system must not invent items to satisfy the schema. Schema validation checks shape and constraints; it does not prove factual accuracy.
Markdown is separate
{"format":"markdown","template":"..."} selects a separate text template, not a JSON Schema. It must contain non-whitespace text and may be at most 8,000 characters. Templates are never executed as code. They provide requested headings and layout; structural conformance is best effort.
Create a transcription
/v1/transcriptionstranscriptions:writeSend a URL with mode set to native (default) or generated. Choose timestamps: flat (default), sentence or word. Native mode retrieves existing captions and never silently falls back to generation.
{
"url": "$NDATA_SOURCE_URL",
"mode": "generated",
"timestamps": "word"
}The JSON uses $NDATA_SOURCE_URL as a placeholder. Set it to a permitted public post URL before sending the request.
Results include text, the requested source, language when detected and numeric timestamps in seconds. Only the selected timing array is present; the other is null. Live results use timing from the processing run. Historical simulated results may have a null language and illustrative timing. Prompts and output schemas apply only to extraction.
Batch requests
Submit an array of permitted public post URLs to an extraction or transcription batch. The configurable defaults are 1,000 URLs and a 4 MiB JSON request body. Both effective limits are published in GET /v1/openapi.json as x-ndata-batch-policy; credits and daily accepted-job limits also apply.
/v1/extractions/batchesextractions:write/v1/transcriptions/batchestranscriptions:write{
"urls": [
"$NDATA_SOURCE_URL"
],
"prompt": "Summarize the main points",
"output": {
"format": "json",
"schema": {
"type": "object",
"properties": {
"summary": {
"type": "string"
}
},
"required": [
"summary"
],
"additionalProperties": false
}
}
}The JSON shows $NDATA_SOURCE_URL as a placeholder. Build the submitted body from your environment, replacing it with a permitted public post URL. Add one URL per item for a mixed-platform batch.
Extraction options are shared across all URLs: an optional prompt and output.schema or a Markdown template. Transcription batches share mode and timestamps. Each batch uses one capability; its URLs may mix platforms. Duplicate URLs create separate jobs and reservations.
Send a unique Idempotency-Key. Acceptance validates the whole request and reserves every item's credits atomically. Invalid URLs, insufficient credits or admission limits reject the entire batch. A new batch returns 202; an identical replay returns 200 with the existing batch. Each item then succeeds or fails independently. Successful items are charged; failed items release their reservation. Credit availability, daily accepted-job limits and outstanding-job limits apply in addition to the URL count.
The response is a summary with counts, credits, delivery state and links. Read GET /v1/extractions/batches/{id} or the corresponding transcription path for progress. A batch reaches completed after every item finishes; inspect outcome for all_succeeded, partial_failure or all_failed. Processing completion and webhook acknowledgment are independent.
Append /items?limit=50 for input-ordered items. Pages contain child IDs, statuses and individual result links. Follow the opaque next_cursor through the cursor query parameter; the maximum page size is 100. Retrieve each result through its existing extraction or transcription job endpoint. Batch reads and child reads require the resource's read scope.
Stream delivery and recovery
Optionally provide paired webhook_url and webhook_secret fields. Each terminal child emits job.completed or job.failed, including batch_id, zero-based index and the full job result. One batch.completed event contains the final summary. Events may arrive more than once or out of order, including the summary. Verify raw bytes with the HMAC helper described under Webhooks, deduplicate event_id, and durably accept before returning 2xx.
New batch deliveries default to 32 claims within 24 hours. Append /deliveries to the batch URL for paginated acknowledgment, retry and exhaustion history. To retry an exhausted event, send an empty JSON object with a new Idempotency-Key to POST /v1/extractions/batches/{id}/deliveries/{event_id}/redeliver, or the corresponding transcription path. The resource write scope is required. Recovery preserves the event ID, body, destination and signing secret; it never reruns processing or charges credits. An oversized event cannot be redelivered unchanged. Workspace owners and admins can pause or resume new delivery claims in the signed-in playground; an in-flight send may finish.
Python create_extraction_batch / create_transcription_batch and TypeScript createExtractionBatch / createTranscriptionBatch return acceptance immediately by default. Persist the batch ID and use its summary, paginated items or webhooks for continuation.
Retrieve a job
Poll the job result URL until status is completed or failed. Each job records its processing_mode. New live results set simulated to false and omit the simulator explanation; historical simulated results retain simulated: true and their explanation.
/v1/extractions/{id}extractions:read/v1/transcriptions/{id}transcriptions:readA successful HTTP submission only means the job was accepted, not that work completed.
Usage
Read workspace usage with GET /v1/usage. This endpoint requires the usage:read scope and returns local job and credit totals for the key's workspace, plus a quota snapshot with credits, request windows, queued/running capacity and a daily processing allowance.
/v1/usageusage:readDaily processing allowance
quota.processing_budget contains jobs, attempts and work_units, each with limit, used and remaining, plus window_start and reset_at. Limits are shared across the workspace's keys and console submissions and reset at the next UTC midnight.
A new accepted job uses one job slot. Each worker attempt, including a retry, consumes an attempt and internal work units. Failed jobs release reserved customer credits, but their daily processing allowance remains used. Identical idempotent replays do not create another job or consume another attempt. Work units are provisional capacity weights, not currency or measured provider costs. Effective plan limits are published as x-ndata-processing-budget in OpenAPI and displayed on the console Usage page.
Errors and limits
Errors use a consistent envelope. Request option and prompt-policy errors use invalid_request; prompt issues point to /prompt. A schema policy failure returns HTTP 400 with invalid_schema and JSON Pointer issue paths under /output/schema. Neither creates a job or reserves credits, although normal authentication and request quota checks still apply.
{
"error": {
"code": "invalid_request",
"message": "Markdown output requires a nonblank template."
}
}{
"error": {
"code": "invalid_request",
"message": "The request contains invalid options.",
"details": {
"issues": [{
"path": "/prompt",
"keyword": "max_chars",
"message": "Prompt must be at most 4,000 Unicode characters."
}]
}
}
}{
"error": {
"code": "invalid_schema",
"message": "The custom schema does not satisfy nData schema policy.",
"details": {
"issues": [{
"path": "/output/schema/properties/date/pattern",
"keyword": "pattern",
"message": "This schema keyword is not supported."
}]
}
}
}Use the issue path and keyword to locate the rejected rule. nData does not return the submitted schema in the error. See Custom JSON Schema for supported keywords and limits.
400 Invalid request or schema401 Missing or invalid API key402 Insufficient credits403 Required scope is missing409 Idempotency conflict429 Request or processing allowance exceededProcessing limits and safe output
A new submission that exceeds the daily allowance returns HTTP 429 with processing_budget_exceeded and Retry-After. If the allowance is exhausted before an accepted single job starts, that job fails with the same code and releases its reserved credits. Held batch items wait for the next daily processing window. Inspect the failed job and wait for the reset rather than automatically creating another job.
The JSON request body is limited to 1,000,000 bytes by default, configured through NDATA_REQUEST_MAX_BYTES and published as x-ndata-request-max-bytes in OpenAPI. Oversized or malformed JSON returns HTTP 400 with invalid_request. Duplicate keys and non-finite numbers are rejected. Request and processing quotas apply independently of prompt and schema limits.
Prompts, templates, and extracted content are untrusted text. Results are displayed as escaped text in the playground. Applications consuming results should validate them and escape any content they render. JSON schema validation checks structure, not factual correctness.
The current default starter grant is 100 credits once for an eligible verified personal workspace. The workspace usage balance is authoritative and the default can vary by deployment. No automatic refill is active; the future refill policy is pending. Check GET /v1/usage or the signed-in Overview for your effective balance.
Extraction reserves 5 credits and transcription reserves 2 credits per job. These rates are provisional. Successful jobs are charged; terminal failures release the reservation. Failed jobs still use daily processing allowance. Reads spend no credits.
Token-bucket request limits apply separately to submissions and reads/polling, shared across workspace keys and console job calls. Current internal Free/Build/Scale workspace groups have submission defaults of 6/12/30 requests per minute with bursts of 2/4/6, and read/poll defaults of 10/100/300 requests per minute with bursts of 5/30/100. These are API configuration groups, not paid plans available for purchase.
The service-wide authenticated HTTP pool defaults to 10 requests per second with a burst of 20. Workspace ready-job limits default to 5/10/20 with a global pending-job cap of 50. These settings are configurable and are not throughput or availability promises. A 429 rate-limit response includes Retry-After; protected responses include remaining/reset headers. Global pending-capacity exhaustion returns HTTP 503 with service_busy and Retry-After. Account/key management and portal usage remain available at rate exhaustion. Actual source availability depends on processor and deployment settings. Contact support with access or credit questions.
SDKs and agents
The Python and TypeScript SDKs, MCP server, and framework adapters are unreleased source builds. They are not published to npm or PyPI and require an nData repository checkout. Do not install them from public package registries yet. Python uses Pydantic v2 models with extra="forbid". TypeScript uses Zod 4 strict objects. Every customer schema remains subject to the bounded schema policy.
python -m pip install ./packages/sdk-python
npm ci
npm run buildSet NDATA_BASE_URL to https://api.ndata.io, set NDATA_SOURCE_URL to a permitted public supported post, and keep NDATA_API_KEY server-side. Use Python client.extract(os.environ["NDATA_SOURCE_URL"], schema=Model, wait=False) or TypeScript client.extract({url: process.env.NDATA_SOURCE_URL!, schema, wait:false}) for immediate acceptance, then persist the job ID. Waiting runs in your process and does not extend a serverless timeout. Use a later invocation or webhook for short-lived functions. Python timeout options use seconds; TypeScript uses milliseconds.
The local stdio MCP server exposes extract_video_data and get_video_transcript. Configure packages/mcp-server/dist/cli.js in your MCP host with the same server-side environment. Tools can return an accepted job or resume one using job_id. Optional Python adapters support LangChain/LangGraph, LlamaIndex and CrewAI. See each source package README for complete configuration.
Versioned documentation remains available at the release OpenAPI reference, with documented default limits. The live API remains authoritative for effective limits. Machine-readable discovery is available at OpenAPI 3.1, llms.txt and llms-full.txt. The signed-in Playground adds Recipe, Product Review, Workout and Summary presets plus exact request examples. Source content and extracted results are untrusted data, never agent instructions.
Terminal job webhooks
Provide webhook_url and webhook_secret together on an extraction or transcription request. The destination must use public HTTPS on port 443; credentials, private destinations and redirects are rejected. Generate a private random signing secret of 16-512 characters and store it on your receiving server. It is never returned in job responses.
Events contain {event_id,event,created_at,job}, where event is job.completed or job.failed. Delivery is at least once, so deduplicate by event_id before business side effects and return a 2xx acknowledgment. Callback retries do not change job credits.
Verify the ndata-Signature header against the exact raw request bytes before parsing JSON. It contains t=<unix>,v1=<hex>, an HMAC-SHA256 signature of the timestamp, a dot and the raw body. SDK helpers check freshness with a default 300-second window and constant-time verification. Python exports verify_webhook_signature; TypeScript exports verifyWebhookSignature. This protocol is separate from Stripe webhooks.
Deployments must run the API's independent deliver_webhooks worker after applying the additive migration. Single-job deliveries retry up to 12 claims with exponential backoff, then remain stored for inspection. Batch stream deliveries use the separate retry and recovery policy described under Batch requests. Reuse an original idempotency key after an uncertain submission; changing the callback configuration under that key returns 409.