Skip to main content
Hcfs • 2 mins read

S3-compatible gateway

S3-compatible gateway

Three endpoints that let any S3 SDK (or any plain multipart client) upload, download, and delete files through HCFS without implementing the native manifest + client-side encryption flow.

These paths are not end-to-end encrypted. The server holds the plaintext of every file uploaded through the gateway. Use the gateway when the client environment cannot hold keys; use the native HCFS path otherwise.

The gateway and the native path share the same /upload URL — the server inspects the first multipart field to decide which handler to dispatch.


POST /upload

Upload a plain file. The server hashes the content, derives path_hash from the filename, and writes a file_records row.

Authentication

Authorization: Bearer <token>. The token's resolved SS58 must match the account_ss58 field in the request body. See auth.md.

Request

POST /upload
Content-Type: multipart/form-data; boundary=<boundary>
Authorization: Bearer <token>

The first multipart field must be account_ss58. (This is the signal the server uses to route to the S3 handler rather than the HCFS native handler.) The file field follows.

FieldContent-TypeBody
account_ss58 (first)text/plainThe uploader's SS58 address
file (second)application/octet-streamRaw file bytes — the server derives path_hash from the field filename

Response — success (200)

{
"Success": {
"file_id": "<64-char hex>",
"upload_id": "<opaque>",
"timestamp": 1713139200
}
}

Response — errors

Statuserror codeCause
400invalid_manifest / missing_fieldFirst field isn't account_ss58, or the file field is missing
401unauthorizedMissing / bad bearer token
403forbiddenToken resolves to a different SS58 than account_ss58
500database_error, storage_inconsistencyTransient

Example

curl -X POST "$SERVER/upload" \
-H "Authorization: Bearer $SS58" \
-F "account_ss58=$SS58" \
-F "file=@/path/to/document.pdf"

GET /download/{ss58}/{file_id}

Stream a file without folder scope. This is the gateway counterpart to the folder-scoped native /download endpoint.

Authentication

Authorization: Bearer <token> matching {ss58}.

Request

GET /download/{ss58}/{file_id}
Authorization: Bearer <token>
Range: bytes=<start>-<end> # optional

Response

StatusMeaning
200 OKFull file returned
206 Partial ContentRange request honored

Response headers mirror the native download: Content-Length, X-Size-Bytes, X-Revision-Id, X-Revision-Seq, X-File-Id, X-Ss58-Address, Accept-Ranges, Content-Range.

The body is raw file bytes (the server stored the plaintext directly — no HCFS chunked envelope).

Response — errors

Statuserror codeCause
400invalid_file_idNot valid 64-char hex
401unauthorizedMissing / bad bearer token
403forbiddenToken resolves to a different SS58 than {ss58}
404not_foundNo such file
500storage_inconsistencyMetadata row exists but blob is missing

Example

curl -H "Authorization: Bearer $SS58" \
-o "document.pdf" \
"$SERVER/download/$SS58/$FILE_ID"

DELETE /delete/{ss58}/{file_id}

Remove a file uploaded via the gateway.

Authentication

Authorization: Bearer <token> matching {ss58}.

Request

DELETE /delete/{ss58}/{file_id}
Authorization: Bearer <token>

Response — success (200)

{
"Success": {
"status": "deleted",
"file_id": "<64-char hex>",
"ss58_address": "5Grw...",
"folder_hash": ""
}
}

folder_hash is empty for gateway-owned files.

Response — errors

Statuserror codeCause
400invalid_file_idNot valid hex
401unauthorizedMissing / bad bearer token
403forbiddenSS58 mismatch
404not_foundNo such file

Example

curl -X DELETE \
-H "Authorization: Bearer $SS58" \
"$SERVER/delete/$SS58/$FILE_ID"

Notes

  • Files uploaded through the gateway are listed by /get_state alongside native uploads — the two paths share the file_records table.
  • Because the server holds plaintext for gateway uploads, do not use this path for anything the user would not put on a conventional S3 bucket.
  • If you need the full end-to-end-encrypted experience (server never sees plaintext, client-side key management), use the native /upload flow instead.