Skip to content

Saved Queries

Saved queries are reusable, named query definitions you store once and execute many times. They are the right tool when a filter, projection, or sort order belongs to your product logic rather than a single caller.

Use a saved query when:

  • the same query runs from multiple clients
  • you want a named report or reusable slice of data
  • you need runtime variables such as dates, user IDs, or statuses
  • you want query logic to live in Centrali instead of being rebuilt in every app

For one-off ad-hoc reads, use Query Records instead.

What a Saved Query Stores

A saved query stores:

  • a name
  • an optional description
  • a canonical query
  • optional typed variables

Canonical Shape

{
  "name": "High Value Paid Orders",
  "description": "Paid orders over a configurable minimum amount",
  "query": {
    "resource": "orders",
    "where": {
      "and": [
        { "data.status": { "eq": "paid" } },
        { "data.amount": { "gte": "${minimumAmount}" } }
      ]
    },
    "sort": [
      { "field": "createdAt", "direction": "desc" }
    ],
    "page": {
      "limit": 50
    },
    "select": {
      "fields": ["id", "data.amount", "data.customerId", "createdAt"]
    }
  },
  "variables": {
    "minimumAmount": {
      "type": "number",
      "required": true,
      "description": "Minimum order amount"
    }
  }
}

Variable Syntax

Saved query variables use ${name} syntax.

{
  "query": {
    "resource": "orders",
    "where": {
      "and": [
        { "data.status": { "eq": "${status}" } },
        { "createdAt": { "gte": "${since}" } }
      ]
    }
  }
}

Variable Types

Common variable types include:

  • string
  • number
  • boolean
  • datetime
  • id

Create and Manage in the Console

Create saved queries from the collection's query area in the Centrali console. Use them for curated product views such as:

  • active subscriptions
  • failed payments in the last 24 hours
  • customers at renewal risk
  • orders awaiting fulfillment

Keep them focused. A saved query should describe a meaningful product concept, not a vague implementation detail.

Execute With the SDK

Use centrali.savedQueries in new code.

List Saved Queries

const all = await centrali.savedQueries.listAll();
const orderQueries = await centrali.savedQueries.list('orders');

Get by Name

const query = await centrali.savedQueries.getByName('orders', 'High Value Paid Orders');
console.log(query.data.id);

Execute

const result = await centrali.savedQueries.execute('orders', 'query-uuid', {
  variables: {
    minimumAmount: 250,
  },
});

console.log(result.data);
console.log(result.meta);

Execute Over HTTP

Use the canonical saved-query routes for write and execution flows:

  • POST /data/workspace/{workspaceSlug}/api/v1/saved-queries
  • PUT /data/workspace/{workspaceSlug}/api/v1/saved-queries/{id}
  • POST /data/workspace/{workspaceSlug}/api/v1/saved-queries/test
  • POST /data/workspace/{workspaceSlug}/api/v1/saved-queries/{id}/execute

Create

curl -X POST "https://api.centrali.io/data/workspace/acme/api/v1/saved-queries" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Recent Failed Payments",
    "query": {
      "resource": "payments",
      "where": {
        "and": [
          { "data.status": { "eq": "failed" } },
          { "createdAt": { "gte": "${since}" } }
        ]
      },
      "sort": [
        { "field": "createdAt", "direction": "desc" }
      ],
      "page": {
        "limit": 100
      }
    },
    "variables": {
      "since": {
        "type": "datetime",
        "required": true
      }
    }
  }'

Test Before Saving

curl -X POST "https://api.centrali.io/data/workspace/acme/api/v1/saved-queries/test" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "query": {
      "resource": "payments",
      "where": {
        "data.status": { "eq": "${status}" }
      },
      "page": { "limit": 5 }
    },
    "variables": {
      "status": "failed"
    }
  }'

Execute

curl -X POST "https://api.centrali.io/data/workspace/acme/api/v1/saved-queries/query-uuid/execute" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "variables": {
      "since": "2026-04-01T00:00:00Z"
    }
  }'

Saved query execution returns the same { data, meta } style result envelope used by canonical record queries.

What to Put in a Saved Query

Good saved queries usually contain:

  • stable business filters
  • a clear sort order
  • a sensible page limit
  • an intentional field projection
  • a small number of well-named variables

Avoid putting every possible option into one giant saved query. If two consumers want meaningfully different behavior, create two saved queries.

Best Practices

  • Name queries after the business meaning, not the implementation.
  • Use variables for values that change at runtime.
  • Use select.fields to keep result payloads focused.
  • Prefer saved queries for product reports, dashboards, and reusable backend reads.
  • Keep ad-hoc exploration in records.query and move to a saved query only when the pattern proves useful.