External Users API
- Base URL:
https://api.samsar.one/v1 - Platform auth:
Authorization: Bearer <PLATFORM_API_KEY> - Scoped external auth:
x-external-user-api-key: <EXTERNAL_USER_API_KEY> - Client auth after login exchange:
Authorization: Bearer <EXTERNAL_AUTH_TOKEN> - Content-Type:
application/json - Billing: upstream model calls still execute against the owning Samsar account internally, while credits, purchases, refunds, request history, and library actions are tracked on each
external_user
Use this surface when many users share one central Samsar account, but each external user still needs their own credits, request history, payments, publishing controls, and login session.
External user identity
Most external endpoints accept an external_user object:
{
"external_user": {
"provider": "whop",
"external_user_id": "usr_123",
"external_app_id": "app_abc",
"external_company_id": "biz_456",
"email": "member@example.com",
"username": "member_handle",
"display_name": "Member Name",
"metadata": {
"membership_id": "mem_123"
}
}
}
Required fields:
providerexternal_user_id
Recommended for multi-app providers:
external_app_idexternal_company_id
The first successful bootstrap request upserts an ExternalUser record mapped to the owning Samsar account internally.
Auth model
There are two supported auth patterns.
1. Server-to-server platform flow
- Your backend calls
POST /external_users/sessionwith the shared platform API key plus anexternal_userobject. - Samsar upserts the external user and returns an
external_api_key. - Subsequent external-user scoped requests include:
Authorization: Bearer <PLATFORM_API_KEY>x-external-user-api-key: <EXTERNAL_USER_API_KEY>
2. Client login flow
- Your backend calls
POST /external_users/create_login_token. - Samsar returns a short-lived
loginTokenand a ready-to-openloginUrl. - The client exchanges that
loginTokenthroughGET /users/verify_token?loginToken=.... - The response contains a long-lived
authToken. - The client can call
/v1/external_users/*routes with:Authorization: Bearer <EXTERNAL_AUTH_TOKEN>
The platform API key should stay server-side. Only the external auth token should reach the browser.
Response conventions
External generation endpoints return external request ids:
{
"request_id": "extreq_...",
"session_id": "extreq_...",
"external_request_id": "extreq_...",
"external_session_id": "extreq_...",
"upstream_request_id": "66ff...",
"upstream_session_id": "66ff...",
"status_endpoint": "/v1/external_users/status?request_id=extreq_..."
}
request_id/session_idare the external ids you should store client-side.upstream_request_id/upstream_session_idare the internal Samsar session ids.- Poll
GET /external_users/statuswith the external request id.
POST /external_users/session
Create or refresh an external-user session and receive that user’s dedicated API key plus current credits.
curl -X POST https://api.samsar.one/v1/external_users/session \
-H "Authorization: Bearer YOUR_PLATFORM_API_KEY_****************" \
-H "Content-Type: application/json" \
-d '{
"external_user": {
"provider": "whop",
"external_user_id": "usr_123",
"external_app_id": "app_abc"
}
}'
Success response:
{
"external_api_key": "sxu_********************************",
"remainingCredits": 1000,
"external_user": {
"provider": "whop",
"external_user_id": "usr_123",
"generation_credits": 1000,
"has_external_api_key": true
}
}
POST /external_users/create_login_token
Create a short-lived external-user login token and a ready-to-open client login URL.
curl -X POST https://api.samsar.one/v1/external_users/create_login_token \
-H "Authorization: Bearer YOUR_PLATFORM_API_KEY_****************" \
-H "x-external-user-api-key: YOUR_EXTERNAL_USER_API_KEY_****************" \
-H "Content-Type: application/json" \
-d '{
"redirect": "/external/studio"
}'
Success response:
{
"loginToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"expiresInSeconds": 600,
"expiresAt": "2026-03-21T12:00:00.000Z",
"loginUrl": "https://app.samsar.one/verify?loginToken=...&redirect=%2Fexternal%2Fstudio",
"external_user": {
"provider": "whop",
"external_user_id": "usr_123"
}
}
GET /users/verify_token
Exchange the external loginToken for a long-lived external authToken.
curl "https://api.samsar.one/users/verify_token?loginToken=LOGIN_TOKEN_****************"
Success response:
{
"_id": "69bbb64111f47422c1083360",
"authToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"isExternalUser": true,
"provider": "whop",
"externalUserId": "user_46cF7yVLkPms5",
"externalAppId": "app_8jnV5WOvSLgyLr",
"generationCredits": 3000
}
Once you have this authToken, call external-user routes with:
-H "Authorization: Bearer EXTERNAL_AUTH_TOKEN_****************"
POST /external_users/assistant/set_system_prompt
Store or clear an assistant system prompt for one external user. This prompt is applied to that external user’s future assistant requests and overrides the owning account prompt for that external user only.
curl -X POST https://api.samsar.one/v1/external_users/assistant/set_system_prompt \
-H "Authorization: Bearer YOUR_PLATFORM_API_KEY_****************" \
-H "x-external-user-api-key: YOUR_EXTERNAL_USER_API_KEY_****************" \
-H "Content-Type: application/json" \
-d '{
"system_prompt": "You are the storefront assistant for this creator. Keep answers concise, visually aware, and commercially practical."
}'
Success response:
{
"system_prompt": "You are the storefront assistant for this creator. Keep answers concise, visually aware, and commercially practical.",
"model": "gpt-5.4",
"selected_assistant_model": "GPT5.4",
"external_user": {
"provider": "whop",
"external_user_id": "usr_123"
}
}
Pass null or an empty string to clear the external-user-specific prompt and fall back to the owning account prompt or Samsar’s minimal default prompt.
POST /external_users/assistant/completion
Create a synchronous assistant response for an external user. Credits are deducted from the external user balance, while the owning Samsar account’s configured assistant model is used internally.
session_idis required.- You can send the external request/session id returned by external generation routes, or the upstream internal session id.
- Request and response format match the standard Assistant API, including multimodal input and image-generation tool calls.
- Pricing follows the same assistant logic as the main Assistant API: actual usage is converted with 100 credits = $1 and multiplied by 2.5x.
curl -X POST https://api.samsar.one/v1/external_users/assistant/completion \
-H "Authorization: Bearer YOUR_PLATFORM_API_KEY_****************" \
-H "x-external-user-api-key: YOUR_EXTERNAL_USER_API_KEY_****************" \
-H "Content-Type: application/json" \
-d '{
"session_id": "extreq_123",
"input": "Write a product caption for this video and suggest a headline.",
"max_output_tokens": 250
}'
Success response:
{
"id": "resp_123",
"object": "response",
"created_at": 1773651000,
"status": "completed",
"model": "gpt-5.4",
"output_text": "Built to move fast: bold design, clean energy, and a launch-ready look in one line.",
"output": [
{
"id": "resp_123_message",
"type": "message",
"role": "assistant",
"content": [
{
"type": "output_text",
"text": "Built to move fast: bold design, clean energy, and a launch-ready look in one line.",
"annotations": []
}
]
}
],
"usage": {
"input_tokens": 482,
"output_tokens": 43,
"total_tokens": 525
}
}
Response headers:
x-credits-chargedx-credits-remaining
POST /external_users/generate_embeddings_from_plain_text
Create embeddings for one external user from already cleaned plain text. This route skips crawling entirely and uses the same compatible embedding template format as the main chat embedding endpoints.
- Request body accepts the same cleaned text shapes as
/chat/generate_embeddings_from_plain_text. - External-user credits are charged on the external balance only.
- Pricing is the embedding token cost with a 2.5x multiplier and no crawl charges.
curl -X POST https://api.samsar.one/v1/external_users/generate_embeddings_from_plain_text \
-H "Authorization: Bearer YOUR_PLATFORM_API_KEY_****************" \
-H "x-external-user-api-key: YOUR_EXTERNAL_USER_API_KEY_****************" \
-H "Content-Type: application/json" \
-d '{
"input": {
"name": "product-docs-clean",
"plain_text": [
{
"url": "https://example.com/docs/getting-started",
"title": "Getting Started",
"content": "Cleaned plain text content from the page."
}
]
}
}'
Success response:
{
"template_id": "66f3b0d64c8bca9c6f2bd1a3",
"template_hash": "b0e6f2d2c2f1d0c4d9f7f3a1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9",
"hash_link": "embedding_template:b0e6f2d2c2f1d0c4d9f7f3a1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9",
"record_count": 1,
"structured_fields": [
{ "key": "hostname", "type": "string" }
],
"unstructured_fields": ["title", "content"],
"external_user": {
"provider": "whop",
"external_user_id": "usr_123",
"generation_credits": 980
}
}
Response headers:
x-credits-chargedx-credits-remaining
POST /external_users/text_to_video
Create a text-to-video request attributed to an external user.
curl -X POST https://api.samsar.one/v1/external_users/text_to_video \
-H "Authorization: Bearer YOUR_PLATFORM_API_KEY_****************" \
-H "x-external-user-api-key: YOUR_EXTERNAL_USER_API_KEY_****************" \
-H "Content-Type: application/json" \
-d '{
"external_user": {
"provider": "whop",
"external_user_id": "usr_123",
"external_app_id": "app_abc"
},
"input": {
"prompt": "A cinematic teaser for a new sneaker drop",
"image_model": "GPTIMAGE1",
"video_model": "RUNWAYML",
"duration": 10,
"tone": "grounded",
"aspect_ratio": "16:9",
"language": "en",
"enable_subtitles": true,
"font_key": "Poppins"
}
}'
Credits are reserved on the external user immediately after validation. Any unused amount is refunded when the request is cancelled, fails, or finishes below the provisional estimate.
POST /external_users/upload_image_data
Upload image data URLs for an external user before calling image_list_to_video.
{
"external_user": {
"provider": "whop",
"external_user_id": "usr_123",
"external_app_id": "app_abc"
},
"input": {
"image_data": [
"data:image/png;base64,..."
]
}
}
Success response:
{
"image_urls": [
"https://static.samsar.one/..."
]
}
POST /external_users/image_list_to_video
Create a video from an ordered list of images attributed to an external user.
curl -X POST https://api.samsar.one/v1/external_users/image_list_to_video \
-H "Authorization: Bearer YOUR_PLATFORM_API_KEY_****************" \
-H "x-external-user-api-key: YOUR_EXTERNAL_USER_API_KEY_****************" \
-H "Content-Type: application/json" \
-d '{
"external_user": {
"provider": "whop",
"external_user_id": "usr_123",
"external_app_id": "app_abc"
},
"input": {
"image_urls": [
"https://cdn.example.com/frame1.png",
"https://cdn.example.com/frame2.png"
],
"prompt": "Fast product reveal pacing",
"metadata": {
"campaign": "drop-07"
},
"language": "en",
"enable_subtitles": true,
"font_key": "Poppins"
}
}'
x-credits-charged and x-credits-remaining are returned on acceptance when available, just like the standard image-list flow.
GET /external_users/status
Poll an external request until completion.
curl "https://api.samsar.one/v1/external_users/status?request_id=extreq_123" \
-H "Authorization: Bearer YOUR_PLATFORM_API_KEY_****************" \
-H "x-external-user-api-key: YOUR_EXTERNAL_USER_API_KEY_****************"
Success response:
{
"request_id": "extreq_123",
"session_id": "extreq_123",
"external_request_id": "extreq_123",
"upstream_session_id": "66ff...",
"status": "COMPLETED",
"result_url": "https://static.samsar.one/...",
"creditsCharged": 750,
"creditsRefunded": 0,
"remainingCredits": 4250
}
If a generation fails or completes with a refund, the external request record is updated to reflect the refund.
GET /external_users/requests
Fetch recent render requests for one external user.
curl "https://api.samsar.one/v1/external_users/requests?provider=whop&external_user_id=usr_123&external_app_id=app_abc&limit=12" \
-H "Authorization: Bearer YOUR_PLATFORM_API_KEY_****************" \
-H "x-external-user-api-key: YOUR_EXTERNAL_USER_API_KEY_****************"
Success response:
{
"requests": [
{
"request_id": "extreq_123",
"route_key": "text_to_video",
"status": "COMPLETED",
"prompt": "A cinematic teaser for a new sneaker drop",
"video_url": "https://static.samsar.one/...",
"credits_charged": 750,
"credits_refunded": 0,
"remaining_credits": 4250,
"is_published": true,
"published_title": "Sneaker teaser"
}
],
"external_user": {
"provider": "whop",
"external_user_id": "usr_123"
}
}
POST /external_users/publish
Publish a completed external-user request to the public library/feed.
curl -X POST https://api.samsar.one/v1/external_users/publish \
-H "Authorization: Bearer YOUR_PLATFORM_API_KEY_****************" \
-H "x-external-user-api-key: YOUR_EXTERNAL_USER_API_KEY_****************" \
-H "Content-Type: application/json" \
-d '{
"request_id": "extreq_123",
"title": "Sneaker teaser",
"description": "Launch-day vertical cut",
"tags": ["launch", "footwear"]
}'
Success response:
{
"request": {
"request_id": "extreq_123",
"is_published": true,
"published_title": "Sneaker teaser"
},
"publication": {
"_id": "pub_123"
}
}
POST /external_users/archive
Archive an external-user request. This costs no credits and also removes the video from publications if it was already published.
curl -X POST https://api.samsar.one/v1/external_users/archive \
-H "Authorization: Bearer YOUR_PLATFORM_API_KEY_****************" \
-H "x-external-user-api-key: YOUR_EXTERNAL_USER_API_KEY_****************" \
-H "Content-Type: application/json" \
-d '{
"request_id": "extreq_123"
}'
Success response:
{
"request": {
"request_id": "extreq_123",
"status": "ARCHIVED"
}
}
GET /external_users/credits
Fetch the remaining credits for one external user plus their attribution summary.
curl "https://api.samsar.one/v1/external_users/credits?provider=whop&external_user_id=usr_123&external_app_id=app_abc" \
-H "Authorization: Bearer YOUR_PLATFORM_API_KEY_****************" \
-H "x-external-user-api-key: YOUR_EXTERNAL_USER_API_KEY_****************"
Success response:
{
"remainingCredits": 4920,
"lastTopUp": {
"amountPaidCents": 5000,
"creditsApplied": 5000
},
"externalUser": {
"provider": "whop",
"external_user_id": "usr_123",
"generation_credits": 4920,
"total_requests": 4,
"total_credits_used": 1820,
"total_credits_refunded": 150,
"total_credits_purchased": 5000
}
}
POST /external_users/credits/grant
Manually grant credits to an external user. This also credits the shared platform account internally so upstream requests stay in sync.
curl -X POST https://api.samsar.one/v1/external_users/credits/grant \
-H "Authorization: Bearer YOUR_PLATFORM_API_KEY_****************" \
-H "Content-Type: application/json" \
-d '{
"external_user": {
"provider": "whop",
"external_user_id": "usr_123",
"external_app_id": "app_abc"
},
"input": {
"credits": 1000
}
}'
Success response:
{
"creditsGranted": 1000,
"remainingCredits": 1000,
"internalRemainingCredits": 12000,
"externalUser": {
"provider": "whop",
"external_user_id": "usr_123",
"generation_credits": 1000
}
}
POST /external_users/credits/recharge
Create a Stripe checkout link for an external-user credit purchase.
{
"external_user": {
"provider": "whop",
"external_user_id": "usr_123",
"external_app_id": "app_abc"
},
"input": {
"credits": 2500
}
}
Success response:
{
"external_payment_id": "extpay_123",
"url": "https://checkout.stripe.com/c/pay/...",
"checkoutSessionId": "cs_test_123",
"paymentIntentId": "pi_123",
"paymentStatusEndpoint": "/v1/external_users/payment_status",
"credits": 2500,
"amountUsd": 25,
"amountCents": 2500,
"currency": "USD"
}
GET /external_users/payment_status
Poll the status of an external-user-attributed recharge.
curl "https://api.samsar.one/v1/external_users/payment_status?external_payment_id=extpay_123" \
-H "Authorization: Bearer YOUR_PLATFORM_API_KEY_****************" \
-H "x-external-user-api-key: YOUR_EXTERNAL_USER_API_KEY_****************"
Success response:
{
"external_payment_id": "extpay_123",
"status": "succeeded",
"mode": "payment",
"checkoutSessionId": "cs_test_123",
"paymentIntentId": "pi_123",
"amountCents": 2500,
"currency": "usd",
"remainingCredits": 5000
}
When payment succeeds, credits are applied to the external user’s generationCredits. The underlying platform API key is not returned to the caller.