# Changelog Source: https://docs.babysea.ai/changelog Product updates, new capabilities, and platform improvements. This changelog records customer-facing changes to the BabySea API, SDK, dashboard, models, and inference provider support. Subscribe to the [status page](https://status.babysea.ai) for incident updates. *** ### Webhook delivery hardening > May 14, 2026 Customer webhook delivery is now more reliable and more strict across the v1 generation API, provider callback recovery, dashboard test/replay actions, dead-letter queue retries, and low-balance credit alerts. BabySea now validates webhook destinations before delivery. Endpoints must use public HTTPS on the default HTTPS port, must not include URL credentials, and must not depend on redirects. Delivery rejects localhost, private, link-local, reserved, multicast, and translated IPv6 destinations, including hosts that resolve to blocked addresses. Outbound webhook delivery now uses a single signed delivery path with DNS pinning, redirect-free HTTPS requests, bounded response handling, and explicit wall-clock timeouts. Retry timing is now kept short and predictable so provider callbacks can finish promptly: immediate attempt, then 0.5s, 1.5s, 3s, and 5s retries. Generation terminal events are now deduplicated more aggressively when provider retries overlap, reducing duplicate `generation.completed`, `generation.failed`, and `generation.canceled` customer webhooks. Disabled endpoints now receive dead-letter queue entries consistently when subscribed events occur, including `credits.low_balance` alerts. Fal and Replicate callback validation is also more resilient. Incoming provider webhook bodies are size-limited while streaming, Replicate signatures now only accept `v1` signature components, and cached signing metadata is reused during temporary provider metadata refresh failures. No customer webhook payload or signature format changed. Existing consumers should continue verifying `X-BabySea-Signature` with the same `t=,v1=` format. *** ### API usage logging reliability > May 13, 2026 API key usage logging across all v1 routes is now awaited with explicit error handling. Logging failures are captured and surfaced in server logs without affecting the response returned to the caller. *** ### Playground > May 12, 2026 The browser playground now supports the full generation workflow end-to-end. Select any image or video model from the catalog, build a request using the schema-aware input panel, and send it directly against the US, EU, or JP API with your API key. The playground includes a model schema viewer, per-field validation, cURL export for every request, and a response panel with syntax-highlighted JSON. While a generation is in-flight, a live loading timeline shows the active provider, elapsed time, and failover steps as they happen, backed by Supabase Realtime for instant DB-driven status updates rather than client-side simulation. Content management operations: retrieve, cancel, and delete, are available in a separate panel below the generation section. *** ### Predictive provider routing and regional event pipeline > May 11, 2026 `generation_provider_order: "fastest"` now routes to providers using real-time rankings computed from generation latency and success data across all regions. Rankings are updated continuously and served from a low-latency cache, so `fastest` selects the best-performing provider for a given model at request time rather than using a static order. The platform now runs a regional event pipeline across US, EU, and JP. Generation events flow through a transactional outbox into a multi-region Kafka cluster and are ingested into a streaming analytics layer. This powers the predictive routing above and improves the accuracy of provider health signals used for failover. These changes are fully transparent, no API or SDK changes are required. `fastest` behavior improves automatically. *** ### Idempotency, concurrency, alerts, and provider order > April 29, 2026 Generation requests now support the `Idempotency-Key` header. Reusing the same key with the same request body returns the original response for 24 hours and includes `Idempotency-Replayed: true`. The TypeScript SDK exposes this through `client.generate()` with `options.idempotencyKey` and sets `idempotency_replayed` on replayed responses. Accounts now have per-plan concurrency caps for in-flight image and video generations. Requests above the cap return `BSE1009` with type `concurrency_limit_exceeded`. The low-balance alert default is now one `$0.50` threshold, and existing custom thresholds remain unchanged. Multi-provider models now accept `fastest` for `generation_provider_order`, and `fastest` is the default when the field is omitted. Explicit provider orders such as `replicate, fal` still override the default. See [idempotency](/setup/api#idempotency), [concurrency limits](/setup/api#concurrency-limits), and [low-balance alerts](/dashboard/credits#low-balance-alerts). *** ### Error handling and dashboard improvements > April 28, 2026 Error classification is more consistent across inference providers. Rate limits, capacity errors, service pause states, and provider-specific failures now map to clearer `BSE` codes so failover and retry behavior are easier to reason about. Credit usage totals now remain accurate across account history. The dashboard also improves provider display names, usage chart layout, and plan budget totals. *** ### Reliability and API consistency > April 27, 2026 Generation attempts now use consistent timeout behavior across inference providers. A slow or unavailable provider no longer blocks the full provider order from continuing. Cancellation and cleanup behavior is more reliable for concurrent requests. Content retrieval now enforces account ownership consistently, and protected health endpoints require API key authentication. Model integrations were updated for provider specification changes, including image editing support, `input_fidelity`, and schema consistency. *** ### Execution analytics and observability > April 22, 2026 The dashboard now shows generation outcomes, request volume, credit movement, webhook delivery, latency, model usage, and provider usage for each account. Use [metrics](/dashboard/metrics), [logs](/dashboard/logs), [credits](/dashboard/credits), and [activity](/dashboard/activity) to review usage and operational history. *** ### Alibaba Cloud > April 17, 2026 Alibaba Cloud is now available as an inference provider. You can select it with `generation_provider_order` when the chosen model supports it. *** ### OpenAI and Runway, plus 6 new models > April 8, 2026 OpenAI and Runway are now available as inference providers. The update also added 6 model identifiers to the catalog. Models added: * openai/gpt-image-1.5 * runway/gen4-aleph * runway/gen4-image * runway/gen4-image-turbo * runway/gen4-turbo * runway/gen4.5 *** ### Black Forest Labs and the FLUX 2 models > April 2, 2026 Black Forest Labs is now available as an inference provider, with support for the FLUX 2 model family. Models added: * bfl/flux-2-flex * bfl/flux-2-klein-9b * bfl/flux-2-max * bfl/flux-2-pro *** ### Public launch > March 27, 2026 BabySea launched with one regional API for image and video generation, signed webhooks, credit billing, API request logs, a browser playground, and the TypeScript SDK. The launch catalog included 74 image and video models across BytePlus, Cloudflare, Fal, and Replicate. Browse the current catalog in [models](/dashboard/models). # Activity Source: https://docs.babysea.ai/dashboard/activity Review the account audit feed and export selected events. Activity is the account audit feed. It records important dashboard, API, billing, webhook, credit, and compliance events in one searchable table. ## Access Activity is visible to all team roles. The page has no write actions. ## Event fields | Field | Description | | ----------- | --------------------------------------------------------- | | Event ID | Unique activity event ID. | | Actor | User ID or `system`. | | Category | Product area, such as `api_key`, `webhook`, or `billing`. | | Action | Machine-readable action name. | | Description | Human-readable event summary. | | Timestamp | Event creation time. | ## Categories BabySea can record events in these categories: | Category | Examples | | -------------- | ----------------------------------------------------------- | | `api_key` | key created, rotated, revoked, deleted | | `webhook` | endpoint created, toggled, secret rotated, delivery actions | | `credit` | credits reserved, charged, refunded, or added | | `generation` | generation lifecycle events | | `subscription` | subscription changes | | `membership` | member joined, role changed, or removed | | `account` | account or team setting changes | | `invitation` | team invitations | | `order` | one-time purchases | | `billing` | billing events | | `notification` | notification lifecycle | | `auth` | authentication events | | `domain` | custom domain changes | | `consent` | consent records | | `bug_report` | bug report submissions | ## Search The search box filters by: * description * action * category * actor The current dashboard loads the full feed and applies search client-side. ## Copy and export Select rows, then export or copy them from the table action menu: * copy selected rows as JSON * copy selected rows as CSV * download selected rows as JSON * download selected rows as CSV The page displays 200 rows per page and includes a fullscreen view. ## Retention Activity logs are pruned by plan: | Plan | Activity retention | | ---------- | ------------------ | | Free | 1 day | | Starter | 7 days | | Pro | 30 days | | Scale | 180 days | | Enterprise | 1 year | Records expire according to the retention window for the account plan. ## When to use activity and logs | Page | Use it for | | -------- | --------------------------------------------------- | | Activity | Who changed what in the account. | | Logs | Per-request API key traffic and API response codes. | | Credits | Credit balance and ledger movements. | | Webhook | Webhook endpoint delivery attempts and payloads. | # API keys Source: https://docs.babysea.ai/dashboard/api-keys Create, scope, rotate, revoke, delete, and audit BabySea API keys. API keys authenticate requests to the BabySea `/v1` API. A key belongs to one account, one region, and one set of scopes. ## Access | Role | Can view | Can create | Can rotate | Can revoke/delete | | --------------- | :------: | :--------: | :--------: | :---------------: | | `primary-owner` | Yes | Yes | Yes | Yes | | `owner` | Yes | Yes | Yes | Yes | | `member` | Yes | No | No | No | Members can inspect key metadata but management actions are disabled. ## Create a key From the dashboard, open **API keys** for the selected account. Use a clear name such as `production-worker-us` or `ci-smoke-tests`. Names can be up to 100 characters. Pick a preset or use custom scope triples. Set an expiration date or an IP allowlist. If no IPs are set, all client IPs are allowed. Copy the full `bye_...` key before closing the dialog. It cannot be retrieved later. ## Permission presets | Preset | Scopes | Use case | | ------------- | --------------------------------------------------------------------------------------------------------- | --------------------------------- | | Full Access | `generation:write`, `generation:read`, `generation:delete`, `account:read`, `health:read`, `library:read` | Admin scripts and development. | | Generate Only | `generation:write`, `generation:read`, `library:read` | Production generation workers. | | Read Only | `generation:read`, `account:read`, `health:read`, `library:read` | Reporting and dashboards. | | Monitor Only | `health:read`, `library:read` | Uptime monitors and catalog sync. | ## Scope reference | Scope | Routes | | ------------------- | ------------------------------------------------------------------------------------------------------------------------- | | `generation:write` | `POST /v1/generate/image/{model_identifier}`, `POST /v1/generate/video/{model_identifier}` | | `generation:read` | `GET /v1/content/{generation_id}`, `GET /v1/content/list` | | `generation:delete` | `DELETE /v1/content/{generation_id}`, `POST /v1/content/generation/cancel/{generation_id}` | | `account:read` | `GET /v1/status`, `GET /v1/usage`, `GET /v1/user/account`, `GET /v1/user/billing` | | `health:read` | `GET /v1/health/inference/providers`, `GET /v1/health/inference/models`, `GET /v1/health/storage`, `GET /v1/health/cache` | | `library:read` | `GET /v1/library/providers`, `GET /v1/library/models`, `GET /v1/estimate/{model_identifier}` | ## IP allowlists Use IP allowlists for fixed server workloads or CI runners. * Up to 50 entries per key. * Each entry can be up to 45 characters. * `null` allowlist means all IPs are allowed. * Disallowed clients receive `BSE1007` with type `ip_not_allowed`. ## Rotate a key Rotation creates a new key with the same scopes and IP allowlist. The old key stays valid during the grace period. | Setting | Value | | -------------------- | --------- | | Default grace period | 24 hours | | Minimum | 1 hour | | Maximum | 168 hours | Open the key action menu and choose **Rotate**. Store the new value in your secret manager and deploy it to all consumers. Confirm logs show traffic from the new key prefix. Revoke early if you are responding to exposure or no longer need the overlap. ## Revoke vs delete | Action | Effect | Use it when | | ------ | ------------------------------------------------------ | ------------------------------------------------- | | Revoke | Sets the key inactive. Metadata remains for audit. | You want to stop access but keep history visible. | | Delete | Permanently deletes the key row and cascades key logs. | You no longer need the key or its logs. | ## What is logged Every API request records key usage metadata: * key prefix * endpoint and method * status code * error code * idempotency replay flag * sanitized query parameters * SHA-256 IP hash * user agent * timestamp View these records in [logs](/dashboard/logs). # Billing Source: https://docs.babysea.ai/dashboard/billing Manage subscriptions, credit packs, billing portal access, and low-balance alerts. Billing shows the account plan, credit balance, checkout actions, billing portal access, credit packs, and low-balance alert settings. ## Access | Role | Can view billing | Can subscribe or purchase | | --------------- | :--------------: | :-----------------------: | | `primary-owner` | Yes | Yes | | `owner` | Yes | No | | `member` | Yes | No | Only the `primary-owner` can start checkout, buy credit packs, and manage low-balance alert settings from this page. ## Plans | Plan | Monthly credits | Yearly credits | General requests/min | Generations/min | Output file retention | | ---------- | ------------------ | ------------------ | -------------------- | --------------- | --------------------- | | Free | \$1 welcome credit | \$1 welcome credit | 30 | 10 | 1 hour | | Starter | \$9 | \$90 | 60 | 20 | 12 hours | | Pro | \$29 | \$290 | 150 | 50 | 1 day | | Scale | \$79 | \$790 | 300 | 100 | 5 days | | Enterprise | \$249 | \$2,490 | 600 | 200 | 7 days | Credit allocation is added to the account credit balance. One credit equals \$1 USD. ## Credit packs Credit packs are one-time add-ons on top of an active subscription. | Pack | Credits added | | ------- | ------------- | | \$10 | 10.000 | | \$25 | 25.000 | | \$50 | 50.000 | | \$100 | 100.000 | | \$500 | 500.000 | | \$1,000 | 1,000.000 | Requirements: * the account has an active subscription * the user is the `primary-owner` * checkout completes successfully with the billing provider If the subscription is no longer active by the time the payment webhook is processed, credits are not allocated automatically and the payment requires manual review. ## Billing portal When an account has a billing customer, the page shows a billing portal action for payment methods, invoices, and subscription management. If no billing data exists yet, the page shows checkout options for available plans. ## Low-balance alerts The **Low Balance Alerts** card lets the `primary-owner` manage alert thresholds and delivery channels. The same settings are available from [notifications](/setup/notifications). See [credits, low-balance alerts](/dashboard/credits#low-balance-alerts) for the defaults, channels, and webhook event. ## Retention by plan | Data category | Free | Starter | Pro | Scale | Enterprise | | ------------------ | ------- | ------- | -------- | -------- | ---------- | | Generation records | 1 day | 7 days | 30 days | 180 days | 1 year | | API request logs | 1 day | 7 days | 30 days | 180 days | 1 year | | Webhook event logs | 1 day | 7 days | 30 days | 180 days | 1 year | | Activity logs | 1 day | 7 days | 30 days | 180 days | 1 year | | Credit ledger | 30 days | 90 days | 180 days | 1 year | 1 year | # Credits Source: https://docs.babysea.ai/dashboard/credits Understand balances, reservations, charges, refunds, alerts, and the credit ledger. Credits are BabySea's spending balance. One credit equals \$1 USD, and balances are stored to three decimal places. ## Balance The Credits page shows the current account balance and the ledger of balance movements. | Concept | Meaning | | ------------- | ------------------------------------------ | | Balance | Current available credits for the account. | | Ledger | Immutable record of credit movements. | | Amount | Credit amount for that ledger event. | | Balance after | Balance after the movement was applied. | ## Ledger event types | Type | Effect | Created when | | --------- | ----------------- | ---------------------------------------------------------------- | | `reserve` | Deducts credits | A generation starts and BabySea reserves the estimated cost. | | `charge` | No balance change | A reserved generation succeeds and the reservation is confirmed. | | `refund` | Adds credits back | A reserved generation fails or is canceled before charge. | | `add` | Adds credits | Subscription renewal, welcome credit, or credit pack purchase. | Credit movements are idempotent for generation charges, refunds, and credit additions. ## Generation credit flow BabySea calculates the model cost from model pricing, output count, duration, resolution, and audio settings when applicable. BabySea checks the account balance and reserves the estimated cost. If the balance is too low, the API returns `BSE1004`. Successful jobs create a `charge` ledger entry. Failed or eligible canceled jobs create a `refund` entry and restore credits. ## Welcome credits New users receive \$1.000 in welcome credits once. ## Credit packs Credit packs are purchased from [billing](/dashboard/billing), not from the Credits page. | Pack | Credits added | | ------- | ------------- | | \$10 | 10.000 | | \$25 | 25.000 | | \$50 | 50.000 | | \$100 | 100.000 | | \$500 | 500.000 | | \$1,000 | 1,000.000 | Credit packs require an active subscription and can be purchased only by the `primary-owner`. ## Low-balance alerts Low-balance alerts are configured from the **Billing** page in the **Low Balance Alerts** card, and from the [notifications](/setup/notifications) page. The default is a single threshold at `$0.50`. You can replace the threshold list with up to 10 positive dollar amounts. Alerts can deliver through: * in-app notification * email * `credits.low_balance` webhook event Each threshold fires once while the balance remains below it. Adding or refunding credits re-arms thresholds that the balance rises above. See [webhooks](/setup/webhooks#credit-alert-payload) for the `credits.low_balance` payload. ## Search and export The ledger table shows type, amount, balance, model, generation ID, description, and timestamp. Search covers type, model, generation ID, description, and amount. The page displays 300 rows per page and includes a fullscreen view. ## Retention Credit audit trails have longer retention than operational logs. | Plan | Credit ledger retention | | ---------- | ----------------------- | | Free | 30 days | | Starter | 90 days | | Pro | 180 days | | Scale | 1 year | | Enterprise | 1 year | # Domains Source: https://docs.babysea.ai/dashboard/domains Configure an Enterprise custom API domain for your BabySea account. Domains let Enterprise accounts use a custom API hostname instead of the default regional BabySea endpoint. ## Availability | Plan | Custom API domain | | ---------- | :---------------: | | Free | No | | Starter | No | | Pro | No | | Scale | No | | Enterprise | Yes | Only the `custom` domain type is supported. Each account can have one custom domain, and a domain name can belong to only one BabySea account globally. ## Access | Role | Can view | Can add | Can verify | Can remove | | --------------- | :------: | :-----: | :--------: | :--------: | | `primary-owner` | Yes | Yes | Yes | Yes | | `owner` | Yes | Yes | Yes | Yes | | `member` | Yes | No | No | No | ## Add a custom domain From the dashboard, open **Domains** for an Enterprise account. Use a fully qualified lowercase hostname, such as `api.example.com`. Add the CNAME target shown in the dashboard at your DNS provider. Click **Verify** after DNS propagates. BabySea checks the domain and marks it active when the CNAME is valid. ## Statuses | Status | Meaning | | ---------- | -------------------------------------------------- | | `pending` | Domain is stored and waiting for DNS verification. | | `active` | Domain is verified and can route API traffic. | | `failed` | Provisioning or verification failed. | | `removing` | Domain removal is in progress. | ## DNS requirements * Use CNAME DNS, not A or AAAA records. * Keep the hostname lowercase. * Do not use a hostname already connected to another BabySea account. * DNS propagation can take time depending on your provider. ## Subscription changes Custom domains require an active Enterprise subscription. If the account is no longer eligible, the custom domain can be removed or disabled. ## Default endpoint All accounts can use the default regional endpoints: | Region value | Default API endpoint | | ------------ | ------------------------------ | | `us` | `https://api.us.babysea.ai/v1` | | `eu` | `https://api.eu.babysea.ai/v1` | | `jp` | `https://api.jp.babysea.ai/v1` | # Logs Source: https://docs.babysea.ai/dashboard/logs Search, inspect, copy, and export API request history. Logs show requests made with BabySea API keys. Use them to debug authentication, scope failures, rate limits, provider errors, and usage patterns. ## What is logged Each row joins request metadata with key metadata. | Field | Description | | ------------ | ------------------------------------------------------- | | API key name | Name assigned when the key was created. | | Key prefix | First 9 characters of the key, used for identification. | | Method | HTTP method. | | Endpoint | API path. | | Query params | Sanitized query string values. | | Status code | HTTP response status. | | Error code | `BSE` code when the request failed inside BabySea. | | Replay | Whether the request returned an idempotency replay. | | IP hash | SHA-256 hash of the client IP. Raw IPs are not shown. | | User agent | Client user agent. | | Timestamp | Request timestamp. | | Key status | Whether the key is active, expired, or rotated. | Logs do not store request bodies or raw API keys. ## Search The search box filters visible rows by: * key name * key prefix * endpoint * method * status code * error code * query params * replay flag * IP hash ## Copy and export Select rows, then use the table action menu to: * copy selected rows as JSON * copy selected rows as CSV * download selected rows as JSON * download selected rows as CSV The page displays 500 rows per page. For wide tables, use the fullscreen view from the top-right action button. ## Common debugging flows ### Invalid key Filter by `BSE1002` or HTTP `401`. Check whether the key is expired, revoked, from the wrong region, or copied incorrectly. ### Missing scope Filter by `BSE1003` or HTTP `403`. Compare the endpoint with the key scopes in [API keys](/dashboard/api-keys#scope-reference). ### IP allowlist issue Filter by `BSE1007`. Add the calling server IP to the key allowlist or remove the allowlist for dynamic client environments. ### Rate limit Filter by `BSE1005` or HTTP `429`. Account-level rate limits are shared by all keys in the account. ### Inference provider failure Filter by `BSE4`. Inference provider errors include timeouts, unavailable providers, upload failures, and all-provider failure states. ## Retention API request logs are pruned by plan: | Plan | API request log retention | | ---------- | ------------------------- | | Free | 1 day | | Starter | 7 days | | Pro | 30 days | | Scale | 180 days | | Enterprise | 1 year | Records expire according to the retention window for the account plan. # Members Source: https://docs.babysea.ai/dashboard/members Invite teammates, review pending invitations, and understand team roles. Members controls access to a team account. Team data is shared across members according to role and permissions. ## Roles BabySea uses a three-level role model in the dashboard. | Role | Description | | --------------- | ------------------------------------------------------------------------------------------------------------------------- | | `primary-owner` | The team creator or transferred owner. Highest privilege. Can manage billing purchases, settings, and ownership transfer. | | `owner` | Can manage operational resources such as API keys, webhooks, domains, and members when permissions allow. | | `member` | Can view many operational pages but cannot perform restricted management actions. | The dashboard treats the account owner as `primary-owner`. Other team members use `owner` or `member`. ## What you can do | Action | Description | | ------------------ | --------------------------------------------------------- | | View members | See current account members and roles. | | Invite members | Send pending invitations to new teammates. | | Review invitations | See pending invitations and their assigned roles. | | Manage roles | Change roles when your own role and permissions allow it. | | Transfer ownership | Available to the current primary owner. | ## Access The Members page is available to owners with member-management permissions. Users without sufficient permissions see a read-only or gated experience. ## Invitations Select the team account and open **Members**. Click the invite action and enter recipient details. Choose a role that does not exceed your own privilege level. Pending invites appear below the members table until accepted or removed. ## Permission boundaries * Users cannot grant a role above their own privilege level. * Ownership transfer is restricted to the primary owner. * Operational pages apply their own gates. For example, members can view API keys and webhooks but cannot create or rotate them. ## Related pages Review who can create and rotate keys. Review billing and purchase permissions. # Metrics Source: https://docs.babysea.ai/dashboard/metrics Review account usage, generation outcomes, webhook delivery, credits, and latency from the dashboard. Metrics shows account-level usage for the selected team account. Use it to check request volume, generation outcomes, credit spend, webhook delivery, and latency trends. ## Access Metrics is visible to every team role. The page has no write actions. ## Sections | Section | Shows | | ------------------ | --------------------------------------------------------------------------------------------- | | Plan card | Current plan, subscription state, renewal date, credit balance, and credits used this period. | | Content generation | Succeeded, failed, canceled, and failover counts, plus model, provider, and output summaries. | | API usage | Requests by status, method, endpoint, API key, and webhook delivery outcome. | | Performance | `P50`, `P95`, `P99`, average latency, inference time, and generation error breakdowns. | ## Time windows Metric cards and charts expose period selectors where history is available. Retention depends on your plan. See [billing](/dashboard/billing#retention-by-plan) for the canonical retention windows. ## Related pages | Page | Use it for | | ------------------------------- | ------------------------------------------------ | | [Logs](/dashboard/logs) | Inspect individual API requests and error codes. | | [Credits](/dashboard/credits) | Review balance movements and generation costs. | | [Webhook](/dashboard/webhook) | Inspect endpoint deliveries and queued events. | | [Activity](/dashboard/activity) | Review account-level audit events. | # Models Source: https://docs.babysea.ai/dashboard/models Browse supported image and video models, prices, schema fields, providers, and usage counts. Models lists the generation models available to the selected account. Use it to find a `model_identifier`, compare cost parameters, and check which inference providers can run a model. ## Access Models is visible to every team role. The page has no write actions. ## Table fields | Column | Description | | ---------------- | ------------------------------------------------------------------- | | Model identifier | API value passed to `client.generate()` or `/v1/generate/...`. | | Type | `image` or `video`. | | AI lab | Model publisher. | | Inference | Inference providers that can serve the model. | | Price | Credit price or price range for the model. | | Cost parameters | Pricing mode, such as per output, per second, resolution, or audio. | | Runs | Platform run count for the model. | | Yours | Run count for the selected account. | ## Search and fullscreen view The search box filters by model identifier, AI lab, model type, cost parameter, and inference provider. The page displays 500 rows per page and includes a fullscreen view. ## Schema and pricing source The dashboard table is a catalog view. Use the public model references for the request fields and prices that your integration should treat as canonical: | Reference | Use it for | | ------------------------------------------------- | -------------------------------------------------------- | | [Model schema](https://babysea.ai/model-schema) | Supported fields, allowed values, and copyable examples. | | [Model pricing](https://babysea.ai/model-pricing) | Per-model credit prices and pricing modes. | | [`GET /v1/library/models`](/setup/api#endpoints) | Programmatic model catalog access. | Use the exact `model_identifier` shown in the table when calling the API or SDK. # My profile Source: https://docs.babysea.ai/dashboard/my-profile Manage personal identity, authentication methods, MFA, linked identities, and account deletion. My profile controls your personal account settings. These settings follow your user, not a specific team account. ## Open profile settings Use **My profile** from the dashboard account menu, or open the personal settings route: ```text theme={null} /home/settings ``` Team-scoped user settings can also be reached from a team context at: ```text theme={null} /home/{account}/user-settings ``` ## What you can manage | Area | Description | | ------------------ | ----------------------------------------------------------- | | Display name | Name shown in the dashboard and account UI. | | Avatar | Personal profile image. | | Email and password | Available when password authentication is enabled. | | Magic link or OTP | Available when those auth providers are enabled. | | OAuth identities | Link or manage identities when identity linking is enabled. | | MFA | Configure multi-factor authentication when enabled. | | Account deletion | Available only when account deletion is enabled. | ## Personal vs team settings | Page | Scope | Use it for | | ------------- | ------------- | --------------------------------------------------------------------- | | My profile | Your user | Name, avatar, auth methods, MFA, linked identities, account deletion. | | Team settings | Selected team | Team name, team avatar, team slug, team deletion. | | Members | Selected team | Invites, roles, and ownership transfer. | ## Authentication changes When you update authentication settings, BabySea may redirect through the configured auth callback path and return you to settings after completion. ## Account deletion Personal account deletion appears only when it is enabled. When available, review your teams, API keys, billing, credits, and active webhooks before deleting your account. Deleting a personal account can remove or affect resources associated with accounts you own. Transfer ownership before deleting if teammates still need access. # Playground Source: https://docs.babysea.ai/dashboard/playground Use the browser playground to test model schemas, regions, generation requests, and content actions. The playground is a public browser console for testing BabySea API requests. It uses the same `/v1` API routes as your production code. Test image and video generation from the browser. ## What you can test | Area | Details | | ---------- | ---------------------------------------------------------------- | | Models | Image and video tabs with searchable model selection. | | Schema | Fields are derived from the registered model schemas. | | Regions | `us`, `eu`, and `jp` endpoints. | | Requests | `POST /v1/generate/image/...` and `POST /v1/generate/video/...`. | | Status | Live status updates with polling fallback. | | Management | Get, cancel, or delete a generation by ID. | ## API key handling The playground requires an API key for requests. * The key is typed manually. * The key must be locked before sending. * The key is never persisted to storage. * The key is cleared when the tab closes or reloads. * Control characters and bidirectional override characters are rejected. Use a scoped test key when possible. Do not paste production keys into shared machines or browser profiles. ## Region selection Choose the same region as your API key: | Region value | API host | | ------------ | ------------------- | | `us` | `api.us.babysea.ai` | | `eu` | `api.eu.babysea.ai` | | `jp` | `api.jp.babysea.ai` | Requests fail authentication if the key and regional hostname do not match. ## Request editor The form updates when you switch models. Supported fields can include: * `generation_prompt` * `generation_ratio` * `generation_output_format` * `generation_output_number` * `generation_input_file` * `generation_input_file_last_content` * `generation_duration` * `generation_resolution` * `generation_generate_audio` * model-specific fields The playground preserves your selected tab and model in session storage. It does not store the API key or request body. ## Send a generation Open the tab that matches the model type. Search by AI lab or model identifier. Paste a `bye_...` key for the same region and lock it. Use the generated form to send only fields supported by the selected model. The playground calls the corresponding `/v1/generate/...` route and shows the response JSON. ## Track results After a request starts, the response includes a `generation_id`. The playground tracks the generation with realtime updates and falls back to polling if the realtime channel disconnects. The response panel truncates very large JSON for display, but copied payloads include the full response subject to browser clipboard limits. ## Manage a generation Use the management section with a generation UUID: | Action | API route | Notes | | -------- | ---------------------------------------------------- | --------------------------------------------------------------------- | | Get info | `GET /v1/content/{generation_id}` | Fetches the current generation record. | | Cancel | `POST /v1/content/generation/cancel/{generation_id}` | Works only while the generation is still cancelable. | | Delete | `DELETE /v1/content/{generation_id}` | Deletes the generation and stored output files. This is irreversible. | Generation IDs must be valid UUIDs. ## Network safety The playground validates request hosts before sending. It blocks private, localhost, single-label, reserved-TLD, and internal hostnames to avoid accidental or unsafe destinations. # Settings Source: https://docs.babysea.ai/dashboard/settings Manage team identity, slug, avatar, and danger-zone actions. Settings controls team account identity. It is separate from personal profile settings. ## Access | Role | Can view | Can edit | | --------------- | :------: | :------: | | `primary-owner` | Yes | Yes | | `owner` | Yes | No | | `member` | Yes | No | The page is visible to team members, but editing is restricted to the `primary-owner`. ## Editable fields | Field | Description | | --------- | ------------------------------------------ | | Team name | Display name for the team account. | | Avatar | Team picture shown in the dashboard. | | Slug | URL segment used in team dashboard routes. | Changing a team slug changes dashboard URLs for that team. Share the new URL with team members if they have bookmarked account pages. ## Danger zone Team deletion appears only when it is enabled for the account. When available, only the `primary-owner` can delete the team. Team deletion is destructive. Review billing, API keys, webhooks, custom domains, logs, and stored generations before deleting a team. ## Related pages Invite members and manage roles. Manage your personal identity and auth settings. # Webhook Source: https://docs.babysea.ai/dashboard/webhook Create endpoints, choose events, rotate secrets, test delivery, and inspect webhook logs. Webhooks let your server receive signed BabySea events without polling. Use this dashboard page to manage endpoints and delivery history. Verify signatures, inspect payloads, and review delivery behavior. ## Access | Role | Can view | Can create/update | Can rotate secret | Can replay or deliver queued events | Can delete | | --------------- | :------: | :---------------: | :---------------: | :---------------------------------: | :--------: | | `primary-owner` | Yes | Yes | Yes | Yes | Yes | | `owner` | Yes | Yes | Yes | Yes | Yes | | `member` | Yes | No | No | No | No | Members can inspect endpoint metadata and delivery logs, but management actions are disabled. ## What you manage | Area | Description | | -------------- | ----------------------------------------------------------------------------------- | | Endpoint URL | Public HTTPS URL on the default HTTPS port that receives `POST` requests. | | Events | Subscribed event types, including `generation.completed` and `credits.low_balance`. | | Signing secret | `whsec_...` secret used to verify `X-BabySea-Signature`. | | Delivery log | Event type, generation ID, payload, status code, error, attempts, and timestamp. | | Queue | Pending generation events that arrived while the endpoint was disabled. | ## Create an endpoint From the dashboard, open **Webhook**. Enter a publicly reachable HTTPS URL on the default HTTPS port that accepts `POST` requests without redirecting. ```text theme={null} https://api.example.com/webhooks/babysea ``` Subscribe to the event types your server handles. Copy the `whsec_...` signing secret before closing the dialog. It cannot be retrieved later. Open the endpoint details page and click **Send test event**. Your handler should return any `2xx` status. ## Endpoint details Owners can use the endpoint details page to: * enable or disable the endpoint * rotate the webhook secret * send a test event * replay an individual delivery * deliver queued events * delete the endpoint Use [webhooks](/setup/webhooks#verify-signatures) for the raw-body verification flow before processing event data. ## Delivery log The delivery table shows: | Column | Description | | ------------- | ------------------------------------------------------------- | | Event | Event type, such as `generation.completed`. | | Generation ID | Related generation ID, when the event is generation-specific. | | Payload | JSON body sent to your endpoint. | | Status code | HTTP status returned by your endpoint. | | Error | Delivery error or non-`2xx` status summary. | | Attempts | Number of attempts recorded for the delivery. | | Timestamp | Delivery log timestamp. | ## Queued events If all retry attempts fail repeatedly, BabySea can disable the endpoint. Matching generation events that arrive while an endpoint is disabled are queued for later delivery. Use **Deliver queued events** after fixing the endpoint and re-enabling it. See [webhook delivery behavior](/setup/webhooks#delivery-behavior) for retry, timeout, auto-disable, and queue details. # Welcome Source: https://docs.babysea.ai/index Use BabySea to run image and video generation through one regional API and one response schema. BabySea is the execution control plane for generative media. Send one normalized request, run it across inference providers, and receive one consistent response shape. Create a key, submit a generation, and fetch the result. Regional base URLs, authentication, endpoints, envelopes, and rate limits. Create, track, cancel, delete, and list image and video generations. Use the official client for retries, typed responses, and webhook verification. Receive, verify, and process signed generation and credit events. Test models in the browser without writing setup code. ## What BabySea gives you | Capability | What it means | | ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Unified schema | Common fields such as `generation_prompt`, `generation_ratio`, `generation_input_file`, and `generation_provider_order` work across supported models. | | Provider routing | Requests use `generation_provider_order` for the selected model. Failed inference providers can be skipped and retried through the chain. | | Standard responses | Success responses include `status`, `request_id`, `message`, `timestamp`, and `data`. Error responses include `status`, `request_id`, and `error`. | | Credit accounting | One credit equals \$1 USD. Credits are reserved before generation, charged on success, and refunded on failure or eligible cancellation. | | Operational tools | Metrics, playground, models, API keys, webhooks, logs, credits, notifications, domains, members, settings, billing, and activity are managed from the dashboard. | ## Core API flow Create a key from the dashboard and choose a preset such as `Generate Only`, `Read Only`, or `Full Access`. Call `POST /v1/generate/image/{model_identifier}` or `POST /v1/generate/video/{model_identifier}` with a Bearer key. Use `GET /v1/content/{generation_id}` to poll, or subscribe to [webhook](/setup/webhooks) events for asynchronous delivery. Use logs, credits, activity, and billing pages to understand cost, failures, and team activity. ## Regions | Region value | Base URL | SDK value | | ------------ | ------------------------------ | --------- | | `us` | `https://api.us.babysea.ai/v1` | `us` | | `eu` | `https://api.eu.babysea.ai/v1` | `eu` | | `jp` | `https://api.jp.babysea.ai/v1` | `jp` | API keys are region-specific. Use the API hostname that matches the region where the key was created. ## Dashboard guides # Quickstart Source: https://docs.babysea.ai/quickstart Create an API key and run your first workload. This guide sends an image generation request, retrieves the result, and shows the same flow with the TypeScript SDK. ## 1. Create an API key Sign in to the [dashboard](https://us.babysea.ai/auth/sign-in), open **API keys**, and click **Create API key**. Choose one of these presets: | Preset | Use it for | | ------------- | ------------------------------------------------------------------------------- | | Full Access | Development, testing, and admin automation. | | Generate Only | Production generation workers. Includes create, read, and model catalog access. | | Read Only | Reporting tools that must not spend credits. | | Monitor Only | Health checks and model catalog sync. | BabySea shows the full key only once. Store it in a secrets manager before closing the dialog. ## 2. Pick the correct region Use the API hostname that matches where the key was created. | Region value | Base URL | | ------------ | ------------------------------ | | `us` | `https://api.us.babysea.ai/v1` | | `eu` | `https://api.eu.babysea.ai/v1` | | `jp` | `https://api.jp.babysea.ai/v1` | In examples below, replace `api.us.babysea.ai` with your region if needed. ## 3. Smoke-test the key `GET /v1/status` verifies the key and returns its account metadata. It requires the `account:read` scope. ```bash Terminal theme={null} curl https://api.us.babysea.ai/v1/status \ -H "Authorization: Bearer bye_your_api_key" ``` A valid key returns a success envelope: ```json JSON theme={null} { "status": "success", "request_id": "req_...", "message": "API connected successfully", "timestamp": "2026-04-28T12:00:00.000Z", "data": { "account_id": "0f0f6cc8-8e33-4f53-90f8-c59362a5b1bd", "apikey_id": "1b8a6d48-c8c5-4f6f-bb61-4e9cb85f0d93", "apikey_name": "Production key", "apikey_prefix": "bye_...", "apikey_created_at": "2026-04-28T11:45:00.000Z", "apikey_last_used_at": "2026-04-28T12:00:00.000Z", "apikey_expires_at": null } } ``` If you created a `Generate Only` key, skip this status check and call a generation or library endpoint instead. That preset does not include `account:read`. ## 4. Submit a generation Use an `Idempotency-Key` when the same user action or queue job might retry. ```bash Terminal theme={null} curl -X POST https://api.us.babysea.ai/v1/generate/image/bfl/flux-schnell \ -H "Authorization: Bearer bye_your_api_key" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: 5b3e1c8a-9c1f-4d2e-9b3f-7c0a1e9d2f4c" \ -d '{ "generation_prompt": "A baby seal playing on Arctic ice", "generation_ratio": "1:1", "generation_output_format": "png" }' ``` ```bash Terminal theme={null} curl -X POST https://api.us.babysea.ai/v1/generate/video/google/veo-2 \ -H "Authorization: Bearer bye_your_api_key" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: 49a13f4d-88b5-4e02-9173-108b2d2a6c61" \ -d '{ "generation_prompt": "A penguin swimming under Antarctic ice", "generation_duration": 5 }' ``` BabySea validates the request, checks the key scope, reserves credits, creates a generation record, and returns a `generation_id`. ```json JSON theme={null} { "status": "success", "request_id": "req_...", "message": "Generation initialized", "timestamp": "2026-04-28T12:00:00.000Z", "data": { "model_identifier": "bfl/flux-schnell", "generation_provider_order": ["bfl", "replicate"], "generation_prediction_id": "pred_...", "generation_id": "550e8400-e29b-41d4-a716-446655440000", "generation_initialized": true } } ``` ## 5. Fetch the result Poll `GET /v1/content/{generation_id}` until `generation_status` is `succeeded`, `failed`, or `canceled`. ```bash Terminal theme={null} curl https://api.us.babysea.ai/v1/content/550e8400-e29b-41d4-a716-446655440000 \ -H "Authorization: Bearer bye_your_api_key" ``` Typical statuses: | Status | Meaning | | ------------ | --------------------------------------------------------------------- | | `pending` | BabySea created the record and is preparing provider execution. | | `processing` | An inference provider is running the generation. | | `succeeded` | Output URLs are available in `generation_output_file`. | | `failed` | The job failed. Check `generation_error_code` and `generation_error`. | | `canceled` | The job was canceled before completion. | ## 6. Use the SDK ```ts TypeScript theme={null} import { BabySea } from 'babysea'; const client = new BabySea({ apiKey: process.env.BABYSEA_API_KEY!, region: 'us', }); const created = await client.generate('bfl/flux-schnell', { generation_prompt: 'A baby seal playing on Arctic ice', generation_ratio: '1:1', generation_output_format: 'png', }); let generation = await client.getGeneration(created.data.generation_id); while (['pending', 'processing'].includes(generation.data.generation_status)) { await new Promise((resolve) => setTimeout(resolve, 2_000)); generation = await client.getGeneration(created.data.generation_id); } console.log( generation.data.generation_status, generation.data.generation_output_file, ); ``` ## Production checklist * Use a `Generate Only` key for generation workers. * Add an IP allowlist when requests come from fixed infrastructure. * Use [idempotency](/setup/api#idempotency) for queue retries and user-triggered retries. * Register a [webhook endpoint](/setup/webhooks) instead of polling in hot paths. * Review the [generation lifecycle](/setup/generations) before adding cancel or delete controls. * Use [errors](/setup/errors) to distinguish retryable provider errors from request issues. * Monitor [logs](/dashboard/logs), [credits](/dashboard/credits), and [activity](/dashboard/activity) after launch. # API Source: https://docs.babysea.ai/setup/api Use regional base URLs, authentication, endpoints, response envelopes, rate limits, and idempotency. BabySea exposes a regional `/v1` API for image and video generation. App-level responses use one envelope and one error format across inference providers. Create, track, cancel, delete, and list generation records. Receive signed generation and credit events. Browse model identifiers, supported fields, pricing, and request examples. ## Base URLs | Region value | Base URL | | ------------ | ------------------------------ | | `us` | `https://api.us.babysea.ai/v1` | | `eu` | `https://api.eu.babysea.ai/v1` | | `jp` | `https://api.jp.babysea.ai/v1` | API keys are region-specific. A key created in one region cannot authenticate against a different regional hostname. ## Authentication Pass the key in the `Authorization` header: ```bash Terminal theme={null} Authorization: Bearer bye_your_api_key ``` Keys start with `bye_`. The full key is shown once when you create or rotate it. ## Endpoints | Method | Path | Scope | Description | | ------ | ----------------------------------------------- | ------------------- | ---------------------------------------------------------------------------------------------------------------------- | | GET | `/v1/status` | `account:read` | API key and account identity. | | GET | `/v1/usage` | `account:read` | Request and generation usage. Accepts `days` from 1 to 90. | | GET | `/v1/user/account` | `account:read` | Account profile. | | GET | `/v1/user/billing` | `account:read` | Plan, credit balance, and subscription period. | | GET | `/v1/estimate/{model_identifier}` | `library:read` | Estimate cost. Accepts `count`, `duration`, `resolution`, and `audio`. `count` defaults to `1` and is capped at `100`. | | POST | `/v1/generate/image/{model_identifier}` | `generation:write` | Start an image generation. | | POST | `/v1/generate/video/{model_identifier}` | `generation:write` | Start a video generation. | | GET | `/v1/content/{generation_id}` | `generation:read` | Retrieve one generation record. | | GET | `/v1/content/list` | `generation:read` | List generation records. See [generations](/setup/generations#list-generations) for pagination defaults. | | DELETE | `/v1/content/{generation_id}` | `generation:delete` | Delete a generation and stored output files. | | POST | `/v1/content/generation/cancel/{generation_id}` | `generation:delete` | Cancel an in-flight generation when it is still cancelable. | | GET | `/v1/health/inference/providers` | `health:read` | Inference provider availability. | | GET | `/v1/health/inference/models` | `health:read` | Model availability by inference provider. | | GET | `/v1/health/storage` | `health:read` | Storage health. | | GET | `/v1/health/cache` | `health:read` | Cache health. | | GET | `/v1/library/providers` | `library:read` | Inference provider catalog. | | GET | `/v1/library/models` | `library:read` | Model catalog, schemas, inference providers, and pricing. | ## Generation request fields Every model has a strict schema. Use `/v1/library/models`, the [playground](/dashboard/playground), or the model schema reference to inspect allowed values for a model. | Field | Type | Notes | | ------------------------------------ | --------- | ---------------------------------------------------------------------------------------------- | | `generation_prompt` | string | Prompt text. Required for most models. | | `generation_ratio` | string | Aspect ratio, such as `1:1` or `16:9`. Allowed values are model-specific. | | `generation_output_format` | string | Output format, such as `png`, `jpg`, `webp`, or `mp4`. | | `generation_output_number` | number | Number of requested outputs. Maximum is model-specific. | | `generation_input_file` | string\[] | Public file URLs for image-to-image or image-to-video models. | | `generation_input_file_last_content` | string | Optional last-frame URL for video models that support it. | | `generation_duration` | number | Required for video models. Allowed durations are model-specific. | | `generation_resolution` | string | Used by models with resolution-specific pricing. | | `generation_generate_audio` | boolean | Used by video models with audio pricing. | | `generation_provider_order` | string | Optional provider priority. Use `fastest` or a model-supported order such as `replicate, fal`. | Unknown or unsupported fields are rejected for strict model schemas. ## Success envelope Successful app-level API responses use this envelope: ```json JSON theme={null} { "status": "success", "request_id": "req_...", "message": "Operation successful", "timestamp": "2026-04-28T12:00:00.000Z", "data": {} } ``` Paginated responses add `total`, `limit`, and `offset` next to `data`. ## Error envelope Structured `BSE` errors use this envelope: ```json JSON theme={null} { "status": "error", "request_id": "req_...", "error": { "code": "BSE1002", "type": "authentication_failed", "message": "Invalid or expired API key.", "retryable": false, "details": {} } } ``` See [errors](/setup/errors) for the full code list. ## Rate limits Limits are per account, not per key. All keys under the same account share the same bucket. | Plan | General requests/min | Generation requests/min | | ---------- | -------------------- | ----------------------- | | Free | 30 | 10 | | Starter | 60 | 20 | | Pro | 150 | 50 | | Scale | 300 | 100 | | Enterprise | 600 | 200 | Rate-limited responses include `Retry-After`. All rate-limited routes include: * `X-RateLimit-Limit` * `X-RateLimit-Remaining` * `X-RateLimit-Reset` ## Concurrency limits In addition to per-minute rate limits, BabySea caps the number of generations that can be in flight at the same time per account. Image and video are tracked separately. | Plan | Image in flight | Video in flight | | ---------- | --------------- | --------------- | | Free | 2 | 1 | | Starter | 5 | 2 | | Pro | 15 | 5 | | Scale | 30 | 10 | | Enterprise | 60 | 20 | When the cap is reached, additional generation create requests return `BSE1009` (`concurrency_limit_exceeded`, HTTP `429`, retryable). Reduce parallelism or retry after active create requests finish. ## Idempotency `POST /v1/generate/image/*` and `POST /v1/generate/video/*` accept an optional `Idempotency-Key` request header. Use it to safely retry a generation request (for example after a network error) without creating duplicate work or duplicate charges. ```bash Terminal theme={null} curl https://api.us.babysea.ai/v1/generate/image/bfl/flux-schnell \ -H "Authorization: Bearer bye_your_api_key" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: 5b3e1c8a-9c1f-4d2e-9b3f-7c0a1e9d2f4c" \ -d '{"generation_prompt":"A baby seal playing on Arctic ice"}' ``` Behavior: * Keys must match `[A-Za-z0-9_\-:.]{1,255}`. UUIDs work well. * Cached responses are returned for 24 hours after the original request completes. * A replayed response includes the `Idempotency-Replayed: true` response header. The original `request_id`, status code, and body are returned exactly as before. * Reusing a key with a different request body returns `BSE2015` (`idempotency_key_conflict`, HTTP `409`). * Reusing a key while the original request is still processing returns `BSE2016` (`idempotency_request_in_progress`, HTTP `409`, retryable). * Idempotency is scoped per account. ## Malformed requests Requests with an invalid method, path, parameter shape, or body shape can be rejected before BabySea returns a structured `BSE` error. Validate the request shape before retrying. # Errors Source: https://docs.babysea.ai/setup/errors Understand BabySea error envelopes, codes, retry behavior, and rate-limit headers. BabySea returns structured `BSE` errors from application routes. Each error includes a stable code, a machine-readable type, a human-readable message, and a `retryable` boolean. ## Error envelope ```json JSON theme={null} { "status": "error", "request_id": "req_...", "error": { "code": "BSE1005", "type": "rate_limit_exceeded", "message": "Rate limit exceeded. Please retry after the period indicated in the Retry-After header.", "retryable": true, "details": { "retry_after_seconds": 17, "limit": 60 } } } ``` When multiple providers fail during failover, the error can include `provider_errors` with provider-level details. ## Retry guidance | Condition | Retry? | Notes | | --------------------------------- | :----: | ---------------------------------------------------------------------- | | `retryable: true` | Yes | Use exponential backoff. The SDK retries these automatically. | | HTTP `429` | Yes | Respect `Retry-After`. | | HTTP `4xx` except `429` | No | Fix authentication, scope, input, or account state. | | HTTP `5xx` with `retryable: true` | Yes | Usually provider or transient infrastructure failure. | | `provider_credits_exhausted` | No | Choose another model/provider or wait for provider capacity to return. | Use the `retryable` field, not only the HTTP status code. Some inference provider failures use `5xx` but are not retryable. ## Authentication and authorization | Code | Type | HTTP | Retryable | Meaning | | --------- | ---------------------------- | ---- | :-------: | ----------------------------------------------------------- | | `BSE1001` | `authentication_required` | 401 | No | Missing API key. | | `BSE1002` | `authentication_failed` | 401 | No | Invalid or expired API key. | | `BSE1003` | `insufficient_permissions` | 403 | No | Key lacks the required scope. | | `BSE1004` | `insufficient_credits` | 402 | No | Account balance cannot cover the request. | | `BSE1005` | `rate_limit_exceeded` | 429 | Yes | Account request limit exceeded. | | `BSE1006` | `auth_rate_limited` | 429 | Yes | Too many authentication attempts from the same IP. | | `BSE1007` | `ip_not_allowed` | 403 | No | Client IP is not in the key allowlist. | | `BSE1008` | `account_not_found` | 404 | No | The account linked to the key was not found. | | `BSE1009` | `concurrency_limit_exceeded` | 429 | Yes | Too many concurrent generations in flight for this account. | ## Input validation | Code | Type | HTTP | Retryable | Meaning | | --------- | ---------------------------------- | ---- | :-------: | --------------------------------------------------------------- | | `BSE2001` | `invalid_input` | 400 | No | Request body has invalid parameters. | | `BSE2002` | `file_too_large` | 422 | No | File dimensions exceed model limits. | | `BSE2003` | `file_too_small` | 422 | No | File dimensions are below model minimums. | | `BSE2004` | `unsupported_file_format` | 422 | No | File type is unsupported. | | `BSE2005` | `file_load_error` | 422 | No | File could not be loaded or processed. | | `BSE2006` | `content_policy_violation` | 422 | No | Input was rejected by safety filters. | | `BSE2007` | `file_size_exceeded` | 422 | No | File exceeds byte-size limits. | | `BSE2008` | `parameter_out_of_range` | 422 | No | Parameter value is outside the allowed range. | | `BSE2009` | `file_download_error` | 422 | No | BabySea could not download a file URL. | | `BSE2010` | `request_body_too_large` | 413 | No | Request body exceeds the maximum allowed size. | | `BSE2011` | `generation_not_found` | 404 | No | Generation does not exist or belongs to another account. | | `BSE2012` | `generation_not_cancelable` | 409 | No | Generation already completed, failed, or was canceled. | | `BSE2013` | `generation_cancel_window_expired` | 409 | No | Generations can only be canceled within 12 seconds of creation. | | `BSE2014` | `unsafe_file_url` | 422 | No | URL targets private, reserved, or non-HTTPS infrastructure. | | `BSE2015` | `idempotency_key_conflict` | 409 | No | `Idempotency-Key` was reused with a different request body. | | `BSE2016` | `idempotency_request_in_progress` | 409 | Yes | Request with this `Idempotency-Key` is still being processed. | | `BSE2017` | `endpoint_not_found` | 404 | No | The requested endpoint does not exist. | ## Model and configuration | Code | Type | HTTP | Retryable | Meaning | | --------- | ----------------------- | ---- | :-------: | --------------------------------------------------- | | `BSE3001` | `model_not_found` | 404 | No | Unknown model identifier. | | `BSE3002` | `model_not_configured` | 500 | No | Model exists but configuration is incomplete. | | `BSE3003` | `feature_not_supported` | 422 | No | Field or combination is not supported by the model. | | `BSE3004` | `model_type_mismatch` | 422 | No | Model type does not match the image or video route. | ## Inference provider errors | Code | Type | HTTP | Retryable | Meaning | | --------- | ------------------------------ | ---- | :-------: | -------------------------------------------------- | | `BSE4001` | `provider_timeout` | 504 | Yes | Inference provider did not respond in time. | | `BSE4002` | `provider_out_of_memory` | 502 | Yes | Inference provider ran out of memory. | | `BSE4003` | `all_providers_failed` | 502 | Yes | Every inference provider in the chain failed. | | `BSE4004` | `provider_internal_error` | 502 | Yes | Inference provider returned an internal error. | | `BSE4005` | `provider_unavailable` | 503 | Yes | Inference provider is temporarily unavailable. | | `BSE4006` | `prediction_canceled` | 409 | No | Inference provider prediction was canceled. | | `BSE4007` | `provider_health_check_failed` | 502 | Yes | Inference provider failed health checks. | | `BSE4008` | `provider_start_error` | 502 | Yes | Inference provider failed to start the prediction. | | `BSE4009` | `provider_upload_failed` | 502 | Yes | Upload to inference provider failed. | | `BSE4010` | `provider_credits_exhausted` | 502 | No | Inference provider capacity is exhausted. | ## Internal errors | Code | Type | HTTP | Retryable | Meaning | | --------- | ----------------------- | ---- | :-------: | ---------------------------------- | | `BSE5001` | `internal_server_error` | 500 | No | Unexpected server error. | | `BSE5002` | `database_error` | 500 | No | Database read or write failed. | | `BSE5003` | `storage_error` | 500 | No | File storage read or write failed. | ## Rate-limit headers Rate-limited routes include these headers: | Header | Description | | ----------------------- | -------------------------------------------------- | | `X-RateLimit-Limit` | Maximum requests in the current 60-second window. | | `X-RateLimit-Remaining` | Remaining requests in the current window. | | `X-RateLimit-Reset` | Unix timestamp when the window resets. | | `Retry-After` | Present on `429`; seconds to wait before retrying. | ## Malformed requests Malformed requests can be rejected before BabySea returns a structured `BSE` envelope. Validate the method, path, body shape, and headers before retrying. # Generations Source: https://docs.babysea.ai/setup/generations Create, track, cancel, delete, and list image and video generations. Generations are asynchronous image or video workloads submitted through the regional `/v1` API. This page covers lifecycle fields, retry safety, and content management routes. ## Lifecycle | Status | Meaning | Terminal | | ------------ | ------------------------------------------------------------------------------ | :------: | | `pending` | BabySea accepted the request and created a generation record. | No | | `processing` | An inference provider is running the generation. | No | | `succeeded` | Output URLs are available in `generation_output_file`. | Yes | | `failed` | The generation failed. Inspect `generation_error_code` and `generation_error`. | Yes | | `canceled` | The generation was canceled before completion. | Yes | Use [webhooks](/setup/webhooks) for production completion handling. Polling is useful for CLIs, tests, and low-throughput workflows. ## Create a generation Image and video generations use separate routes. Use the model schema reference, the [models](/dashboard/models) page, or `GET /v1/library/models` to inspect supported fields for each `model_identifier`. | Type | Route | Required body signal | | ----- | -------------------------------------------- | --------------------------------------------------------------------- | | Image | `POST /v1/generate/image/{model_identifier}` | Model-specific image fields. | | Video | `POST /v1/generate/video/{model_identifier}` | Model-specific video fields, usually including `generation_duration`. | ```bash Terminal theme={null} curl -X POST https://api.us.babysea.ai/v1/generate/image/bfl/flux-schnell \ -H "Authorization: Bearer bye_your_api_key" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: 5b3e1c8a-9c1f-4d2e-9b3f-7c0a1e9d2f4c" \ -d '{ "generation_prompt": "A baby seal playing on Arctic ice", "generation_ratio": "1:1", "generation_output_format": "png", "generation_provider_order": "fastest" }' ``` A successful create response returns a `generation_id` immediately. ```json JSON theme={null} { "status": "success", "request_id": "req_...", "message": "Generation initialized", "timestamp": "2026-04-28T12:00:00.000Z", "data": { "model_identifier": "bfl/flux-schnell", "generation_provider_order": ["bfl", "replicate"], "generation_prediction_id": "pred_...", "generation_id": "550e8400-e29b-41d4-a716-446655440000", "generation_initialized": true } } ``` ## Retry safely Send an `Idempotency-Key` header on generation create requests when retries can happen from your queue, browser, worker, or SDK client. | Case | Result | | ------------------------------------------------------- | -------------------------------------------------------------------------------- | | Same key and same body within the replay window | BabySea returns the original response and includes `Idempotency-Replayed: true`. | | Same key with a different body | BabySea returns `BSE2015` with HTTP `409`. | | Same key while the original request is still processing | BabySea returns `BSE2016` with HTTP `409`. | See [Idempotency](/setup/api#idempotency) for the replay window and full contract. ## Provider order `generation_provider_order` controls the order used for a model that supports more than one inference provider. | Value | Behavior | | -------------- | ------------------------------------------------------------------------------ | | Omitted | Uses the model default. | | `fastest` | Lets BabySea choose the provider order from current regional performance data. | | Explicit order | Uses a model-supported value such as `replicate, fal`. | The create response returns the resolved `generation_provider_order` as an array. ## Fetch a generation Poll `GET /v1/content/{generation_id}` until `generation_status` is terminal. ```bash Terminal theme={null} curl https://api.us.babysea.ai/v1/content/550e8400-e29b-41d4-a716-446655440000 \ -H "Authorization: Bearer bye_your_api_key" ``` ```json JSON theme={null} { "status": "success", "request_id": "req_...", "message": "Generation info retrieved successfully", "timestamp": "2026-04-28T12:00:12.000Z", "data": { "account_id": "0f0f6cc8-8e33-4f53-90f8-c59362a5b1bd", "generation_id": "550e8400-e29b-41d4-a716-446655440000", "model_identifier": "bfl/flux-schnell", "generation_provider_order": ["bfl", "replicate"], "generation_provider_used": "bfl", "generation_prediction_id": "pred_...", "generation_status": "succeeded", "generation_output_file": ["https://cdn.example.com/output.png"] } } ``` ## List generations `GET /v1/content/list` returns paginated generation records for the authenticated account. | Query parameter | Default | Limit | | --------------- | ------- | -------------- | | `limit` | `50` | Maximum `100`. | | `offset` | `0` | Minimum `0`. | ```bash Terminal theme={null} curl "https://api.us.babysea.ai/v1/content/list?limit=50&offset=0" \ -H "Authorization: Bearer bye_your_api_key" ``` Paginated responses include `total`, `limit`, and `offset` next to `data`. ## Cancel a generation Use `POST /v1/content/generation/cancel/{generation_id}` when a generation is still cancelable. ```bash Terminal theme={null} curl -X POST https://api.us.babysea.ai/v1/content/generation/cancel/550e8400-e29b-41d4-a716-446655440000 \ -H "Authorization: Bearer bye_your_api_key" ``` Cancel requests can return: | Code | Meaning | | --------- | ---------------------------------------------------------- | | `BSE2011` | The generation does not exist for the account. | | `BSE2012` | The generation already completed, failed, or was canceled. | | `BSE2013` | The cancel window has expired. | Eligible cancellations refund reserved credits. See [Errors](/setup/errors#input-validation) for the current cancel window. ## Delete a generation `DELETE /v1/content/{generation_id}` deletes the generation record and stored output files for that generation. ```bash Terminal theme={null} curl -X DELETE https://api.us.babysea.ai/v1/content/550e8400-e29b-41d4-a716-446655440000 \ -H "Authorization: Bearer bye_your_api_key" ``` ```json JSON theme={null} { "status": "success", "request_id": "req_...", "message": "Generation deleted successfully", "timestamp": "2026-04-28T12:05:00.000Z", "data": { "generation_id": "550e8400-e29b-41d4-a716-446655440000", "files_deleted": 1 } } ``` Deletion is irreversible. Output file and generation record retention windows are listed in [billing](/dashboard/billing#retention-by-plan). # Notifications Source: https://docs.babysea.ai/setup/notifications Manage low-balance alert thresholds and delivery channels for an account. Notifications controls account-level low-balance alert preferences. The same settings can also appear in the Billing credit balance card. ## Access | Role | Can view | Can manage | | --------------- | :------: | :--------: | | `primary-owner` | Yes | Yes | | `owner` | Yes | No | | `member` | Yes | No | Only the `primary-owner` can change thresholds or delivery channels. ## Low-balance settings | Setting | Description | | ---------- | --------------------------------------------------------------------- | | Enabled | Turns low-balance alerts on or off for the account. | | Thresholds | Dollar amounts that trigger alerts when the balance drops below them. | | In-app | Sends an in-app notification. | | Email | Sends an email to the account owner. | | Webhook | Sends the `credits.low_balance` webhook event. | See [Credits, low-balance alerts](/dashboard/credits#low-balance-alerts) for the default threshold, threshold limit, and alert behavior. ## Behavior Each threshold fires once while the balance remains below it. Adding or refunding credits re-arms thresholds that the balance rises above. See [webhooks](/setup/webhooks#credit-alert-payload) for the `credits.low_balance` payload. ## Related pages View plan status, credit balance, credit packs, and embedded alert settings. Review credit ledger entries, reservations, charges, refunds, and alert behavior. # SDK Source: https://docs.babysea.ai/setup/sdk Install the TypeScript SDK, create generations, handle errors, and verify webhooks. The `babysea` package calls the `/v1` API with typed responses, request timeouts, retry handling, and webhook signature verification. Install the official TypeScript SDK. View the package source and examples. ## Install ```bash npm theme={null} npm install babysea ``` ```bash pnpm theme={null} pnpm add babysea ``` ```bash yarn theme={null} yarn add babysea ``` ## Create a client ```ts TypeScript theme={null} import { BabySea } from 'babysea'; const client = new BabySea({ apiKey: process.env.BABYSEA_API_KEY!, region: 'us', }); ``` | Option | Type | Default | Description | | ------------ | ------------------- | -------- | ------------------------------------------------------------- | | `apiKey` | string | required | BabySea API key, for example `bye_...`. | | `region` | `us`, `eu`, or `jp` | `us` | Regional endpoint. Ignored when `baseUrl` is set. | | `baseUrl` | string | none | Full API origin override, without requiring a region. | | `timeout` | number | `30000` | Request timeout in milliseconds. | | `maxRetries` | number | `2` | Automatic retries for API errors where `retryable` is `true`. | ## Generate an image ```ts TypeScript theme={null} const created = await client.generate('bfl/flux-schnell', { generation_prompt: 'A baby seal playing on Arctic ice', generation_ratio: '1:1', generation_output_format: 'png', }); console.log(created.data.generation_id); ``` `client.generate()` chooses the route from the request body: * no `generation_duration`: `POST /v1/generate/image/{model_identifier}` * `generation_duration` present: `POST /v1/generate/video/{model_identifier}` ## Generate a video ```ts TypeScript theme={null} const created = await client.generate('google/veo-2', { generation_prompt: 'A penguin swimming under Antarctic ice', generation_duration: 5, }); ``` ## Idempotent retries Pass an `Idempotency-Key` to safely retry a generation request without creating duplicate work or duplicate charges. The SDK forwards it as the `Idempotency-Key` request header. ```ts TypeScript theme={null} import { randomUUID } from 'node:crypto'; const idempotencyKey = randomUUID(); const created = await client.generate( 'bfl/flux-schnell', { generation_prompt: 'A baby seal playing on Arctic ice' }, { idempotencyKey }, ); if (created.idempotency_replayed) { console.log('Got cached response for', idempotencyKey); } ``` Persist the key alongside the action that triggers the request, and reuse the same key for every retry of that action. See [idempotency](/setup/api#idempotency) for the replay window and full contract. ## Poll a generation ```ts TypeScript theme={null} let generation = await client.getGeneration(created.data.generation_id); while (['pending', 'processing'].includes(generation.data.generation_status)) { await new Promise((resolve) => setTimeout(resolve, 2_000)); generation = await client.getGeneration(created.data.generation_id); } if (generation.data.generation_status === 'succeeded') { console.log(generation.data.generation_output_file); } ``` Use [webhooks](/setup/webhooks) for production paths that should not poll. ## Generate and wait `client.generateAndWait()` creates a generation and polls until it reaches a terminal status. It returns the generation when `generation_status` is `succeeded` and throws `BabySeaGenerationFailedError` when the generation fails or is canceled. Use it for scripts and demos. For production throughput, prefer `client.generate()` with webhooks. ```ts TypeScript theme={null} const generation = await client.generateAndWait( 'bfl/flux-schnell', { generation_prompt: 'A baby seal playing on Arctic ice', generation_ratio: '1:1', }, { timeout: 120_000, interval: 2_000, }, ); console.log(generation.data.generation_output_file); ``` `client.waitForGeneration()` accepts the same `timeout`, `interval`, and `signal` options when you already have a `generation_id`. ## Client methods | Method | Endpoint | | ----------------------------------------------------------- | --------------------------------------------------------------- | | `client.status()` | `GET /v1/status` | | `client.usage(days?)` | `GET /v1/usage` | | `client.account()` | `GET /v1/user/account` | | `client.billing()` | `GET /v1/user/billing` | | `client.estimate(modelIdentifier, options?)` | `GET /v1/estimate/{model_identifier}` | | `client.generate(modelIdentifier, params, options?)` | `POST /v1/generate/image/...` or `POST /v1/generate/video/...` | | `client.generateAndWait(modelIdentifier, params, options?)` | `POST /v1/generate/...`, then `GET /v1/content/{generation_id}` | | `client.waitForGeneration(generationId, options?)` | `GET /v1/content/{generation_id}` until terminal status | | `client.getGeneration(generationId)` | `GET /v1/content/{generation_id}` | | `client.listGenerations({ limit, offset })` | `GET /v1/content/list` | | `client.cancelGeneration(generationId)` | `POST /v1/content/generation/cancel/{generation_id}` | | `client.deleteGeneration(generationId)` | `DELETE /v1/content/{generation_id}` | | `client.library.providers()` | `GET /v1/library/providers` | | `client.library.models()` | `GET /v1/library/models` | | `client.health.providers()` | `GET /v1/health/inference/providers` | | `client.health.models()` | `GET /v1/health/inference/models` | | `client.health.storage()` | `GET /v1/health/storage` | | `client.health.cache()` | `GET /v1/health/cache` | ## Estimate cost ```ts TypeScript theme={null} const estimate = await client.estimate('google/veo-2', { count: 1, duration: 5, }); console.log(estimate.data.cost_total_consumed); ``` For resolution-priced or audio-priced models, pass `resolution` and `audio` when relevant. ## Errors and retries ```ts TypeScript theme={null} import { BabySeaError, BabySeaRetryError, BabySeaTimeoutError } from 'babysea'; try { await client.generate('bfl/flux-schnell', { generation_prompt: 'A baby seal playing on Arctic ice', }); } catch (error) { if (error instanceof BabySeaRetryError) { console.error('Retries exhausted', error.attempts, error.lastError); } else if (error instanceof BabySeaTimeoutError) { console.error('Request timed out'); } else if (error instanceof BabySeaError) { console.error(error.status, error.code, error.type, error.retryable); } } ``` The SDK retries structured API errors with `retryable: true`, up to `maxRetries`. It also retries transient network failures for idempotent methods. For `POST` generation requests, network retries require an `Idempotency-Key`. ## Verify webhooks ```ts TypeScript theme={null} import { isGenerationCompleted, verifyWebhook } from 'babysea/webhooks'; export async function POST(request: Request) { const rawBody = await request.text(); const signature = request.headers.get('X-BabySea-Signature') ?? ''; const event = await verifyWebhook( rawBody, signature, process.env.BABYSEA_WEBHOOK_SECRET!, ); if (isGenerationCompleted(event)) { console.log(event.webhook_data.generation_output_file); } return new Response('ok'); } ``` `verifyWebhook()` checks the `t=,v1=` signature, validates the timestamp tolerance, and returns the parsed payload. ## Runtime support The SDK uses web-standard `fetch` and `crypto.subtle` APIs. | Runtime | Supported | | ------------------ | :-------: | | Node.js 18+ | Yes | | Deno | Yes | | Bun | Yes | | Cloudflare Workers | Yes | | Vercel Edge | Yes | | Netlify Edge | Yes | | Modern browsers | Yes | # Webhooks Source: https://docs.babysea.ai/setup/webhooks Receive, verify, and process signed BabySea webhook events. Webhooks send signed HTTP `POST` events to your server when generation state changes or a low-credit threshold is crossed. ## Event types | Event | Sent when | | ---------------------- | ------------------------------------------------------------- | | `generation.started` | A generation is accepted and processing begins. | | `generation.completed` | A generation succeeds and output files are available. | | `generation.failed` | A generation fails. | | `generation.canceled` | A generation is canceled. | | `credits.low_balance` | The account balance crosses an enabled low-balance threshold. | | `webhook.test` | You send a test event from the dashboard. | ## Set up an endpoint Add an HTTPS route in your application that accepts `POST` requests and reads the raw request body before parsing JSON. Open **Webhook** in the dashboard, add the HTTPS URL, and choose the events your server handles. Endpoint URLs must use public HTTPS on the default HTTPS port and must not rely on redirects. Copy the `whsec_...` signing secret and store it in your secrets manager. BabySea shows it once. Click **Send test event** from the endpoint details page. Return any `2xx` status when verification succeeds. ## Delivery headers Every webhook delivery includes these headers: | Header | Value | | ----------------------- | ------------------------------------------- | | `Content-Type` | `application/json` | | `X-BabySea-Signature` | `t=,v1=` | | `X-BabySea-Event` | Event type, such as `generation.completed`. | | `X-BabySea-Timestamp` | ISO timestamp for the delivery. | | `X-BabySea-Delivery-Id` | Unique delivery UUID. | ## Verify signatures BabySea signs the exact raw JSON body with HMAC-SHA256. The signed payload is: ```text theme={null} . ``` Use `verifyWebhook()` from the TypeScript SDK when possible. ```ts TypeScript theme={null} import { isCreditLowBalance, isGenerationCompleted, verifyWebhook, } from 'babysea/webhooks'; export async function POST(request: Request) { const rawBody = await request.text(); const signature = request.headers.get('X-BabySea-Signature') ?? ''; const event = await verifyWebhook( rawBody, signature, process.env.BABYSEA_WEBHOOK_SECRET!, ); if (isGenerationCompleted(event)) { await saveOutput( event.webhook_data.generation_id, event.webhook_data.generation_output_file ?? [], ); } if (isCreditLowBalance(event)) { await notifyBillingOwner(event.webhook_data.current_balance); } return new Response('ok'); } ``` `verifyWebhook()` rejects missing signatures, invalid signatures, malformed signature headers, and timestamps outside the tolerance window. The default tolerance is `300` seconds. ## Generation payload Generation lifecycle events share this shape: ```json JSON theme={null} { "webhook_event": "generation.completed", "webhook_timestamp": "2026-04-28T12:00:00.000Z", "webhook_delivery_id": "0f0f6cc8-8e33-4f53-90f8-c59362a5b1bd", "webhook_data": { "account_id": "0f0f6cc8-8e33-4f53-90f8-c59362a5b1bd", "model_identifier": "bfl/flux-schnell", "generation_provider_used": "bfl", "generation_status": "succeeded", "generation_prediction_id": "pred_...", "generation_id": "550e8400-e29b-41d4-a716-446655440000", "generation_output_file": ["https://example.com/babysea/output.png"] } } ``` `generation.failed` can include `generation_error` and `generation_error_code`. `generation.canceled` can include `credits_refunded`. ## Credit alert payload `credits.low_balance` uses a billing payload instead of generation fields. ```json JSON theme={null} { "webhook_event": "credits.low_balance", "webhook_timestamp": "2026-04-28T12:00:00.000Z", "webhook_delivery_id": "0f0f6cc8-8e33-4f53-90f8-c59362a5b1bd", "webhook_data": { "account_id": "0f0f6cc8-8e33-4f53-90f8-c59362a5b1bd", "current_balance": 0.42, "thresholds_crossed": [ { "threshold": 0.5, "balance_at": 0.42 } ] } } ``` Configure thresholds and delivery channels from [credits, low-balance alerts](/dashboard/credits#low-balance-alerts). ## Delivery behavior Generation lifecycle deliveries use retries. Credit alert, test, and replay deliveries are one-shot deliveries. | Event category | Timeout | Attempts | Retry behavior | | --------------------- | --------------------- | -------- | --------------------------------------------------------- | | `generation.*` | 5 seconds per attempt | 5 total | Immediate, then after `0.5`, `1.5`, `3`, and `5` seconds. | | `credits.low_balance` | 5 seconds | 1 total | No automatic retry. | | `webhook.test` | 10 seconds | 1 total | No automatic retry. | | Replayed delivery | 10 seconds | 1 total | No automatic retry. | Any `2xx` response marks the delivery successful. Generation endpoints are automatically disabled after `15` consecutive failed generation deliveries. When matching generation events arrive while an endpoint is disabled, BabySea queues them for later delivery. | Queue behavior | Value | | ------------------------ | ------------------------------------------------------------------------ | | Queue retention | 72 hours | | Deliver queued events | Sends pending items after you re-enable the endpoint. | | Queued delivery attempts | One attempt per item with pacing and early stop after repeated failures. | | Test events | Not queued. | ## Idempotency in your handler Webhook delivery is at-least-once for generation lifecycle events. Store `webhook_delivery_id` before applying side effects so retries and replays do not duplicate work. Recommended handler behavior: * Verify `X-BabySea-Signature` against the raw body. * Reject events with stale timestamps. * Store `webhook_delivery_id` with a unique constraint. * Return `2xx` only after durable side effects complete. * Return `4xx` for permanently invalid requests and `5xx` for temporary failures. ## Dashboard management Use [webhook](/dashboard/webhook) to create endpoints, rotate secrets, send test events, inspect deliveries, replay deliveries, deliver queued events, and delete endpoints.