> ## Documentation Index
> Fetch the complete documentation index at: https://docs.eachlabs.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Changelog

> Product updates and releases from each::labs

<Update label="June 17, 2026" description="API" rss={{ title: "Filter executions by error type", description: "API" }}>
  ## Filter your executions by error type

  * `GET /v1/executions` now accepts an `error_classification` query parameter,
    so you can narrow a listing to just the executions that failed for a
    specific reason — for example `provider_rate_limit` or `content_moderation`.
  * Pass a comma-separated list to match any of several types (e.g.
    `error_classification=provider_rate_limit,provider_unavailable`); an
    unrecognized value returns a `400` so typos surface immediately.
  * The canonical values are `content_moderation`, `execution_timeout`,
    `invalid_user_input`, `invalid_model_config`, `provider_auth`,
    `provider_error`, `provider_rate_limit`, `provider_unavailable`,
    `internal_error`, and `unknown`.
</Update>

<Update label="June 11, 2026" description="each::storage" rss={{ title: "Filter your files by model", description: "each::storage" }}>
  ## Filter your files by model

  * The [storage page](https://eachlabs.ai/storage) now lets you filter your
    files by the **model** that generated them, so you can pull up everything a
    given model produced in one view.
  * You can also filter by **source** — separate the files you uploaded via the
    API from the outputs each::labs auto-saved from your executions.
  * These join the existing date-range, execution, and file-type filters on the
    same page.
</Update>

<Update label="June 9, 2026" description="Usage Analytics" rss={{ title: "Compare a model's error rate against the each::labs average", description: "Usage Analytics" }}>
  ## See whether a model's error rate is normal, or just yours

  * Error Analytics now lets you filter to a single model and see your
    workspace's error rate for it next to the **each::labs platform-wide
    average** for the same model, so you can tell at a glance whether a failure
    spike is something on your side or the model itself.
  * The comparison is color-coded — green when you're beating the platform
    average, red when you're worse — and the benchmark window is labeled so you
    know what it's averaged over.
  * The page also gained quality-of-life upgrades alongside it: sortable
    columns, CSV export, error-type tooltips, and a "Yesterday" quick range.
</Update>

<Update label="June 9, 2026" description="each::storage" rss={{ title: "Set how long an uploaded file is kept", description: "each::storage" }}>
  ## Set how long an uploaded file is kept

  * When you upload a file you can now pass `expires_in_seconds` to control how
    long it's retained. Once that window passes the file is removed
    automatically, so there's no manual cleanup to schedule.
  * Leave it out and files keep the default retention, so nothing changes for
    existing integrations.
  * An expired file drops out of list, download, and storage totals exactly
    like a manual delete, and is purged from the CDN.
</Update>

<Update label="June 8, 2026" description="each::workflows" rss={{ title: "Create workflows straight from the API", description: "each::workflows" }}>
  ## Create workflows straight from the API

  * You can now create a workflow programmatically with
    `POST /v1/workflows/create` (API-key auth), so a whole pipeline can be
    provisioned from code instead of only being assembled by hand in the
    dashboard.
  * It's the same workflow object either way: anything you create over the API
    shows up in the dashboard and runs through the existing trigger flow.
  * This is the first half of full workflow management over the API — create
    now, with more lifecycle operations to follow.
</Update>

<Update label="June 8, 2026" description="Usage Analytics" rss={{ title: "A new Error Analytics view shows why your executions fail", description: "Usage Analytics" }}>
  ## A new Error Analytics view shows why your executions fail

  * The dashboard now has an Error Analytics page that surfaces your
    workspace's error rate and breaks failures down by type, so you can see at
    a glance what's going wrong instead of opening runs one at a time.
  * Failures are also broken down per model, so you can tell which model is
    driving your errors.
  * It builds on the clearer, provider-side failure messages shipped earlier,
    now aggregated into rates you can actually act on.
</Update>

<Update label="June 4, 2026" description="API" rss={{ title: "Every model now ships an OpenAPI schema", description: "API" }}>
  ## Every model now ships an OpenAPI schema

  * Every model exposes an OpenAPI 3.0 schema at
    `GET /v1/models/{slug}/schemas/openapi`, and its inputs and outputs render
    as a typed reference in the model page's API tab.
  * The machine-readable schema plugs straight into code generators,
    validators, and API explorers, while the same schema drives the
    human-readable reference (types, required flags, defaults, enum values,
    ranges).
  * Coverage is automatic and always in sync: both the endpoint and the API
    tab are derived from each model's request schema, so there's nothing to
    author or maintain per model.
</Update>

<Update label="June 4, 2026" description="each::storage" rss={{ title: "Delete an uploaded file over the API", description: "each::storage" }}>
  ## Delete an uploaded file over the API

  * API customers can now delete an uploaded file with `DELETE /v1/files/:id`
    (API-key auth, returns `204`). Files uploaded through the presign flow had
    no delete path before, so once stored there was no way to remove the
    object or its record. This closes that gap for storage cleanup and
    data-deletion or privacy requests.
  * A delete removes the S3 object and soft-deletes the record, so the file
    drops out of list, download, and storage totals immediately.
  * Deletes are org-scoped: callers can only delete files their own org owns.
</Update>

<Update label="June 4, 2026" description="Models" rss={{ title: "New image models: MAI-Image-2.5 Edit and Ideogram v4", description: "Models" }}>
  ## New image models in the catalog

  * **MAI-Image-2.5 Edit** is now available for image editing, through both the
    API and the dashboard.
  * **Ideogram v4** is available too, with a rendering-speed selector so you
    can trade quality against latency on each run.
</Update>

<Update label="June 2, 2026" description="Security" rss={{ title: "Your API key can no longer leak from the browser", description: "Security" }}>
  ## Your API key can no longer leak from the browser

  The dashboard used to keep a copy of your key in your browser. Now it never
  does. Your key stays on the server and signing in uses a secure session.
  Even a fully compromised browser has no key to steal. Nothing changes for
  you day to day; the biggest place a key could leak is simply gone.
</Update>

<Update label="June 2, 2026" description="API Keys" rss={{ title: "API keys are owned by the organization", description: "API Keys" }}>
  ## Keys are owned by the organization, so they survive people coming and going

  * Keys belong to the organization, not the person who created them. So when
    a teammate leaves, their keys keep working and your integrations don't
    break.
  * Any API Key Manager or the organization's primary Owner can delete any of
    the org's keys: one place of control, no orphaned keys.
  * Every key records who created it, for audit and accountability.
  * A new **"Can manage API keys"** permission (shown as **"API key access"**
    in the UI) controls who can create and delete keys, and only that. It
    doesn't touch billing, model access, or whether existing keys work.
  * Removing that permission from someone never breaks their existing keys.
    They keep working; the person just can no longer create or delete keys.
  * A Manager manages all of the org's keys; there's no per-key granularity
    today.
</Update>

<Update label="June 2, 2026" description="Security" rss={{ title: "Copy your key once, then keep it safe", description: "Security" }}>
  ## You hold your key, we don't, so copy it when you create it

  For security, the full key value is shown only once, at the moment you
  create it, and is never stored anywhere it can be shown again. Copy it then
  and keep it safe. If it's ever lost, just create a new key and delete the
  old one.
</Update>

<Update label="June 2, 2026" description="Usage Analytics" rss={{ title: "Tell dashboard runs apart from API runs", description: "Usage Analytics" }}>
  ## You can finally tell dashboard runs apart from API runs

  * Executions, usage, and per-model request history now filter by source
    (**Dashboard** vs **API**), by specific **key**, and by **teammate**, so
    you can attribute every run and every dollar of spend to the right key or
    person. You can even recover history from keys that were later deleted.
    This came straight from customer feedback.
  * The selected view is deep-linkable, so you can share a URL that lands on
    exactly the breakdown you're looking at.
  * Reported usage is more accurate: internal dashboard traffic no longer
    inflates your API usage totals.
</Update>

<Update label="June 2, 2026" description="API" rss={{ title: "API keys are recognizable at a glance", description: "API" }}>
  ## Keys are recognizable at a glance: they start with `smk_`

  The keys you create for the API now begin with `smk_`, so they're easy to
  spot in your code, your logs, and support tickets.
</Update>

<Update label="June 2, 2026" description="API Keys" rss={{ title: "New accounts start clean, no unused key", description: "API Keys" }}>
  ## New accounts start clean, no confusing unused key

  Signing up no longer auto-creates a key you could neither see nor use.
  Running and uploading inside the dashboard work immediately with zero
  setup; you create a key only when you actually need external API access.
</Update>

<Update label="May 23, 2026" description="Catalog" rss={{ title: "Faster model browsing", description: "Catalog" }}>
  ## Faster model browsing

  Model, provider, and family pages are rebuilt on a new data layer, with
  noticeably faster loads and the newest models shown first.
</Update>

<Update label="May 22, 2026" description="each::storage" rss={{ title: "A home for all your files", description: "each::storage" }}>
  ## A home for all your files

  The storage page brings every file you've uploaded or generated into one
  place. Browse inputs and outputs together, and filter by date range,
  execution, or file type to find exactly what you need.
</Update>

<Update label="May 12, 2026" description="each::workflows" rss={{ title: "Clearer failure messages", description: "each::workflows" }}>
  ## Clearer failure messages

  When an execution fails, you now get more specific error detail, including
  provider-side reasons from image and video models, so you can tell what
  went wrong without digging through logs.
</Update>
