Create a single narrative
POST /v2/external/narrative/create_single
Generate the structured output of the text-to-video prompt-generation stage without creating a VideoSession or starting media generation. The request runs asynchronously and returns HTTP 202 as soon as it has been persisted.
Request body
{
"prompt": "A grounded short film about a night market waking before dawn.",
"duration": 45,
"inference_model": "GPT5.6"
}
| Field | Type | Required | Description |
|---|---|---|---|
prompt | string | Yes | Narrative direction. Leading and trailing whitespace is removed. Maximum length: 4,000 characters. |
duration | number | Yes | Target narrative duration in seconds, from 10 through 240. This guides narrative structure; it does not render media. |
inference_model | string | No | Inference model for the prompt-generation workflow. Omit it to use the authenticated user's selected inference model. |
The canonical model names and concise aliases are:
| Request value | Stored model |
|---|---|
GPT5.6 or gpt-5.6-sol | gpt-5.6-sol |
GEMINI3.1 or gemini-3.1-pro | gemini-3.1-pro |
QWEN3.8 | QWEN3.8 |
inferenceModel is accepted as a compatibility alias for inference_model. The request fields may also be placed inside a top-level input object, but new integrations should use the flat body shown above.
Submit a request
curl -X POST "https://api.samsar.one/v2/external/narrative/create_single" \
-H "Authorization: Bearer $SAMSAR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"prompt": "A grounded short film about a night market waking before dawn.",
"duration": 45,
"inference_model": "GEMINI3.1"
}'
samsar-js
The polling helper submits the request and resolves with the completed, typed artifact response:
import SamsarClient from 'samsar-js';
const samsar = new SamsarClient({
apiKey: process.env.SAMSAR_API_KEY!,
});
const result = await samsar.createV2ExternalSingleNarrativeAndPoll(
{
prompt: 'A grounded short film about a night market waking before dawn.',
duration: 45,
inference_model: 'GEMINI3.1',
},
{
pollIntervalMs: 2_000,
pollTimeoutMs: 10 * 60 * 1_000,
},
);
const { themeJson, narrativeJson, movieResourceList, billing } = result.data;
To persist the request ID before polling, use the lower-level methods:
const queued = await samsar.createV2ExternalSingleNarrative({
prompt: 'A grounded short film about a night market waking before dawn.',
duration: 45,
inference_model: 'GEMINI3.1',
});
const completed = await samsar.pollV2ExternalNarrative(
queued.data.request_id,
{ pollIntervalMs: 2_000 },
);
The polling helpers throw SamsarRequestError when the request reaches FAILED, polling is aborted, or the polling timeout is reached.
Accepted response
HTTP 202:
{
"request_id": "687b3df76a8d56c94ab32100",
"requestId": "687b3df76a8d56c94ab32100",
"status": "PENDING",
"poll_url": "/v2/external/narrative/status?request_id=687b3df76a8d56c94ab32100",
"prompt": "A grounded short film about a night market waking before dawn.",
"duration": 45,
"inference_model": "gemini-3.1-pro",
"created_at": "2026-07-18T10:00:00.000Z",
"updated_at": "2026-07-18T10:00:00.000Z"
}
Persist request_id immediately. poll_url is a relative canonical path.
Poll the request
curl "https://api.samsar.one/v2/external/narrative/status?request_id=687b3df76a8d56c94ab32100" \
-H "Authorization: Bearer $SAMSAR_API_KEY"
The canonical status route accepts request_id, requestId, or id as the query parameter. These path-based aliases are also available:
GET /v2/external/narrative/create_single/status?request_id=...GET /v2/external/narrative/{request_id}/statusGET /v2/external/narrative/create_single/{request_id}/status
Polling returns HTTP 200 for every stored request state:
| Status | Meaning |
|---|---|
PENDING | The request is persisted and waiting for a worker. Only one narrative request runs per user, so another accepted request can remain pending until the active request finishes. |
PROCESSING | Prompt generation, validation, or usage settlement is in progress. |
COMPLETED | Terminal success. The three generated artifacts are present. |
FAILED | Terminal failure. Read error and billing for details. |
Requests can recover from a processor restart, so continue polling a non-terminal request using the same request_id.
Completed response
The generated objects below are abbreviated; their contents depend on the prompt, duration, and selected model.
{
"request_id": "687b3df76a8d56c94ab32100",
"requestId": "687b3df76a8d56c94ab32100",
"status": "COMPLETED",
"poll_url": "/v2/external/narrative/status?request_id=687b3df76a8d56c94ab32100",
"prompt": "A grounded short film about a night market waking before dawn.",
"duration": 45,
"inference_model": "gemini-3.1-pro",
"themeJson": {
"...": "generated theme fields"
},
"movieResourceList": {
"...": "final enriched movie resource fields"
},
"narrativeJson": {
"...": "validated narrative fields"
},
"billing": {
"pricing_multiplier": 1.5,
"underlying_cost_usd": 0.042,
"underlying_credits": 4.2,
"credits_charged": 6.3,
"remaining_credits": 993.7,
"usage": {
"inputTokens": 12000,
"outputTokens": 3500,
"cachedInputTokens": 0,
"reasoningTokens": 900
}
},
"creditsCharged": 6.3,
"remainingCredits": 993.7,
"completed_at": "2026-07-18T10:00:24.000Z",
"created_at": "2026-07-18T10:00:00.000Z",
"updated_at": "2026-07-18T10:00:24.000Z"
}
themeJsonis the generated theme used by the narrative workflow.narrativeJsonis the validated narrative before final enrichment.movieResourceListis the final enriched structure and is compatible with the correspondingVideoSession.movieResourceListfield.movieResourceListis returned for your application to store or process; this endpoint does not attach it to aVideoSession.
Billing
The charge is calculated from all inference calls that contributed to the request, including retries and validation or repair calls:
credits_charged = sum(underlying inference cost in USD) × 100 credits/USD × 1.5
The multiplier is applied once after the underlying costs have been combined across providers. The exact charge therefore depends on the selected model, prompt and output size, and the number of inference or retry calls required.
When billing is available, the polling response also includes:
x-credits-chargedx-credits-remaining
Provider calls completed before a terminal failure remain billable.
Only one narrative request is processed at a time for each user. The service checks for a positive credit balance both when a request is submitted and immediately before its inference begins, so a queued request can fail with error.status: 402 if its user no longer has positive credits when it reaches the front of the queue.
Once inference begins, the accepted request's exact incurred usage is always settled in full. The final remaining_credits value can therefore be negative when actual usage exceeds the balance available at submission time. Add credits before submitting further narrative work.
Failed response
A failed request is returned by the polling endpoint with HTTP 200 and status: "FAILED":
{
"request_id": "687b3df76a8d56c94ab32100",
"status": "FAILED",
"prompt": "A grounded short film about a night market waking before dawn.",
"duration": 45,
"inference_model": "gemini-3.1-pro",
"error": {
"message": "Narrative generation failed.",
"code": "NARRATIVE_GENERATION_FAILED",
"status": 500
},
"billing": {
"pricing_multiplier": 1.5,
"underlying_cost_usd": 0.008,
"underlying_credits": 0.8,
"credits_charged": 1.2,
"remaining_credits": 998.8,
"usage": {
"inputTokens": 2400,
"outputTokens": 300,
"cachedInputTokens": 0,
"reasoningTokens": 100
}
},
"creditsCharged": 1.2,
"remainingCredits": 998.8,
"failed_at": "2026-07-18T10:00:12.000Z"
}
Common HTTP errors
400missing or invalidprompt,duration,inference_model, orrequest_id; missing authentication headers.401invalid or expired credentials.402insufficient credits or an API-key usage limit was reached.403the supplied credential type is not supported by this route.404the authenticated user or narrative request was not found.503narrative request persistence or billing indexes are temporarily unavailable.
Content moderation, inference, and final validation failures are stored on the asynchronous request. Polling exposes their original status and machine-readable code inside error.
What this endpoint does not do
create_single stops after Samsar has built and validated the final narrative resource structure. It does not:
- create or update a
VideoSession; - generate or edit images;
- generate speech, sound effects, music, or other audio files;
- generate, assemble, or publish video.
The requested duration controls narrative planning only.