API Reference
newcharactersheet API
Generate character sheets and scenes programmatically. The default path is credit-based generation with API-key auth.
Read first
Agent Brief
- Base URL
https://newcharactersheet.com- Auth header
X-API-Key: ncs_...- Default billing
CREDITS when platform keys are configured- Generate response
POST /api/generate returns { id }- Video endpoint
POST /api/scene/video-preview returns videoUrl or pending- Fetch assets
GET /api/sheets/:id returns accessUrl fields- OpenAPI
/api/openapi.json
Start here
Quick Start
Three calls cover the normal integration path: confirm auth, check credits, generate, then fetch the saved sheet.
Create or reuse an API key
Sign in at Settings, then create an API key. Keys begin with ncs_.
curl https://newcharactersheet.com/api/auth/me \
-H "X-API-Key: ncs_your_key_here"Check credits before work
New accounts receive 300 credits by default. Top-up credits do not expire.
curl https://newcharactersheet.com/api/credits/balance \
-H "X-API-Key: ncs_your_key_here"Generate and fetch
Generation returns the sheet ID. Fetch the sheet to get signed or public asset URLs.
curl -X POST https://newcharactersheet.com/api/generate \
-H "X-API-Key: ncs_your_key_here" \
-F "prompt=A cyberpunk street samurai with neon tattoos" \
-F "visibility=private"
curl https://newcharactersheet.com/api/sheets/6d3f... \
-H "X-API-Key: ncs_your_key_here"Default model
Billing & Credits
Credit-based billing is the default account mode when platform model keys are available. Credits are spent before generation and refunded when credit-mode generation fails.
Subscription credits reset each billing cycle. Top-up credits do not expire and are spent after subscription credits.
Video pricing scales with clip length: the tier price covers the model's default duration, and the charge grows or shrinks proportionally when you change the duration setting. A 5-second clip costs a third of a 15-second clip on the same model. Resolution and audio settings can also adjust the price: 4K output doubles the cost, and turning audio off discounts models that price for sound. A few specialty models carry custom per-model pricing above their tier — the cost shown next to the model in the app is authoritative.
Provider-key mode is still available for accounts that want to use their own model provider keys.
One-time credit packs are bought with SOL or USDC on Solana. Create an order for the pack, send one wallet transaction for the quoted amount, then verify it to receive the credits. USDC is charged at the pack's USD price; SOL is quoted at the live market price when the order is created. Orders expire after 15 minutes.
Get credit balance and recent transactions
Response
{
"balance": 1000,
"subscriptionCredits": 0,
"topUpCredits": 1000,
"tier": "free",
"totalPurchased": 1000,
"totalSpent": 0,
"transactions": [
{
"id": "txn_abc...",
"type": "purchase",
"amount": 1000,
"balance": 1000,
"description": "Starter credit pack",
"createdAt": 1708300000000
}
]
}Get billing mode and provider availability
Response
{
"mode": "CREDITS",
"managedPlanAvailable": false,
"creditsAvailable": true,
"platformProviders": ["nanobanana", "replicate"],
"hasByoApiKey": false,
"imageProvider": "nanobanana",
"videoProvider": "nanobanana"
}Switch billing mode or save a provider key
Use CREDITS for account credits, or BYO for saved provider keys. Saving a provider key switches the account to BYO mode.
Parameters
| Field | Type | Required | Description |
|---|---|---|---|
mode | "CREDITS" | "BYO" | "MANAGED" | No | Billing mode for future generations |
providerName | string | No | Provider name when saving a BYO key |
apiKey | string | No | Provider API key to encrypt and save |
Request body
{
"mode": "CREDITS"
}Response
{
"mode": "CREDITS",
"creditsAvailable": true,
"hasByoApiKey": false
}Create a SOL or USDC payment order for a credit pack
Quotes the pack in the chosen token. Pay by sending one Solana transaction that transfers tokenAmountRaw to treasuryWallet and includes the order memo, then call POST /api/credits/checkout/verify. Orders expire after 15 minutes.
Parameters
| Field | Type | Required | Description |
|---|---|---|---|
packageId | "starter" | "creator" | "studio" | "enterprise" | Yes | Credit pack to buy |
paymentToken | "SOL" | "USDC" | Yes | Token to pay with |
returnPath | string | No | App path stored with the order |
Request body
{
"packageId": "starter",
"paymentToken": "USDC",
"returnPath": "/settings"
}Response
{
"order": {
"orderId": "c3145f43-...",
"paymentKind": "credit_purchase",
"packageId": "starter",
"credits": 1000,
"priceUsd": 10,
"tokenSymbol": "USDC",
"tokenAmount": "10",
"tokenAmountRaw": "10000000",
"tokenDecimals": 6,
"pricingSource": "jupiter",
"pricingMode": "spot_bootstrap",
"tokenUsdPrice": 1,
"mintAddress": "...",
"treasuryWallet": "...",
"memo": "newcharactersheet:credits:c3145f43-...:uid",
"expiresAt": 1760000000000
}
}Verify a confirmed SOL or USDC payment and grant credits
Checks the Solana transaction against the pending order (amount, recipient, signer, and memo) and grants the credits. Safe to retry: a payment is only credited once.
Parameters
| Field | Type | Required | Description |
|---|---|---|---|
orderId | string | Yes | Pending order returned by /api/credits/checkout |
signature | string | Yes | Confirmed Solana transaction signature |
walletAddress | string | Yes | Wallet that signed and sent the payment |
Request body
{
"orderId": "c3145f43-...",
"signature": "5Ue...",
"walletAddress": "9xQe..."
}Response
{
"ok": true,
"balance": 1300,
"credits": 1000,
"signature": "5Ue..."
}Create a Stripe checkout for a credit pack (legacy)
Legacy flow: credits are now bought with SOL or USDC via POST /api/credits/checkout. Stripe no longer sells base credit packs.
Parameters
| Field | Type | Required | Description |
|---|---|---|---|
packageId | "starter" | "creator" | "studio" | "enterprise" | Yes | Credit pack to buy with Stripe |
returnPath | string | No | App path Stripe returns to after payment or cancellation |
Request body
{
"packageId": "starter",
"returnPath": "/settings"
}Response
{
"url": "https://checkout.stripe.com/c/pay/cs_test_..."
}| Top-up pack | Credits | USD price | SOL / USDC price |
|---|---|---|---|
starter | 1000 | $10 | Quoted at checkout |
creator | 3000 | $30 | Quoted at checkout |
studio | 11000 | $100 | Quoted at checkout |
enterprise | 30000 | $260 | Quoted at checkout |
Map
Endpoint Index
A compact routing table for people and agents. Each row links to the detailed endpoint contract below.
| Method | Path | Auth | Purpose |
|---|---|---|---|
| GET | /api/auth/me | Optional | Check auth status |
| GET | /api/credits/balance | Required | Read credit balance |
| GET | /api/billing | Required | Read billing mode |
| PUT | /api/billing | Required | Switch billing or save a provider key |
| POST | /api/credits/checkout | Required | Create a SOL or USDC credit-pack order |
| POST | /api/credits/checkout/verify | Required | Verify a SOL or USDC payment |
| POST | /api/credits/stripe-checkout | Required | Create a Stripe credit-pack checkout (legacy) |
| POST | /api/generate | Required | Generate a character sheet |
| POST | /api/scene/generate | Required | Generate a scene image |
| POST | /api/scene/video-preview | Required | Generate a scene video |
| GET | /api/sheets/:id | Optional | Fetch a sheet |
| PATCH | /api/sheets/:id | Required | Update sheet metadata |
| DELETE | /api/sheets/:id | Required | Delete a sheet |
| GET | /api/sheets/search?q=query | Optional | Search public sheets |
| PATCH | /api/visibility/:id | Required | Change visibility |
| GET | /api/api-keys | Required | List API key metadata |
| POST | /api/api-keys | Required | Create an API key |
| DELETE | /api/api-keys | Required | Revoke an API key |
Identity
Auth
Check authentication status
Response
{
"authenticated": true,
"uid": "fWx8k2mN..."
}Create
Generation
Generate a character reference sheet
Accepts multipart/form-data. In credit mode, image generation usually costs 12 credits and may be lower or higher by model tier. Credits are refunded if generation fails. Returns the new sheet ID; fetch image URLs via GET /api/sheets/:id.
Parameters
| Field | Type | Required | Description |
|---|---|---|---|
prompt | string | Yes | Character description (max 10,000 chars) |
keywords | string | No | Comma-separated tags |
visibility | string | No | "public" or "private" (default) |
style | string | No | Art style hint |
referenceImages | file[] | No | Reference images (max 50 MB each) |
projectMode | "new" | "existing" | No | Attach the sheet to a project |
projectId | string | No | Existing project ID when projectMode is existing |
projectName | string | No | New project name when projectMode is new |
folderId | string | No | Folder to place the generated sheet in |
Request
curl -X POST https://newcharactersheet.com/api/generate \
-H "X-API-Key: ncs_..." \
-F "prompt=A medieval knight with golden armor" \
-F "keywords=knight,medieval,armor" \
-F "visibility=public" \
-F "style=anime"Response 201
{
"id": "6d3f..."
}Generate a scene image with characters
Create a scene image featuring your characters. Scene access still follows the account feature gate; generation uses credits when the account is in CREDITS mode.
Parameters
| Field | Type | Required | Description |
|---|---|---|---|
prompt | string | No | Scene description |
sheetIds | string[] | No | Character sheet IDs to include (max 8) |
outputMode | string | No | "picture" by default; video workflows use dedicated video endpoints |
projectMode | "new" | "existing" | No | Attach the scene to a project |
existingProjectId | string | No | Existing project ID when projectMode is existing |
projectName | string | No | New project name when projectMode is new |
Request body
{
"prompt": "Epic battle in a volcanic landscape",
"sheetIds": ["6d3f..."],
"outputMode": "picture"
}Response 201
{
"id": "s9f2...",
"imageBase64": "iVBORw0KGgo...",
"contentType": "image/png",
"outputMode": "picture"
}Workflow Example
Generate a character
curl -X POST https://newcharactersheet.com/api/generate \
-H "X-API-Key: ncs_..." \
-F "prompt=A fire mage with flowing red robes"Create a scene image
curl -X POST https://newcharactersheet.com/api/scene/generate \
-H "X-API-Key: ncs_..." \
-H "Content-Type: application/json" \
-d '{
"prompt": "Standing on a cliff overlooking a burning city",
"sheetIds": ["char_abc..."],
"outputMode": "picture"
}'Fetch the saved scene
curl https://newcharactersheet.com/api/sheets/scene_xyz... \
-H "X-API-Key: ncs_..."Generate a scene video
Direct video generation endpoint. Use a prompt with sheetIds, sceneIds, a first frame, or inline reference images. In credit mode, video cost is model-tiered and charged before submit; resumable provider jobs return pending.
Parameters
| Field | Type | Required | Description |
|---|---|---|---|
prompt | string | No | Video prompt (max 10,000 chars) |
sheetIds | string[] | No | Character sheet IDs to reference (max 8) |
sceneIds | string[] | No | Scene sheet IDs to reference (max 4) |
firstImageId | string | No | Sheet ID to use as the first frame |
lastImageId | string | No | Sheet ID to use as the last frame for interpolation |
firstFrameImage | object | No | Inline first-frame image payload |
lastFrameImage | object | No | Inline last-frame image payload |
durationSeconds | number | No | Requested duration, clamped by model capability |
aspectRatio | string | No | Example: "16:9", "9:16", "1:1" |
resolution | string | No | Model-specific resolution option |
modelOverride | string | No | Video model ID to use |
providerJob | object | No | Pass a prior pending providerJob to resume polling without recharging |
Request body
{
"prompt": "Camera slowly pushes in as embers drift through the air",
"sheetIds": ["char_abc..."],
"sceneIds": ["scene_xyz..."],
"durationSeconds": 5,
"aspectRatio": "16:9",
"modelOverride": "veo-3.1-fast-generate-preview"
}Response
{
"videoUrl": "https://...",
"contentType": "video/mp4",
"sourceUri": null,
"videos": [
{
"videoUrl": "https://...",
"contentType": "video/mp4",
"sourceUri": null
}
],
"textResponse": "Here's the generated video. What do you think?"
}Pending providers may return { pending: true, providerName, providerJob }. Poll again with the same providerJob to resume.
Read and manage
Sheets
Get a sheet by ID
Public sheets need no auth. Private sheets require owner auth.
Response
{
"id": "6d3f...",
"ownerUid": "fWx8k2mN...",
"sheetType": "character",
"visibility": "public",
"prompt": "A medieval knight...",
"keywords": ["knight", "medieval"],
"handle": "golden-knight",
"createdAt": 1708300000000,
"updatedAt": 1708300000000,
"image": {
"storagePath": "sheets/...",
"publicUrl": "https://...",
"contentType": "image/png",
"width": 2048,
"height": 2048
},
"accessUrl": "https://...",
"videoAccessUrl": "https://...",
"project": { "id": "proj_1", "name": "My Project" },
"viewerHasLiked": false
}Update sheet metadata
Request body
{
"keywords": ["knight", "medieval", "armor"],
"handle": "golden-knight"
}Response
{
"id": "6d3f...",
"keywords": ["knight", "medieval", "armor"],
"handle": "golden-knight"
}Delete a sheet you own
Returns 204 with no body.
Search sheets
Response
{
"results": [
{
"id": "6d3f...",
"prompt": "A medieval knight...",
"keywords": ["knight", "medieval"],
"handle": "golden-knight",
"imageUrl": "https://..."
}
]
}Change sheet visibility
Request body
{ "visibility": "public" }Response
{
"id": "6d3f...",
"visibility": "public"
}Access
API Keys
List your API keys
Returns metadata only. Plaintext key secrets are never returned after creation.
Response
{
"keys": [
{
"keyId": "a1b2c3...",
"label": "my-agent",
"last4": "Zw4x",
"createdAt": 1708300000000
}
]
}Create a new API key
The plaintext key is returned only once.
Request body
{ "label": "production" }Response 201
{
"key": "ncs_dG9rZW4...",
"keyId": "a1b2c3..."
}Revoke an API key
Request body
{ "keyId": "a1b2c3..." }Response
{ "ok": true }Guardrails
Limits & Quotas
Production API routes are rate-limited per IP. API keys also have a daily request quota. Credit exhaustion returns a separate 402 response.
| Scope | Limit |
|---|---|
| Global reads | 2,000 requests / minute per IP |
| Global writes | 300 requests / minute per IP |
| Generation routes | 10 requests / minute per IP |
| API key daily quota | 1,000 requests / day per key |
| Prompt length | 10,000 characters |
| File size | 50 MB each, 100 MB total |
| Reference images | Max 8 per request |
Responses
Errors
{
"error": {
"code": "UNAUTHENTICATED",
"message": "Authentication required"
}
}401402403404429500Rate-limited responses return 429 with Retry-After. Insufficient credits return 402 with INSUFFICIENT_CREDITS.