Indraft Reporting API

The reporting API from Indraft — 2 operation(s) for reporting.

GitHub OpenAPI

Operations 2

GET /v1/aggregate Count, sum, average, min or max, optionally grouped #
GET /v1/stale Records nobody has touched for a while, quietest first #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/indraft-io:indraft-io-reporting-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

indraft-io-reporting-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: Indraft Io Reporting API
  version: '1'
  description: 'Operations tagged reporting across 2 of this provider''s published API definitions: indraft-io-openapi.json, indraft-io.json. Each path carries the servers of the definition it was published in.'
servers:
- url: https://api.indraft.io
security:
- bearerAuth: []
tags:
- name: Reporting
paths:
  /v1/aggregate:
    get:
      summary: Count, sum, average, min or max, optionally grouped
      description: 'Count, sum, average, min or max over one object type, grouped by up to TWO dimensions. Answers ''how is the quarter going'', ''pipeline by owner by quarter'', ''pipeline by customer segment'' and ''how many have no owner'' in ONE call, with the database doing the arithmetic. Use this instead of paging records and adding them up yourself: it is one call rather than hundreds, and the number is computed rather than estimated. Filters use the same field:op:value language as the list tools. groupBy takes one dimension or an array of two, and a dimension written as hop.field crosses one declared relationship, so opportunity can group by company.industry. Dates must be bucketed to day, week, month, quarter or year, and quarter and year follow the workspace''s own fiscal calendar, which the answer states. Too many groups is refused rather than truncated, and the cap applies to the PRODUCT of two dimensions, because a truncated total reads exactly like a real one. convertTo totals across currencies at a rate this workspace STORED and names the rate it used; a currency with no stored rate is refused rather than converted, because Indraft never invents one. For weighted pipeline, reduce the DERIVED field weighted_amount_minor: ''sum weighted_amount_minor where status is open'' is your weighted pipeline in one call, computed by the database as amount times probability, and it obeys the currency rule exactly as the unweighted amount does. Derived fields can be reduced and not grouped by, because they are measures rather than dimensions. get_crm_schema lists the dimensions, the hops, the derived fields, the fiscal calendar and the stored rates.'
      tags:
      - Reporting
      operationId: get_v1_aggregate
      x-indraft-capability: crm:read
      x-indraft-scopes:
      - crm:read
      - crm:write
      - crm:configure
      - crm:admin
      - crm:revert
      - data:export
      parameters:
      - name: objectType
        in: query
        required: true
        schema:
          type: string
          minLength: 1
          maxLength: 64
          pattern: ^[a-z][a-z0-9_]*$
          description: 'What is being counted: a canonical type, or the key of a type this workspace defined.'
      - name: function
        in: query
        required: true
        schema:
          type: string
          enum:
          - count
          - sum
          - avg
          - min
          - max
          description: The reduction. Count needs no field; the rest need one that carries a number.
      - name: field
        in: query
        required: false
        schema:
          type: string
          minLength: 1
          maxLength: 64
          description: The field to reduce. Refused when the function needs one and the field cannot carry it, rather than returning zero.
      - name: groupBy
        in: query
        required: false
        schema:
          anyOf:
          - type: string
            minLength: 1
            maxLength: 130
          - type: array
            items:
              type: string
              minLength: 1
              maxLength: 130
          description: A dimension to group by, repeatable for a second one. Only dimensions an index serves, and a request for one that is not names every dimension that is, including those one hop away on a related record.
      - name: bucket
        in: query
        required: false
        schema:
          type: string
          enum:
          - day
          - week
          - month
          - quarter
          - year
          description: 'How to cut a date dimension: day, week, month or quarter. Required when grouping by a date, because a raw instant produces one group per record, which is a list wearing an aggregate''s clothes.'
      - name: convertTo
        in: query
        required: false
        schema:
          type: string
          pattern: ^[A-Z]{3}$
          description: 'Express the total in one currency. Refused unless this workspace has asserted a rate for every currency in the answer: Indraft never invents a rate, and a converted number nobody chose is worse than no number.'
      - name: rateAsOf
        in: query
        required: false
        schema:
          type: string
          pattern: ^\d{4}-\d{2}-\d{2}$
          description: Which asserted rates to convert at. Absent means the latest, which is what a live report wants and what a historical one must not use.
      - name: includeArchived
        in: query
        required: false
        schema:
          type: boolean
          description: Include archived rows. Off by default, because a list is what you are working on and history is somewhere you go deliberately.
      - name: filter
        in: query
        required: false
        schema:
          anyOf:
          - type: string
            minLength: 1
            maxLength: 560
          - type: array
            items:
              type: string
              minLength: 1
              maxLength: 560
            maxItems: 8
          description: Predicates, all of which must hold, written field:op:value. Only fields an index serves are accepted, and asking for one that is not names the ones that are.
      - name: or
        in: query
        required: false
        schema:
          anyOf:
          - type: string
            minLength: 1
            maxLength: 560
          - type: array
            items:
              type: string
              minLength: 1
              maxLength: 560
            maxItems: 4
          description: 'Alternatives, ORed with each other and ANDed with filter. One level and never a tree: owned by me or owned by nobody is the question people ask, and anything deeper has a cost the caller cannot read off it.'
      - name: sort
        in: query
        required: false
        schema:
          type: string
          minLength: 1
          maxLength: 65
          description: A field to order by, with a leading minus for descending. Indexed fields only, for the same reason as filter.
      responses:
        '200':
          description: Success
          headers:
            ratelimit-limit:
              description: Requests permitted in the window closest to refusing this caller.
              schema:
                type: integer
            ratelimit-remaining:
              description: Requests left in that window. Zero means the next request is refused.
              schema:
                type: integer
            ratelimit-reset:
              description: Seconds until that window resets.
              schema:
                type: integer
            ratelimit-policy:
              description: Every window in force, not only the one reported above.
              schema:
                type: string
          content:
            application/json:
              schema:
                type: object
                properties:
                  objectType:
                    type: string
                  function:
                    type: string
                    enum:
                    - count
                    - sum
                    - avg
                    - min
                    - max
                  field:
                    type: string
                  matched:
                    type: integer
                  value:
                    anyOf:
                    - type: integer
                    - type: string
                  groupBy:
                    type: object
                    properties:
                      field:
                        type: string
                      bucket:
                        type: string
                        enum:
                        - day
                        - week
                        - month
                        - quarter
                        - year
                      overlapping:
                        type: boolean
                    required:
                    - field
                    - bucket
                    - overlapping
                    additionalProperties: true
                  dimensions:
                    type: array
                    items:
                      type: object
                      properties:
                        field:
                          type: string
                        bucket:
                          type: string
                          enum:
                          - day
                          - week
                          - month
                          - quarter
                          - year
                        overlapping:
                          type: boolean
                        via:
                          type: string
                      required:
                      - field
                      - bucket
                      - overlapping
                      - via
                      additionalProperties: true
                  groups:
                    type: array
                    items:
                      type: object
                      properties:
                        key:
                          anyOf:
                          - type: string
                          - type: integer
                          - type: 'null'
                        label:
                          type: string
                        value:
                          anyOf:
                          - type: integer
                          - type: string
                        count:
                          type: integer
                        keys:
                          type: array
                          items:
                            type: object
                            properties:
                              field:
                                type: string
                              bucket:
                                type: string
                                enum:
                                - day
                                - week
                                - month
                                - quarter
                                - year
                              key:
                                anyOf:
                                - type: string
                                - type: integer
                                - type: 'null'
                              label:
                                type: string
                            required:
                            - field
                            - bucket
                            - key
                            - label
                            additionalProperties: true
                      required:
                      - key
                      - label
                      - value
                      - count
                      additionalProperties: true
                  calendar:
                    type: object
                    properties:
                      fiscalYearStartMonth:
                        type: integer
                        minimum: 1
                        maximum: 12
                      isCalendarYear:
                        type: boolean
                      note:
                        type: string
                    required:
                    - fiscalYearStartMonth
                    - isCalendarYear
                    - note
                    additionalProperties: true
                  conversion:
                    type: object
                    properties:
                      to:
                        type: string
                      asOf:
                        type: string
                      rates:
                        type: array
                        items:
                          type: object
                          properties:
                            id:
                              type: string
                            from:
                              type: string
                            to:
                              type: string
                            ratePpm:
                              type: integer
                            effectiveFrom:
                              type: string
                            sourceLabel:
                              type: string
                            assertedByActorId:
                              type: string
                            assertionKind:
                              type: string
                          required:
                          - id
                          - from
                          - to
                          - ratePpm
                          - effectiveFrom
                          - sourceLabel
                          - assertedByActorId
                          - assertionKind
                          additionalProperties: true
                    required:
                    - to
                    - asOf
                    - rates
                    additionalProperties: true
                  requestId:
                    type: string
                required:
                - objectType
                - function
                - field
                - matched
                - requestId
                additionalProperties: true
        '401':
          description: No credential, or one that has been revoked.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Authenticated, and this capability is not held.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: The request does not satisfy the schema on this page.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: Infrastructure protection tripped. This is not a product quota.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          headers:
            ratelimit-limit:
              description: Requests permitted in the window closest to refusing this caller.
              schema:
                type: integer
            ratelimit-remaining:
              description: Requests left in that window. Zero means the next request is refused.
              schema:
                type: integer
            ratelimit-reset:
              description: Seconds until that window resets.
              schema:
                type: integer
            ratelimit-policy:
              description: Every window in force, not only the one reported above.
              schema:
                type: string
            retry-after:
              description: Seconds to wait before retrying. The request itself was fine.
              schema:
                type: integer
        '500':
          description: A defect on our side. The hint says so, and carries an incident id.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
    servers:
    - url: https://api.indraft.io
  /v1/stale:
    get:
      summary: Records nobody has touched for a while, quietest first
      description: 'Records nobody has touched for a while, quietest first, with how many days each has been quiet. Use this to find what has stopped being maintained: the change feed tells you what DID happen, and this tells you what did not. Returns a list and dates, never a score.'
      tags:
      - Reporting
      operationId: get_v1_stale
      x-indraft-capability: crm:read
      x-indraft-scopes:
      - crm:read
      - crm:write
      - crm:configure
      - crm:admin
      - crm:revert
      - data:export
      parameters:
      - name: quietForDays
        in: query
        required: false
        schema:
          type: integer
          minimum: 1
          maximum: 3650
          description: How long counts as quiet. A record nobody has ever touched is the quietest of all and is included, rather than being excluded by a join.
      - name: limit
        in: query
        required: false
        schema:
          type: integer
          minimum: 1
          maximum: 200
          description: How many to return. The page bound is published in the schema call, and asking for more is refused rather than quietly truncated.
      - name: objectType
        in: query
        required: false
        schema:
          type: string
          minLength: 1
          maxLength: 48
          description: 'What is being counted: a canonical type, or the key of a type this workspace defined.'
      responses:
        '200':
          description: Success
          headers:
            ratelimit-limit:
              description: Requests permitted in the window closest to refusing this caller.
              schema:
                type: integer
            ratelimit-remaining:
              description: Requests left in that window. Zero means the next request is refused.
              schema:
                type: integer
            ratelimit-reset:
              description: Seconds until that window resets.
              schema:
                type: integer
            ratelimit-policy:
              description: Every window in force, not only the one reported above.
              schema:
                type: string
          content:
            application/json:
              schema:
                type: object
                properties:
                  quietForDays:
                    type: integer
                  counts:
                    type: object
                    additionalProperties:
                      type: integer
                  items:
                    type: array
                    items:
                      type: object
                      properties:
                        objectType:
                          type: string
                        id:
                          type: string
                        label:
                          type: string
                        updatedAt:
                          type: string
                        quietDays:
                          type: integer
                      required:
                      - objectType
                      - id
                      - label
                      - updatedAt
                      - quietDays
                      additionalProperties: true
                  requestId:
                    type: string
                required:
                - quietForDays
                - counts
                - items
                - requestId
                additionalProperties: true
        '401':
          description: No credential, or one that has been revoked.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Authenticated, and this capability is not held.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: The request does not satisfy the schema on this page.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: Infrastructure protection tripped. This is not a product quota.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          headers:
            ratelimit-limit:
              description: Requests permitted in the window closest to refusing this caller.
              schema:
                type: integer
            ratelimit-remaining:
              description: Requests left in that window. Zero means the next request is refused.
              schema:
                type: integer
            ratelimit-reset:
              description: Seconds until that window resets.
              schema:
                type: integer
            ratelimit-policy:
              description: Every window in force, not only the one reported above.
              schema:
                type: string
            retry-after:
              description: Seconds to wait before retrying. The request itself was fine.
              schema:
                type: integer
        '500':
          description: A defect on our side. The hint says so, and carries an incident id.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
    servers:
    - url: https://api.indraft.io
components:
  schemas:
    ErrorDetail:
      type: object
      additionalProperties: true
      description: The structured payload a recovery needs. Its shape differs per code; the keys below are the ones that recur, and anything else a code carries is present alongside them.
      properties:
        fieldErrors:
          type: object
          additionalProperties:
            type: string
          description: One message per field the caller sent, keyed by that field. The key `(body)` is the request body itself, which is what an unrecognised key reports under.
        reason:
          type: string
          description: One sentence, where the refusal is about the request rather than a field. A refusal that names alternatives puts them here.
        available:
          type: array
          items:
            type: string
          description: What could have been asked for instead. Present on a filter, sort or group-by the API does not serve, so a correction is one edit rather than a round trip to read the schema.
        options:
          type: array
          items:
            type: string
          description: The values an enum accepts, on a value it does not.
        currentVersion:
          type: integer
          description: What the record's version actually is, on `stale_version`. With the value you sent it is everything needed to decide whether to re-read and retry or to stop.
        expectedVersion:
          type: integer
          description: The version you sent, echoed back on `stale_version`.
        requiredScope:
          type: string
          description: 'The capability the credential lacks. Empty nowhere: a route no credential can reach is human-only and says so in its scopes instead.'
    Error:
      type: object
      required:
      - code
      - message
      - recoveryHint
      - requestId
      properties:
        code:
          type: string
          enum:
          - unauthorized
          - forbidden_scope
          - standing_override_refused
          - workspace_not_found
          - validation_error
          - record_not_found
          - ambiguous_identity
          - duplicate_identity
          - stale_version
          - invalid_stage_transition
          - idempotency_conflict
          - not_reversible
          - merge_conflict
          - rate_limited
          - quota_exceeded
          - payload_too_large
          - workspace_capacity
          - payment_required
          - billing_state_stale
          - operation_in_flight
          - internal_error
        message:
          type: string
        recoveryHint:
          type: string
        requestId:
          type: string
        detail:
          $ref: '#/components/schemas/ErrorDetail'
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: An Indraft API token, or a WorkOS-issued session or MCP access token.
x-refined-from:
- indraft-io-openapi.json
- indraft-io.json