Totalum SDK
If your project was created before 8 October 2026 or doesn't have the v2 engine flag, it runs the v1 Totalum engine, which is now legacy and doesn't have some of the features. See the legacy docs.
totalum-sdk is the package every Totalum v2 app uses for Totalum's built-in features: the project's database
(totalum-sdk/d1, used through Drizzle), file storage, e-mail, AI, payments, real-time rooms, scheduled jobs, vector
search, web scraping, a cloud browser, the user's connected accounts and more. Every call goes over HTTPS to the
Totalum API with the project key, so it works the same in the preview, the published app (Cloudflare Workers), the
coding agent's sandbox and a laptop. Never add a third-party SDK or provider key for something listed here.
The whole reference as one Markdown file, for a coding agent: /totalum-sdk.md.
#Contents
| Module | Import | What it is for |
|---|---|---|
The totalum object | totalum-sdk | The default totalum object and createTotalum() give you every namespace on one object: totalum.files, totalum.ai, totalum.email and the rest. |
| Database driver | totalum-sdk/d1 | The project's SQL database (Cloudflare D1, SQLite), used through Drizzle: drizzle(totalumD1()). |
| Files & Storage | totalum-sdk/files | Store and serve your app's files (uploads, images, generated PDFs). |
| Payments | totalum-sdk/payments | Take payments and subscriptions with Stripe on the project owner's own Stripe account (Stripe Connect), without handling card data: create a hosted Checkout, send the buyer to its url, and read the result back. |
| Webhooks | totalum-sdk/webhooks | Receive Totalum's signed events (payments, e-mail delivery, browser programs, connected-account events, credits exhausted) and check that they really come from Totalum. |
| Web Scraping & Search | totalum-sdk/web | Read the web from your app: one page as Markdown or HTML (scrape), a web search (search), every URL of a site (map), a whole site in the background (crawl) and screenshots. |
totalum-sdk/pdf | Turn HTML or a web page into a PDF stored in the project's files: invoices, tickets, reports. | |
| Document Scan / OCR | totalum-sdk/scan | Read documents and images: extract the fields you describe (an invoice's number, date and total) as JSON with document(), or get the plain text of every page with ocr(). |
| Vector Search | totalum-sdk/vectors | Semantic search over your own content: store texts or images as vectors with metadata (upsert), then find the closest ones to a question, a text or an image (query). |
| Connected Accounts | totalum-sdk/connections | Let your app's users connect their own accounts of about 1,500 apps — Google Calendar, Gmail, Google Drive, Outlook, Slack, HubSpot, Notion, GitHub, Stripe, Airtable and more — and act on them from your server: create a calendar event, send an e-mail from their Gmail, read their files, or receive their events. |
| Speech | totalum-sdk/speech | Speech to text (transcribe) and text to speech (synthesize): transcribe a recording or a voice note, read a text aloud, store the audio as a project file. |
| AI | totalum-sdk/ai | AI from your server without any provider account: chat completions (streamed or not), structured JSON, a label out of a list, embeddings, image generation and editing, video generation and image description. |
totalum-sdk/email | Send transactional e-mail (sign-up confirmations, receipts, notifications) from the project's own sender, and check whether it was delivered. | |
| Cron Jobs | totalum-sdk/cron | Run a route of your own app on a schedule: every night at 8:00, every 15 minutes, the first day of the month. |
| SEO & IndexNow | totalum-sdk/seo | Tell search engines that pages of your custom domain changed (IndexNow), so new and edited pages are indexed in minutes instead of days. |
| Browser Automation | totalum-sdk/browser | A real Chrome in the cloud, driven over HTTPS from your server, so it works inside the published app: open pages, click, type, log in, fill forms, download files, take screenshots and PDFs, extract data. |
| Realtime | totalum-sdk/realtime | Live updates between the people using your app: chat, notifications, presence ("who is online"), collaborative editing, live dashboards and games. |
| Logs | totalum-sdk/logs | Read your app's own server logs: the requests the published app (env: 'live') or the preview ('dev') handled, with their console lines, status codes and errors. |
| Site Analytics | totalum-sdk/analytics | Your site's own traffic: page views, visits, unique visitors, errors, bytes and response times, as a time series or a top list (top pages, referrers, countries, devices, browsers). |
| React Realtime Hooks | totalum-sdk/react | The browser side of realtime rooms for React client components: useRealtimeChannel(room) connects to a room, keeps the messages received, shows who else is present, and reconnects by itself (every deploy drops sockets). |
#Quick start
Install the package (it is already installed in every Totalum project):
npm install --save-exact totalum-sdkGive the server its project key. Totalum sets
TOTALUM_PROJECT_KEY(tlm_pk_…) on the preview, the published app and the sandbox; on your own machine put it in.env.local. It is a secret: use it only in server code (route handlers, server actions, cron routes, scripts), never in aNEXT_PUBLIC_variable or a client component.Call a namespace on the default
totaluminstance:// src/app/api/welcome/route.ts import { totalum } from 'totalum-sdk'; export async function POST(request: Request) { const { email } = (await request.json()) as { email: string }; const sent = await totalum.email.send({ to: email, subject: 'Welcome to Acme', html: '<p>Thanks for signing up.</p>', }); return Response.json({ id: sent.id, credits: sent.usage.credits }); }sentis:{ "success": true, "message": "Email sent successfully", "messageId": "01a12c0c-9e5f-74ea-a128-a72d3fdd47ae", "id": "em_01M4P0S77M6XCM69SYZWP1XME9", "status": "queued", "usage": { "credits": 0.0515 } }Read the database with Drizzle on
totalumD1():import { drizzle } from 'drizzle-orm/d1'; import { totalumD1 } from 'totalum-sdk/d1'; import { users } from '@/db/schema'; const db = drizzle(totalumD1()); const rows = await db.select().from(users).limit(10);
Paid calls return what they cost in usage.credits (Totalum credits). Failures throw TotalumError: see
Errors.
#Install and configure
npm install --save-exact totalum-sdkServer-side only (route handlers, server actions, cron handlers, npx tsx scripts/<name>.ts). Every namespace reads the
same environment at call time, never at import; an option of the same name wins:
| Variable | Option | Meaning |
|---|---|---|
TOTALUM_PROJECT_KEY | key | The project key tlm_pk_…. Never NEXT_PUBLIC_. Missing → SDK_NOT_CONFIGURED. |
TOTALUM_SDK_API_URL | apiUrl | Default https://sdk-api.totalum.app. |
TOTALUM_ENV | env | dev or live (default), sent as x-totalum-env: the database totalum-sdk/d1 targets over HTTPS, and dev vs live usage. |
TOTALUM_FILES_URL | filesUrl | The public files host of files.url(). |
TOTALUM_AI_BASE_URL | aiBaseUrl | The OpenAI-compatible AI gateway ai.gatewayConfig() returns. |
TOTALUM_APP_KEY | key | Set by Totalum in the sandbox only: the deployed app's own key, used before TOTALUM_PROJECT_KEY by every namespace but the database, so the agent's checks have the app's permissions. |
TOTALUM_WEBHOOK_SECRET | argument | The secret webhooks.verify checks Totalum-Signature with. Totalum sets it on the preview, the published site and the sandbox, and a rotation reaches them at once: never set it yourself. |
import { totalum } from 'totalum-sdk'; // or one namespace: import { totalumFiles } from 'totalum-sdk/files';
const file = await totalum.files.upload(blob, { name: 'avatar.png' });#Errors
Every failure throws TotalumError (isTotalumError(e)) with errorCode (frozen), status, details and
requestId; TotalumD1Error (message shaped like a native D1 error) and TotalumWebhookError extend it. A capped
or disabled feature (FEATURE_LIMIT_REACHED 429, FEATURE_DISABLED 403) refuses only its own namespace; at a zero
balance paid calls answer INSUFFICIENT_CREDITS 402. A project makes at most 100 built-in calls per second (AI, e-mail,
file uploads, web, scan, PDF, speech, vectors, browser, realtime, payments): above it the Totalum API answers RATE_LIMITED 429 with
Retry-After, which the SDK retries twice (with jitter) before throwing — handle it, and never fan out hundreds of calls
at once (batch, queue or await them in small groups).
import { isTotalumError, totalum } from 'totalum-sdk';
try {
await totalum.files.get('p/my-app/01M4P0PZXJ0DPQM7R20QVZ0EKC.txt');
} catch (e) {
if (isTotalumError(e) && e.errorCode === 'FILE_NOT_FOUND') return null;
throw e; // logs as: TotalumError [CODE]: message
}These are the errors every call can throw; each method lists its own below it.
| Code | HTTP | Meaning |
|---|---|---|
SDK_NOT_CONFIGURED | — | No project key: set TOTALUM_PROJECT_KEY (server-side) or pass { key }. Thrown before any request is sent. |
NETWORK_ERROR | 0 | The Totalum API could not be reached (DNS, TLS, connection reset). cause holds the original error. |
RESPONSE_PARSE_ERROR | any | The answer was not the JSON the SDK expects (a proxy or gateway page in between). |
UNAUTHORIZED | 401 | The key is unknown or revoked. |
LEGACY_KEY_NOT_SUPPORTED | 401 | An account key (tlm_sk_…) or a legacy key was used: v2 projects need a project key tlm_pk_…. |
SANDBOX_KEY_EXPIRED | 401 | The coding agent's temporary sandbox key expired (only inside Totalum's sandbox). |
FORBIDDEN_SCOPE | 403 | The key lacks the scope this namespace needs (for example email, ai, files:write). |
VALIDATION_ERROR | 400 | The input does not match what the method accepts; details names the fields. |
PAYLOAD_TOO_LARGE | 413 | The request body is over 26 MB. |
RATE_LIMITED | 429 | More than the project's built-in calls per second (100). The SDK already waited and retried twice; details.retryAfterMs says how long to wait. |
RATE_LIMIT_EXCEEDED | 429 | A per-visitor or per-feature limit that lasts up to a minute; details says which and when to retry. |
INSUFFICIENT_CREDITS | 402 | The account has no credits left for a paid call. Nothing was charged. |
FEATURE_LIMIT_REACHED | 429 | The plan's limit for this feature is used up for the period; only this namespace is refused. |
FEATURE_DISABLED | 403 | The project owner turned this feature off; only this namespace is refused. |
AI_MEDIA_PAUSED_THIS_HOUR | 429 | The project used a lot of credits this hour, so image, video and speech AI pause until the hour ends (details.resetsAt). Text AI keeps working. |
PROJECT_PAUSED_RUNAWAY | 429 | The project was paused because its usage passed the safety threshold. |
PROJECT_PAUSED_BALANCE | 402 | The project is paused because the account balance is negative. |
PROJECT_SUSPENDED | 402 | The project is suspended because of a negative credit balance. |
PROJECT_PAUSED_BY_USER | 402 | The owner paused the project; it works again once resumed. |
PROJECT_HIBERNATED | 410 | The project is hibernated; the owner reactivates it in Totalum (free, about a minute). |
PROJECT_DELETED | 410 | The project was deleted. |
PROVIDER_UNAVAILABLE | 503 | The service behind this feature is unavailable right now. Retry later. |
ENGINE_UNAVAILABLE | 500 | An unexpected error on Totalum's side; details.errorId identifies it for support. |
Database failures read D1_ERROR: … on every connection, whichever engine holds the project's database:
Network connection lost. (a transient failure), D1 DB is overloaded. … (too many statements at once: send
fewer, or group writes in db.batch), D1 DB exceeded its CPU time limit and was reset. (one statement ran too
long: add an index or split it), Memory limit exceeded before EOF. (a result too big for the Worker: select fewer
rows or columns, paginate), statement too long: SQLITE_TOOBIG. The driver repeats a statement up to twice (after
≈ 0.1 s and ≈ 0.4 s) only when that is safe: a read (SELECT, or a batch of them) after a transient failure, and a
write only when the failure says the statement never reached the database. A write that may have been applied, an
overloaded database, a limit and a SQL error are thrown at once — make a write you retry yourself idempotent
(INSERT … ON CONFLICT DO NOTHING, a unique key).
Node-only methods throw NODE_ONLY inside a Worker (the preview and the published app both run on Cloudflare
Workers) and name the HTTPS replacement: ai.video.wait().
All client-side codes: SDK_NOT_CONFIGURED, NOT_SUPPORTED, BATCH_FOREIGN_STATEMENT, TRANSACTIONS_NOT_SUPPORTED, NETWORK_ERROR, TIMEOUT, RESPONSE_PARSE_ERROR, NODE_ONLY, WEBHOOK_SECRET_MISSING, WEBHOOK_SIGNATURE_INVALID, WEBHOOK_TIMESTAMP_EXPIRED.
All server codes: SERVICE_UNAUTHORIZED, SERVICE_REPLAY, ACTOR_MISMATCH, PAYLOAD_TOO_LARGE, VALIDATION_ERROR, PROJECT_NOT_FOUND, PROJECT_NOT_READY, OPERATION_IN_PROGRESS, AGENT_RUNNING, PROJECT_MOVED, OBJECT_MIGRATING, INDEX_SHARD_UNAVAILABLE, RATE_LIMIT_EXCEEDED, RATE_LIMITED, PROJECT_PAUSED_RUNAWAY, AI_MEDIA_PAUSED_THIS_HOUR, PROJECT_PAUSED_BALANCE, PROJECT_SUSPENDED, PROJECT_HIBERNATED, PROJECT_DELETED, PROJECT_PAUSED_BY_USER, LIFECYCLE_NOT_APPLICABLE, PROJECT_NOT_PAUSED, PAUSE_DUMP_EXPIRED, PAUSE_VERIFICATION_FAILED, DEPLOYMENT_IN_PROGRESS, REACTIVATE_IMPORT_MISMATCH, RESUME_IMPORT_MISMATCH, INSUFFICIENT_CREDITS, VCAAS_INSUFFICIENT_CREDITS, PROJECT_CREDIT_LIMIT_REACHED, FREE_PROMPTS_DISABLED, PLAN_REQUIRED, FEATURE_LIMIT_REACHED, FEATURE_DISABLED, VECTORS_LIMIT_REACHED, CONNECTION_REQUIRED, CONNECTION_ACTION_FAILED, TOOLKIT_NOT_AVAILABLE, TOOLKIT_NEEDS_OWN_APP, AGENT_ALREADY_RUNNING, IMPORT_IN_PROGRESS, MIGRATION_TOO_LARGE, MIGRATION_START_FAILED, TOO_MANY_RUN_REQUESTS, PROMPT_SECURITY_VIOLATION, NO_PROCESS_RUNNING, RUN_NOT_FOUND, KEY_NOT_FOUND, DEPLOYMENT_RUNNING, AUTO_EXECUTION_ALREADY_ACTIVE, REBUILD_RUNNING, SECRET_ALREADY_EXISTS, SECRET_LIMIT_EXCEEDED, RESERVED_SECRET_NAME, DUMP_NOT_FOUND, DUMP_INVALID, RESTORE_TARGET_NOT_EMPTY, ENGINE_NOT_SUPPORTED, ENGINE_V2_DISABLED, V2_TEMPORARILY_DISABLED, ENGINE_REQUEST_NOT_ELIGIBLE, ENGINE_MISMATCH, INVALID_ENGINE_VERSION, PROJECT_ENGINE_MISMATCH, ENGINE_UNAVAILABLE, PREVIEW_LABEL_TOO_LONG, PROJECT_ALREADY_EXISTS, CLOUDFLARE_API_ERROR, PROVISIONING_BUSY, UNAUTHORIZED, LEGACY_KEY_NOT_SUPPORTED, SANDBOX_KEY_EXPIRED, AUTH_RATE_LIMITED, FORBIDDEN_SCOPE, KEY_ENV_MISMATCH, KEY_LIMIT_EXCEEDED, LIVE_DB_READ_ONLY, LIVE_WRITE_NEEDS_CONFIRMATION, DDL_NOT_ALLOWED, MIGRATION_IN_PROGRESS, MIGRATION_EDITED, SCHEMA_OUT_OF_SYNC, LIVE_MIGRATION_FAILED, DESTRUCTIVE_MIGRATION_NEEDS_CONFIRMATION, DESTRUCTIVE_MIGRATION_UNDONE_BY_RESTORE, DEV_DATABASE_NOT_FOUND, DATABASE_ROLE_NOT_FOUND, BOOKMARK_NOT_FOUND, BACKUP_NOT_FOUND, BACKUP_NOT_DELETABLE, BACKUP_RATE_LIMITED, BACKUP_TOO_LARGE_FOR_IMPORT, PRE_RESTORE_BACKUP_FAILED, RESTORE_VERIFY_FAILED, RESTORE_BEFORE_LIVE_MIGRATION, RUN_NOT_LATEST, DEV_DATABASE_EXISTS, SQL_ERROR, SQL_MULTI_STATEMENT, SQL_STATEMENT_TOO_LARGE, SQL_TOO_MANY_PARAMS, STATEMENT_NOT_ALLOWED, VIRTUAL_TABLES_NOT_SUPPORTED, USE_STORAGE_FOR_FILES, D1_TYPE_ERROR, MIGRATION_INVALID, SYSTEM_TABLE_READ_ONLY, SQL_READ_ONLY, RESULT_TOO_LARGE, NL_QUERY_UNANSWERABLE, QUERY_TIMEOUT, DB_OVERLOADED, D1_TRANSIENT, DB_FULL_NEAR_LIMIT, IDEMPOTENCY_KEY_REUSED, IDEMPOTENT_REPLAY_UNAVAILABLE, TABLE_NOT_FOUND, SCHEMA_TOO_LARGE_FOR_COUNTS, EXEC_REQUIRES_MIGRATE_MODE, MIGRATION_UNKNOWN_IN_DB, QUERY_LIMIT_EXCEEDED, STORAGE_LIMIT_EXCEEDED, METER_UNAVAILABLE, COLUMN_NOT_FOUND, VALUE_NOT_ALLOWED, COLUMN_REQUIRED, FILTER_TOO_COMPLEX, OFFSET_TOO_LARGE, BULK_TOO_LARGE, NOT_A_JUNCTION_TABLE, AMBIGUOUS_RELATION, LIVE_WRITE_CONFIRMATION_REQUIRED, RECORD_NOT_FOUND, RECORD_KEY_REQUIRED, AMBIGUOUS_RECORD_ID, DEV_NAME_GUARD, PROD_NAME_GUARD, INVALID_RUN_REQUEST, RUN_ALREADY_ACTIVE, RUN_CONFLICT, INVALID_CREDENTIALS, ADAPTER_UNAVAILABLE, DISK_FULL, DEPLOY_FIX_ATTEMPTS_EXHAUSTED, TOKEN_REVOKED, AM_UPDATE_DOWNLOAD_FAILED, AM_UPDATE_BAD_SHA, AM_UPDATE_BAD_SIGNATURE, AM_UPDATE_INCOMPATIBLE_IMAGE, AM_UPDATE_START_FAILED, AM_VERSION_UNAVAILABLE, AM_UPDATE_FAILED, RELEASE_CANARY_NOT_PASSED, RELEASE_NOT_FOUND, RELEASE_ROLLOUT_ACTIVE, RELEASE_GUARD_PAUSED, RELEASE_BUILD_UNAVAILABLE, RELEASE_BELOW_MIN_SAFE_VERSION, VISUAL_EDIT_PREVIEW_DEPLOYING, VISUAL_EDIT_NOT_PATCHABLE, VISUAL_EDIT_BASE_MISMATCH, VISUAL_EDIT_TYPECHECK_FAILED, INVALID_VISUAL_EDIT, IMAGE_VERSION_NOT_FOUND, IMAGE_VERSION_NOT_PROMOTABLE, REALTIME_TICKET_INVALID, REALTIME_TICKET_EXPIRED, REALTIME_PERMISSION_DENIED, REALTIME_MESSAGE_TOO_LARGE, REALTIME_MESSAGE_RATE_EXCEEDED, REALTIME_CONNECTION_LIMIT_REACHED, REALTIME_ROOM_LIMIT_REACHED, CONFIRMATION_REQUIRED, MIGRATION_NOT_REVERSIBLE, ALREADY_ON_PROVIDER, DATABASE_MIGRATING, TURSO_STORAGE_INSUFFICIENT, LOGWATCH_INACTIVE, AGENT_LOG_READS_LIMIT, LOGS_UPSTREAM_ERROR, ANALYTICS_INVALID_QUERY, ANALYTICS_UPSTREAM_ERROR, ANALYTICS_WINDOW_OUT_OF_RETENTION, INVALID_CIDR, RATE_LIMIT_ABOVE_PLAN, RATE_LIMIT_DISABLE_NOT_ALLOWED, OWNER_ONLY, SIGNING_NOT_CONFIGURED, SIGNING_ALREADY_CONFIGURED, SIGNING_INVALID_KEYSTORE, SIGNING_INVALID_ASC_KEY, KEYSTORE_DOWNLOAD_EXPIRED, KEYSTORE_NOT_DOWNLOADABLE, MOBILE_BUILD_RUNNING, MOBILE_BUILD_RATE_LIMITED, MOBILE_BUILD_QUEUE_TIMEOUT, MOBILE_BUILD_NOT_CANCELLABLE, MOBILE_BUILD_NOT_FOUND, MOBILE_BUILD_NOT_READY, MOBILE_REQUIRES_PUBLISHED_PROJECT, DOWNLOAD_EXPIRED, PROCESS_IN_PROGRESS, SANDBOX_NOT_RUNNING, MOBILE_LAYER_MISSING, MOBILE_BUILD_FAILED, MOBILE_ARTIFACT_INVALID, SIGNING_FINGERPRINT_MISMATCH, AM_RESTARTED, MOBILE_BUILD_NOT_SIGNED, STORE_NOT_CONFIGURED, STORE_CREDENTIALS_INVALID, STORE_APP_NOT_FOUND, STORE_UPLOAD_RUNNING, STORE_UPLOAD_LIMIT_REACHED, STORE_UPLOAD_NOT_FOUND, STORE_UPLOAD_FAILED, PLAY_FIRST_UPLOAD_MANUAL, STORE_PROCESSING_TIMEOUT, LIMIT_ABOVE_PLAN_CEILING, UNKNOWN_FEATURE, INVALID_LIMIT, FEATURE_NOT_DISABLABLE, USE_PUT_LIMITS, LIMIT_NOT_USER_EDITABLE, NOT_AVAILABLE_FOR_ENGINE, INVALID_AMOUNT, REFUND_EXCEEDS_CHARGES, IDEMPOTENCY_CONFLICT, ORGANIZATION_NOT_FOUND, ACCOUNT_NOT_FOUND, PROVIDER_UNAVAILABLE, URL_NOT_ALLOWED, JOB_NOT_FOUND, CONCURRENCY_QUEUE_TIMEOUT, CONCURRENCY_QUEUE_FULL, PROVIDER_TIMEOUT, FILE_TOO_LARGE, UNSUPPORTED_FILE_TYPE, FILE_NOT_FOUND, FILE_KEY_FORBIDDEN, FILE_UPLOAD_ERROR, FILE_DOWNLOAD_ERROR, FILE_DELETE_ERROR, UPLOAD_NOT_COMPLETED, MISSING_URL, MISSING_INPUT, MISSING_EXTRACTION_CONFIG, MISSING_QUERY, SCRAPE_FAILED, EXTRACT_FAILED, SCREENSHOT_FAILED, SEARCH_FAILED, SCRAPE_BLOCKED, SESSION_NOT_FOUND, SESSION_EXPIRED, SESSION_BUSY, SESSION_LIMIT_REACHED, SESSION_ENDED_INSUFFICIENT_CREDITS, ACTION_TIMEOUT, ACTION_FAILED, UNKNOWN_COMMAND, BATCH_TOO_LARGE, SKIPPED, UPLOAD_TOO_LARGE, DOWNLOAD_TOO_LARGE, CAPTURE_LIMIT_REACHED, CAPTCHA_UNSOLVED, BROWSER_CDP_NODE_ONLY, DIALOG_NOT_OPEN, STEALTH_TIER_UNAVAILABLE, DOMAIN_NOT_ALLOWED, CONTEXT_SEED_UNSUPPORTED, EXTENSION_TOO_LARGE, NL_PROVIDER_UNAVAILABLE, PROGRAM_TOO_LARGE, PROGRAM_UNBOUNDED, UNKNOWN_STEP, PROGRAM_IN_FLIGHT, PROGRAM_TIMEOUT, PROGRAM_NOT_FOUND, PROGRAM_STEP_FAILED, PROGRAM_LIMIT_REACHED, CREATE_PDF_FROM_HTML_ERROR, GENERATE_PDF_BY_URL_ERROR, PDF_TIMEOUT, PDF_TOO_LARGE, FILENAME_REQUIRED, SCANUM_EYE_ARRAY_NOT_SUPPORTED, INVALID_EXTRA_FIELD_TYPE, SCANUM_EYE_PDF_NOT_SUPPORTED, UNSUPPORTED_SCAN_MODEL, SCAN_DOCUMENT_ERROR, SCAN_INVOICE_ERROR, OCR_IMAGE_PROCESSING_ERROR, OCR_PDF_PROCESSING_ERROR, SCAN_TOO_MANY_PAGES, SCAN_PDF_ENCRYPTED, SCAN_XFA_UNSUPPORTED, AUDIO_FILE_REQUIRED, AUDIO_FILE_TOO_LARGE, INVALID_AUDIO_FORMAT, AUDIO_TRANSCRIPTION_ERROR, TTS_TEXT_TOO_LONG, TTS_VOICE_UNKNOWN, TOO_MANY_AUDIO_TRANSCRIPTIONS, EMAIL_SEND_FAILED, TOO_MANY_ATTACHMENTS, INVALID_ATTACHMENT_URL, ATTACHMENT_TOO_LARGE, TOO_MANY_RECIPIENTS, EMAIL_RECIPIENT_SUPPRESSED, EMAIL_DOMAIN_NOT_VERIFIED, EMAIL_LOCAL_PART_TAKEN, EMAIL_SENDING_PAUSED, EMAIL_DOMAINS_REQUIRE_PAID_PLAN, SUPPRESSION_PERMANENT, DEV_RECIPIENT_NOT_ALLOWED, CRON_LIMIT_REACHED, INVALID_SCHEDULE, CRON_URL_NOT_ALLOWED, CRON_JOB_NOT_FOUND, CRON_REQUIRES_PUBLISHED_PROJECT, LIVE_CRON_READ_ONLY, URL_NOT_PROJECT_HOST, INDEXNOW_ERROR, MCP_VERIFY_FAILED, MCP_NAME_RESERVED, MCP_LIMIT_REACHED, MCP_SERVER_NOT_FOUND, PAYMENTS_NOT_ENABLED, PAYMENTS_LIVE_ONBOARDING_REQUIRED, PAYMENTS_PUBLISH_FIRST, PAYMENTS_ACCOUNT_DISCONNECTED, CARD_DATA_NOT_ACCEPTED, STRIPE_ERROR, STRIPE_RATE_LIMITED, PAYMENTS_WEBHOOK_SIGNATURE_INVALID, AI_MODEL_NOT_ALLOWED, AI_MODEL_UNKNOWN, AI_INVALID_SCHEMA, AI_CONTENT_BLOCKED, AI_CONTEXT_TOO_LONG, AI_PROVIDER_QUOTA, AI_PROVIDER_UNAVAILABLE, AI_STREAM_ERROR, AI_VIDEO_JOB_NOT_FOUND, AI_VIDEO_FAILED, MISSING_VIDEO_URL, MISSING_PROMPT, INVALID_VIDEO_URL, INVALID_VIDEO_URL_PROTOCOL, INVALID_MIME_TYPE_HINT, VIDEO_TOO_LARGE, VIDEO_URL_UNREACHABLE, VIDEO_URL_NOT_A_VIDEO, YOUTUBE_VIDEO_UNAVAILABLE, NO_PAYMENT_METHOD, DOMAIN_CONTACT_REQUIRED, DOMAIN_UNAVAILABLE, DOMAIN_PREMIUM_NOT_ALLOWED, DOMAIN_PRICE_OVER_CAP, TLD_NOT_ALLOWED, DOMAIN_LIMIT_REACHED, PRICE_CHANGED, PAYMENT_FAILED, REGISTRATION_FAILED, DOMAIN_NOT_RENEWABLE, DOMAIN_ALREADY_ATTACHED, DNS_RECORD_MANAGED, DNS_RECORD_CONFLICT, DNS_RECORD_LIMIT, DOMAIN_TRANSFER_LOCKED, DOMAIN_NOT_FOUND, DOMAIN_IN_USE, DOMAIN_ALREADY_ADDED, PROJECT_HAS_CUSTOM_DOMAIN, NO_DEPLOYMENT, REDIRECT_LIMIT_REACHED, REDIRECT_INVALID, APEX_NOT_FLATTENABLE, SECOND_FACTOR_NOT_CONFIGURED, PASSWORD_REQUIRED, PASSWORD_INCORRECT, TOO_MANY_ATTEMPTS, CONFIRMATION_MISMATCH, INVALID_TOKEN, MISSING_PERMISSIONS, REPO_NOT_FOUND, REPO_MISSING_BRANCHES, UNKNOWN, SANDBOX_NOT_READY, SYNC_FAILED, TOKEN_EXPIRED, GITHUB_NOT_CONNECTED, FIGMA_TOKEN_MISSING, FIGMA_TOKEN_MALFORMED, FIGMA_TOKEN_INVALID, FIGMA_TOKEN_FORBIDDEN, FIGMA_RATE_LIMITED, FIGMA_UNREACHABLE, INVALID_IMPORT_CODE, IMPORT_SOURCE_GONE, PROJECT_NOT_IMPORTABLE, PROJECT_IMPORT_LIMIT_REACHED, PROJECT_EXPORT_LIMIT_REACHED, VERSION_NOT_FOUND, INVALID_CODE_EDIT, CODE_EDIT_FAILED, BADGE_IN_SOURCE.
#Versions and deprecations
Semantic versioning from 1.0.0: a minor release only adds, so an app written against 1.a runs unchanged on every
later 1.b. A replaced name keeps working for at least one major version: it is marked Deprecated below and logs
one console.warn naming its replacement the first time it runs — switch to the replacement when you touch that
code. The package's CHANGELOG.md lists every change.
#totalum-sdk
The default totalum object and createTotalum() give you every namespace on one object: totalum.files,
totalum.ai, totalum.email and the rest. Import it in server code and call the namespace you need; nothing is
read or sent until the first call. Every subpath (totalum-sdk/files, totalum-sdk/ai, …) also exports its own
factory (totalumFiles(), totalumAi(), …) for a smaller bundle, and the root re-exports all of them.
import { totalum } from 'totalum-sdk';
const page = await totalum.files.list({ limit: 20 });| Export | What it does |
|---|---|
createTotalum | Creates a totalum object with your own options — another project key, the dev environment, a test API URL. |
totalum | The default instance, configured from the environment (TOTALUM_PROJECT_KEY, TOTALUM_SDK_API_URL, TOTALUM_ENV): import it and call any namespace. |
Totalum | The type of totalum and of createTotalum()'s result: one property per namespace. |
TotalumOptions | The options of createTotalum(): every namespace's options in one object (each falls back to its env var). |
#createTotalum
createTotalum(options?: TotalumOptions): TotalumCreates a totalum object with your own options — another project key, the dev environment, a test API URL.
Every integration namespace is on it, each built on first access with the same options — no I/O and no env read
until a method is called. The database is totalumD1() from totalum-sdk/d1, not a namespace.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
options | TotalumOptions | no | Every namespace's options: key, apiUrl, env, filesUrl, aiBaseUrl; each falls back to its environment variable. |
options.aiBaseUrl | string | no | The OpenAI-compatible AI gateway gatewayConfig() returns; default TOTALUM_AI_BASE_URL, else https://ai.totalum.app/api/v1. |
options.key | string | no | Project key tlm_pk_…; default TOTALUM_PROJECT_KEY. Server-side only. |
options.apiUrl | string | no | The Totalum API's URL: default TOTALUM_SDK_API_URL, else https://sdk-api.totalum.app. |
options.env | 'dev' | 'live' | no | Sent as x-totalum-env on every call (the database it targets, and dev vs live usage); default TOTALUM_ENV, else live. |
options.filesUrl | string | no | The public files host files.url() uses; default TOTALUM_FILES_URL, else https://files.totalum-project.com. |
Returns Totalum — An object with every namespace (files, ai, email, …), like totalum.
Example
import { createTotalum } from 'totalum-sdk';
const devTotalum = createTotalum({ env: 'dev' });
await devTotalum.email.send({ to: 'ana@example.com', subject: 'Test', html: '<p>Test</p>' });#totalum
const totalum: TotalumThe default instance, configured from the environment (TOTALUM_PROJECT_KEY, TOTALUM_SDK_API_URL, TOTALUM_ENV):
import it and call any namespace. Use it in server code only.
Example
import { totalum } from 'totalum-sdk';
const page = await totalum.files.list({ limit: 10 });#Totalum type
The type of totalum and of createTotalum()'s result: one property per namespace.
| Field | Type | Always present | Description |
|---|---|---|---|
ai | TotalumAi | yes | AI from your server without any provider account: chat completions (streamed or not), structured JSON, a label out of a list, embeddings, image generation and editing, video generation and image description. See AI. |
analytics | TotalumAnalytics | yes | Your site's own traffic: page views, visits, unique visitors, errors, bytes and response times, as a time series or a top list (top pages, referrers, countries, devices, browsers). See Site Analytics. |
browser | TotalumBrowser | yes | A real Chrome in the cloud, driven over HTTPS from your server, so it works inside the published app: open pages, click, type, log in, fill forms, download files, take screenshots and PDFs, extract data. See Browser Automation. |
connections | TotalumConnections | yes | Let your app's users connect their own accounts of about 1,500 apps — Google Calendar, Gmail, Google Drive, Outlook, Slack, HubSpot, Notion, GitHub, Stripe, Airtable and more — and act on them from your server: create a calendar event, send an e-mail from their Gmail, read their files, or receive their events. See Connected Accounts. |
cron | TotalumCron | yes | Run a route of your own app on a schedule: every night at 8:00, every 15 minutes, the first day of the month. See Cron Jobs. |
email | TotalumEmail | yes | Send transactional e-mail (sign-up confirmations, receipts, notifications) from the project's own sender, and check whether it was delivered. See Email. |
files | TotalumFiles | yes | Store and serve your app's files (uploads, images, generated PDFs). See Files & Storage. |
logs | TotalumLogs | yes | Read your app's own server logs: the requests the published app (env: 'live') or the preview ('dev') handled, with their console lines, status codes and errors. See Logs. |
payments | TotalumPayments | yes | Take payments and subscriptions with Stripe on the project owner's own Stripe account (Stripe Connect), without handling card data: create a hosted Checkout, send the buyer to its url, and read the result back. See Payments. |
pdf | TotalumPdf | yes | Turn HTML or a web page into a PDF stored in the project's files: invoices, tickets, reports. See PDF. |
realtime | TotalumRealtime | yes | Live updates between the people using your app: chat, notifications, presence ("who is online"), collaborative editing, live dashboards and games. See Realtime. |
scan | TotalumScan | yes | Read documents and images: extract the fields you describe (an invoice's number, date and total) as JSON with document(), or get the plain text of every page with ocr(). See Document Scan / OCR. |
seo | TotalumSeo | yes | Tell search engines that pages of your custom domain changed (IndexNow), so new and edited pages are indexed in minutes instead of days. See SEO & IndexNow. |
speech | TotalumSpeech | yes | Speech to text (transcribe) and text to speech (synthesize): transcribe a recording or a voice note, read a text aloud, store the audio as a project file. See Speech. |
vectors | TotalumVectors | yes | Semantic search over your own content: store texts or images as vectors with metadata (upsert), then find the closest ones to a question, a text or an image (query). See Vector Search. |
web | TotalumWeb | yes | Read the web from your app: one page as Markdown or HTML (scrape), a web search (search), every URL of a site (map), a whole site in the background (crawl) and screenshots. See Web Scraping & Search. |
webhooks | TotalumWebhooks | yes | Receive Totalum's signed events (payments, e-mail delivery, browser programs, connected-account events, credits exhausted) and check that they really come from Totalum. See Webhooks. |
#TotalumOptions
The options of createTotalum(): every namespace's options in one object (each falls back to its env var).
| Name | Type | Required | Description |
|---|---|---|---|
aiBaseUrl | string | no | The OpenAI-compatible AI gateway gatewayConfig() returns; default TOTALUM_AI_BASE_URL, else https://ai.totalum.app/api/v1. |
key | string | no | Project key tlm_pk_…; default TOTALUM_PROJECT_KEY. Server-side only. |
apiUrl | string | no | The Totalum API's URL: default TOTALUM_SDK_API_URL, else https://sdk-api.totalum.app. |
env | 'dev' | 'live' | no | Sent as x-totalum-env on every call (the database it targets, and dev vs live usage); default TOTALUM_ENV, else live. |
filesUrl | string | no | The public files host files.url() uses; default TOTALUM_FILES_URL, else https://files.totalum-project.com. |
