Skip to main content
POST
Execute Superleap Object Query

Overview

Run a Superleap Object Query against a Superleap object and return the resulting records - for analytics and reporting use cases such as field selection, counts, grouped summaries, and filtered datasets.
Replace <domain> with your Superleap workspace domain. For example, app.superleap.com, sandbox.superleap.dev, or your tenant-specific domain.
Execute only read-only SELECT queries. Discover the object slug and field slugs first; do not guess table or field names.

Authentication

Bearer token scoped to the Superleap organization.

Headers

string
required
Bearer token for authentication. Click here to generate one.
string
default:"application/json"
required
Must be application/json.

Request Body

string
required
Raw PostgreSQL SELECT query to execute. The top-level FROM table must exactly match slug.
string
required
Base CRM object slug used in the query’s top-level FROM clause, for example account, contact, deal, or another object slug from your workspace.

Query Rules

The query field is written in the Superleap Query Language, a PostgreSQL-compatible SELECT syntax that understands your objects and their relations.

Structure

Only SELECT queries are accepted. The top-level FROM must be the object slug exactly as returned by list_objects ('lead', never 'leads'), and it must match the request’s slug. Always end the query with a LIMIT; use LIMIT 100 when you have no specific number in mind.

Dates and times

Every date and datetime field stores epoch milliseconds as a bigint. Compare epoch to epoch in WHERE clauses, and compute the boundaries inside the SQL instead of pasting precomputed numbers, date strings, CURRENT_DATE, or to_timestamp(...) comparisons:
The relative form needs AT TIME ZONE twice; with only one, the boundary silently lands at 05:30 IST instead of midnight. For grouping and display, use date_trunc('day', to_timestamp(field/1000) AT TIME ZONE 'Asia/Kolkata'). Avoid DATE(...), interval-offset timezone tricks, and selecting raw epoch values in result columns. Fields whose data_type is 'date' are stored as UTC-midnight epochs: build the same epoch boundaries but without AT TIME ZONE, and display them with to_timestamp(field/1000)::date.

Relations

Dot notation (owner.name) is always safe in SELECT, WHERE, and GROUP BY. Most objects carry id, name, created_at, updated_at, owner, created_by, and updated_by; confirm the rest with describe_object. One caution: IN subqueries (in either direction) fail on columns whose relationship_type is 'virtual'. The failure is silent, the subquery yields raw NULLs and the query returns 0 rows with no error. Use dot notation or a correlated EXISTS for those (see Working with Relationships).

Multi-select fields

Multi-select values are arrays. Use array operators, not string functions: array_length and array subscripts are not supported.

Supported SQL surface

JOIN, UNION, CTEs (WITH), EXTRACT, FILTER (WHERE ...), casts other than ::date, and pg_* system references are not supported. The available functions are: count, sum, avg, min, max, lower, upper, concat, trim, abs, round, coalesce, date_trunc, to_timestamp, date_part, if, case. For conditional counts, use COUNT(CASE WHEN condition THEN 1 END). Style: keep identifiers bare (never double-quote them), quote strings with single quotes, use ILIKE for case-insensitive matching, and write booleans as 0/1. Do not add is_deleted filters; deletion handling is automatic.

Currency units

Convert amounts inside the SQL so results come back ready to display: ROUND(SUM(amount)/10000000, 2) for crore, ROUND(SUM(amount)/100000, 2) for lakh.

Good Query Patterns

Field selection

Count by owner

Date grouping

Unsupported Query Patterns

Working with Relationships

Superleap objects reference each other through relation fields. There are two kinds - direct (to-one) and virtual (one-to-many) - and each supports a few query styles. Pick based on what you are computing.

Direct (to-one) relations

A lookup field on the row itself (owner, account): each row points to at most one related record. Dot notation reads or filters the related record, and hops can be chained:
When filtering on a related record you already know by ID, compare the relation field itself (WHERE stage_record = '<id>') rather than a field on it (WHERE stage_record.name = 'Open'). The ID form skips a join and is noticeably faster on large objects.

Virtual (one-to-many) relations

A reverse link from a parent to its children (associated_opportunities on lead). Three supported ways to use them: 1. Dot notation - filter parents by a child field:
The underlying join returns one row per matching child, so a parent with three matching children appears three times. Use COUNT(DISTINCT id) for counts and SELECT DISTINCT id for row lists whenever a virtual relation appears in the query. 2. Correlated EXISTS / NOT EXISTS - a semi-join with no fan-out, so plain COUNT(id) is fine. Recommended for “has none” checks and for combining conditions across two different virtual relations:
3. Querying the child object and climbing up - when the child object is much smaller than the parent, start FROM the child; every hop up is to-one, so there is no fan-out and the scan is smaller:

Recommendations for virtual relations

  • To check that a parent has no children, prefer NOT EXISTS (or count the complement: |no child| = |all| − |has child|) over IS NULL on the relation field - the explicit forms are unambiguous about “no child rows exist”.
  • To combine conditions on two different virtual relations with OR, prefer OR of two EXISTS subqueries, or split into one query per relation and merge with inclusion-exclusion (below). A single dot-notation OR across two virtual relations is expensive on large objects and may hit the execution timeout.
  • AND across two virtual relations in dot notation is fine.

Performance Patterns

Many metrics in one scan

Compute related metrics as conditional aggregates in a single pass instead of one query per metric - the scan dominates the cost, extra CASE columns are nearly free:

Capped counts with LIMIT

SELECT id ... LIMIT N stops scanning once N rows are found. Paired with the count endpoint, this answers “at least N?” quickly on huge cohorts: if the returned count equals the limit, show “N+”; if below, it is already the exact count. Useful for dashboards where big tiles can display a capped value with an on-demand exact count.

Unions via inclusion-exclusion

For counts across two virtual relations, running the parts separately and combining arithmetically is often the fastest reliable approach:
Each part is a simple query the engine executes efficiently, and the arithmetic composes per metric column.

General tips

  • Long queries are terminated at the execution timeout - decompose work so every query finishes with margin, and retry transient failures with backoff.
  • Keep concurrent heavy analytics queries from one client low (around 2); the replica slows under parallel heavy scans.
  • All date fields are epoch ms bigint (rule 2). data_type 'date' fields are stored as UTC-midnight epochs - use epoch boundaries WITHOUT AT TIME ZONE for those.

Response

boolean
true when the request succeeds.
object
Execute result payload.

Example Request

Example Response

Error Responses

400
429
504