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

# Create or replace draft

> Creates an unpublished draft for a custom schema so you can iterate on
changes without affecting any exports that reference the current published version.

Two modes:

- **Empty body** — copies the latest published version into a new draft. Useful when
  you want to start editing from the current state.
- **JSON body** (same shape as `PUT /v1/export-schemas/{id}/draft`) — creates the
  draft directly with the supplied content.

If a draft already exists, it is replaced. The published version is not touched.
Built-in schemas have no drafts — the request returns `404 not_found`.

Publish the draft with `POST /v1/export-schemas/{id}/publish`, or discard it with
`DELETE /v1/export-schemas/{id}/draft`.




## OpenAPI

````yaml post /v1/export-schemas/{id}/draft
openapi: 3.1.0
info:
  title: Ticksupply API
  version: 1.0.0
  description: >
    The Ticksupply API provides programmatic access to cryptocurrency market
    data.

    Subscribe to real-time data streams, manage subscriptions, and export
    historical data.
  contact:
    name: Ticksupply Support
    email: support@ticksupply.com
  termsOfService: https://ticksupply.com/terms
  license:
    name: Proprietary
    url: https://ticksupply.com/terms
servers:
  - url: https://api.ticksupply.com
    description: Production API
security:
  - ApiKeyAuth: []
tags:
  - name: Catalog
    description: Browse available exchanges, instruments, and data streams
  - name: Subscriptions
    description: Manage data stream subscriptions
  - name: Exports
    description: Export historical data to downloadable files
  - name: Availability
    description: Query data availability for specific streams
  - name: Export Schemas
    description: Manage export column schemas for customized CSV output
  - name: Billing
    description: Inspect your plan, access status, and usage for the current billing period
paths:
  /v1/export-schemas/{id}/draft:
    parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
          pattern: ^sch_[a-f0-9]{32}$
        description: Export schema ID
        example: sch_0194a1b2c3d4e5f6a7b8c9d0e1f2a3b4
    post:
      tags:
        - Export Schemas
      summary: Create or replace draft
      description: >
        Creates an unpublished draft for a custom schema so you can iterate on

        changes without affecting any exports that reference the current
        published version.


        Two modes:


        - **Empty body** — copies the latest published version into a new draft.
        Useful when
          you want to start editing from the current state.
        - **JSON body** (same shape as `PUT /v1/export-schemas/{id}/draft`) —
        creates the
          draft directly with the supplied content.

        If a draft already exists, it is replaced. The published version is not
        touched.

        Built-in schemas have no drafts — the request returns `404 not_found`.


        Publish the draft with `POST /v1/export-schemas/{id}/publish`, or
        discard it with

        `DELETE /v1/export-schemas/{id}/draft`.
      operationId: createExportSchemaDraft
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateSchemaContentRequest'
            example:
              columns:
                - output_column: timestamp_ns
                  meta:
                    value: collection_timestamp_ns
                    format: ns
                - output_column: price
                  data:
                    binance:
                      json:
                        path: data.p
                        type: decimal(18)
                - output_column: quantity
                  data:
                    binance:
                      json:
                        path: data.q
                        type: decimal(18)
      responses:
        '201':
          description: >-
            Draft created. `has_draft` is `true` and `version` reflects the
            latest published version (unchanged).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ExportSchemaWithVersion'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          description: Schema not found, or schema is built-in.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiError'
        '408':
          $ref: '#/components/responses/RequestTimeout'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'
      x-codeSamples:
        - lang: python
          label: Python (ticksupply library)
          source: |
            # pip install ticksupply
            from ticksupply import Client

            client = Client(api_key="<api-key>")
            # Empty body: copies the latest published version into a new draft.
            draft = client.export_schemas.create_draft(
                "sch_0194a1b2c3d4e5f6a7b8c9d0e1f2a3b4",
            )
            print(draft)
        - lang: rust
          label: Rust (ticksupply crate)
          source: |
            // cargo add ticksupply
            // cargo add tokio --features full
            use ticksupply::Client;

            #[tokio::main]
            async fn main() -> ticksupply::Result<()> {
                let client = Client::with_api_key("<api-key>")?;
                // No body: copies the latest published version into a new draft.
                // Pass `.content(SchemaContent)` to create with explicit content instead.
                let draft = client.export_schemas()
                    .create_draft("sch_0194a1b2c3d4e5f6a7b8c9d0e1f2a3b4")
                    .send()
                    .await?;
                println!("{draft:#?}");
                Ok(())
            }
components:
  parameters:
    IdempotencyKey:
      name: Idempotency-Key
      in: header
      required: false
      description: >
        Unique key for idempotent requests. If you retry a request with the same
        key,

        you'll receive the original response without the operation being
        performed again.


        Must be a valid UUID (any version — v4 recommended for uniqueness), up
        to 128 characters.
      schema:
        type: string
        format: uuid
        maxLength: 128
  schemas:
    UpdateSchemaContentRequest:
      type: object
      description: >
        Body for replacing a schema's content. Used by atomic update (`PUT
        /v1/export-schemas/{id}`), and by draft create/update (`POST` / `PUT
        /v1/export-schemas/{id}/draft`). `name` and `stream_category` are
        immutable — they are set when the schema is first created and cannot be
        changed by these endpoints.
      required:
        - columns
      properties:
        columns:
          type: array
          minItems: 1
          description: >
            Replacement column definitions, in output order. Must contain at
            least one column. Capped at 100 columns by default; contact support
            to request a higher limit. Exceeding the limit returns `400
            invalid_argument`.
          items:
            $ref: '#/components/schemas/CreateSchemaColumnRequest'
        unfold:
          type: object
          additionalProperties:
            $ref: '#/components/schemas/UnfoldConfig'
          description: >
            Per-exchange unfold rules. Omit (or send `null`) to clear any
            previously configured unfold rules.
        derive:
          type: object
          additionalProperties:
            type: array
            items:
              $ref: '#/components/schemas/DeriveField'
          description: >
            Per-exchange derived-field rules (same shape as on create). Omit (or
            send `null`) to clear any previously configured derive rules.
    ExportSchemaWithVersion:
      type: object
      description: >
        Export schema with the content of its latest published version. Returned
        by create and get-by-id. Exports that reference the schema by name or ID
        snapshot the latest published version at the time the export is created.
      allOf:
        - $ref: '#/components/schemas/ExportSchema'
        - type: object
          required:
            - version
            - has_draft
            - columns
          properties:
            version:
              type: integer
              description: >-
                Published version number reflected in this response. `1` for a
                newly created schema.
              example: 1
            has_draft:
              type: boolean
              description: Whether an unpublished draft version exists for this schema.
              example: false
            columns:
              type: array
              description: >-
                Column definitions from the latest published version, in output
                order.
              items:
                $ref: '#/components/schemas/CreateSchemaColumnRequest'
            unfold:
              type: object
              additionalProperties:
                $ref: '#/components/schemas/UnfoldConfig'
              description: >
                Per-exchange unfold rules. When an exchange packs multiple
                events into

                one JSON array, unfold expands each element into its own row.

                Keys are exchange codes, values specify the JSON path to the
                array.

                Omitted when no unfold rules are configured.
            derive:
              type: object
              additionalProperties:
                type: array
                items:
                  $ref: '#/components/schemas/DeriveField'
              description: >
                Per-exchange derived-field rules. Each exchange maps to a list
                of synthetic fields computed before column extraction. Omitted
                when no derive rules are configured.
    ApiError:
      type: object
      required:
        - error
      properties:
        error:
          type: object
          required:
            - code
            - message
          properties:
            code:
              type: string
              description: Error code for programmatic handling
              enum:
                - invalid_argument
                - unauthenticated
                - permission_denied
                - not_found
                - already_exists
                - request_timeout
                - rate_limited
                - payment_required
                - internal
                - unavailable
            message:
              type: string
              description: Human-readable error message
            details:
              type: object
              description: Additional error details (optional)
    CreateSchemaColumnRequest:
      type: object
      required:
        - output_column
      properties:
        output_column:
          type: string
          description: Column name in the exported file
          example: price
        meta:
          $ref: '#/components/schemas/MetaExtraction'
        data:
          type: object
          additionalProperties:
            $ref: '#/components/schemas/ExchangeExtractor'
          description: Per-exchange extraction map (keys are exchange codes)
    UnfoldConfig:
      type: object
      required:
        - path
      properties:
        path:
          type: string
          description: >
            Dot-notation path to a JSON array within the raw message. Each
            element of the array becomes its own row in the output.
          example: data
    DeriveField:
      type: object
      description: >
        A synthetic field computed from the raw message before column
        extraction. Derived fields can be referenced by column paths
        (`data.{field}.{...}`) and targeted by `unfold.path`. The built-in
        `book_update` / `normalized` schema uses this to merge `bids` and `asks`
        into one tagged array.
      required:
        - field
        - op
        - arrays
        - tag_field
        - value_field
      properties:
        field:
          type: string
          description: Name of the synthetic field added to the message before extraction.
          example: changes
        op:
          type: string
          enum:
            - tagged_concat
          description: >-
            Derivation operation. `tagged_concat` concatenates each input array
            and tags its elements with a discriminator.
        arrays:
          type: array
          items:
            type: object
            required:
              - path
              - tag
            properties:
              path:
                type: string
                description: Dot-notation path into the raw message pointing at an array.
                example: data.b
              tag:
                type: string
                description: Tag value applied to each element coming from this array.
                example: bid
        tag_field:
          type: string
          description: Name of the field that receives the tag on each derived element.
          example: side
        value_field:
          type: string
          description: >-
            Name of the field that receives the original array element on each
            derived element.
          example: level
    ExportSchema:
      type: object
      description: Identity fields shared by every export schema response.
      required:
        - id
        - name
        - stream_category
        - is_built_in
        - created_at
      properties:
        id:
          type: string
          pattern: ^sch_[a-f0-9]{32}$
          description: Export schema ID
          example: sch_0194a1b2c3d4e5f6a7b8c9d0e1f2a3b4
        name:
          type: string
          description: Schema name
          example: normalized
        stream_category:
          type: string
          enum:
            - trade
            - orderbook
            - book_update
            - quote
            - kline
            - ticker
            - liquidation
          description: Stream category this schema applies to
          example: trade
        is_built_in:
          type: boolean
          description: >
            `true` for schemas provided by Ticksupply (e.g., `normalized`,
            `book_5`, `book_20`). Built-ins are read-only and cannot be deleted.
            `false` for schemas you created.
          example: false
        created_at:
          type: string
          format: date-time
          description: Creation timestamp
    MetaExtraction:
      type: object
      required:
        - value
      properties:
        value:
          type: string
          enum:
            - collection_timestamp_ns
          description: System metadata value to extract
        format:
          type: string
          enum:
            - ns
            - us
            - ms
            - s
            - iso8601
          default: ns
          description: Timestamp output format
    ExchangeExtractor:
      type: object
      properties:
        json:
          $ref: '#/components/schemas/JsonExtraction'
        transform:
          type: string
          description: SQL expression with {v} placeholder applied after extraction
    JsonExtraction:
      type: object
      required:
        - path
        - type
      properties:
        path:
          type: string
          description: Dot-notation path into the JSON data (e.g., "p", "data.price")
        type:
          type: string
          description: >
            Data type for extraction. Use decimal(N) for financial values
            (recommended for price/quantity), f64 for percentages, i64 for
            integers, string for text, bool for booleans.
          examples:
            - decimal(18)
            - f64
            - i64
            - string
            - bool
  responses:
    BadRequest:
      description: Invalid request parameters
      headers:
        X-Request-Id:
          description: Unique request identifier for support inquiries
          schema:
            type: string
            example: req_abc123def456
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiError'
          example:
            error:
              code: invalid_argument
              message: 'Invalid datastream_id: must be a positive integer'
    Unauthorized:
      description: Missing or invalid API key
      headers:
        X-Request-Id:
          description: Unique request identifier for support inquiries
          schema:
            type: string
            example: req_abc123def456
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiError'
          example:
            error:
              code: unauthenticated
              message: Invalid or missing API key
    RequestTimeout:
      description: |
        Request did not complete within the 10-second deadline. Retry with
        exponential backoff. If you see this consistently on a particular
        endpoint, contact support.
      headers:
        X-Request-Id:
          description: Unique request identifier for support inquiries
          schema:
            type: string
            example: req_abc123def456
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiError'
          example:
            error:
              code: request_timeout
              message: Request exceeded 10s deadline
    RateLimited:
      description: Rate limit exceeded
      headers:
        X-Request-Id:
          description: Unique request identifier for support inquiries
          schema:
            type: string
            example: req_abc123def456
        Retry-After:
          description: Seconds to wait before retrying
          schema:
            type: integer
        X-RateLimit-Limit-Minute:
          description: Maximum requests allowed per minute
          schema:
            type: integer
        X-RateLimit-Remaining-Minute:
          description: Requests remaining in the current minute window
          schema:
            type: integer
        X-RateLimit-Reset-Minute:
          description: >-
            Unix timestamp (seconds) when the minute window next has capacity.
            Included only when the minute bucket is exhausted.
          schema:
            type: integer
        X-RateLimit-Limit-Hour:
          description: Maximum requests allowed per hour
          schema:
            type: integer
        X-RateLimit-Remaining-Hour:
          description: Requests remaining in the current hour window
          schema:
            type: integer
        X-RateLimit-Reset-Hour:
          description: >-
            Unix timestamp (seconds) when the hour window next has capacity.
            Included only when the hour bucket is exhausted.
          schema:
            type: integer
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiError'
          example:
            error:
              code: rate_limited
              message: Rate limit exceeded. Retry after 30 seconds.
    InternalError:
      description: Internal server error
      headers:
        X-Request-Id:
          description: Unique request identifier for support inquiries
          schema:
            type: string
            example: req_abc123def456
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiError'
          example:
            error:
              code: internal
              message: An internal error occurred
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-Api-Key
      description: >-
        Your API key. Get one from the dashboard at
        https://app.ticksupply.com/api-keys

````