Open app

Expanding responses

Embed related sub-resources in a single response by passing the expand query parameter.

By default, list and retrieve responses return the smallest useful representation of each resource. When the related data is small and the caller usually needs it on the next render, pass the expand query parameter to embed named sub-resources directly in the response — one round trip instead of two.

Syntax

expand accepts a comma-separated list of expandable field names:

GET /v1/organizations?expand=stores
GET /v1/organizations?expand=stores,billing

Whitespace around each name is trimmed and duplicates are ignored. The set of expandable fields is per-endpoint — each operation lists what it accepts in its OpenAPI parameter docs and on its reference page. Passing an unknown field returns 400 VALIDATION:

{
  "error": {
    "code": "VALIDATION",
    "message": "Unknown expand field: \"foo\". Available: stores."
  }
}

Example

GET /v1/organizations returns the list of organizations the caller belongs to, with the user's role and computed org permission set:

{
  "data": [
    {
      "id": "org_01HJ…",
      "slug": "acme",
      "name": "Acme",
      "logo": null,
      "role": "admin",
      "permissions": ["org:members:read", "org:members:write", "..."]
    }
  ],
  "nextPageUrl": null,
  "previousPageUrl": null
}

Pass ?expand=stores to embed each organization's stores in the same response, with the user's resolved per-store role and permission set:

{
  "data": [
    {
      "id": "org_01HJ…",
      "slug": "acme",
      "name": "Acme",
      "logo": null,
      "role": "admin",
      "permissions": ["org:members:read", "..."],
      "stores": [
        {
          "id": "str_01HJ…",
          "slug": "main",
          "name": "Main",
          "image": null,
          "role": "admin",
          "implicit": true,
          "permissions": ["store:products:read", "store:products:write", "..."]
        }
      ]
    }
  ],
  "nextPageUrl": null,
  "previousPageUrl": null
}

In the typed SDK, expand accepts the same string and the response type widens to include the embedded fields:

import { listOrganizations } from "@mercel/sdk";

const { data } = await listOrganizations({
  client,
  query: { expand: "stores" },
});

for (const org of data.data) {
  for (const store of org.stores ?? []) {
    // …
  }
}

When to expand

Expand when the next thing the caller will do is iterate the embedded collection. Two common cases on Mercel:

  • Mobile app cold start issues GET /v1/me and GET /v1/organizations?expand=stores in parallel to hydrate the user identity and the permission cache used by every gated screen — one network round trip instead of 1 + N.
  • Permission-gated dashboards that render an org switcher with per-store role badges read the full tree in one call.

If the embedded data isn't always needed, leave expand off — the default response is leaner.

Limitations

  • One level of nesting. expand=stores is valid; expand=stores.products is not. Resources reached through two hops are fetched via a follow-up request.
  • Per-endpoint allowlist. Each operation declares the fields it accepts. Unknown fields return 400 VALIDATION.
  • Pagination is unchanged by expand. Pass-through parameters (limit, cursors) behave the same whether or not sub-resources are embedded.

On this page