uploads

Register Upload

Changed on

Finalize a signed-URL upload into a Moda file row.

Streams the staged blob through download_with_hash (writes to a temp file on disk, hashes in 8 KiB chunks) so a 250 MB upload never fully materializes in process memory — loading even a couple of those concurrently on Cloud Run would risk OOM and defeat the point of the direct-to-storage flow.

Deduplicates against existing team files by content hash. On a dedup miss the staged blob is server-side-copied to the canonical teams/<team>/files/<id> key via storage.copy (zero data transfer on GCS) and registered via create_file_from_storage. The pending blob is best-effort deleted either way.

post/uploads/register

Request

  • Base URL
    https://api.moda.app/v1
  • URL
    https://api.moda.app/v1/uploads/register
  • Auth
    HTTP bearer

Headers

Moda-Version'2026-04-12' | '2026-05-01'
Example:2026-05-01

Calendar-dated API version pin. New integrations should pin 2026-05-01 to opt into the newest response shapes. For back-compat the server also accepts requests with no header and resolves them to the current default (today: 2026-04-12); that default advances on each sunset date. Any unsupported value returns 400 unsupported_version.

Request body

storage_keystring required

storage_key returned by a prior POST /v1/uploads/url after the PUT completed.

filenamestring nullable

Filename to record on the File row. Defaults to the basename embedded in storage_key.

mime_typestring nullable

MIME type to record on the File row. Defaults to the type the signed URL was originally bound to (inferred from the filename when not supplied).

folder_idstring nullable

Prefixed fld_ wire ID (Crockford base32 body) — the canonical, recommended form. For back-compat, a bare UUID string is also accepted in both path parameters and JSON request bodies (older integrations that stored raw UUIDs keep working), as is the prefix over a UUID body (fld_00000000-0000-4000-8000-000000000000). All three are permanent, supported inputs; only the canonical form is ever emitted.

purpose'voice_source' nullable

voice_source marks a transient recording: the seed of POST /v1/voices/similar or the source_audio of a speech-to-speech take. It always gets its own file (never a duplicate of one you already have, and never handed to another upload of the same bytes), stays out of My Media, and Moda deletes it 24 hours later (expires_at) unless a canvas, brand kit or other surface references it by then. Delete it yourself with DELETE /v1/drive/items/{id} once used. Omit for an ordinary, permanent upload.

Example request

{
  "folder_id": "fld_01HT9WK8N3M2J4A5Z6P7Q8R9TV"
}

Response

Successful Response

idstring required

Unique file identifier (prefixed file_...).

urlstring required

Stable proxy URL for the uploaded file. Use this in attachment URLs.

filenamestring required

Filename of the uploaded file.

mime_typestring required

MIME type of the file.

size_bytesinteger nullable

File size in bytes.

was_duplicateboolean

True if an identical file already existed (deduplicated).

folder_idstring nullable

Prefixed fld_ wire ID (Crockford base32 body) — the canonical, recommended form. For back-compat, a bare UUID string is also accepted in both path parameters and JSON request bodies (older integrations that stored raw UUIDs keep working), as is the prefix over a UUID body (fld_00000000-0000-4000-8000-000000000000). All three are permanent, supported inputs; only the canonical form is ever emitted.

expires_atstring nullable

ISO 8601 UTC time after which Moda deletes this transient upload (purpose voice_source), or null for a file that never expires.

Example response

{
  "id": "file_01HT9WK8N3M2J4A5Z6P7Q8R9TV",
  "folder_id": "fld_01HT9WK8N3M2J4A5Z6P7Q8R9TV"
}

Changes

    • info

      added the new optional request property

    • info

      added the new optional request property

    • info

      added the non-success response with the status

    • info

      added the non-success response with the status

    • info

      added the optional property to the response with the status

    • info

      added the optional property to the response with the status

    • info

      added the optional property to the response with the status

    • info

      added the optional property to the response with the status

    • info

      added the optional property to the response with the status

    • info

      added the optional property to the response with the status

    • info

      added the optional property to the response with the status

    • info

      added the optional property to the response with the status

    • info

      added the optional property to the response with the status