Validate Import
Alpha
The contract may change without notice, and imports created with it are not guaranteed to remain compatible. Not covered by the deprecation policy.
The third phase of a design import. Call this once every asset returned in uploads[] has been uploaded. The API verifies that every expected S3 object is in place, moves the import from WAITING_FOR_VALIDATION to QUEUED, and queues it for backend processing.
Skip when no uploads were needed
If uploads[] was empty in the Create Import response, the import is already QUEUED — do not call PUT. Skip straight to polling Import Status.
Use the URL the response gives you
The exact URL is returned as links.validate in the POST response — prefer using that over constructing the URL by hand.
uploads[] was empty
The import is already QUEUED. Skip PUT entirely and go straight to polling Import Status.
uploads[] had entries
After uploading all of them, call PUT to verify every asset is in place and queue the import.
Path parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string (uuid) | Yes | Import UUID returned by POST /designs/import/json. |
Response
| Field | Type | Description |
|---|---|---|
id | string (uuid) | Import UUID. |
status | string | QUEUED after a successful call. |
next_check_after_ms | integer | Suggested delay before the first status poll (2000). |
links.status | string (url) | Poll URL. |
links.dashboard | — | Not returned by PUT. At this point the target does not exist yet, so there is nowhere to link. Use the link from POST (workspace-template imports) or from GET once the import is DONE. |
Response example
{
"id": "1a8b2c3d-4869-11f0-96f2-0a00d9eb8f78",
"status": "QUEUED",
"next_check_after_ms": 2000,
"links": {
"status": "https://api.abyssale.com/designs/import/json/1a8b2c3d-4869-11f0-96f2-0a00d9eb8f78"
}
}Pre-flight asset check
Before transitioning to QUEUED, the API issues a HEAD against every S3 key declared in the original uploads[]. If any expected object is missing, the call is rejected with 422 Unprocessable Entity:
{
"errors": [
{
"path": "uploads",
"code": "missing_assets",
"message": "2 expected assets have not been uploaded.",
"expected": [
{ "target": "layer", "name": "hero" },
{ "target": "layer", "name": "logo" }
]
}
]
}Upload the missing assets to their original presigned URLs (still valid until expires_at_ts), then retry the PUT.
The same 422 + missing_assets pair is also returned when the presigned window has expired — the assets can never arrive, so the import is rejected rather than queued for work whose inputs cannot exist. The message names that cause explicitly; there is no expected list, because the point is no longer which assets are missing:
{
"errors": [
{
"path": "uploads",
"code": "missing_assets",
"message": "The presigned upload window expired before the assets were uploaded and validated. This import can no longer be validated; create a new import and upload its assets within the window."
}
]
}In that case, re-POST the original payload to get fresh presigned URLs.
Conflicts and replays
- Imports past
QUEUEDcannot be re-validated: the API returns409 Conflictwith codetemplate_import_already_processed. The message names the import's public status only — internal substates are never surfaced. - Replaying the
PUTis a safe no-op while the import is stillQUEUED, so the call is idempotent in principle. In practice it usually isn't observable: the backend claims a queued import within milliseconds, so a retry normally returns that409.
Treat the 409 as success
If your first PUT timed out and the retry comes back 409 template_import_already_processed, that is confirmation the first PUT succeeded. Stop retrying and start polling Import Status.
Example
curl -X PUT "$VALIDATE_URL" \
-H "x-api-key: $API_KEY"$VALIDATE_URL is the links.validate value from the POST response.
Next step
After PUT returns, backend processing picks the import up and progresses it through PROCESSING → DONE (or FAILED). Poll Import Status — the response includes next_check_after_ms to guide your polling cadence.
