When you register one base URL with the platform, the platform calls three paths under it. In the examples, https://data.example.com/api is the base URL.

#Method · pathPurpose
1GET {base}/datasetsDataset list + update time
2GET {base}/datasets/{id}/manifestFile list + SHA-256 — the only basis for detecting changes
3GET {base}/datasets/{id}/files/{file_id}File body (binary)

The paths must have exactly this shape. In return, the field names in responses can follow your own conventions — the platform accepts several names with the same meaning (see Field aliases below).

Common conventions

ItemRequirement
AuthenticationA single Authorization: Bearer <token> header. For a server without a token, leave the token field empty when you register it. The platform has to present this token, so it stores it in the clear. Issue a read-only token dedicated to the platform
TransportHTTPS recommended. The platform accepts only http:// · https:// and rejects link-local (169.254.x.x) and multicast IP addresses
Ids in paths{id} · {file_id} are percent-encoded into the path (/ becomes %2F). Ids made of letters, digits, -, _ and . avoid encoding issues
Response format1 · 2 return an application/json (UTF-8) object; 3 returns binary
TimesISO 8601 with a time zone (for example 2026-07-21T09:30:00Z). Without a time zone, the time is read as UTC
ErrorsHTTP status code + JSON body. 401 for authentication failure, 404 for a missing resource. For list and manifest calls, the first 200 characters of the error body go into the on-screen message as is (file calls show only the status code)
Call frequencyCalled only when a person presses a button (no scheduled sync)
Time limitEach request must start responding within 30 seconds. Large files are timed per read, so a long transfer is fine

1. Dataset list

curl -H "Authorization: Bearer $TOKEN" \
  "https://data.example.com/api/datasets?page=1&page_size=50&updated_after=2026-07-01T00:00:00Z"
{
  "items": [
    {
      "id": "ds-inspect-2026w29",
      "name": "Line inspection images 2026-W29",
      "modality": "image",
      "file_count": 412,
      "size_bytes": 1073741824,
      "updated_at": "2026-07-21T09:30:00Z"
    }
  ],
  "page": 1,
  "total": 3
}
FieldRequiredDescription
idRequiredA unique ID that never changes (256 characters or fewer). It must stay the same even if the name changes — it is the key the platform uses to find what to sync again. If any entry lacks an id, the whole list fails
nameRecommendedName shown in the remote dataset chooser. id is used if missing
modalityRecommendedimage · pointcloud · timeseries · tabular. Becomes the default modality when a new dataset is created on screen
file_count · size_bytesRecommendedFor display on the selection screen
updated_atRecommendedMust change whenever a file is added, changed or deleted. Shown as the "updated" time in the chooser, and the basis for updated_after queries
  • The platform sends page (starting at 1). page_size is added only by the connection test (page=1&page_size=1) and when a caller of the platform API supplies it. The on-screen remote dataset list sends only page.
  • If you split the list into pages, always return total. The screen asks for the next page through "Load more" only while it has loaded fewer items than total. Without total it treats the first response as the whole list, so later pages never show. If you do not paginate, ignore page · page_size and return everything.
  • When updated_after arrives, return only what changed after that time (recommended). The screen does not send it; it is passed on, in UTC (…Z), only when a script calls GET /api/v1/external-sources/{id}/remote-datasets?updated_after=….
  • A sync does not call the list. It uses only the manifest and file paths.

2. Manifest

curl -H "Authorization: Bearer $TOKEN" \
  "https://data.example.com/api/datasets/ds-inspect-2026w29/manifest"
{
  "dataset_id": "ds-inspect-2026w29",
  "name": "Line inspection images 2026-W29",
  "modality": "image",
  "updated_at": "2026-07-21T09:30:00Z",
  "annotation_format": "coco",
  "classes": [{ "id": 0, "name": "defect_a" }, { "id": 1, "name": "defect_b" }],
  "files": [
    {
      "file_id": "f-0001",
      "filename": "20260721_line3_0001.png",
      "kind": "image",
      "size_bytes": 2493833,
      "sha256": "9f8a1c…",
      "meta": { "line": "line-3", "measured_at": "2026-07-21T09:30:12+09:00" }
    }
  ]
}
FieldRequiredDescription
nameRecommendedUsed as the name when a new dataset is created with the name left empty. Without it, the remote id becomes the name. Keep it the same as the list's name
modalityOptionalUsed when a dataset is created through the API without a modality
updated_atRecommendedAfter a sync ends, shown as the "remote update time" on the external source card
files[].file_idRequiredA file key used in the download path that never changes. It must stay the same even when the file's contents change (only then is it judged "changed" and the same row replaced)
files[].filenameRequiredFile name including the extension. The platform decides the file kind from the extension. A path (a/b.png) is dropped and only the last name (b.png) is used, so the same name in different folders clashes and the later one is skipped
files[].sha256Effectively requiredSHA-256 of the body (hex, case-insensitive). Without it, that file is downloaded again every time
files[].size_bytesRecommendedFor progress display
files[].kindOptionalUsed only for CSV · TSV · Parquet files: timeseries or tabular classifies the file as that. The kind of other files is decided by the extension
files[].metaOptionalPer-file metadata. Kept as is in the platform file's meta.source
annotation_format · classesOptionalOnly recorded, not interpreted. Platform validators read labels directly from the annotation files received

If any entry lacks a file_id or filename, the whole manifest cannot be read and that sync fails.

3. File body

curl -H "Authorization: Bearer $TOKEN" -o 0001.png \
  "https://data.example.com/api/datasets/ds-inspect-2026w29/files/f-0001"
  • Stream the file body as is. Any Content-Type works.
  • Redirects are followed, so you may return a 302 to a presigned URL instead of the body. The Authorization header is not sent to a different host, so the presigned URL must work without the token.
  • Resuming (Range) is not used yet. A failed file is fetched again in full on the next sync.
  • Each file can be up to 2 GiB (configurable in the server settings). A larger file is cut off mid-transfer and recorded as a warning.

Error responses

// 401
{ "error": "invalid_token", "message": "The token has expired." }
// 404
{ "error": "dataset_not_found", "message": "ds-xxxx was not found." }
// 429
{ "error": "rate_limited", "message": "Please try again later." }

The platform does not interpret this body; it shows the start of it to the user. It must contain one sentence that states the cause.

The platform does not retry an error response and does not read Retry-After. If a file call fails, only that file is recorded as a warning and it is fetched again on the next sync. If the manifest call fails, that sync fails.

Field aliases

You can use any of the names below for response fields. The platform looks for them in order and uses the first non-empty value.

MeaningAccepted names
List arrayitems · datasets · results · data
Total counttotal · count · total_count
Dataset idid · dataset_id · datasetId
Namename · title
Modalitymodality · type
File countfile_count · fileCount · files
Sizesize_bytes · sizeBytes · size
Update timeupdated_at · updatedAt · modified_at · last_modified (for the manifest, updated_at · updatedAt)
File arrayfiles · items · entries
File idfile_id · fileId · id
File namefilename · name · path
Checksumsha256 · checksum_sha256 · checksum · hash
File kindkind · type
Class tableclasses · categories · labels
Annotation formatannotation_format · annotationFormat · label_format

If you really need a name not in this table, ask the platform team to add an alias.

Supported file formats

KindFormats
ImagesPNG · JPG · BMP · TIFF · WebP
Time series · tablesCSV · TSV · Parquet (a header in the first row is required)
Point cloudsPLY — if there is a per-point integer label property, it is found automatically and classes are counted
AnnotationsCOCO JSON · LabelMe JSON · VOC XML

The extension cannot tell CSV · TSV · Parquet time series from tables. If the manifest gives a per-file kind of timeseries or tabular, the platform follows it. Otherwise the dataset modality decides (tabular gives tables, anything else time series); in that case report modality as tabular in the list, or choose the modality directly when the dataset is created.

Integration checklist (provider side)

Before registering with the platform, call the three paths yourself with curl. The commands are the same as "Try it" in the Reference implementation. The platform's Test connection (연결 확인) calls only the list, so check the manifest and file paths here.

#CheckIf it fails
1Does the list return 200 with the token?Fix the authentication method first
2Does every list and manifest entry have an id · file_id · filename?The whole list or manifest cannot be read
3If you paginate, is total present?Only the first page shows on screen
4Does updated_after work?Use full listing instead of incremental queries
5Does the sha256 in the manifest match sha256sum of the downloaded file?The file is dropped with a warning
6Do received files open without corruption?Check the transport layer
7If the same dataset is synced twice, does the second sync fetch 0 files?Incremental sync does not work (check whether file_id changes)

Written for the platform as of 2026-10-02.

© MLOps Central Platform