Skip to main content

External Requests API

Base URL
https://api.samsar.one
Route prefix
/v2/external
Authentication
Bearer Samsar API key
Execution
Provider-style calls; sync or async by route
Billing
Endpoint-specific; credit headers report usage
Content type
application/json

Legacy /external/* aliases may exist on some deployments, but new integrations should use /v2/external/*.

Use this surface when a deployed SamsarOne environment wants to call the central Samsar service as a fallback provider. Native provider credentials can still be used directly by a deployment; when they are present, they override the corresponding model settings for that deployment.

This is different from /external_users/*. External users track per-customer credits, history, and login state. External requests are one-off provider-style calls authenticated by a Samsar API key.

Validate a Samsar API key

GET /v2/external/api_key/validate

curl "https://api.samsar.one/v2/external/api_key/validate" \
-H "Authorization: Bearer $SAMSAR_API_KEY"

Success response:

{
"valid": true,
"authType": "api_key",
"email": "admin@example.com",
"remainingCredits": 12000
}

Provider capabilities

GET /v2/external/providers/capabilities

Returns the provider, model, and action capability map used by deployment onboarding.

curl "https://api.samsar.one/v2/external/providers/capabilities"

Validate deployment providers

POST /v2/external/providers/validate

Use this from the local deployment wizard to validate optional provider credentials before enabling model settings. The SDK sends credentials only to the local processor or configured Samsar API host; do not persist provider secrets in client code.

curl -X POST "https://api.samsar.one/v2/external/providers/validate" \
-H "Content-Type: application/json" \
-d '{
"samsarApiKey": "sk_live_...",
"openaiApiKey": "sk-...",
"falApiKey": "fal_...",
"runwayApiKey": "rw_..."
}'

Success response:

{
"providers": {
"samsar": {
"ok": true,
"status": "valid",
"remainingCredits": 12000
}
},
"available": {
"providers": ["samsar"],
"models": ["GOOGLE_TTS", "GPTIMAGE2", "HAPPYHORSEI2V", "KIMIK3", "LATENT_SYNC", "LYRIA3", "MMAUDIO", "OPENAI_TTS", "QWEN3.8", "RUNWAYML", "VEO3.1I2V", "WAN2.7PRO", "gemini-3.1-pro", "gpt-5.6-sol"],
"actions": ["assistant", "audio", "chat", "image", "lip_sync", "moderation", "sound_effect", "video"]
}
}

Chat

External assistant and chat completions

The external assistant endpoints accept OpenAI-compatible chat completion payloads. They are intended for deployed Samsar environments and other integrations that use Samsar as a managed inference provider.

The /assistant/* paths below are naming aliases for the same provider-style chat handler. They are separate from the session-bound POST /v1/assistant/completion API.

Routes

Create a completion with any of these POST routes:

  • /v2/external/chat
  • /v2/external/chat/completions — preferred for OpenAI-compatible integrations
  • /v2/external/assistant
  • /v2/external/assistant/completions

Read queued request status with any of these GET routes:

  • /v2/external/chat/status
  • /v2/external/chat/completions/status
  • /v2/external/assistant/status

The same routes are available under /api/v2/external. Legacy deployments may also expose the unversioned /external prefix. There is no /v2/external/assistant/completions/status route; use /v2/external/assistant/status or the canonical /v2/external/chat/status path.

Synchronous completion

Polling is opt-in. Without a polling control, the endpoint waits for inference and returns the raw OpenAI-compatible completion with HTTP 200.

curl -X POST "https://api.samsar.one/v2/external/chat/completions" \
-H "Authorization: Bearer $SAMSAR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-5.6-sol",
"messages": [
{ "role": "user", "content": "Write a launch caption for a travel reel." }
],
"max_tokens": 300
}'

The default server execution timeout is 10 minutes. stream: true is not supported. When available, billing is returned through these headers:

  • x-credits-charged
  • x-credits-remaining

Queued completion with polling

Use polling for long-running assistant work such as narrative or theme generation. It avoids holding one HTTP connection open for the entire model call and allows the request to recover after a client disconnect, network reset, or processor restart.

Generate and persist a stable client_request_id before submitting. Retry the same logical submission with the same ID if the initial response is lost.

curl -X POST "https://api.samsar.one/v2/external/assistant/completions" \
-H "Authorization: Bearer $SAMSAR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-5.6-sol",
"messages": [
{ "role": "user", "content": "Create a cinematic theme for this video." }
],
"response_mode": "polling",
"client_request_id": "video-67df0d8e:theme:v1",
"client_session_id": "video-67df0d8e",
"client_request_key": "theme"
}'

async: true, poll: true, or response_mode: "async" | "poll" | "polling" all enable queued mode. Prefer response_mode: "polling" for new integrations.

The canonical fields are:

FieldPurpose
client_request_idOptional idempotency key. Make it unique for one logical request and reuse it only when retrying that request.
client_session_idOptional local session correlation value. It is persisted and echoed only when client_request_id is present.
client_request_keyOptional local stage or operation name, such as theme or narrative. It is persisted and echoed only when client_request_id is present.
timeout / timeoutMsOptional server execution timeout in milliseconds. The default is 600000 (10 minutes).

A queued request returns HTTP 202:

{
"request_id": "67df0d8ebc4f9d0b7f4fd123",
"requestId": "67df0d8ebc4f9d0b7f4fd123",
"status": "PENDING",
"poll_url": "/v2/external/chat/status?request_id=67df0d8ebc4f9d0b7f4fd123",
"client_request_id": "video-67df0d8e:theme:v1",
"client_session_id": "video-67df0d8e",
"client_request_key": "theme",
"created_at": "2026-07-16T13:00:00.000Z",
"updated_at": "2026-07-16T13:00:00.000Z"
}

poll_url is a relative canonical path. Store request_id as soon as it is returned. If the submit response is lost, you can still look up the request by the persisted client_request_id.

Poll by provider request ID:

curl "https://api.samsar.one/v2/external/chat/status?request_id=67df0d8ebc4f9d0b7f4fd123" \
-H "Authorization: Bearer $SAMSAR_API_KEY"

Or recover by client request ID:

curl "https://api.samsar.one/v2/external/chat/status?client_request_id=video-67df0d8e%3Atheme%3Av1" \
-H "Authorization: Bearer $SAMSAR_API_KEY"

Status reads are immediate rather than long-polling. Poll every 1–2 seconds until the request reaches a terminal state:

StatusMeaning
PENDINGPersisted and waiting to be claimed. Polling also repairs a request persisted immediately before a processor restart.
PROCESSINGClaimed by the hosted processor. An expired worker lease can be reclaimed safely.
COMPLETEDTerminal success. Read the OpenAI-compatible completion from response.
FAILEDTerminal failure. Read the provider-safe details from error.
Terminal status payload examplesCompleted and failed queued inference responses

Completed status response:

{
"request_id": "67df0d8ebc4f9d0b7f4fd123",
"status": "COMPLETED",
"response": {
"id": "chatcmpl_123",
"object": "chat.completion",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "A precise cinematic theme..."
},
"finish_reason": "stop"
}
]
},
"creditsCharged": 12,
"remainingCredits": 9988
}

Failed status response (HTTP 200):

{
"request_id": "67df0d8ebc4f9d0b7f4fd123",
"status": "FAILED",
"error": {
"message": "External assistant request failed.",
"code": null,
"status": 500
}
}

Request status is retained for 24 hours from creation. Idempotent submission replays return the original request and do not replace its payload; use a new client_request_id for an intentional retry after FAILED or COMPLETED. Fetch status to obtain completion credit headers and body fields, including after an idempotent replay.

Common errors:

  • 400 missing authentication headers, missing or invalid messages, unsupported stream: true, or an invalid status lookup ID.
  • 401 invalid or expired credentials.
  • 402 insufficient credits for a synchronous request.
  • 403 the supplied credential type is not supported by this provider route.
  • 404 request not found for the authenticated account.
  • Async provider failures are represented by HTTP 200 with status: "FAILED" and the nested error object.

Embeddings

POST /v2/external/embeddings

Create OpenAI-compatible embedding vectors with text-embedding-3-small at 1536 dimensions. Send one string or up to 100 strings; each input may contain up to 12,000 characters. Billing is 100 credits per 1M tokens.

curl -X POST "https://api.samsar.one/v2/external/embeddings" \
-H "Authorization: Bearer $SAMSAR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"input": ["A launch-ready product description", "A concise campaign tagline"],
"model": "text-embedding-3-small",
"dimensions": 1536
}'

Image

/v2/external/image mounts the canonical Image API behind external-provider authentication. The request bodies, status behavior, and pricing are unchanged; add /v2/external before the documented /image/... path.

RoutePurpose and billing
POST /v2/external/image/text_to_imageGenerate images for 15 credits/output. /generate and /generations are compatibility aliases.
POST /v2/external/image/assign_titleGenerate an image title with usage-based inference billing at 1.5×.
POST /v2/external/image/enhanceEnhance to 0.5k, 1k, 2k, or 4k for 11, 15, 22, or 29 credits.
POST /v2/external/image/remove_brandingRemove a logo, watermark, or brand text for 15 credits/request.
POST /v2/external/image/add_image_setExtend an image set for 15 credits/generated image.
GET /v2/external/image/statusPoll an asynchronous hosted image request.

The mounted surface also includes image history, receipt-template, receipt-query, and rollup-banner routes. Use the Image API as the canonical contract and rate reference for those paths.

Example:

curl -X POST "https://api.samsar.one/v2/external/image/enhance" \
-H "Authorization: Bearer $SAMSAR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"image_url": "https://cdn.example.com/photo.png",
"resolution": "1k"
}'

Async image routes return a request_id. Poll:

curl "https://api.samsar.one/v2/external/image/status?request_id=img_enh_123" \
-H "Authorization: Bearer $SAMSAR_API_KEY"

Video

POST /v2/external/video/{video_route}

The external video surface combines the canonical Video API with standalone provider-first routes for remote deployments that bill through a Samsar API key. Add /v2/external before a documented /video/... path to use the mounted canonical surface; the table below highlights the provider-first additions.

RoutePurpose
POST /v2/external/video/text_to_videoCreate an express text-to-video request.
POST /v2/external/video/image_to_videoCreate an express image-to-video request from exactly one public image URL.
POST /v2/external/video/direct_image_to_videoAnimate one public image directly, without image generation or the full express narrative pipeline.
POST /v2/external/video/narrative_to_videoRender a completed singular or branched NarrativeRequest without rerunning prompt generation.
POST /v2/external/video/text_to_interactive_videoBuild and render a branching interactive-video workflow from text.
POST /v2/external/video/lip_syncCreate a lip-sync video-to-video request from public video_url and audio_url inputs.
POST /v2/external/video/sound_effectCreate a sound-effect video-to-video request from a public video_url input and prompt.
GET /v2/external/video/statusPoll by request_id or session_id.
GET /v2/external/video/{request_id}/statusPath-param status polling alias.
GET /v2/external/video/status_detailedPoll detailed status plus normalized video preview data.
GET /v2/external/video/{request_id}/status_detailedPath-param detailed status polling alias.

status and status_detailed also accept POST with request_id or session_id in the JSON body.

Hosted SEEDANCE2.5I2V requests use the validated GMICloud model seedance-2-5-260628 for both the text-to-video agent's scene animation and direct external image-to-video handling. Hosted routing does not fall back to Fal, and one logical layer request is dispatched to one adapter only.

On terminal video failure, both status routes return the exact stored provider or model message instead of replacing it with a generic pipeline error. Compact status exposes it through generationError, expressGenerationError, error, and message. Detailed status also retains the failed asset's error under session.layers, such as aiVideoGenerationError, imageSession.generationError, lipSyncVideoGenerationError, or soundEffectVideoGenerationError.

Session listing, translation, joining, subtitle, reroll, clone, outro/footer, and render-control paths from the Video API are also available through this mounted prefix.

For lip_sync and sound_effect, media inputs must be publicly reachable HTTP(S) URLs. Raw bytes, base64/data URLs, local filesystem paths, localhost URLs, and private network URLs are rejected. Docker deployments should publish local media through configured S3-compatible storage, CloudFront, or another signed/public URL strategy before calling these hosted external routes.

Example:

curl -X POST "https://api.samsar.one/v2/external/video/text_to_video" \
-H "Authorization: Bearer $SAMSAR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"input": {
"prompt": "A cinematic product launch reel",
"image_model": "GPTIMAGE2",
"video_model": "RUNWAYML",
"duration": 10,
"aspect_ratio": "9:16",
"inference_model": "gpt-5.6-sol"
},
"webhookUrl": "https://example.com/webhook"
}'

Image-to-video example:

curl -X POST "https://api.samsar.one/v2/external/video/image_to_video" \
-H "Authorization: Bearer $SAMSAR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"input": {
"image_url": "https://cdn.example.com/scene-1.png",
"prompt": "A polished destination reel",
"video_model": "RUNWAYML",
"aspect_ratio": "16:9"
}
}'

Narrative-to-video example:

curl -X POST "https://api.samsar.one/v2/external/video/narrative_to_video" \
-H "Authorization: Bearer $SAMSAR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"input": {
"narrative_request_id": "687b4127b503e2b4acdf9876"
}
}'

The source can be singular or branched. For a branched source, polling returns a normalized branching manifest with one path per leaf, choice-point metadata, path-specific frame/video state, and aggregate progress. The compact status response avoids raw frame data; status_detailed adds path timelines that reference each shared layer and audio asset by ID for client-side preview.

The request reaches top-level COMPLETED only after every leaf video has rendered. The terminal manifest exposes the complete branching.outputs.paths URL mapping, while compatibility fields keep result_url as the default path, return every leaf in ordered result_urls, and retain branch_results. See Render a narrative as video for the full lifecycle, normalized response, and interactive switching flow.

Lip-sync example:

curl -X POST "https://api.samsar.one/v2/external/video/lip_sync" \
-H "Authorization: Bearer $SAMSAR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"input": {
"video_url": "https://cdn.example.com/clip.mp4",
"audio_url": "https://cdn.example.com/dialogue.wav",
"lip_sync_model": "SYNCLIPSYNC",
"duration": 8,
"prompt": "Match the speaker performance to the supplied audio."
}
}'

Sound-effect example:

curl -X POST "https://api.samsar.one/v2/external/video/sound_effect" \
-H "Authorization: Bearer $SAMSAR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"input": {
"video_url": "https://cdn.example.com/clip.mp4",
"prompt": "Soft ocean waves and distant city ambience",
"sound_effect_model": "MIRELOAI",
"duration": 8
}
}'

Poll:

curl "https://api.samsar.one/v2/external/video/status?request_id=66ff..." \
-H "Authorization: Bearer $SAMSAR_API_KEY"

Detailed status:

curl "https://api.samsar.one/v2/external/video/status_detailed?request_id=66ff..." \
-H "Authorization: Bearer $SAMSAR_API_KEY"

For branched video sessions, read branching.summary to display progress and branching.paths to display each leaf render. In detailed status, build maps of session.layers and session.audioLayers by id, then resolve each selected path's timeline[].layer_id and audio_timeline[].audio_layer_id references to preview its current assets. At a branching.tree.choice_points[].switch_at_seconds boundary, the selected option's leaf_path_ids narrows the candidate final videos; selection_trail provides the exact ordered choices for each leaf.

Audio

Hosted audio is asynchronous. Submit one of the canonical routes below, persist the returned request_id, then poll /v2/external/audio/status.

RouteModel/provider valuesPrice
POST /v2/external/audio/text_to_speechOPENAI, ELEVENLABS, GOOGLE, PLAYAI1 credit/request
POST /v2/external/audio/text_to_musicELEVENLABS_MUSIC, LYRIA32 credits/request
POST /v2/external/audio/text_to_sound_effectSDAUDIO and configured aliases1 credit/request
POST /v2/external/audio/transcript_alignOpenAI whisper-1Usage based; 0.9 credits/min by default
curl -X POST "https://api.samsar.one/v2/external/audio/text_to_music" \
-H "Authorization: Bearer $SAMSAR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"input": {
"prompt": "Warm cinematic synth backing track, instrumental only",
"model": "ELEVENLABS_MUSIC",
"duration": 30,
"is_instrumental": true
}
}'

Poll:

curl "https://api.samsar.one/v2/external/audio/status?request_id=66ff..." \
-H "Authorization: Bearer $SAMSAR_API_KEY"

samsar-js

import SamsarClient from 'samsar-js';

const samsar = new SamsarClient({ apiKey: process.env.SAMSAR_API_KEY! });

await samsar.validateV2ExternalSamsarApiKey();

const chat = await samsar.createV2ExternalChatCompletion({
model: 'gpt-5.6-sol',
messages: [{ role: 'user', content: 'Write a concise product caption.' }],
});

const video = await samsar.createV2ExternalVideoRequestFromText({
prompt: 'A cinematic product launch reel',
image_model: 'GPTIMAGE2',
video_model: 'RUNWAYML',
duration: 10,
});

const status = await samsar.getV2ExternalVideoStatus(video.data.request_id!);

const imageVideo = await samsar.createV2ExternalVideoRequestFromImage({
image_url: 'https://cdn.example.com/scene-1.png',
video_model: 'RUNWAYML',
});

const lipSync = await samsar.createV2ExternalLipSyncVideo({
video_url: 'https://cdn.example.com/clip.mp4',
audio_url: 'https://cdn.example.com/dialogue.wav',
lip_sync_model: 'SYNCLIPSYNC',
});

const soundEffect = await samsar.createV2ExternalSoundEffectVideo({
video_url: 'https://cdn.example.com/clip.mp4',
prompt: 'Soft ocean waves and distant city ambience',
sound_effect_model: 'MIRELOAI',
});

const detailed = await samsar.getV2ExternalVideoStatusDetailed(lipSync.data.request_id!);

await samsar.requestV2ExternalImage('enhance', {
image_url: 'https://cdn.example.com/photo.png',
resolution: '1k',
});

const music = await samsar.createV2ExternalTextToMusicAudio({
prompt: 'Warm cinematic synth backing track, instrumental only',
model: 'ELEVENLABS_MUSIC',
duration: 30,
is_instrumental: true,
});

const audioStatus = await samsar.getV2ExternalAudioStatus(music.data.request_id!);

The shorter aliases also use the v2 external routes:

  • validateSamsarApiKey
  • getExternalProviderCapabilities
  • validateDeploymentProviders
  • createExternalChat
  • createExternalChatCompletion
  • requestExternalImage
  • requestExternalVideo
  • createExternalVideoRequestFromText
  • createExternalVideoRequestFromImageList
  • createExternalVideoRequestFromImage
  • createExternalLipSyncVideo
  • createExternalSoundEffectVideo
  • getExternalImageStatus
  • getExternalVideoStatus
  • getExternalVideoStatusDetailed
  • getExternalVideoDetailedStatus
  • requestExternalAudio
  • requestExternalAudioRoute
  • createExternalTextToMusicAudio
  • getExternalAudioStatus