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

# Export object records

> Exports formula-safe CSV for the object. A custom object export without search, in created_at or updated_at order, holds at most 1,000 records per response. Request again with next_cursor until has_more is false. Each response is a complete CSV with its own header row. To export a date range, pass a created_at or updated_at filter in filters_json. Any other export reads the engine window of 1,000 rows, answers has_more false, and sets is_capped when more rows remain.

**Required scopes:** `data_objects.export`


## OpenAPI

````yaml /api-reference/openapi.yaml get /api/v1/objects/{object_id}/export
openapi: 3.1.0
info:
  title: RoofKit Partner API
  version: 1.0.0
  summary: REST JSON API for external RoofKit partner integrations.
  contact:
    name: RoofKit Engineering
  description: >
    RoofKit Partner API v1 authenticates requests with workspace API keys. API
    keys bind each request to exactly one workspace; Partner API paths do not
    accept roofer_id, workspace_id, or tenant identifiers. Authenticated
    endpoints are limited to 60 requests per minute per API key, method, and
    route template; invalid authentication attempts are limited separately at 20
    requests per minute per client and endpoint. Date-time parameters and fields
    accept ISO 8601 with Z or a ±HH:MM offset, for example 2026-09-07T04:00:00Z
    or 2026-09-07T00:00:00-04:00. Both name the same instant and return the same
    result. Encode + as %2B in a query string. Responses return UTC.


    A date-time without an offset, for example 2026-09-07T04:00:00, is
    deprecated. Until the sunset on 2027-01-10T00:00:00Z it is read as UTC, and
    the response carries a `Deprecation` header (RFC 9745) and a `Sunset` header
    (RFC 8594). From the sunset, Z or a ±HH:MM offset is required. A date-time
    without an offset then returns 400 with the `VALIDATION_ERROR` code, and the
    response carries no `Deprecation` or `Sunset` header.


    Each API key holds only the scopes that a workspace owner or admin chose
    when the key was created, and its scopes never change. Each operation lists
    the scopes it requires in `x-required-scopes`. A new key in Settings starts
    on the Read-only preset: `leads.read`, `analytics.read`, `reports.read`, and
    `data_objects.read`. A Read-only key can call every read operation except
    exports, Sales Visualizer reads, and trashed Data Objects, and it cannot
    call any write operation. A call that needs a scope the key does not hold
    returns 403 `FORBIDDEN`, and `error.details.required_scope` names a missing
    scope.
servers:
  - url: https://api.roofkit.ai
    description: Canonical RoofKit Partner API origin
security:
  - ApiKeyBearer: []
tags:
  - name: Foundation
    description: Authentication and contract foundation endpoints.
  - name: Leads
    description: Partner CRM lead sync endpoints.
  - name: Attribution
    description: >-
      Partner marketing attribution, campaign analytics, and event ingestion
      endpoints.
  - name: Pipeline
    description: Partner-readable lead pipeline metadata.
  - name: Reports
    description: Partner report import, listing, fetch, export, and download endpoints.
  - name: Visualizer
    description: >-
      Partner Sales Visualizer creation, generation, hosted photo upload links,
      image reads, session history, and share-link endpoints.
  - name: Estimates
    description: Partner Budget Estimate creation and reads for the key-bound workspace.
  - name: Objects
    description: >-
      Partner Data Objects discovery, schema, records, relations, views, and
      admin endpoints.
paths:
  /api/v1/objects/{object_id}/export:
    get:
      tags:
        - Objects
      summary: Export object records
      description: >-
        Exports formula-safe CSV for the object. A custom object export without
        search, in created_at or updated_at order, holds at most 1,000 records
        per response. Request again with next_cursor until has_more is false.
        Each response is a complete CSV with its own header row. To export a
        date range, pass a created_at or updated_at filter in filters_json. Any
        other export reads the engine window of 1,000 rows, answers has_more
        false, and sets is_capped when more rows remain.
      operationId: Export object records
      parameters:
        - $ref: '#/components/parameters/ObjectId'
        - $ref: '#/components/parameters/Search'
        - $ref: '#/components/parameters/Cursor'
        - $ref: '#/components/parameters/ObjectViewId'
        - $ref: '#/components/parameters/ObjectFiltersJson'
        - $ref: '#/components/parameters/ObjectSortsJson'
      responses:
        '200':
          description: CSV export payload.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ObjectExportResponse'
        '400':
          $ref: '#/components/responses/ValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'
components:
  parameters:
    ObjectId:
      name: object_id
      in: path
      required: true
      description: Object id, system key such as system:leads, or slug from discovery.
      x-docs-test-value: system:leads
      schema:
        type: string
        minLength: 1
        maxLength: 200
    Search:
      name: search
      in: query
      schema:
        type: string
        maxLength: 200
    Cursor:
      name: cursor
      in: query
      description: >-
        Opaque cursor returned by list/export responses. Send it back unchanged;
        malformed cursors return 400.
      schema:
        type: string
        maxLength: 500
    ObjectViewId:
      name: view_id
      in: query
      schema:
        type: string
        maxLength: 200
    ObjectFiltersJson:
      name: filters_json
      in: query
      description: >-
        JSON text of an ObjectFilterQuery. Send an array of filters that must
        all match, or an object with filters and an advanced filter whose rules
        join with and or or. Each filter names a field in fieldId by its id or
        its key, as GET /api/v1/objects/{object_id} lists them. Operators:
        is_empty and is_not_empty take no value. equals, not_equals, contains,
        and has_reached take value. any_of takes an array of strings.
        greater_than and less_than take a number, and between takes value and
        valueTo. before and after take a date (YYYY-MM-DD) or an ISO 8601
        datetime and exclude the day they name. within_range takes value and
        valueTo and includes both days. A bare date covers the whole UTC day. A
        datetime with an offset is converted to UTC. Without filters_json the
        read applies the filters of view_id, or none. Invalid JSON, an unknown
        operator, a missing value, an unknown field, or a field that cannot be
        filtered returns 400 with the path of each issue. Example, records
        created in October 2026:
        [{"fieldId":"created_at","operator":"within_range","value":"2026-10-01","valueTo":"2026-10-31"}]
      schema:
        type: string
        maxLength: 20000
        contentMediaType: application/json
        contentSchema:
          $ref: '#/components/schemas/ObjectFilterQuery'
    ObjectSortsJson:
      name: sorts_json
      in: query
      description: >-
        JSON text of an array of ObjectSort. Each sort names a field in fieldId
        by its id or its key. Without sorts_json the read uses the sort of
        view_id, or created_at, newest first. Only one sort on created_at or
        updated_at keeps the keyset cursor. Any other sort pages by number.
        Invalid JSON, an unknown field, or a formula field returns 400. Example,
        oldest records first: [{"fieldId":"created_at","direction":"asc"}]
      schema:
        type: string
        maxLength: 20000
        contentMediaType: application/json
        contentSchema:
          type: array
          maxItems: 5
          items:
            $ref: '#/components/schemas/ObjectSort'
  schemas:
    ObjectExportResponse:
      type: object
      additionalProperties: false
      required:
        - filename
        - csv
        - record_count
        - is_capped
        - next_cursor
        - has_more
      properties:
        filename:
          type: string
        csv:
          type: string
        record_count:
          type: integer
        is_capped:
          type: boolean
        next_cursor:
          type:
            - string
            - 'null'
          description: Cursor for the next export response, or null on the last one.
        has_more:
          type: boolean
          description: True while more records follow. Request again with next_cursor.
        total:
          type: integer
          minimum: 0
          description: >-
            Exact number of records that match the export. Some exports include
            it and others do not, so treat it as optional.
    ErrorResponse:
      type: object
      additionalProperties: false
      required:
        - error
      properties:
        error:
          type: object
          additionalProperties: false
          required:
            - code
            - message
            - request_id
          properties:
            code:
              $ref: '#/components/schemas/ErrorCode'
            message:
              type: string
            request_id:
              type: string
            details:
              type: object
              additionalProperties: true
    ErrorCode:
      type: string
      enum:
        - UNAUTHORIZED
        - FORBIDDEN
        - RATE_LIMITED
        - VALIDATION_ERROR
        - NOT_FOUND
        - CONFLICT
        - INSUFFICIENT_CREDITS
        - INTERNAL_ERROR
  responses:
    ValidationError:
      description: Request payload, query, or required header is invalid.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    Unauthorized:
      description: Missing, malformed, revoked, deleted, or unknown API key.
      headers:
        WWW-Authenticate:
          schema:
            type: string
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    Forbidden:
      description: >-
        The API key lacks a required scope, or the workspace is not active. A
        scope failure names a missing scope in `details.required_scope`. When
        the key lookup refuses the call, `details.missing_scopes` lists every
        required scope that the key does not hold.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          examples:
            missing_scope:
              summary: A Read-only key calls a write operation
              value:
                error:
                  code: FORBIDDEN
                  message: 'API key does not include the required scope: leads.write.'
                  request_id: req_123
                  details:
                    required_scope: leads.write
                    missing_scopes:
                      - leads.write
    NotFound:
      description: Resource not found in the key-bound workspace.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    RateLimited:
      description: Rate limit exceeded for this key and endpoint or invalid-auth bucket.
      headers:
        X-RateLimit-Limit:
          $ref: '#/components/headers/RateLimitLimit'
        X-RateLimit-Remaining:
          $ref: '#/components/headers/RateLimitRemaining'
        X-RateLimit-Reset:
          $ref: '#/components/headers/RateLimitReset'
        Retry-After:
          $ref: '#/components/headers/RetryAfter'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    InternalError:
      description: Internal authentication or server error.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
  headers:
    RateLimitLimit:
      description: Maximum requests allowed in the current window.
      schema:
        type: string
    RateLimitRemaining:
      description: Requests remaining in the current window.
      schema:
        type: string
    RateLimitReset:
      description: ISO timestamp when the current rate-limit window resets.
      schema:
        type: string
        format: date-time
    RetryAfter:
      description: Seconds until the caller should retry.
      schema:
        type: string
  securitySchemes:
    ApiKeyBearer:
      type: http
      scheme: bearer
      bearerFormat: RoofKit API key
      description: 'Use `Authorization: Bearer rk_live_...`.'

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.