Skip to main content

V2 API

Base URL
https://api.samsar.one
Route prefix
/v2 · alias /api/v2
Authentication
Internal, app-key, or external-user actor
Execution
Unified synchronous and asynchronous workflows
Billing
Delegates to the canonical route's existing billing rules
Content type
application/json

/v2 is an additive API surface. /v1 is not deprecated. The same router is also available under /api/v2 for clients that use the longer API prefix.

The /v2 routes are designed for clients where either an internal Samsar account or an external user can be authenticated in the same UI. Each route resolves the authenticated actor and routes the request through the existing internal or external-user handling path so the same validation, pricing, and credit deduction rules continue to apply.

Route map

The tables favor canonical paths. Compatibility aliases are called out only when they are useful during a migration; use the endpoint sections below for request contracts and status behavior.

Core session and request routes

RoutePurpose
GET /v2/healthCheck V2 service health without authentication.
POST /v2/sessionCreate a V2 session.
POST /v2/create_login_tokenCreate a login token for authenticated flows.
GET /v2/requestsList requests visible to the authenticated actor.
GET /v2/statusPoll request or session status.
GET /v2/status_detailedPoll status plus normalized video-session preview data.
POST /v2/status_detailedPOST alias for detailed status checks.

Credits and billing routes

RoutePurpose
GET /v2/creditsFetch resolved actor credits.
POST /v2/credits/rechargeCreate an internal recharge flow.
POST /v2/credits/grantGrant credits to an external user.
GET /v2/payment_statusFetch payment status for a resolved actor.
POST /v2/payment_statusCheck payment status with a request body.

User account routes

RoutePurpose
POST /v2/user/recharge_creditsCreate or top up a Samsar user by email.
GET /v2/user/recharge_creditsGET alias for user credit recharge.
POST /v2/user/create_external_userCreate or update an external user mapped to the authenticated internal user.
POST /v2/user/refresh_tokenRotate a user refresh token.
GET /v2/user/refresh_tokenGET alias for user refresh token rotation.
GET /v2/user/creditsFetch authenticated user credits.
GET /v2/user/usage/logsFetch authenticated user usage logs.
GET /v2/user/payment_statusFetch user payment status.
POST /v2/user/payment_statusCheck user payment status with a request body.

App key routes

RoutePurpose
POST /v2/users/app_keyCreate a long-running app key.
GET /v2/users/app_keyFetch active app key metadata.
DELETE /v2/users/app_keyRevoke the active app key.
POST /v2/users/app_key/refreshRotate an app key.
GET /v2/users/app_key/refreshGET alias for app key rotation.

Assistant and utility routes

RoutePurpose
POST /v2/assistant/set_system_promptSet an assistant system prompt.
POST /v2/assistant/completionCreate an assistant completion.
POST /v2/external/chatCreate an OpenAI-compatible external inference completion.
POST /v2/external/chat/completionsAlias for external inference completions.
POST /v2/external/assistantAssistant-named alias for external chat completions.
POST /v2/external/assistant/completionsAssistant-named OpenAI-compatible completion alias.
GET /v2/external/chat/statusPoll an external assistant request by request_id or client_request_id.
GET /v2/external/chat/completions/statusStatus alias for external assistant requests.
GET /v2/external/assistant/statusAssistant-named status alias.
POST /v2/external/moderationCreate a no-charge external moderation check.
POST /v2/external/moderationsAlias for external moderation checks.
GET /v2/external/api_key/validateValidate a Samsar provider API key.
GET /v2/external/providers/capabilitiesRead provider, model, and action capabilities.
POST /v2/external/providers/validateValidate deployment provider credentials.
POST /v2/external/narrative/create_singleCreate a singular structured narrative.
POST /v2/external/narrative/create_branchingCreate a branching structured narrative.
GET /v2/external/narrative/statusPoll a singular or branching narrative request.
POST /v2/external/audio/text_to_speechCreate hosted speech for 1 credit/request.
POST /v2/external/audio/text_to_musicCreate an API-key billed hosted text-to-music request.
POST /v2/external/audio/text_to_sound_effectCreate a hosted sound effect for 1 credit/request.
POST /v2/external/audio/transcript_alignAlign transcript audio with usage-based per-minute billing.
GET /v2/external/audio/statusPoll hosted external audio request status.
POST /v2/external/embeddingsCreate 1536-dimension external embeddings with text-embedding-3-small.
POST /v2/external/image/text_to_imageGenerate hosted images; /generate and /generations are aliases.
POST /v2/external/image/assign_titleGenerate an image title with usage-based billing.
POST /v2/external/image/enhanceEnhance a hosted image.
POST /v2/external/image/remove_brandingRemove branding from a hosted image.
POST /v2/external/image/add_image_setExtend a hosted image set.
GET /v2/external/image/statusPoll a hosted image request.
POST /v2/utils/assistant_sessionCreate or resolve an assistant session.
POST /v2/utils/usage_chargeApply a usage charge.
POST /v2/generate_embeddings_from_plain_textCreate embeddings from cleaned plain text.

Media generation routes

RoutePurpose
POST /v2/upload_image_dataUpload image data for later generation routes.
POST /v2/image/assign_titleAssign a short SEO-friendly image title. Returns { "content": "..." } synchronously and uses usage-based credits.
POST /v2/images/assign_titleAlias for POST /v2/image/assign_title.
POST /v2/image/enhanceEnhance or upscale an image using the same pricing as /v1/image/enhance.
POST /v2/image/remove_brandingRemove watermark, logo, or brand text using the same pricing as /v1/image/remove_branding.
POST /v2/image/add_image_setExtend an image set using the same pricing as /v1/image/add_image_set.
POST /v2/image/text_to_imageGenerate images for 15 credits per output.
POST /v2/text_to_videoCreate a video from text input.
POST /v2/image_list_to_videoCreate a video from image URLs.
POST /v2/video/step/text_to_videoCreate a step-controlled text-to-video request.
POST /v2/video/step/image_to_videoCreate a step-controlled image-to-video request.
POST /v2/video/step/lip_syncCreate a step-controlled lip-sync request.
POST /v2/video/step/sound_effectCreate a step-controlled sound-effect request.
GET /v2/video/step/:request_id/statusPoll step-controlled request status and completed resources.
GET /v2/video/step/:request_id/status_detailedPoll step status plus normalized preview data for completed media.
POST /v2/video/step/:request_id/status_detailedPOST alias for detailed step status checks.
POST /v2/video/step/:request_id/process_nextContinue a completed step-controlled request to the next stage.
POST /v2/external/video/text_to_videoCreate an API-key billed hosted text-to-video request for remote deployments.
POST /v2/external/video/image_to_videoCreate an API-key billed hosted image-to-video request for remote deployments.
POST /v2/external/video/direct_image_to_videoGenerate hosted video directly from a public image URL.
POST /v2/external/video/narrative_to_videoStart hosted media generation from a completed singular or branched NarrativeRequest.
POST /v2/external/video/lip_syncCreate an API-key billed hosted lip-sync request from public media URLs.
POST /v2/external/video/sound_effectCreate an API-key billed hosted sound-effect request from a public video URL.
GET /v2/external/video/statusPoll hosted external video request status.
GET /v2/external/video/status_detailedPoll hosted external video detailed status and preview data.
POST /v2/text_to_interactive_videoGenerate an interactive video workflow.
POST /v2/external/video/text_to_interactive_videoExternal-provider alias for interactive video generation.
POST /v2/text_to_interactive_video/sessionCreate an interactive-video draft session.
POST /v2/translate_videoTranslate an existing video.
POST /v2/retranslate_videoAlias for translating an existing video.
POST /v2/add_outro_imageAdd an outro image to an existing video.
POST /v2/update_outro_imageUpdate an existing outro image.
POST /v2/update_footer_imageUpdate or remove an existing video footer CTA.
POST /v2/add_subtitlesAdd subtitles; /v2/video/add_subtitles is an alias.
POST /v2/remove_subtitlesRemove subtitles; /v2/video/remove_subtitles is an alias.
POST /v2/join_videosJoin videos into one output.
POST /v2/video/cloneDeep-copy a completed video session and render a new final video URL.
POST /v2/regenerate_avatarRegenerate the narrator avatar; /v2/video/regenerate_avatar is an alias.
POST /v2/reroll-layersReroll selected 1-based layers from image generation, then rerender the session.
POST /v2/video/reroll-layersAlias for POST /v2/reroll-layers.
POST /v2/cancel_renderCancel active render work.
POST /v2/pause_renderPause active render work.
POST /v2/resume_renderResume paused render work.

Publishing routes

RoutePurpose
POST /v2/archiveArchive a generated asset.
POST /v2/publishPublish a generated asset.
POST /v2/interactive_publication/generate_metaGenerate interactive publication metadata at 1.5×; requires a user auth token.

Authentication behavior

  • Internal API key or internal auth token with no external_user payload uses the internal account and deducts internal generation credits.
  • APP_KEY authentication uses Authorization: AppKey <APP_KEY> plus x-app-secret: <APP_SECRET>. It is a third internal-account auth method for /v2 routes after the APP_KEY has been created with a normal API key or user auth token.
  • Internal API key/auth token plus an external_user payload uses the external-user path and deducts that external user's credits.
  • External-user auth tokens, internal API keys paired with an external-user API key, and customer sub-account API keys use the external-user path.
  • Repeated video routes and status routes resolve request_id / session_id through external request records and GlobalSession records, so either returned extreq_... ids, normalized external ids, or internal video session ids can be used.
  • POST /v2/interactive_publication/generate_meta is the exception to the general credential rules: it accepts a user auth_token, not an API key or APP_KEY.

External user registration

Use POST /v2/user/create_external_user to create or update an external user record under the authenticated internal Samsar user. Authenticate with an internal API key, internal user auth token, or APP_KEY. External-user auth tokens and customer sub-account auth cannot create new external users.

The route accepts a unique_key for the external user, such as a wallet address, email address, or your platform's user id. If unique_key is omitted, Samsar uses external_user_id as the unique_key. Future V2 calls can reference that external user with unique_key.

Request

curl -X POST "https://api.samsar.one/v2/user/create_external_user" \
-H "Authorization: Bearer $SAMSAR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"unique_key": "wallet:0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
"email": "member@example.com",
"display_name": "Member Name"
}'

You can also send provider, external_user_id, external_app_id, external_company_id, external_account_id, username, avatar_url, user_type, and metadata. If provider is omitted, Samsar stores the record under the default V2 provider.

Success response (201)

{
"unique_key": "wallet:0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
"provider": "samsar_v2",
"external_user_id": "wallet:0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
"external_app_id": null,
"external_user": {
"id": "65f...",
"provider": "samsar_v2",
"external_user_id": "wallet:0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
"unique_key": "wallet:0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
"email": "member@example.com",
"display_name": "Member Name",
"generation_credits": 0
},
"reference": {
"provider": "samsar_v2",
"unique_key": "wallet:0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
"external_user_id": "wallet:0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
"external_app_id": null
}
}

If a matching unique_key or external identity already belongs to another internal user, the route returns 409.

User credits and tokens

Use /v2/user/recharge_credits when a client needs to create or top up a Samsar user account by email without first holding an API key. The route accepts POST or GET; POST is recommended.

Request

curl -X POST "https://api.samsar.one/v2/user/recharge_credits" \
-H "Content-Type: application/json" \
-d '{
"amount": 25,
"email": "customer@example.com",
"redirect_url": "https://example.com/samsar/callback"
}'

Fields:

  • amount is a positive USD amount. Recharge credits use the deployment's configured credits-per-dollar rate, which defaults to 100 credits per USD.
  • email must be a valid email address.
  • redirect_url must be HTTPS. The payment success webhook sends the token callback to this URL.

Success response (200)

{
"url": "https://checkout.stripe.com/c/pay/cs_test_...",
"checkoutSessionId": "cs_test_...",
"paymentStatusEndpoint": "/v2/user/payment_status",
"amount": 25,
"amountCents": 2500,
"credits": 2500,
"currency": "USD",
"redirectUrl": "https://example.com/samsar/callback"
}

On Stripe payment success, Samsar:

  • creates a user for email if one does not already exist,
  • sends the new user a Samsar Studio email to confirm email and set a password,
  • applies the purchased credits idempotently,
  • mints a 10-day authToken,
  • mints a rotating refreshToken,
  • calls redirect_url with authToken, refreshToken, and expiryDate query parameters.

The webhook first attempts GET <redirect_url>?authToken=...&refreshToken=...&expiryDate=.... If that returns 404, it retries POST to the same URL with the same query parameters and a JSON body containing the token and payment metadata.

Clients should store authToken, refreshToken, and expiryDate. Poll for a replacement token when the app opens within 3 days of expiryDate.

Refresh token rotation

curl -X POST "https://api.samsar.one/v2/user/refresh_token" \
-H "Content-Type: application/json" \
-d '{"refreshToken": "srf_..."}'

Success response (200)

{
"tokenType": "Bearer",
"authToken": "eyJ...",
"refreshToken": "srf_new...",
"expiryDate": "2026-05-08T12:00:00.000Z",
"expiresInSeconds": 864000,
"refreshTokenExpiresAt": "2026-07-27T12:00:00.000Z"
}

/v2/user/refresh_token consumes the old refresh token and returns both a new 10-day auth token and a new refresh token. Reusing the previous refresh token returns 401.

Use the returned authToken as Authorization: Bearer <authToken> for /v2/user/credits, /v2/user/usage/logs, /v2/user/payment_status, and the rest of the internal /v2 routes.

App key credentials

Use /v2/users/app_key to mint one long-running APP_KEY for a user after the user is already authenticated with a Samsar API key or user auth token. /v2/user/app_key is accepted as an alias.

The client supplies a custom secret. Samsar returns the APP_KEY once, stores only an HMAC hash of the APP_KEY, and stores only a bcrypt hash of the secret. If an active APP_KEY already exists for the user, creation returns 409.

Create APP_KEY

curl -X POST "https://api.samsar.one/v2/users/app_key" \
-H "Authorization: Bearer $SAMSAR_AUTH_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"secret": "a-client-generated-secret-at-least-32-chars"
}'

Success response (201)

{
"app_key": "sapp_...",
"appKey": "sapp_...",
"token_type": "AppKey",
"expires_at": "2027-04-28T12:00:00.000Z",
"app_key_record": {
"id": "appkey_...",
"appKeyPrefix": "sapp_abc12",
"appKeyLast4": "9xyz",
"status": "active",
"expiresAt": "2027-04-28T12:00:00.000Z",
"authScheme": "AppKey",
"authHeader": "Authorization: AppKey <APP_KEY>",
"secretHeader": "x-app-secret"
}
}

Use the APP_KEY on authenticated /v2 routes:

curl "https://api.samsar.one/v2/user/credits" \
-H "Authorization: AppKey $SAMSAR_APP_KEY" \
-H "x-app-secret: $SAMSAR_APP_SECRET"

If the APP_KEY expires, rotate it with the APP_KEY and APP_SECRET. The old APP_KEY is consumed and replaced; the APP_SECRET stays the same.

curl -X POST "https://api.samsar.one/v2/users/app_key/refresh" \
-H "Content-Type: application/json" \
-d '{
"app_key": "sapp_...",
"secret": "a-client-generated-secret-at-least-32-chars"
}'

GET /v2/users/app_key returns APP_KEY metadata for an authenticated user without returning the secret or full key. DELETE /v2/users/app_key revokes the active APP_KEY so the user can create a replacement.

Media generation

POST /v2/text_to_video and POST /v2/image_list_to_video accept the corresponding /v1/video/* request shapes, either nested under input or sent as a flat JSON payload.

SettingAccepted values
inference_model / inferenceModelgpt-5.6-sol (default), gemini-3.1-pro, QWEN3.8 (Qwen 3.8 Max for text and vision), kimi-k3
backingtrack_model / music_providerLYRIA3, ELEVENLABS_MUSIC
tts_model / tts_providerELEVENLABS, OPENAI, GOOGLE
speakerOptions / speaker_optionsProvider-specific speaker lists and Google speaker details

video_model_sub_type is not part of the V2 request shape; put style direction in prompt. See Models & pricing for current model keys, per-second rates, and runtime-availability guidance.

Internal billing example

curl -X POST "https://api.samsar.one/v2/image_list_to_video" \
-H "Authorization: Bearer $SAMSAR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"input": {
"image_urls": ["https://cdn.example.com/a.png", "https://cdn.example.com/b.png"],
"video_model": "RUNWAYML",
"express_cta_generation": true,
"cta_url": "https://example.com/book",
"limit_single_narrator": true
}
}'

External-user billing example

curl -X POST "https://api.samsar.one/v2/image_list_to_video" \
-H "Authorization: Bearer $SAMSAR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"external_user": {
"provider": "guidestination",
"unique_key": "traveler_123",
"external_user_id": "traveler_123"
},
"input": {
"image_urls": ["https://cdn.example.com/a.png", "https://cdn.example.com/b.png"],
"video_model": "KLINGIMGTOVID3PRO",
"add_narrator_avatar": true,
"add_footer_animation": true,
"footer_metadata": [
{ "url": "https://example.com/stop/1", "title": "Stop 1" },
{ "url": "https://example.com/stop/2", "title": "Stop 2" }
]
}
}'

For /v2/image_list_to_video, choose one outro mode and keep its fields together:

ModeFieldsNotes
QR CTA outrocta_urlSamsar generates the centered QR outro.
Center-image CTAoutro_cta_imageUse { "top_text", "middle_image", "bottom_text" }.
Express CTAexpress_cta_generation: true, one cta_urlGenerates per-scene footer titles and outro text; adds 1 credit/sec.

add_outro_animation defaults to true. limit_single_narrator keeps one narrator identity; add_narrator_avatar enables it automatically and adds 4 credits/sec. The V2 route uses the same model defaults and rates as the V1 image-list route, summarized in the video model rate table.

V2 image edit routes

The /v2/image/enhance, /v2/image/remove_branding, and /v2/image/add_image_set routes are thin aliases over the existing image API handlers and use the same image edit queue, validation, credit headers, and status polling behavior as /v1/image/*. Request bodies may be sent either directly or inside the standard V2 { "input": { ... } } wrapper.

Pricing is unchanged from the Image API: POST /v2/image/enhance charges 11 credits at 0.5k, 15 credits at 1k, 22 credits at 2k, and 29 credits at 4k; POST /v2/image/remove_branding charges 15 credits per request; POST /v2/image/add_image_set charges 15 × requested_images.

Step-controlled video generation

Use the /v2/video/step/* routes when a client needs step-aware generation and detailed timeline preview data. Step requests use the same express video models and stage billing rules as /v2/text_to_video and /v2/image_list_to_video.

Step routes support two render modes:

  • 1-step express render: set auto_render_full_video: true and manual_step_stages: []. The request generates the full video without waiting for user approval before ai_video_generation.
  • 2-step render: set auto_render_full_video: false and manual_step_stages: ["ai_video_generation"]. The request pauses after image/audio assets are ready, then waits for process_next before the image-to-video stage.

When your request body uses the standard { "input": { ... } } wrapper, include these fields inside input. Clients may also send the same fields at the top level for compatibility. Only call process_next when the status response says waiting_for_process_next, requires_user_action, or can_process_next is true.

Step-controlled routes are internal-account routes. Authenticate with a Samsar API key, user auth token, or APP_KEY.

Create from text

curl -X POST "https://api.samsar.one/v2/video/step/text_to_video" \
-H "Authorization: Bearer $SAMSAR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"auto_render_full_video": true,
"manual_step_stages": [],
"input": {
"prompt": "A 20 second launch teaser for a new travel app",
"image_model": "GPTIMAGE2",
"video_model": "RUNWAYML",
"duration": 20,
"aspect_ratio": "16:9",
"enable_subtitles": true,
"auto_render_full_video": true,
"manual_step_stages": []
},
"webhookUrl": "https://example.com/video-webhook"
}'

Create from an image

curl -X POST "https://api.samsar.one/v2/video/step/image_to_video" \
-H "Authorization: Bearer $SAMSAR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"auto_render_full_video": false,
"manual_step_stages": ["ai_video_generation"],
"input": {
"image_url": "https://cdn.example.com/product-frame.png",
"prompt": "Turn this product frame into a cinematic ad",
"video_model": "KLINGIMGTOVID3PRO",
"aspect_ratio": "16:9",
"enable_subtitles": true,
"auto_render_full_video": false,
"manual_step_stages": ["ai_video_generation"]
}
}'

The response includes the normal request_id / session_id plus a step object. For 1-step requests, poll the detailed step status route until the final video is complete. For 2-step requests, poll until the response asks for user action, inspect current_step_resources, optionally edit resources through the relevant session/resource APIs, then call process_next.

curl "https://api.samsar.one/v2/video/step/65f1234567890abcdef12345/status" \
-H "Authorization: Bearer $SAMSAR_API_KEY"
{
"request_id": "65f1234567890abcdef12345",
"session_id": "65f1234567890abcdef12345",
"status": "COMPLETED",
"step_status": "COMPLETED",
"current_step": "image_generation",
"current_step_label": "Images",
"next_step": "ai_video_generation",
"waiting_for_process_next": true,
"requires_user_action": true,
"can_process_next": true,
"manual_step_stages": ["ai_video_generation"],
"process_next_url": "/v2/video/step/process_next",
"current_step_resources": {
"step": "image_generation",
"label": "Images",
"status": "COMPLETED",
"completed_at": "2026-05-07T10:30:00.000Z",
"resources": {
"layers": [
{
"index": 0,
"prompt": "Wide product shot with cinematic lighting",
"selected_image_url": "https://cdn.samsar.one/generated/layer-0.png"
}
]
}
},
"completed_step_resources": {
"prompt_generation": {
"completed_at": "2026-05-07T10:27:00.000Z",
"resources": {
"input_prompt": "A 20 second launch teaser for a new travel app",
"scenes": []
}
},
"image_generation": {
"completed_at": "2026-05-07T10:30:00.000Z",
"resources": {
"layers": []
}
}
}
}

For preview playback before the final render, use status_detailed. It returns the same top-level status fields plus status_detail_schema and a normalized session object. The session payload includes only the data needed to reconstruct the current playable stage on the client: scene layers, audioLayers, globalAudioLayers, globalVideos, and final result metadata when available. Layer timing is normalized to startTime and endTime; the response does not expose internal fields such as durationOffset.

curl "https://api.samsar.one/v2/video/step/65f1234567890abcdef12345/status_detailed" \
-H "Authorization: Bearer $SAMSAR_API_KEY"

Example response after ai_video_generation has completed, before lip sync, effects, or the final render:

Full detailed-status payloadLayers, audio, stages, and preview metadata
{
"request_id": "65f1234567890abcdef12345",
"session_id": "65f1234567890abcdef12345",
"status": "COMPLETED",
"type": "video",
"provider": "RUNWAYML",
"step_status": "COMPLETED",
"current_step": "ai_video_generation",
"current_step_label": "AI video",
"next_step": "lip_sync_generation",
"waiting_for_process_next": true,
"process_next_url": "/v2/video/step/process_next",
"status_detail_schema": "video_session_preview.v1",
"session": {
"id": "65f1234567890abcdef12345",
"requestId": "65f1234567890abcdef12345",
"type": "video",
"routeType": "step",
"aspectRatio": "16:9",
"framesPerSecond": 30,
"duration": 12,
"language": "en",
"hasSubtitles": true,
"hasFooter": false,
"inputPrompt": "A 12 second launch teaser for a new travel app",
"generationType": "text_to_video",
"provider": "RUNWAYML",
"currentStage": "lip_sync_generation",
"previewStage": "ai_video_generation",
"completedStages": [
"prompt_generation",
"image_generation",
"speech_generation",
"music_generation",
"audio_generation",
"ai_video_generation"
],
"stages": {
"prompt_generation": "COMPLETED",
"image_generation": "COMPLETED",
"speech_generation": "COMPLETED",
"music_generation": "COMPLETED",
"audio_generation": "COMPLETED",
"ai_video_generation": "COMPLETED",
"lip_sync_generation": "INIT",
"sound_effect_generation": "INIT",
"video_generation": "INIT"
},
"layers": [
{
"index": 0,
"id": "65f1234567890abcdef0001",
"startTime": 0,
"endTime": 6,
"duration": 6,
"prompt": "Wide product shot with cinematic lighting",
"videoPrompt": "Slow push-in over the mobile booking screen",
"image": {
"status": "COMPLETED",
"url": "https://cdn.samsar.one/generated/scene-0.png"
},
"aiVideo": {
"status": "COMPLETED",
"url": "https://cdn.samsar.one/generated/scene-0-ai.mp4"
},
"preview": {
"stage": "ai_video_generation",
"type": "video",
"url": "https://cdn.samsar.one/generated/scene-0-ai.mp4"
}
},
{
"index": 1,
"id": "65f1234567890abcdef0002",
"startTime": 6,
"endTime": 12,
"duration": 6,
"prompt": "Traveler checking into a hotel from the app",
"videoPrompt": "Handheld travel lifestyle shot with warm daylight",
"image": {
"status": "COMPLETED",
"url": "https://cdn.samsar.one/generated/scene-1.png"
},
"aiVideo": {
"status": "COMPLETED",
"url": "https://cdn.samsar.one/generated/scene-1-ai.mp4"
},
"preview": {
"stage": "ai_video_generation",
"type": "video",
"url": "https://cdn.samsar.one/generated/scene-1-ai.mp4"
}
}
],
"audioLayers": [
{
"index": 0,
"type": "speech",
"status": "COMPLETED",
"startTime": 0,
"endTime": 6,
"duration": 6,
"url": "https://cdn.samsar.one/generated/scene-0-speech.mp3",
"speaker": "alloy",
"connectedLayerIndex": 0
},
{
"index": 1,
"type": "speech",
"status": "COMPLETED",
"startTime": 6,
"endTime": 12,
"duration": 6,
"url": "https://cdn.samsar.one/generated/scene-1-speech.mp3",
"speaker": "alloy",
"connectedLayerIndex": 1
}
],
"globalAudioLayers": [
{
"index": 0,
"type": "music",
"status": "COMPLETED",
"startTime": 0,
"endTime": 12,
"duration": 12,
"url": "https://cdn.samsar.one/generated/music-bed.mp3",
"volume": 0.25
}
],
"result": {
"hasSubtitles": true,
"hasFooter": false,
"language": "en"
}
}
}

Continue to the next stage:

curl -X POST "https://api.samsar.one/v2/video/step/65f1234567890abcdef12345/process_next" \
-H "Authorization: Bearer $SAMSAR_API_KEY"

Step status values:

  • INIT: the step request exists but has not started its first tracked stage.
  • PENDING: the current stage is running.
  • COMPLETED: the final video stage is complete, or a 2-step request is paused at a manual checkpoint and waiting for process_next.
  • FAILED: the request failed.

The stage sequence is prompt_generation, image_generation, speech_generation, music_generation, ai_video_generation, lip_sync_generation, sound_effect_generation, narrator_avatar_generation, and video_generation.

Translate example

curl -X POST "https://api.samsar.one/v2/translate_video" \
-H "Authorization: Bearer $SAMSAR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"input": {
"videoSessionId": "vid_a1b2c3d4",
"language": "es",
"enable_subtitles": false,
"translate_outro": true,
"translate_footer": true
},
"webhookUrl": "https://example.com/video-webhook"
}'

/v2/translate_video and /v2/retranslate_video accept the same payload as /v1/video/translate_video. enable_subtitles defaults to false; when true, Samsar regenerates translated transcript/subtitle text. translate_outro and translate_footer default to true and localize stored generated-outro CTA text and footer CTA text when those metadata fields exist. The translate route no longer accepts outro_image_url; use /v2/update_outro_image for outro replacement.

Footer update example

curl -X POST "https://api.samsar.one/v2/update_footer_image" \
-H "Authorization: Bearer $SAMSAR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"input": {
"videoSessionId": "vid_a1b2c3d4",
"cta_text": "Scan to book",
"cta_logo": "https://cdn.example.com/logo-white.png",
"cta_url": "https://example.com/book"
}
}'

Set remove_footer: true in the input object to clone the session and remove all scene footers instead. Like /v1/video/update_footer_image, the V2 route queues only footer/frame/video work and charges 75 credits/request.

Deep clone example

curl -X POST "https://api.samsar.one/v2/video/clone" \
-H "Authorization: Bearer $SAMSAR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"input": {
"videoSessionId": "vid_a1b2c3d4"
},
"webhookUrl": "https://example.com/video-webhook"
}'

/v2/video/clone is free for an authenticated user who owns the source session. It copies the session data and local generated assets into a new session, marks all upstream generation stages complete, and queues only the final video_generation stage so the clone receives its own rendered video path and URL. Poll /v2/status?request_id=<new_session_id> until it returns the standard completed video payload with result_url, has_subtitles, and result_language.

Reroll layers example

curl -X POST "https://api.samsar.one/v2/reroll-layers" \
-H "Authorization: Bearer $SAMSAR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"input": {
"videoSessionId": "vid_a1b2c3d4",
"layer_indexes": [3, 6, 11]
},
"webhookUrl": "https://example.com/video-webhook"
}'

/v2/reroll-layers and /v2/video/reroll-layers update the same owned session in place. The selected 1-based layers restart from image generation, then required AI-video and lip-sync/sound-effect work runs for those layers before frame/outro/final video generation reruns for the whole session. Credits are the selected image-generation costs plus the selected layers' AI-video stage credits; send quote_only: true in input to estimate without charging.

External video provider routes

Use /v2/external/video/* when a remote deployment needs hosted Samsar generation through a Samsar API key. These are standalone provider-style endpoints, separate from /v2/video/step/*.

Supported routes:

  • POST /v2/external/video/text_to_video
  • POST /v2/external/video/image_to_video
  • POST /v2/external/video/direct_image_to_video
  • POST /v2/external/video/narrative_to_video
  • POST /v2/external/video/text_to_interactive_video
  • POST /v2/external/video/lip_sync
  • POST /v2/external/video/sound_effect
  • GET or POST /v2/external/video/status
  • GET or POST /v2/external/video/{request_id}/status
  • GET or POST /v2/external/video/status_detailed
  • GET or POST /v2/external/video/{request_id}/status_detailed

text_to_video accepts the same express text input shape as /v2/text_to_video. image_to_video requires exactly one public image_url (or a one-item image_urls array) plus video_model. narrative_to_video accepts a completed singular or branched narrative_request_id, inherits its prompt and duration, and skips prompt generation; see Render a narrative as video. lip_sync requires public video_url and audio_url values. sound_effect requires a public video_url and prompt. Raw media bytes, data URLs, local filesystem paths, localhost URLs, and private network URLs are not accepted for hosted external video-to-video routes.

For a branched narrative-to-video request, both status routes return a normalized branching manifest. The normal status response is compact and contains tree choices, aggregate path progress, per-path frame/video status, and any completed path result. Detailed status adds path timelines that reference the shared session.layers and session.audioLayers catalogs by ID; it does not return internal frame lists. A top-level COMPLETED result is published only after every required leaf video is ready.

Assistant and utilities

Assistant and utility routes use the same actor resolution behavior as the rest of /v2. Use them when a mixed internal/external-user client needs assistant completions, assistant sessions, usage charges, or cleaned-text embeddings through one API prefix.

Supported assistant and utility routes:

  • POST /v2/assistant/set_system_prompt
  • POST /v2/assistant/completion
  • POST /v2/external/chat
  • POST /v2/external/chat/completions
  • POST /v2/external/assistant
  • POST /v2/external/assistant/completions
  • GET /v2/external/chat/status
  • GET /v2/external/chat/completions/status
  • GET /v2/external/assistant/status
  • POST /v2/external/moderation
  • POST /v2/external/moderations
  • POST /v2/external/audio/text_to_speech
  • POST /v2/external/audio/text_to_music
  • POST /v2/external/audio/text_to_sound_effect
  • POST /v2/external/audio/transcript_align
  • GET or POST /v2/external/audio/status
  • POST /v2/external/embeddings
  • POST /v2/utils/assistant_session
  • POST /v2/utils/usage_charge
  • POST /v2/generate_embeddings_from_plain_text

External chat and assistant aliases accept OpenAI-compatible text and vision messages and use the Chat API external inference pricing table. They execute synchronously by default. Set response_mode: "polling" for an HTTP 202 queued response, persist request_id, and poll one of the status routes until COMPLETED or FAILED. A stable client_request_id makes submission retry-safe after a network reset and can also be used for status lookup. The default execution timeout is 10 minutes and request records are retained for 24 hours. See External assistant and chat completions for the complete request and response contract.

External moderation routes accept OpenAI-compatible moderation input and do not charge credits. Hosted audio charges 1 credit/request for text to speech or sound effects and 2 credits/request for text to music; music accepts ELEVENLABS_MUSIC and LYRIA3. Transcript alignment is usage based, and external embeddings cost 100 credits per 1M tokens.

Request status and publishing

Use GET /v2/status with any request_id returned by a V2 generation route. Status resolution accepts external request ids, normalized external ids, and internal video session ids where available.

Use GET /v2/status_detailed or POST /v2/status_detailed when a video client needs preview assets before the final render finishes. Detailed status is additive: every existing /v2/status field remains unchanged, and video requests also include status_detail_schema: "video_session_preview.v1" with a normalized session preview payload. Use session.previewStage to choose the furthest playable stage, then render scene clips from session.layers[].preview, speech from session.audioLayers, background audio from session.globalAudioLayers, and final output metadata from session.result once available.

When image, AI-video, lip-sync, sound-effect, or final video generation reaches a terminal failure, /v2/status and /v2/status_detailed promote the exact stored provider/model message to generationError, expressGenerationError, error, and message. Detailed status also keeps the error on the failed layer asset (session.layers[].imageSession.generationError, aiVideoGenerationError, lipSyncVideoGenerationError, or soundEffectVideoGenerationError). Clients should display this message as-is for the terminal failure. Stale errors from a layer that is actively retrying or has since completed are not treated as terminal.

Branched video sessions additionally include branching.schema: "branched_video_status.v1" on both status responses. Use branching.summary for aggregate leaf-render progress, branching.tree.choice_points for interactive choices, and branching.paths for path-specific frame/video state. On detailed status, each path also includes a normalized timeline and audio_timeline; resolve their layer_id and audio_layer_id references against the shared assets in session.layers and session.audioLayers. This keeps preview responses normalized even when several paths share the same parent scenes.

When all leaf renders complete, branching.outputs.ready becomes true, branching.outputs.paths maps each leaf path_id to its final URL, top-level result_url identifies the default path, and ordered result_urls contains all leaf videos. The older branch_results mapping remains available for compatibility. See Render a narrative as video for the complete response and client-switching flow.

Publishing and archive routes operate on the resolved actor's accessible assets:

  • POST /v2/archive
  • POST /v2/publish