Download OpenAPI specification:
Converts SLPK/TPKX/IFC/RVT/LAS/raster/mesh packages uploaded to an S3 input bucket into i3sREST or tile format in an output bucket, and (optionally) publishes the result as an ArcGIS Enterprise service item. Built for both the browser SPA and machine-to-machine callers (FME and similar) — both use the exact same endpoints and header scheme below.
Every endpoint except the health probes requires:
| Header | Purpose |
|---|---|
X-Client-Id |
Identifies the calling client — resolves the customer's S3/portal configuration |
X-Client-Secret |
Authenticates the call for that client |
X-Portal-Token |
The ArcGIS Portal user's access token. Required whenever the call publishes (auto_publish, POST /publish, register_source_item, or a non-private sharing_level) or lists job history (GET /jobs); not required for an upload-only call |
X-Portal-Token is obtained the same way for a browser SPA and a machine client —
generateToken (client=requestip) for a scripted/scheduled caller, or an ArcGIS API Key
for unattended production automation.
Two ways to run the full pipeline — pick whichever shape suits the integration. Both end up enqueuing the exact same background job with the same parameters.
POST /upload (multipart form) with auto_publish=true, service_name, and
X-Portal-Token set does everything: streams the file to S3, then immediately enqueues
extraction + publish. The response is a Server-Sent-Events stream:
data: {"status": "uploading", "bytes_uploaded": 1048576, "total": 52428800, "progress_pct": 2.0}
...
data: {"status": "uploaded", "input_key": "tileserver/input/model.slpk"}
data: {"status": "queued", "task_id": "abc123", "task_name": "process_slpk", "poll_url": "/tasks/abc123"}
Take task_id from the final queued event and poll GET /tasks/{task_id}.
Useful for confirming the upload succeeded before committing to a publish, letting a user pick the service name/sharing afterwards, or re-publishing an already-uploaded file.
POST /upload with auto_publish omitted (defaults to false) — same SSE stream as
above, but it stops after the uploaded event. Keep the input_key from that event.POST /publish with {"portal_url", "input_key", "service_name", ...} and
X-Portal-Token — enqueues the same extraction+publish job. Responds immediately with
a TaskModel (id / poll_url), as plain JSON rather than a stream.GET /tasks/{task_id} works for a task from either option above. Poll until status is
SUCCESS or FAILURE; result then holds either the published service info
(PackageResult: service_url, item_id, ...) or a FailureResult.
.slpk .tpkx .las/.laz/.zlas .tif/.tiff/.img/.ecw .ifc/.rvt
.osgb/.obj/.dae. An .ifc/.rvt may also be uploaded as a .zip bundle together
with georeferencing sidecars (.prj/.wld3) — the model file inside determines the task.
POST /tasks/process_slpk / POST /tasks/process_tpkx and their matching GET
endpoints are deprecated — use POST /publish and GET /tasks/{task_id} instead, which
work for every supported file type.
Upload a package to S3 and run it through extraction + publish, in one call or two. See the description above for the full sequence.
| x-client-id required | string (X-Client-Id) |
| x-client-secret required | string (X-Client-Secret) |
| x-portal-token required | string (X-Portal-Token) |
| portal_url required | string (Portal Url) |
| input_key required | string (Input Key) |
| service_name | string (Service Name) Default: "" |
| referer | string (Referer) Default: "" |
| register_source_item | boolean (Register Source Item) Default: false |
| sharing_level | string (Sharing Level) Default: "private" |
| group_ids | Array of strings (Group Ids) Default: [] |
{- "portal_url": "string",
- "input_key": "string",
- "service_name": "",
- "referer": "",
- "register_source_item": false,
- "sharing_level": "private",
- "group_ids": [ ]
}{- "id": "string",
- "name": "string",
- "status": "string",
- "poll_url": ""
}{- "id": "string",
- "name": "string",
- "status": "string",
- "poll_url": "",
- "info": { },
- "result": {
- "bucket": "string",
- "key": "string",
- "item_id": "",
- "service_url": "",
- "source_item_id": "",
- "sharing_level": "",
- "not_shared_with": [ ]
}
}| x-client-id required | string (X-Client-Id) |
| x-client-secret required | string (X-Client-Secret) |
| x-portal-token required | string (X-Portal-Token) |
| portal_url required | string (Portal Url) |
| input_key required | string (Input Key) |
| service_name | string (Service Name) Default: "" |
| referer | string (Referer) Default: "" |
| register_source_item | boolean (Register Source Item) Default: false |
| sharing_level | string (Sharing Level) Default: "private" |
| group_ids | Array of strings (Group Ids) Default: [] |
{- "portal_url": "string",
- "input_key": "string",
- "service_name": "",
- "referer": "",
- "register_source_item": false,
- "sharing_level": "private",
- "group_ids": [ ]
}{- "id": "string",
- "name": "string",
- "status": "string",
- "poll_url": ""
}{- "id": "string",
- "name": "string",
- "status": "string",
- "poll_url": "",
- "info": { },
- "result": {
- "bucket": "string",
- "key": "string",
- "item_id": "",
- "service_url": "",
- "source_item_id": "",
- "sharing_level": "",
- "not_shared_with": [ ]
}
}{- "id": "string",
- "name": "string",
- "status": "string",
- "poll_url": "",
- "info": { },
- "result": {
- "bucket": "string",
- "key": "string",
- "item_id": "",
- "service_url": "",
- "source_item_id": "",
- "sharing_level": "",
- "not_shared_with": [ ]
}
}| x-client-id required | string (X-Client-Id) |
| x-client-secret required | string (X-Client-Secret) |
| x-portal-token | string (X-Portal-Token) Default: |
| file required | string <binary> (File) |
| portal_url required | string (Portal Url) |
| auto_publish | boolean (Auto Publish) Default: false |
| service_name | string (Service Name) Default: "" |
| referer | string (Referer) Default: "" |
| register_source_item | boolean (Register Source Item) Default: false |
| sharing_level | string (Sharing Level) Default: "private" |
| group_ids | string (Group Ids) Default: "" |
null| x-client-id required | string (X-Client-Id) |
| x-client-secret required | string (X-Client-Secret) |
| x-portal-token required | string (X-Portal-Token) |
| portal_url required | string (Portal Url) |
| input_key required | string (Input Key) |
| service_name | string (Service Name) Default: "" |
| referer | string (Referer) Default: "" |
| register_source_item | boolean (Register Source Item) Default: false |
| sharing_level | string (Sharing Level) Default: "private" |
| group_ids | Array of strings (Group Ids) Default: [] |
{- "portal_url": "string",
- "input_key": "string",
- "service_name": "",
- "referer": "",
- "register_source_item": false,
- "sharing_level": "private",
- "group_ids": [ ]
}{- "id": "string",
- "name": "string",
- "status": "string",
- "poll_url": ""
}Look up past jobs and fetch a permanent link back to an originally-uploaded source file.
| portal_url required | string (Portal Url) |
| limit | integer (Limit) Default: 10 |
| offset | integer (Offset) Default: 0 |
| referer | string (Referer) Default: "" |
| x-client-id required | string (X-Client-Id) |
| x-client-secret required | string (X-Client-Secret) |
| x-portal-token required | string (X-Portal-Token) |
{- "persisted": true,
- "jobs": [
- {
- "job_id": "",
- "job_date": 0,
- "filename": "",
- "status": "",
- "publish_url": ""
}
]
}Liveness/readiness probes and a startup-config diagnostic view — not part of the integration flow.
Readiness: can this pod actually serve? Broker reachable + clients.json parses.
Sync def so the blocking broker probe runs in FastAPI's threadpool, not the event loop. Deliberately does NOT check downstream portals, per-tenant S3, or worker health — those being down doesn't make this API unable to accept and queue work, and gating on them would take the API out on someone else's outage.
{ }| x-client-id required | string (X-Client-Id) |
| x-client-secret required | string (X-Client-Secret) |
| portal_url required | string (Portal Url) |
| filename required | string (Filename) |
| size required | integer (Size) |
{- "portal_url": "string",
- "filename": "string",
- "size": 0
}{- "upload_id": "string",
- "input_key": "string",
- "part_size": 0
}| x-client-id required | string (X-Client-Id) |
| x-client-secret required | string (X-Client-Secret) |
| portal_url required | string (Portal Url) |
| input_key required | string (Input Key) |
| upload_id required | string (Upload Id) |
| part_numbers required | Array of integers (Part Numbers) |
{- "portal_url": "string",
- "input_key": "string",
- "upload_id": "string",
- "part_numbers": [
- 0
]
}{- "urls": [
- {
- "part_number": 0,
- "url": "string"
}
]
}| x-client-id required | string (X-Client-Id) |
| x-client-secret required | string (X-Client-Secret) |
| x-portal-token | string (X-Portal-Token) Default: |
| portal_url required | string (Portal Url) |
| input_key required | string (Input Key) |
| upload_id required | string (Upload Id) |
required | Array of objects (Parts) |
| auto_publish | boolean (Auto Publish) Default: false |
| service_name | string (Service Name) Default: "" |
| referer | string (Referer) Default: "" |
| register_source_item | boolean (Register Source Item) Default: false |
| sharing_level | string (Sharing Level) Default: "private" |
| group_ids | Array of strings (Group Ids) Default: [] |
{- "portal_url": "string",
- "input_key": "string",
- "upload_id": "string",
- "parts": [
- {
- "part_number": 0,
- "etag": "string"
}
], - "auto_publish": false,
- "service_name": "",
- "referer": "",
- "register_source_item": false,
- "sharing_level": "private",
- "group_ids": [ ]
}{- "input_key": "string",
- "task": {
- "id": "string",
- "name": "string",
- "status": "string",
- "poll_url": ""
}
}| upload_id required | string (Upload Id) |
| portal_url required | string (Portal Url) |
| input_key required | string (Input Key) |
| x-client-id required | string (X-Client-Id) |
| x-client-secret required | string (X-Client-Secret) |
{- "detail": [
- {
- "loc": [
- "string"
], - "msg": "string",
- "type": "string"
}
]
}