{
  "swagger": "2.0",
  "info": {
    "title": "Ingest service",
    "version": "0.1507.0",
    "description": "Send your API key as a bearer token: `Authorization: Bearer <api key>`."
  },
  "consumes": [
    "application/json"
  ],
  "produces": [
    "application/json"
  ],
  "securityDefinitions": {
    "ApiKey": {
      "type": "apiKey",
      "in": "header",
      "name": "Authorization",
      "description": "Your API key as a bearer token: `Authorization: Bearer <api key>`."
    }
  },
  "security": [
    {
      "ApiKey": []
    }
  ],
  "paths": {
    "/ingest/v1/ingest": {
      "post": {
        "operationId": "IngestService_ingest",
        "summary": "Ingest",
        "tags": [
          "Ingest Service"
        ],
        "description": "Triggers an ingest job, allowing either creating a new dataset or uploading to an existing one. This endpoint is meant to supersede all other ingestion endpoints as their functionality gets migrated to this one.",
        "parameters": [
          {
            "name": "triggerIngest",
            "in": "body",
            "schema": {
              "$ref": "#/definitions/IngestRequest"
            },
            "required": true,
            "x-example": {
              "options": {
                "type": "dataflash",
                "dataflash": {
                  "source": {
                    "type": "s3",
                    "s3": {
                      "path": "<path>"
                    }
                  },
                  "target": {
                    "type": "new",
                    "new": {
                      "datasetName": "<dataset name>",
                      "datasetDescription": "<dataset description>",
                      "properties": {
                        "<key>": "<property value>"
                      },
                      "labels": [
                        "<label>"
                      ],
                      "channelConfig": {
                        "prefixTreeDelimiter": "<prefix tree delimiter>"
                      },
                      "workspace": "<workspace rid>",
                      "markingRids": [
                        "<marking rid>"
                      ]
                    }
                  }
                }
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A successful response.",
            "schema": {
              "$ref": "#/definitions/IngestResponse"
            },
            "x-example": {
              "details": {
                "type": "dataset",
                "dataset": {
                  "datasetFileId": "<dataset file id>",
                  "datasetRid": "<dataset rid>"
                }
              },
              "ingestJobRid": "<ingest job rid>"
            }
          }
        }
      }
    },
    "/ingest/v1/re-ingest": {
      "post": {
        "operationId": "IngestService_rerunIngest",
        "summary": "Rerun ingest",
        "tags": [
          "Ingest Service"
        ],
        "description": "Triggers an ingest job using an existing ingest job RID. Returns the same response format as the /ingest endpoint.\n\nOnly a job that has finished can be re-run: re-running one still in flight races or duplicates the run already in progress. Cancel it first.",
        "parameters": [
          {
            "name": "request",
            "in": "body",
            "schema": {
              "$ref": "#/definitions/RerunIngestRequest"
            },
            "required": true,
            "x-example": {
              "ingestJobRid": "<ingest job rid>"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A successful response.",
            "schema": {
              "$ref": "#/definitions/IngestResponse"
            },
            "x-example": {
              "details": {
                "type": "dataset",
                "dataset": {
                  "datasetFileId": "<dataset file id>",
                  "datasetRid": "<dataset rid>"
                }
              },
              "ingestJobRid": "<ingest job rid>"
            }
          }
        }
      }
    },
    "/ingest/v1/ingest-run": {
      "post": {
        "operationId": "IngestService_ingestRun",
        "summary": "Ingest run",
        "tags": [
          "Ingest Service"
        ],
        "description": "Creates a run and ingests data sources to be added to the run.",
        "parameters": [
          {
            "name": "request",
            "in": "body",
            "schema": {
              "$ref": "#/definitions/IngestRunRequest"
            },
            "required": true,
            "x-example": {
              "title": "<title>",
              "description": "<description>",
              "startTime": {
                "secondsSinceEpoch": 1
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A successful response.",
            "schema": {
              "$ref": "#/definitions/IngestRunResponse"
            },
            "x-example": {
              "runRid": "<run rid>"
            }
          }
        }
      }
    },
    "/ingest/v1/ingest-video": {
      "post": {
        "operationId": "IngestService_ingestVideo",
        "summary": "Ingest video",
        "tags": [
          "Ingest Service"
        ],
        "description": "Ingests video data from a S3 Nominal upload bucket.",
        "deprecated": true,
        "x-deprecated": "Replaced by ingest.",
        "parameters": [
          {
            "name": "ingestVideo",
            "in": "body",
            "schema": {
              "$ref": "#/definitions/IngestVideoRequest"
            },
            "required": true,
            "x-example": {
              "timestamps": {
                "type": "noManifest",
                "noManifest": {
                  "startingTimestamp": {
                    "secondsSinceEpoch": 1
                  }
                }
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A successful response.",
            "schema": {
              "$ref": "#/definitions/IngestVideoResponse"
            },
            "x-example": {
              "videoRid": "<video rid>",
              "videoFileRid": "<video file rid>",
              "asyncHandle": {
                "rid": "<rid>"
              }
            }
          }
        }
      }
    },
    "/ingest/v1/reingest-dataset-files": {
      "post": {
        "operationId": "IngestService_reingestFromDatasets",
        "summary": "Reingest from datasets",
        "tags": [
          "Ingest Service"
        ],
        "description": "Re-ingests data from provided source datasets into either an existing target dataset, or a new one. Only supported for CSV and Parquet dataset files. Will only reingest dataset files and will drop streaming data from datasets.",
        "parameters": [
          {
            "name": "request",
            "in": "body",
            "schema": {
              "$ref": "#/definitions/ReingestDatasetsRequest"
            },
            "required": true,
            "x-example": {
              "targetDataset": {
                "type": "new",
                "new": {
                  "datasetName": "<dataset name>",
                  "datasetDescription": "<dataset description>",
                  "properties": {
                    "<key>": "<property value>"
                  },
                  "labels": [
                    "<label>"
                  ],
                  "channelConfig": {
                    "prefixTreeDelimiter": "<prefix tree delimiter>"
                  },
                  "workspace": "<workspace rid>",
                  "markingRids": [
                    "<marking rid>"
                  ]
                }
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A successful response.",
            "schema": {
              "$ref": "#/definitions/ReingestDatasetsResponse"
            },
            "x-example": {
              "datasets": {
                "<key>": {
                  "fileMap": {
                    "<key>": {
                      "type": "dataset",
                      "dataset": {
                        "datasetFileId": "<dataset file id>",
                        "datasetRid": "<dataset rid>"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/ingest/v1/delete-file/{datasetRid}/file/{fileId}": {
      "delete": {
        "operationId": "IngestService_deleteFile",
        "summary": "Delete file",
        "tags": [
          "Ingest Service"
        ],
        "description": "This is a best effort deletion of the file's data based on the ingestedAt timestamp. This is an unreversible action. Only v2 dataset file deletion is supported. !!!WARNING!!! It's possible that the file has overwritten points, in which case, those older points will not be recovered. Only use this endpoint if this is acceptable, the data across files are disjoint, or you're willing to re-ingest files to manually recover older points.",
        "parameters": [
          {
            "name": "datasetRid",
            "in": "path",
            "type": "string",
            "format": "rid",
            "x-alias": "DatasetRid",
            "required": true
          },
          {
            "name": "fileId",
            "in": "path",
            "type": "string",
            "format": "uuid",
            "required": true
          }
        ],
        "responses": {
          "204": {
            "description": "No content."
          }
        }
      }
    }
  },
  "definitions": {
    "Empty": {
      "type": "object",
      "properties": {}
    },
    "McapChannelLocator": {
      "description": "Locator for a channel in an mcap file. Channel name is not guaranteed to be unique, so channel ID should be used for mcap files with duplicate channel names.\n\nSet `type` to the name of one of the other fields, and set only that field.",
      "type": "object",
      "x-union": true,
      "properties": {
        "type": {
          "type": "string",
          "enum": [
            "topic",
            "id"
          ]
        },
        "topic": {
          "type": "string",
          "x-alias": "McapChannelTopic"
        },
        "id": {
          "type": "integer",
          "format": "int32",
          "x-alias": "McapChannelId"
        }
      },
      "required": [
        "type"
      ],
      "example": {
        "type": "topic",
        "topic": "string"
      }
    },
    "TimeUnit": {
      "type": "string",
      "enum": [
        "DAYS",
        "HOURS",
        "MINUTES",
        "SECONDS",
        "MILLISECONDS",
        "MICROSECONDS",
        "NANOSECONDS"
      ]
    },
    "Timestamp": {
      "description": "Deprecated for new APIs. Use google.protobuf.Timestamp for absolute instants in proto APIs.\n\nThis legacy nanosecond precision timestamp type is represented by an epoch time in seconds and a nanosecond offset. The nanosecond offset is from the start of the epoch second, so must be less than 1 billion.",
      "type": "object",
      "properties": {
        "seconds": {
          "type": "integer",
          "format": "int64"
        },
        "nanos": {
          "type": "integer",
          "format": "int64"
        }
      },
      "required": [
        "seconds",
        "nanos"
      ]
    },
    "AbsoluteTimestamp": {
      "type": "object",
      "x-union": true,
      "properties": {
        "type": {
          "type": "string",
          "enum": [
            "iso8601",
            "epochOfTimeUnit",
            "customFormat"
          ]
        },
        "iso8601": {
          "$ref": "#/definitions/Iso8601Timestamp"
        },
        "epochOfTimeUnit": {
          "$ref": "#/definitions/EpochTimestamp"
        },
        "customFormat": {
          "$ref": "#/definitions/CustomTimestamp"
        }
      },
      "required": [
        "type"
      ],
      "description": "Set `type` to the name of one of the other fields, and set only that field.",
      "example": {
        "type": "iso8601",
        "iso8601": {}
      }
    },
    "AsyncHandle": {
      "type": "object",
      "properties": {
        "rid": {
          "type": "string",
          "format": "rid"
        }
      },
      "required": [
        "rid"
      ]
    },
    "AvroNumericTimestampType": {
      "description": "Describes how the numeric `timestamps` column in an Avro Stream file should be interpreted. The Avro schema models `timestamps` as an array of longs, so only numeric timestamp variants are supported (no ISO-8601 / custom string formats).\n\nSet `type` to the name of one of the other fields, and set only that field.",
      "type": "object",
      "x-union": true,
      "properties": {
        "type": {
          "type": "string",
          "enum": [
            "epoch",
            "relative"
          ]
        },
        "epoch": {
          "$ref": "#/definitions/EpochTimestamp"
        },
        "relative": {
          "$ref": "#/definitions/RelativeTimestamp"
        }
      },
      "required": [
        "type"
      ],
      "example": {
        "type": "epoch",
        "epoch": {
          "timeUnit": "DAYS"
        }
      }
    },
    "AvroStreamOpts": {
      "description": "Options for ingesting Avro data with the following schema. This is a \"stream-like\" file format to support use cases where a columnar/tabular format does not make sense. This closely matches Nominal's streaming API, making it useful for use cases where network connection drops during streaming and a backup file needs to be created.\n\nIf this schema is not used, will result in a failed ingestion. { \"type\": \"record\", \"name\": \"AvroStream\", \"namespace\": \"io.nominal.ingest\", \"fields\": [ { \"name\": \"channel\", \"type\": \"string\", \"doc\": \"Channel/series name (e.g., 'vehicle_id', 'col_1', 'temperature')\", }, { \"name\": \"timestamps\", \"type\": {\"type\": \"array\", \"items\": \"long\"}, \"doc\": \"Array of numeric timestamps; see timestampType for interpretation\", }, { \"name\": \"values\", \"type\": {\"type\": \"array\", \"items\": [\"double\", \"string\"]}, \"doc\": \"Array of values. Can either be doubles or strings\", }, { \"name\": \"tags\", \"type\": {\"type\": \"map\", \"values\": \"string\"}, \"default\": {}, \"doc\": \"Key-value metadata tags\", }, ], }",
      "type": "object",
      "properties": {
        "source": {
          "$ref": "#/definitions/IngestSource"
        },
        "target": {
          "$ref": "#/definitions/DatasetIngestTarget"
        },
        "additionalFileTags": {
          "type": "object",
          "additionalProperties": {
            "type": "string",
            "x-alias": "TagValue"
          },
          "x-map-key": "TagName",
          "description": "Specifies a tag set to apply to all data in the file."
        },
        "timestampType": {
          "allOf": [
            {
              "$ref": "#/definitions/AvroNumericTimestampType"
            }
          ],
          "description": "How to interpret the numeric values in the `timestamps` array. Defaults to epoch-nanoseconds when omitted, matching the original contract of this API."
        }
      },
      "required": [
        "source",
        "target"
      ]
    },
    "ChannelConfig": {
      "type": "object",
      "properties": {
        "prefixTreeDelimiter": {
          "type": "string",
          "description": "If set, will construct a prefix tree for channels of the dataset using the given delimiter."
        }
      }
    },
    "ContainerizedOpts": {
      "type": "object",
      "properties": {
        "sources": {
          "type": "object",
          "additionalProperties": {
            "$ref": "#/definitions/IngestSource"
          },
          "x-map-key": "EnvironmentVariable"
        },
        "arguments": {
          "type": "object",
          "additionalProperties": {
            "type": "string"
          },
          "x-map-key": "EnvironmentVariable"
        },
        "extractorRid": {
          "type": "string",
          "format": "rid",
          "x-alias": "ContainerizedExtractorRid"
        },
        "timestampMetadata": {
          "$ref": "#/definitions/TimestampMetadata"
        },
        "tag": {
          "type": "string"
        },
        "target": {
          "$ref": "#/definitions/DatasetIngestTarget"
        },
        "additionalFileTags": {
          "type": "object",
          "additionalProperties": {
            "type": "string",
            "x-alias": "TagValue"
          },
          "x-map-key": "TagName",
          "description": "Specifies a tag set to apply to all data in the file."
        }
      },
      "required": [
        "extractorRid",
        "target"
      ]
    },
    "CsvOpts": {
      "description": "Options for ingesting csv files. Supported file formats include .csv, .csv.gz",
      "type": "object",
      "properties": {
        "source": {
          "$ref": "#/definitions/IngestSource"
        },
        "target": {
          "$ref": "#/definitions/DatasetIngestTarget"
        },
        "timestampMetadata": {
          "$ref": "#/definitions/TimestampMetadata"
        },
        "channelPrefix": {
          "type": "string",
          "x-alias": "ChannelPrefix"
        },
        "channelNameOverrides": {
          "type": "object",
          "additionalProperties": {
            "type": "string",
            "x-alias": "Channel"
          },
          "x-map-key": "ColumnName"
        },
        "tagKeysFromColumns": {
          "type": "array",
          "items": {
            "type": "string",
            "x-alias": "TagName"
          },
          "uniqueItems": true,
          "x-deprecated": "Deprecated in favor of tagColumns."
        },
        "tagColumns": {
          "type": "object",
          "additionalProperties": {
            "type": "string",
            "x-alias": "ColumnName"
          },
          "x-map-key": "TagName",
          "description": "A map of tag names to column names to derive the tag values from."
        },
        "additionalFileTags": {
          "type": "object",
          "additionalProperties": {
            "type": "string",
            "x-alias": "TagValue"
          },
          "x-map-key": "TagName",
          "description": "Specifies a tag set to apply to all data in the file."
        },
        "excludeColumns": {
          "type": "array",
          "items": {
            "type": "string",
            "x-alias": "ColumnName"
          },
          "uniqueItems": true,
          "description": "A set of column names to exclude from ingestion. These columns will not be ingested as channels. Useful for excluding columns that contain unsupported data types like multidimensional arrays."
        }
      },
      "required": [
        "source",
        "target",
        "timestampMetadata",
        "channelPrefix"
      ]
    },
    "CustomTimestamp": {
      "type": "object",
      "properties": {
        "format": {
          "type": "string",
          "description": "The format string should be in the format of the `DateTimeFormatter` class in Java."
        },
        "defaultYear": {
          "type": "integer",
          "format": "int32",
          "description": "Default year is accepted as an optional field for cases like IRIG time format and will be overridden by year in time format."
        },
        "defaultDayOfYear": {
          "type": "integer",
          "format": "int32",
          "description": "Default day of year is accepted as an optional field for cases like IRIG time format and will be overridden by day of year in time format."
        }
      },
      "required": [
        "format"
      ]
    },
    "DataflashOpts": {
      "type": "object",
      "properties": {
        "source": {
          "$ref": "#/definitions/IngestSource"
        },
        "target": {
          "$ref": "#/definitions/DatasetIngestTarget"
        },
        "ignoreInvalidTimestamps": {
          "type": "boolean",
          "description": "If true, skips dataflash records whose timestamp cannot be represented (corrupted/out-of-range) instead of failing the entire ingest. If not provided, defaults to false."
        },
        "additionalFileTags": {
          "type": "object",
          "additionalProperties": {
            "type": "string",
            "x-alias": "TagValue"
          },
          "x-map-key": "TagName",
          "description": "Specifies a tag set to apply to all data in the file."
        }
      },
      "required": [
        "source",
        "target"
      ]
    },
    "DatasetIngestTarget": {
      "type": "object",
      "x-union": true,
      "properties": {
        "type": {
          "type": "string",
          "enum": [
            "new",
            "existing"
          ]
        },
        "new": {
          "$ref": "#/definitions/NewDatasetIngestDestination"
        },
        "existing": {
          "$ref": "#/definitions/ExistingDatasetIngestDestination"
        }
      },
      "required": [
        "type"
      ],
      "description": "Set `type` to the name of one of the other fields, and set only that field.",
      "example": {
        "type": "new",
        "new": {
          "datasetName": "string",
          "datasetDescription": "string",
          "properties": {
            "key": "string"
          },
          "labels": [
            "string"
          ],
          "channelConfig": {
            "prefixTreeDelimiter": "string"
          },
          "workspace": "string",
          "markingRids": [
            "string"
          ]
        }
      }
    },
    "DeprecatedNewCsv": {
      "type": "object",
      "properties": {
        "source": {
          "$ref": "#/definitions/IngestSource"
        },
        "name": {
          "type": "string"
        },
        "properties": {
          "type": "object",
          "additionalProperties": {
            "type": "string"
          }
        },
        "timeColumnSpec": {
          "$ref": "#/definitions/TimestampMetadata"
        },
        "channelConfig": {
          "$ref": "#/definitions/ChannelConfig"
        }
      },
      "required": [
        "source"
      ]
    },
    "DeprecatedNewDataSource": {
      "type": "object",
      "x-union": true,
      "properties": {
        "type": {
          "type": "string",
          "enum": [
            "csv"
          ]
        },
        "csv": {
          "$ref": "#/definitions/DeprecatedNewCsv"
        }
      },
      "required": [
        "type"
      ],
      "description": "Set `type` to the name of one of the other fields, and set only that field.",
      "example": {
        "type": "csv",
        "csv": {
          "source": {
            "type": "s3",
            "s3": {
              "path": "string"
            }
          },
          "name": "string",
          "properties": {
            "key": "string"
          },
          "timeColumnSpec": {
            "seriesName": "string",
            "timestampType": {
              "type": "relative",
              "relative": {
                "timeUnit": "DAYS",
                "offset": "2026-01-01T00:00:00Z"
              }
            }
          },
          "channelConfig": {
            "prefixTreeDelimiter": "string"
          }
        }
      }
    },
    "EpochTimestamp": {
      "type": "object",
      "properties": {
        "timeUnit": {
          "$ref": "#/definitions/TimeUnit"
        }
      },
      "required": [
        "timeUnit"
      ]
    },
    "ExistingDatasetIngestDestination": {
      "type": "object",
      "properties": {
        "datasetRid": {
          "type": "string",
          "format": "rid"
        },
        "expandRunBounds": {
          "type": "array",
          "items": {
            "type": "string",
            "format": "rid",
            "x-alias": "RunRid"
          },
          "description": "The ingest will keep track of the range of timestamps in the ingested data and update the included run's time bounds. For runs with no end time (uninitialized), it will always set the start time to the file's start time and set the end time to the file's end time. For runs with existing end times, it will only expand the bounds (earliest start time, latest end time)."
        }
      },
      "required": [
        "datasetRid"
      ]
    },
    "ExistingSpatialIngestDestination": {
      "type": "object",
      "properties": {
        "spatialRid": {
          "type": "string",
          "format": "rid",
          "x-alias": "SpatialRid"
        }
      },
      "required": [
        "spatialRid"
      ]
    },
    "ExistingVideoIngestDestination": {
      "type": "object",
      "properties": {
        "videoRid": {
          "type": "string",
          "format": "rid",
          "x-alias": "VideoRid",
          "description": "RID of the video to ingest the newly created video file to."
        },
        "videoFileDetails": {
          "allOf": [
            {
              "$ref": "#/definitions/VideoFileIngestDetails"
            }
          ],
          "description": "Metadata to associate with any created video file"
        }
      },
      "required": [
        "videoRid"
      ]
    },
    "FileStoreIngestSource": {
      "description": "A resolved File Store revision to ingest, whose bytes are read in place from File Store storage.",
      "type": "object",
      "properties": {
        "fileRevisionRid": {
          "type": "string",
          "format": "rid",
          "x-alias": "DriveFileRevisionRid"
        }
      },
      "required": [
        "fileRevisionRid"
      ]
    },
    "GcsIngestSource": {
      "type": "object",
      "properties": {
        "path": {
          "type": "string"
        }
      },
      "required": [
        "path"
      ]
    },
    "IngestDataSource": {
      "type": "object",
      "x-union": true,
      "properties": {
        "type": {
          "type": "string",
          "enum": [
            "existingDataSource",
            "newDataSource",
            "newDataSourceV2"
          ]
        },
        "existingDataSource": {
          "type": "string",
          "format": "rid",
          "x-alias": "DataSourceRid"
        },
        "newDataSource": {
          "$ref": "#/definitions/DeprecatedNewDataSource"
        },
        "newDataSourceV2": {
          "$ref": "#/definitions/NewDataSource"
        }
      },
      "required": [
        "type"
      ],
      "description": "Set `type` to the name of one of the other fields, and set only that field.",
      "example": {
        "type": "existingDataSource",
        "existingDataSource": "string"
      }
    },
    "IngestDatasetFileDetails": {
      "type": "object",
      "properties": {
        "datasetFileId": {
          "type": "string",
          "format": "uuid"
        },
        "datasetRid": {
          "type": "string",
          "format": "rid",
          "x-alias": "DatasetRid"
        }
      },
      "required": [
        "datasetRid"
      ]
    },
    "IngestDetails": {
      "type": "object",
      "x-union": true,
      "properties": {
        "type": {
          "type": "string",
          "enum": [
            "dataset",
            "video",
            "spatial"
          ]
        },
        "dataset": {
          "$ref": "#/definitions/IngestDatasetFileDetails"
        },
        "video": {
          "allOf": [
            {
              "$ref": "#/definitions/IngestVideoFileDetails"
            }
          ],
          "x-deprecated": "Returned only for legacy Video-entity ingests; videoV2 ingests return dataset details carrying the created dataset file id."
        },
        "spatial": {
          "$ref": "#/definitions/IngestSpatialDetails"
        }
      },
      "required": [
        "type"
      ],
      "description": "Set `type` to the name of one of the other fields, and set only that field.",
      "example": {
        "type": "dataset",
        "dataset": {
          "datasetFileId": "string",
          "datasetRid": "string"
        }
      }
    },
    "IngestMetadata": {
      "type": "object",
      "properties": {
        "timestampMetadata": {
          "allOf": [
            {
              "$ref": "#/definitions/TimestampMetadata"
            }
          ],
          "description": "The timestamp metadata will be recovered from the dataset files if possible. Older datasets may have unrecoverable timestamp metadata. If unrecoverable, reingestion will throw MissingMetadataForReingest if not provided in request."
        },
        "channelPrefix": {
          "type": "string",
          "description": "Channel prefix to use when reingesting the dataset. Defaults to empty string. Not recoverable from prior ingests and must be provided in request if needed."
        },
        "channelNameOverrides": {
          "type": "object",
          "additionalProperties": {
            "type": "string",
            "x-alias": "Channel"
          },
          "x-map-key": "ColumnName",
          "description": "Renames individual columns to explicit channel names. Composes with channelPrefix: `final name = channelPrefix + channelNameOverrides.getOrDefault(column, column)`. Defaults to empty map. Not recoverable from prior ingests and must be provided in request if needed. At most 1000 entries may be provided. Resolved channel names must be unique across columns; renaming a column onto another column's name fails the ingest."
        },
        "tagColumns": {
          "type": "object",
          "additionalProperties": {
            "type": "string",
            "x-alias": "ColumnName"
          },
          "x-map-key": "TagName",
          "description": "A map of tag names to column names to derive the tag values from. Not recoverable from prior ingests and must be provided in request if needed."
        },
        "additionalFileTags": {
          "type": "object",
          "additionalProperties": {
            "type": "string",
            "x-alias": "TagValue"
          },
          "x-map-key": "TagName",
          "description": "Additional tags to apply to all dataset files within the the given dataset. Not recoverable from prior ingests and must be provided in request if needed."
        }
      }
    },
    "IngestOptions": {
      "type": "object",
      "x-union": true,
      "properties": {
        "type": {
          "type": "string",
          "enum": [
            "dataflash",
            "mcapProtobufTimeseries",
            "journalJson",
            "csv",
            "parquet",
            "video",
            "videoV2",
            "containerized",
            "avroStream",
            "pointCloud"
          ]
        },
        "dataflash": {
          "$ref": "#/definitions/DataflashOpts"
        },
        "mcapProtobufTimeseries": {
          "$ref": "#/definitions/McapProtobufTimeseriesOpts"
        },
        "journalJson": {
          "$ref": "#/definitions/JournalJsonOpts"
        },
        "csv": {
          "$ref": "#/definitions/CsvOpts"
        },
        "parquet": {
          "$ref": "#/definitions/ParquetOpts"
        },
        "video": {
          "allOf": [
            {
              "$ref": "#/definitions/VideoOpts"
            }
          ],
          "x-deprecated": "Legacy Video-entity ingest. Use videoV2, which ingests video as a channel on a dataset."
        },
        "videoV2": {
          "$ref": "#/definitions/VideoOptsV2"
        },
        "containerized": {
          "$ref": "#/definitions/ContainerizedOpts"
        },
        "avroStream": {
          "$ref": "#/definitions/AvroStreamOpts"
        },
        "pointCloud": {
          "$ref": "#/definitions/PointCloudOpts"
        }
      },
      "required": [
        "type"
      ],
      "description": "Set `type` to the name of one of the other fields, and set only that field.",
      "example": {
        "type": "dataflash",
        "dataflash": {
          "source": {
            "type": "s3",
            "s3": {
              "path": "string"
            }
          },
          "target": {
            "type": "new",
            "new": {
              "datasetName": "string",
              "datasetDescription": "string",
              "properties": {
                "key": "string"
              },
              "labels": [
                "string"
              ],
              "channelConfig": {
                "prefixTreeDelimiter": "string"
              },
              "workspace": "string",
              "markingRids": [
                "string"
              ]
            }
          },
          "ignoreInvalidTimestamps": true,
          "additionalFileTags": {
            "key": "string"
          }
        }
      }
    },
    "IngestRequest": {
      "type": "object",
      "properties": {
        "options": {
          "$ref": "#/definitions/IngestOptions"
        }
      },
      "required": [
        "options"
      ],
      "example": {
        "options": {
          "type": "dataflash",
          "dataflash": {
            "source": {
              "type": "s3",
              "s3": {
                "path": "<path>"
              }
            },
            "target": {
              "type": "new",
              "new": {
                "datasetName": "<dataset name>",
                "datasetDescription": "<dataset description>",
                "properties": {
                  "<key>": "<property value>"
                },
                "labels": [
                  "<label>"
                ],
                "channelConfig": {
                  "prefixTreeDelimiter": "<prefix tree delimiter>"
                },
                "workspace": "<workspace rid>",
                "markingRids": [
                  "<marking rid>"
                ]
              }
            }
          }
        }
      }
    },
    "IngestResponse": {
      "type": "object",
      "properties": {
        "details": {
          "$ref": "#/definitions/IngestDetails"
        },
        "ingestJobRid": {
          "type": "string",
          "format": "rid",
          "x-alias": "IngestJobRid"
        }
      },
      "required": [
        "details"
      ]
    },
    "IngestRunDataSource": {
      "type": "object",
      "properties": {
        "dataSource": {
          "$ref": "#/definitions/IngestDataSource"
        },
        "timeOffsetSpec": {
          "$ref": "#/definitions/TimeOffsetSpec"
        }
      },
      "required": [
        "dataSource"
      ]
    },
    "IngestRunRequest": {
      "type": "object",
      "properties": {
        "rid": {
          "type": "string",
          "format": "rid",
          "description": "If a run with the same rid already exists, the run will be updated."
        },
        "title": {
          "type": "string"
        },
        "description": {
          "type": "string"
        },
        "startTime": {
          "$ref": "#/definitions/UtcTimestamp"
        },
        "endTime": {
          "$ref": "#/definitions/UtcTimestamp"
        },
        "properties": {
          "type": "object",
          "additionalProperties": {
            "type": "string",
            "x-alias": "PropertyValue"
          },
          "x-map-key": "PropertyName"
        },
        "labels": {
          "type": "array",
          "items": {
            "type": "string",
            "x-alias": "Label"
          },
          "uniqueItems": true
        },
        "runPrefix": {
          "type": "string",
          "description": "for example, SIM, HTL, FLT"
        },
        "dataSources": {
          "type": "object",
          "additionalProperties": {
            "$ref": "#/definitions/IngestRunDataSource"
          },
          "x-map-key": "DataSourceRefName"
        },
        "workspace": {
          "type": "string",
          "format": "rid",
          "x-alias": "WorkspaceRid",
          "description": "The workspace in which to create the dataset. If not provided, the dataset will be created in the default workspace for the user's organization, if the default workspace for the organization is configured."
        }
      },
      "required": [
        "title",
        "description",
        "startTime"
      ],
      "example": {
        "title": "<title>",
        "description": "<description>",
        "startTime": {
          "secondsSinceEpoch": 1
        }
      }
    },
    "IngestRunResponse": {
      "type": "object",
      "properties": {
        "runRid": {
          "type": "string",
          "format": "rid",
          "x-alias": "RunRid"
        }
      },
      "required": [
        "runRid"
      ]
    },
    "IngestSource": {
      "type": "object",
      "x-union": true,
      "properties": {
        "type": {
          "type": "string",
          "enum": [
            "s3",
            "gcs",
            "presignedFile",
            "fileStore"
          ]
        },
        "s3": {
          "$ref": "#/definitions/S3IngestSource"
        },
        "gcs": {
          "$ref": "#/definitions/GcsIngestSource"
        },
        "presignedFile": {
          "$ref": "#/definitions/PresignedFileIngestSource"
        },
        "fileStore": {
          "$ref": "#/definitions/FileStoreIngestSource"
        }
      },
      "required": [
        "type"
      ],
      "description": "Set `type` to the name of one of the other fields, and set only that field.",
      "example": {
        "type": "s3",
        "s3": {
          "path": "string"
        }
      }
    },
    "IngestSpatialDetails": {
      "type": "object",
      "properties": {
        "spatialRid": {
          "type": "string",
          "format": "rid",
          "x-alias": "SpatialRid"
        }
      },
      "required": [
        "spatialRid"
      ]
    },
    "IngestVideoFileDetails": {
      "type": "object",
      "properties": {
        "videoFileRid": {
          "type": "string",
          "format": "rid",
          "x-alias": "VideoFileRid"
        },
        "videoRid": {
          "type": "string",
          "format": "rid",
          "x-alias": "VideoRid"
        }
      },
      "required": [
        "videoFileRid",
        "videoRid"
      ]
    },
    "IngestVideoRequest": {
      "type": "object",
      "properties": {
        "sources": {
          "type": "array",
          "items": {
            "$ref": "#/definitions/IngestSource"
          }
        },
        "properties": {
          "type": "object",
          "additionalProperties": {
            "type": "string",
            "x-alias": "PropertyValue"
          },
          "x-map-key": "PropertyName"
        },
        "labels": {
          "type": "array",
          "items": {
            "type": "string",
            "x-alias": "Label"
          },
          "uniqueItems": true
        },
        "title": {
          "type": "string"
        },
        "description": {
          "type": "string"
        },
        "timestamps": {
          "$ref": "#/definitions/VideoTimestampManifest"
        },
        "workspace": {
          "type": "string",
          "format": "rid",
          "x-alias": "WorkspaceRid",
          "description": "The workspace in which to create the video. If not provided, the video will be created in the default workspace for the user's organization, if the default workspace for the organization is configured."
        }
      },
      "required": [
        "timestamps"
      ],
      "example": {
        "timestamps": {
          "type": "noManifest",
          "noManifest": {
            "startingTimestamp": {
              "secondsSinceEpoch": 1
            }
          }
        }
      }
    },
    "IngestVideoResponse": {
      "type": "object",
      "properties": {
        "videoRid": {
          "type": "string",
          "format": "rid",
          "x-alias": "VideoRid"
        },
        "videoFileRid": {
          "type": "string",
          "format": "rid",
          "x-alias": "VideoFileRid"
        },
        "asyncHandle": {
          "allOf": [
            {
              "$ref": "#/definitions/AsyncHandle"
            }
          ],
          "x-deprecated": "Deprecated"
        }
      },
      "required": [
        "videoRid",
        "videoFileRid"
      ]
    },
    "Iso8601Timestamp": {
      "type": "object",
      "properties": {}
    },
    "JournalJsonOpts": {
      "type": "object",
      "properties": {
        "source": {
          "$ref": "#/definitions/IngestSource"
        },
        "target": {
          "$ref": "#/definitions/DatasetIngestTarget"
        },
        "channel": {
          "type": "string",
          "x-alias": "Channel",
          "description": "If provided, ingests logs to the given channel. By default, log data will be ingested to a channel named 'logs'."
        },
        "timestampMetadata": {
          "allOf": [
            {
              "$ref": "#/definitions/JournalTimestampMetadata"
            }
          ],
          "description": "Optional timestamp field for the JSON lines. When provided, each line is timestamped from this field instead of the journald default `__REALTIME_TIMESTAMP`, allowing non-journald JSON logs to ingest. Each line must still contain a `MESSAGE` field. Only numeric epoch timestamps are supported. When absent, the journald default (`__REALTIME_TIMESTAMP`, microseconds) is used."
        }
      },
      "required": [
        "source",
        "target"
      ]
    },
    "JournalTimestampMetadata": {
      "type": "object",
      "properties": {
        "fieldName": {
          "type": "string"
        },
        "epochOfTimeUnit": {
          "$ref": "#/definitions/EpochTimestamp"
        }
      },
      "required": [
        "fieldName",
        "epochOfTimeUnit"
      ]
    },
    "LogTime": {
      "type": "object",
      "properties": {}
    },
    "McapChannels": {
      "type": "object",
      "x-union": true,
      "properties": {
        "type": {
          "type": "string",
          "enum": [
            "all",
            "include",
            "exclude"
          ]
        },
        "all": {
          "$ref": "#/definitions/Empty"
        },
        "include": {
          "type": "array",
          "items": {
            "$ref": "#/definitions/McapChannelLocator"
          }
        },
        "exclude": {
          "type": "array",
          "items": {
            "$ref": "#/definitions/McapChannelLocator"
          }
        }
      },
      "required": [
        "type"
      ],
      "description": "Set `type` to the name of one of the other fields, and set only that field.",
      "example": {
        "type": "all",
        "all": {}
      }
    },
    "McapProtobufTimeseriesOpts": {
      "type": "object",
      "properties": {
        "source": {
          "$ref": "#/definitions/IngestSource"
        },
        "target": {
          "$ref": "#/definitions/DatasetIngestTarget"
        },
        "channelFilter": {
          "$ref": "#/definitions/McapChannels"
        },
        "timestampType": {
          "$ref": "#/definitions/McapTimestampType"
        },
        "ignoreInvalidTopics": {
          "type": "boolean",
          "description": "If true, skips invalid MCAP topics during ingestion instead of failing the entire ingest. If not provided, defaults to false."
        },
        "additionalFileTags": {
          "type": "object",
          "additionalProperties": {
            "type": "string",
            "x-alias": "TagValue"
          },
          "x-map-key": "TagName",
          "description": "Specifies a tag set to apply to all data in the file."
        }
      },
      "required": [
        "source",
        "target",
        "channelFilter",
        "timestampType"
      ]
    },
    "McapTimestampType": {
      "description": "LogTime is default timestamp for MCAP messages and should be used in most cases.\n\nSet `type` to the name of one of the other fields, and set only that field.",
      "type": "object",
      "x-union": true,
      "properties": {
        "type": {
          "type": "string",
          "enum": [
            "logTime"
          ]
        },
        "logTime": {
          "$ref": "#/definitions/LogTime"
        }
      },
      "required": [
        "type"
      ],
      "example": {
        "type": "logTime",
        "logTime": {}
      }
    },
    "NewDataSource": {
      "type": "object",
      "properties": {
        "source": {
          "$ref": "#/definitions/IngestSource"
        },
        "properties": {
          "type": "object",
          "additionalProperties": {
            "type": "string",
            "x-alias": "PropertyValue"
          },
          "x-map-key": "PropertyName"
        },
        "labels": {
          "type": "array",
          "items": {
            "type": "string",
            "x-alias": "Label"
          },
          "uniqueItems": true
        },
        "description": {
          "type": "string"
        },
        "name": {
          "type": "string"
        },
        "timeColumnSpec": {
          "$ref": "#/definitions/TimestampMetadata"
        },
        "channelConfig": {
          "$ref": "#/definitions/ChannelConfig"
        }
      },
      "required": [
        "source"
      ]
    },
    "NewDatasetIngestDestination": {
      "type": "object",
      "properties": {
        "datasetName": {
          "type": "string"
        },
        "datasetDescription": {
          "type": "string"
        },
        "properties": {
          "type": "object",
          "additionalProperties": {
            "type": "string",
            "x-alias": "PropertyValue"
          },
          "x-map-key": "PropertyName"
        },
        "labels": {
          "type": "array",
          "items": {
            "type": "string",
            "x-alias": "Label"
          },
          "uniqueItems": true
        },
        "channelConfig": {
          "$ref": "#/definitions/ChannelConfig"
        },
        "workspace": {
          "type": "string",
          "format": "rid",
          "x-alias": "WorkspaceRid",
          "description": "The workspace in which to create the dataset. If not provided, the dataset will be created in the default workspace for the user's organization, if the default workspace for the organization is configured."
        },
        "markingRids": {
          "type": "array",
          "items": {
            "type": "string",
            "format": "rid",
            "x-alias": "MarkingRid"
          },
          "uniqueItems": true,
          "description": "The markings to apply to the created dataset. If not provided, the dataset will be visible to all users in the same workspace."
        }
      }
    },
    "NewVideoIngestDestination": {
      "type": "object",
      "properties": {
        "title": {
          "type": "string",
          "description": "Title of the Video that will get created. If not provided, a name is deduced from the ingested file."
        },
        "description": {
          "type": "string",
          "description": "Description that is applied to the newly created video"
        },
        "properties": {
          "type": "object",
          "additionalProperties": {
            "type": "string",
            "x-alias": "PropertyValue"
          },
          "x-map-key": "PropertyName",
          "description": "Key-Value properties that are applied to the newly created video"
        },
        "labels": {
          "type": "array",
          "items": {
            "type": "string",
            "x-alias": "Label"
          },
          "uniqueItems": true,
          "description": "Labels that are applied to the newly created video"
        },
        "videoFileDetails": {
          "allOf": [
            {
              "$ref": "#/definitions/VideoFileIngestDetails"
            }
          ],
          "description": "Metadata to associate with any created video file"
        },
        "workspace": {
          "type": "string",
          "format": "rid",
          "x-alias": "WorkspaceRid",
          "description": "The workspace in which to create the video. If not provided, the video will be created in the default workspace for the user's organization, if the default workspace for the organization is configured."
        },
        "markingRids": {
          "type": "array",
          "items": {
            "type": "string",
            "format": "rid",
            "x-alias": "MarkingRid"
          },
          "uniqueItems": true,
          "description": "The markings to apply to the created video. If not provided, the video will be visible to all users in the same workspace."
        }
      }
    },
    "ingest.api.NoTimestampManifest": {
      "type": "object",
      "properties": {
        "startingTimestamp": {
          "$ref": "#/definitions/UtcTimestamp"
        },
        "scaleParameter": {
          "allOf": [
            {
              "$ref": "#/definitions/ingest.api.ScaleParameter"
            }
          ],
          "description": "A field that specifies that the frame rate of the video does not match the frame rate of the camera | i.e. a slowed down or sped up video. Can specify either the camera frame rate or the absolute end time."
        }
      },
      "required": [
        "startingTimestamp"
      ]
    },
    "ParquetOpts": {
      "description": "Options for ingesting parquet files. Supported file formats include .parquet, .parquet.gz and archives such as .tar, .tar.gz, and .zip (must set the isArchive flag).",
      "type": "object",
      "properties": {
        "source": {
          "$ref": "#/definitions/IngestSource"
        },
        "target": {
          "$ref": "#/definitions/DatasetIngestTarget"
        },
        "timestampMetadata": {
          "$ref": "#/definitions/TimestampMetadata"
        },
        "channelPrefix": {
          "type": "string",
          "x-alias": "ChannelPrefix"
        },
        "channelNameOverrides": {
          "type": "object",
          "additionalProperties": {
            "type": "string",
            "x-alias": "Channel"
          },
          "x-map-key": "ColumnName"
        },
        "tagKeysFromColumns": {
          "type": "array",
          "items": {
            "type": "string",
            "x-alias": "TagName"
          },
          "uniqueItems": true,
          "x-deprecated": "Deprecated in favor of tagColumns."
        },
        "tagColumns": {
          "type": "object",
          "additionalProperties": {
            "type": "string",
            "x-alias": "ColumnName"
          },
          "x-map-key": "TagName",
          "description": "A map of tag names to column names to derive the tag values from."
        },
        "additionalFileTags": {
          "type": "object",
          "additionalProperties": {
            "type": "string",
            "x-alias": "TagValue"
          },
          "x-map-key": "TagName",
          "description": "Specifies a tag set to apply to all data in the file."
        },
        "isArchive": {
          "type": "boolean",
          "description": "If true, the file is an archive. Supported archive formats include .tar, .tar.gz, and .zip. Only files ending in .parquet within the archive will be ingested. If field not provided, defaults to false."
        },
        "excludeColumns": {
          "type": "array",
          "items": {
            "type": "string",
            "x-alias": "ColumnName"
          },
          "uniqueItems": true,
          "description": "A set of column names to exclude from ingestion. These columns will not be ingested as channels. Useful for excluding columns that contain unsupported data types like multidimensional arrays."
        }
      },
      "required": [
        "source",
        "target",
        "timestampMetadata",
        "channelPrefix"
      ]
    },
    "PointCloudIngestTarget": {
      "type": "object",
      "x-union": true,
      "properties": {
        "type": {
          "type": "string",
          "enum": [
            "existing"
          ]
        },
        "existing": {
          "$ref": "#/definitions/ExistingSpatialIngestDestination"
        }
      },
      "required": [
        "type"
      ],
      "description": "Set `type` to the name of one of the other fields, and set only that field.",
      "example": {
        "type": "existing",
        "existing": {
          "spatialRid": "string"
        }
      }
    },
    "PointCloudOpts": {
      "description": "Options for ingesting point cloud data into Dagger via Nominal.",
      "type": "object",
      "properties": {
        "source": {
          "$ref": "#/definitions/IngestSource"
        },
        "target": {
          "$ref": "#/definitions/PointCloudIngestTarget"
        },
        "daggerImportConfig": {
          "description": "The Dagger **v2** `ImportRequest` body — everything from that schema except `source_uri`, which Nominal fills in from the resolved presigned URL for `source`. Forwarded to Dagger's `POST /v2/imports/{model_uuid}`. Construct via the language's generated dagger-client types (e.g. `dagger_client.models.ImportRequest` in Python). Carries the required `archetype` (attribute definitions and sampler configuration), an optional `format` (the source format and its format-specific parameters, including the `geometry_type` and `columns` a CSV source needs; omit it to let Dagger infer the format from the file extension), and an optional `quiche_config` — all of which are domain knowledge the client owns when it produced the file. The legacy v1 shape, with `geometry_type` and `columns` at the top level, is rejected."
        },
        "sensorMetadata": {
          "allOf": [
            {
              "$ref": "#/definitions/PointCloudMetadata"
            }
          ],
          "description": "Sensor metadata to associate with the point cloud."
        },
        "channel": {
          "type": "string",
          "x-alias": "Channel",
          "description": "Channel name for workbook integration."
        },
        "tags": {
          "type": "object",
          "additionalProperties": {
            "type": "string",
            "x-alias": "TagValue"
          },
          "x-map-key": "TagName",
          "description": "Tags to apply to the point cloud series."
        }
      },
      "required": [
        "source",
        "target",
        "daggerImportConfig",
        "channel"
      ]
    },
    "PresignedFileIngestSource": {
      "type": "object",
      "properties": {
        "url": {
          "type": "string"
        }
      },
      "required": [
        "url"
      ]
    },
    "ReingestDatasetsRequest": {
      "type": "object",
      "properties": {
        "sourceDatasets": {
          "type": "array",
          "items": {
            "type": "string",
            "format": "rid",
            "x-alias": "DatasetRid"
          },
          "description": "The datasets to reingest data from. Can only include tagless, non-streaming datasets (V1). The datasets must be of the same granularity and must only include CSV or Parquet files. Will attempt to reingest from datasets in list order."
        },
        "targetDataset": {
          "allOf": [
            {
              "$ref": "#/definitions/DatasetIngestTarget"
            }
          ],
          "description": "The dataset to ingest data into. Can either be a new dataset or an existing dataset RID."
        },
        "ingestMetadata": {
          "type": "object",
          "additionalProperties": {
            "$ref": "#/definitions/IngestMetadata"
          },
          "x-map-key": "DatasetRid",
          "description": "Mapping of dataset to ingest metadata. Ingest metadata only needs to be provided in request if it cannot be recovered from prior ingests. See documentation on each field to determine what metadata can be auto-recovered."
        }
      },
      "required": [
        "targetDataset"
      ],
      "example": {
        "targetDataset": {
          "type": "new",
          "new": {
            "datasetName": "<dataset name>",
            "datasetDescription": "<dataset description>",
            "properties": {
              "<key>": "<property value>"
            },
            "labels": [
              "<label>"
            ],
            "channelConfig": {
              "prefixTreeDelimiter": "<prefix tree delimiter>"
            },
            "workspace": "<workspace rid>",
            "markingRids": [
              "<marking rid>"
            ]
          }
        }
      }
    },
    "ReingestDatasetsResponse": {
      "description": "The response to a reingest request. Maps the source dataset RID and file ID to the destination dataset RID and file ID.",
      "type": "object",
      "properties": {
        "datasets": {
          "type": "object",
          "additionalProperties": {
            "$ref": "#/definitions/ReingestFilesMapping"
          },
          "x-map-key": "DatasetRid"
        }
      }
    },
    "ReingestFilesMapping": {
      "description": "Maps the source dataset file ID to the destination dataset and file ID.",
      "type": "object",
      "properties": {
        "fileMap": {
          "type": "object",
          "additionalProperties": {
            "$ref": "#/definitions/IngestDetails"
          },
          "x-map-key": "DatasetFileId"
        }
      }
    },
    "RelativeTimestamp": {
      "type": "object",
      "properties": {
        "timeUnit": {
          "$ref": "#/definitions/TimeUnit"
        },
        "offset": {
          "type": "string",
          "format": "date-time",
          "description": "Starting timestamp to use when indexing the file. This field is required when uploading a new file to an existing dataset."
        }
      },
      "required": [
        "timeUnit"
      ]
    },
    "RerunIngestRequest": {
      "type": "object",
      "properties": {
        "ingestJobRid": {
          "type": "string",
          "format": "rid",
          "x-alias": "IngestJobRid"
        }
      },
      "required": [
        "ingestJobRid"
      ],
      "example": {
        "ingestJobRid": "<ingest job rid>"
      }
    },
    "S3IngestSource": {
      "type": "object",
      "properties": {
        "path": {
          "type": "string"
        }
      },
      "required": [
        "path"
      ]
    },
    "ingest.api.ScaleParameter": {
      "type": "object",
      "x-union": true,
      "properties": {
        "type": {
          "type": "string",
          "enum": [
            "trueFrameRate",
            "endingTimestamp",
            "scaleFactor"
          ]
        },
        "trueFrameRate": {
          "type": "number",
          "format": "double"
        },
        "endingTimestamp": {
          "allOf": [
            {
              "$ref": "#/definitions/UtcTimestamp"
            }
          ],
          "description": "the timestamp corresponding to absolute starting timestamp plus absolute duration of the video."
        },
        "scaleFactor": {
          "type": "number",
          "format": "double",
          "description": "the scale factor can be used to calculate whether media duration differs from a video's | real duration, and if so, the true frame rate of the camera. The video time will thus be scaled | by the ratio of the real duration to media duration, or media frame rate to true frame rate."
        }
      },
      "required": [
        "type"
      ],
      "description": "Set `type` to the name of one of the other fields, and set only that field.",
      "example": {
        "type": "trueFrameRate",
        "trueFrameRate": 1
      }
    },
    "TimeOffsetSpec": {
      "type": "object",
      "x-union": true,
      "properties": {
        "type": {
          "type": "string",
          "enum": [
            "nanos"
          ]
        },
        "nanos": {
          "$ref": "#/definitions/Duration"
        }
      },
      "required": [
        "type"
      ],
      "description": "Set `type` to the name of one of the other fields, and set only that field.",
      "example": {
        "type": "nanos",
        "nanos": {
          "seconds": 1,
          "nanos": 1
        }
      }
    },
    "TimestampManifest": {
      "description": "The timestamp manifest files will contain a list of absolute timestamps, in nanoseconds, that correspond to each frame in a video. Each file should be of type JSON and store a single list, the length of which equals the number of frames in its corresponding video.",
      "type": "object",
      "properties": {
        "sources": {
          "type": "array",
          "items": {
            "$ref": "#/definitions/IngestSource"
          }
        }
      }
    },
    "TimestampMetadata": {
      "type": "object",
      "properties": {
        "seriesName": {
          "type": "string"
        },
        "timestampType": {
          "$ref": "#/definitions/TimestampType"
        }
      },
      "required": [
        "seriesName",
        "timestampType"
      ]
    },
    "TimestampType": {
      "type": "object",
      "x-union": true,
      "properties": {
        "type": {
          "type": "string",
          "enum": [
            "relative",
            "absolute"
          ]
        },
        "relative": {
          "$ref": "#/definitions/RelativeTimestamp"
        },
        "absolute": {
          "$ref": "#/definitions/AbsoluteTimestamp"
        }
      },
      "required": [
        "type"
      ],
      "description": "Set `type` to the name of one of the other fields, and set only that field.",
      "example": {
        "type": "relative",
        "relative": {
          "timeUnit": "DAYS",
          "offset": "2026-01-01T00:00:00Z"
        }
      }
    },
    "UtcTimestamp": {
      "type": "object",
      "properties": {
        "secondsSinceEpoch": {
          "type": "integer",
          "format": "int64"
        },
        "offsetNanoseconds": {
          "type": "integer",
          "format": "int64"
        }
      },
      "required": [
        "secondsSinceEpoch"
      ]
    },
    "VideoFileIngestDetails": {
      "type": "object",
      "properties": {
        "fileDescription": {
          "type": "string",
          "description": "Description that is applied to the newly created video file. If not provided, defaults to the description used to create the video."
        },
        "fileProperties": {
          "type": "object",
          "additionalProperties": {
            "type": "string",
            "x-alias": "PropertyValue"
          },
          "x-map-key": "PropertyName",
          "description": "Key-Value properties that are applied to the newly created video file.",
          "x-deprecated": "Field is ignored as video files do not have properties. Will be removed after 4/5/2025"
        },
        "fileLabels": {
          "type": "array",
          "items": {
            "type": "string",
            "x-alias": "Label"
          },
          "uniqueItems": true,
          "description": "Labels that are applied to the newly created video file.",
          "x-deprecated": "Field is ignored as video files do not have labels. Will be removed after 4/5/2025"
        }
      }
    },
    "VideoIngestTarget": {
      "type": "object",
      "x-union": true,
      "properties": {
        "type": {
          "type": "string",
          "enum": [
            "new",
            "existing"
          ]
        },
        "new": {
          "$ref": "#/definitions/NewVideoIngestDestination"
        },
        "existing": {
          "$ref": "#/definitions/ExistingVideoIngestDestination"
        }
      },
      "required": [
        "type"
      ],
      "description": "Set `type` to the name of one of the other fields, and set only that field.",
      "example": {
        "type": "new",
        "new": {
          "title": "string",
          "description": "string",
          "properties": {
            "key": "string"
          },
          "labels": [
            "string"
          ],
          "videoFileDetails": {
            "fileDescription": "string",
            "fileProperties": {
              "key": "string"
            },
            "fileLabels": [
              "string"
            ]
          },
          "workspace": "string",
          "markingRids": [
            "string"
          ]
        }
      }
    },
    "VideoOpts": {
      "type": "object",
      "properties": {
        "source": {
          "$ref": "#/definitions/IngestSource"
        },
        "target": {
          "$ref": "#/definitions/VideoIngestTarget"
        },
        "timestampManifest": {
          "$ref": "#/definitions/VideoFileTimestampManifest"
        },
        "overWriteSegments": {
          "type": "boolean",
          "description": "If true, overlapping segments from other video files within the same video will be deleted before inserting new segments. The cached segment metadata for affected files will be recomputed."
        }
      },
      "required": [
        "source",
        "target",
        "timestampManifest"
      ]
    },
    "VideoOptsV2": {
      "type": "object",
      "properties": {
        "source": {
          "$ref": "#/definitions/IngestSource"
        },
        "target": {
          "$ref": "#/definitions/DatasetIngestTarget"
        },
        "timestampManifest": {
          "$ref": "#/definitions/VideoFileTimestampManifest"
        },
        "channel": {
          "type": "string",
          "x-alias": "Channel"
        },
        "tags": {
          "type": "object",
          "additionalProperties": {
            "type": "string",
            "x-alias": "TagValue"
          },
          "x-map-key": "TagName"
        },
        "overWriteSegments": {
          "type": "boolean",
          "description": "If true, overlapping segments from other dataset files within the same series will be deleted before inserting new segments. The cached segment metadata for affected files will be recomputed."
        }
      },
      "required": [
        "source",
        "target",
        "timestampManifest",
        "channel"
      ]
    },
    "VideoTimestampManifest": {
      "type": "object",
      "x-union": true,
      "properties": {
        "type": {
          "type": "string",
          "enum": [
            "noManifest",
            "timestampManifests"
          ]
        },
        "noManifest": {
          "$ref": "#/definitions/ingest.api.NoTimestampManifest"
        },
        "timestampManifests": {
          "$ref": "#/definitions/TimestampManifest"
        }
      },
      "required": [
        "type"
      ],
      "description": "Set `type` to the name of one of the other fields, and set only that field.",
      "example": {
        "type": "noManifest",
        "noManifest": {
          "startingTimestamp": {
            "secondsSinceEpoch": 1,
            "offsetNanoseconds": 1
          },
          "scaleParameter": {
            "type": "trueFrameRate",
            "trueFrameRate": 1
          }
        }
      }
    },
    "Duration": {
      "type": "object",
      "properties": {
        "seconds": {
          "type": "integer",
          "format": "int64"
        },
        "nanos": {
          "type": "integer",
          "format": "int64"
        }
      },
      "required": [
        "seconds",
        "nanos"
      ]
    },
    "PointCloudMetadata": {
      "description": "Metadata about the sensor that captured a point cloud.",
      "type": "object",
      "properties": {
        "sensorModel": {
          "type": "string",
          "description": "The sensor model name, e.g. \"Velodyne VLP-16\", \"Ouster OS1-128\"."
        },
        "coordinateSystem": {
          "type": "string",
          "description": "Coordinate reference system identifier, e.g. \"EPSG:4326\", \"ENU\"."
        },
        "resolutionMm": {
          "type": "number",
          "format": "double",
          "description": "Spatial resolution of the point cloud in millimeters."
        },
        "scanPattern": {
          "allOf": [
            {
              "$ref": "#/definitions/ScanPattern"
            }
          ],
          "description": "The scan pattern of the lidar sensor."
        }
      }
    },
    "ScanPattern": {
      "type": "string",
      "enum": [
        "ROTATING",
        "SOLID_STATE",
        "FLASH",
        "MECHANICAL"
      ]
    },
    "McapTimestampManifest": {
      "description": "Timestamps are derived from the mcap file containing the video frames.",
      "type": "object",
      "properties": {
        "mcapChannelLocator": {
          "$ref": "#/definitions/McapChannelLocator"
        }
      },
      "required": [
        "mcapChannelLocator"
      ]
    },
    "video.api.NoTimestampManifest": {
      "description": "these values will not be updated after ingest time, to allow for resetting. The updated values are stored implicitly through the segment timestamps.",
      "type": "object",
      "properties": {
        "startingTimestamp": {
          "allOf": [
            {
              "$ref": "#/definitions/Timestamp"
            }
          ],
          "description": "Specifies the original starting timestamp of the video."
        },
        "scaleParameter": {
          "allOf": [
            {
              "$ref": "#/definitions/video.api.ScaleParameter"
            }
          ],
          "description": "A field that specifies that the frame rate of the video does not match the frame rate of the camera | i.e. a slowed down or sped up video. Can specify either the camera frame rate or the absolute end time."
        }
      },
      "required": [
        "startingTimestamp"
      ]
    },
    "video.api.ScaleParameter": {
      "type": "object",
      "x-union": true,
      "properties": {
        "type": {
          "type": "string",
          "enum": [
            "trueFrameRate",
            "endingTimestamp",
            "scaleFactor"
          ]
        },
        "trueFrameRate": {
          "type": "number",
          "format": "double"
        },
        "endingTimestamp": {
          "$ref": "#/definitions/Timestamp"
        },
        "scaleFactor": {
          "type": "number",
          "format": "double",
          "description": "the scale factor can be used to calculate whether media duration differs from a video's | real duration, and if so, the true frame rate of the camera. The video time will thus be scaled | by the ratio of the real duration to media duration, or media frame rate to true frame rate."
        }
      },
      "required": [
        "type"
      ],
      "description": "Set `type` to the name of one of the other fields, and set only that field.",
      "example": {
        "type": "trueFrameRate",
        "trueFrameRate": 1
      }
    },
    "VideoFileTimestampManifest": {
      "description": "A video file’s timestamp manifest specifies how to determine absolute timestamps for each frame. In an MCAP file, this data is embedded within the source file. Alternatively, the manifest may be provided as an external sidecar file. If no manifest is available, the timestamps are calculated by applying a starting offset to the presentation timestamp of each frame.\n\nSet `type` to the name of one of the other fields, and set only that field.",
      "type": "object",
      "x-union": true,
      "properties": {
        "type": {
          "type": "string",
          "enum": [
            "mcap",
            "s3path",
            "s3paths",
            "noManifest"
          ]
        },
        "mcap": {
          "$ref": "#/definitions/McapTimestampManifest"
        },
        "s3path": {
          "type": "string",
          "x-alias": "S3Path"
        },
        "s3paths": {
          "type": "array",
          "items": {
            "type": "string",
            "x-alias": "S3Path"
          },
          "description": "Multiple sidecar manifest files whose per-frame timestamps are concatenated in list order. Used when a video's frame timestamps are recorded across several files."
        },
        "noManifest": {
          "$ref": "#/definitions/video.api.NoTimestampManifest"
        }
      },
      "required": [
        "type"
      ],
      "example": {
        "type": "mcap",
        "mcap": {
          "mcapChannelLocator": {
            "type": "topic",
            "topic": "string"
          }
        }
      }
    }
  },
  "tags": [
    {
      "name": "Ingest Service",
      "x-displayName": "Ingest service",
      "description": "The Ingest Service handles the data ingestion into Nominal/data store.",
      "x-errors": [
        {
          "status": 400,
          "errorCode": "INVALID_ARGUMENT",
          "errorName": "UploadService:EmptyMultipartUpload"
        },
        {
          "status": 400,
          "errorCode": "INVALID_ARGUMENT",
          "errorName": "UploadService:IncorrectSizeBytes"
        },
        {
          "status": 400,
          "errorCode": "INVALID_ARGUMENT",
          "errorName": "UploadService:NullKey"
        },
        {
          "status": 400,
          "errorCode": "INVALID_ARGUMENT",
          "errorName": "UploadService:SignDownloadPathOutsideUploadsBucket"
        },
        {
          "status": 400,
          "errorCode": "INVALID_ARGUMENT",
          "errorName": "UploadService:UploadBucketNotAllowed",
          "description": "A multipart-upload follow-up call specified a `bucket` this service does not recognize. It must be the value returned as `bucket` by initiateMultipartUpload, unchanged."
        },
        {
          "status": 404,
          "errorCode": "NOT_FOUND",
          "errorName": "UploadService:UploadObjectNotFound",
          "description": "A multipart-upload follow-up call named a File Store object the ledger has no row for. A malformed key and an unknown one are reported identically, so a caller cannot tell which of the two it supplied."
        },
        {
          "status": 403,
          "errorCode": "PERMISSION_DENIED",
          "errorName": "UploadService:SignDownloadUnauthorized"
        },
        {
          "status": 404,
          "errorCode": "NOT_FOUND",
          "errorName": "UploadService:ResourceNotFoundOrUnauthorized",
          "description": "The resource referenced by an upload's `resource` field was not found or the caller is not authorized to access it. Returned as NOT_FOUND (rather than PERMISSION_DENIED) to avoid leaking existence information about resources the caller cannot see."
        },
        {
          "status": 400,
          "errorCode": "INVALID_ARGUMENT",
          "errorName": "UploadService:WorkspaceResourceMismatch",
          "description": "Both `workspace` and `resource` were set on the upload request, but the workspace derived from the resource does not match the explicitly-supplied workspace. Returned as a defensive sanity check so callers don't accidentally believe they're uploading to one workspace while the file is actually being routed to another."
        },
        {
          "status": 400,
          "errorCode": "INVALID_ARGUMENT",
          "errorName": "IngestService:RunBoundsInverted"
        },
        {
          "status": 400,
          "errorCode": "INVALID_ARGUMENT",
          "errorName": "IngestService:IncompatibleConnectionTypeAndLogQuery"
        },
        {
          "status": 400,
          "errorCode": "INVALID_ARGUMENT",
          "errorName": "IngestService:InvalidS3Path"
        },
        {
          "status": 400,
          "errorCode": "INVALID_ARGUMENT",
          "errorName": "IngestService:InvalidUrl"
        },
        {
          "status": 500,
          "errorCode": "INTERNAL",
          "errorName": "IngestService:FailedToDownloadFile"
        },
        {
          "status": 400,
          "errorCode": "INVALID_ARGUMENT",
          "errorName": "IngestService:FailedToDownloadFileUserError"
        },
        {
          "status": 400,
          "errorCode": "INVALID_ARGUMENT",
          "errorName": "IngestService:FrameCountTimestampsMismatch"
        },
        {
          "status": 400,
          "errorCode": "INVALID_ARGUMENT",
          "errorName": "IngestService:InvalidBucket"
        },
        {
          "status": 400,
          "errorCode": "INVALID_ARGUMENT",
          "errorName": "IngestService:InvalidCustomTimestampFormat"
        },
        {
          "status": 400,
          "errorCode": "INVALID_ARGUMENT",
          "errorName": "IngestService:UnsupportedIngestSource"
        },
        {
          "status": 400,
          "errorCode": "INVALID_ARGUMENT",
          "errorName": "IngestService:IncompatibleFileForDataset"
        },
        {
          "status": 400,
          "errorCode": "INVALID_ARGUMENT",
          "errorName": "IngestService:IncompatibleInputs",
          "description": "The inputs provided to the ingest job are incompatible with each other"
        },
        {
          "status": 404,
          "errorCode": "NOT_FOUND",
          "errorName": "IngestService:S3PathNotFound"
        },
        {
          "status": 400,
          "errorCode": "INVALID_ARGUMENT",
          "errorName": "IngestService:BatchGranularityMismatch",
          "description": "All dataset granularities must match."
        },
        {
          "status": 400,
          "errorCode": "INVALID_ARGUMENT",
          "errorName": "IngestService:ParallelReingestIntoDatasetV1",
          "description": "Cannot ingest multiple datasets in parallel into older datasets. It is recommended to reingest all source datasets and the target dataset into a new dataset destination."
        },
        {
          "status": 400,
          "errorCode": "INVALID_ARGUMENT",
          "errorName": "IngestService:MissingMetadataForReingest",
          "description": "The timestamp metadata required to reingest the dataset is missing and must be provided in the request."
        },
        {
          "status": 400,
          "errorCode": "INVALID_ARGUMENT",
          "errorName": "IngestService:ReingestTooManyFiles",
          "description": "The number of files to reingest is too large."
        },
        {
          "status": 400,
          "errorCode": "INVALID_ARGUMENT",
          "errorName": "IngestService:RecursiveReingest",
          "description": "The target dataset is included in the source datasets."
        },
        {
          "status": 500,
          "errorCode": "INTERNAL",
          "errorName": "IngestService:ContainerizedExtractorContainerFailed"
        },
        {
          "status": 404,
          "errorCode": "NOT_FOUND",
          "errorName": "IngestService:IngestJobNotFound"
        },
        {
          "status": 500,
          "errorCode": "FAILED_PRECONDITION",
          "errorName": "IngestService:IngestJobMissingDatasetForIdempotencyKey",
          "description": "A prior ingest job already exists for this idempotency key but never produced a dataset (the original submit did not get far enough). The idempotency key deduplicates to that existing job and does not re-run ingestion; rerun the job identified by ingestJobRid to complete it."
        },
        {
          "status": 404,
          "errorCode": "NOT_FOUND",
          "errorName": "IngestService:IngestTransformNotFound",
          "description": "The ingest transform does not exist, or its parent ingest job is not visible to the caller. Returned as NOT_FOUND (rather than PERMISSION_DENIED) to avoid leaking existence information about transforms the caller cannot see."
        },
        {
          "status": 409,
          "errorCode": "CONFLICT",
          "errorName": "IngestService:IngestJobNotCancellable",
          "description": "The ingest job exists but is in a terminal state (COMPLETED, FAILED, or CANCELLED) and therefore cannot be cancelled."
        },
        {
          "status": 400,
          "errorCode": "INVALID_ARGUMENT",
          "errorName": "IngestService:UnsupportedRequestTypeForReIngest"
        },
        {
          "status": 400,
          "errorCode": "INVALID_ARGUMENT",
          "errorName": "IngestService:IngestJobNotCompatibleForRerun",
          "description": "The ingest job exists but is not compatible to be re-run."
        },
        {
          "status": 404,
          "errorCode": "NOT_FOUND",
          "errorName": "IngestService:DatasetNotFound",
          "description": "The target dataset could not be found."
        },
        {
          "status": 404,
          "errorCode": "NOT_FOUND",
          "errorName": "IngestService:StreamingSessionNotFound",
          "description": "The streaming session could not be found."
        },
        {
          "status": 404,
          "errorCode": "NOT_FOUND",
          "errorName": "IngestService:DatasetFileNotFound",
          "description": "The target dataset file could not be found."
        },
        {
          "status": 400,
          "errorCode": "INVALID_ARGUMENT",
          "errorName": "IngestService:FileDeletionNotSupported",
          "description": "The dataset file is part of a multi-file ingest job and cannot be deleted on its own. Delete the entire ingest job instead."
        },
        {
          "status": 403,
          "errorCode": "PERMISSION_DENIED",
          "errorName": "IngestService:ContainerizedExtractorUnauthorizedPasswordAccess",
          "description": "The user is not authorized to access the containerized extractor password."
        },
        {
          "status": 400,
          "errorCode": "INVALID_ARGUMENT",
          "errorName": "IngestService:ContainerizedExtractorTimestampMetadataMissing",
          "description": "Neither the containerized extractor (or its active container image) nor the ingest request provides timestamp metadata, so the extractor output cannot be indexed. Register the image with default timestamp metadata or supply it on the request."
        }
      ]
    }
  ]
}
