REST API

POST /v1/drives/{sg}/nodes

Upload a file

POST /v1/drives/{sg}/nodes

Encrypts and uploads file into security group sg, optionally inside folder parent_id and linked to exam_id; single PUT or multipart is chosen by the SDK from its size. The whole multipart body is buffered (python-multipart's SpooledTemporaryFile, 1 MiB in RAM before it spills to disk) before this handler even runs, so request size is what bounds memory, not this endpoint's own logic.

Path parameters #

  • sg string required

    The security group (the drive).

Responses #

  • 201 Successful Response

    • node_id string required
    • workspace_id string required
    • security_group_id string required
    • kind enum("file" | "folder")
    • status enum("pending" | "ready" | "failed") required
    • exam_id object
    • parent_id object
    • mode object
    • media_kind object
    • declared_size object
    • size object
    • mime_type object
    • encrypted_name object required

      The `{salt, nonce, ciphertext}` shape (all b64url) that crosses the wire. This is the only envelope shape in the protocol — a `HybridSeal` (§6) reuses these same three field names even though its `salt` carries a KEM encapsulation instead of an HKDF salt, so the wire JSON of both looks identical to anything that doesn't know the difference.

    • encrypted_keys object required
    • storage_path object
    • optimized_variants object[]
    • processing_status object
    • processing_error object
    • total_size object
    • created_by string required
    • created_at string required
    • completed_at object
    • is_deleted boolean
  • 400 The vault refused the request as invalid.

    • error object required

      The body of every non-2xx response: what went wrong, for a program and for a person.

  • 401 No client certificate, or the SDK session was rejected or expired (`session_expired`).

    • error object required

      The body of every non-2xx response: what went wrong, for a program and for a person.

  • 402 The workspace has no credit for this.

    • error object required

      The body of every non-2xx response: what went wrong, for a program and for a person.

  • 403 CN not allowed, permission denied, or no key for the data's security group (`group_key_unavailable`).

    • error object required

      The body of every non-2xx response: what went wrong, for a program and for a person.

  • 404 Not found — also a node read under a group it does not belong to.

    • error object required

      The body of every non-2xx response: what went wrong, for a program and for a person.

  • 409 A pending or newer version, a replay, or an upload that never reached storage.

    • error object required

      The body of every non-2xx response: what went wrong, for a program and for a person.

  • 422 The body or query failed validation (`invalid_request`).

    • error object required

      The body of every non-2xx response: what went wrong, for a program and for a person.

  • 429 Rate limited, after the SDK's own backoff gave up.

    • error object required

      The body of every non-2xx response: what went wrong, for a program and for a person.

  • 500 An envelope did not open (`crypto_error`, no detail on purpose).

    • error object required

      The body of every non-2xx response: what went wrong, for a program and for a person.

  • 502 The vault failed, or answered outside the protocol (`protocol_error`).

    • error object required

      The body of every non-2xx response: what went wrong, for a program and for a person.

curl --cert client.crt --key client.key \
  -X POST "https://api.imgexam.com/v1/drives/<sg>/nodes" \
  -H "Content-Type: application/json"
{
  "node_id": "string",
  "workspace_id": "string",
  "security_group_id": "string",
  "kind": "file",
  "status": "pending",
  "exam_id": {},
  "parent_id": {},
  "mode": {},
  "media_kind": {},
  "declared_size": {},
  "size": {},
  "mime_type": {},
  "encrypted_name": {
    "salt": "string",
    "nonce": "string",
    "ciphertext": "string"
  },
  "encrypted_keys": {},
  "storage_path": {},
  "optimized_variants": [
    {
      "kind": "string",
      "storage_bucket": "string",
      "storage_path": "string",
      "storage_size": 0,
      "storage_mime_type": "string",
      "created_at": "string"
    }
  ],
  "processing_status": {},
  "processing_error": {},
  "total_size": {},
  "created_by": "string",
  "created_at": "string",
  "completed_at": {},
  "is_deleted": false
}