CorebanqCorebanq Developer Docs
Uploadsv1Files

Delete file

Delete a file

DELETE
/v1/uploads/{id}

Authorization

bearerAuth
AuthorizationBearer <token>

In: header

Path Parameters

id*string

Response Body

application/json

application/json

application/json

application/json

application/json

application/json

application/json

application/json

curl -X DELETE "https://example.com/v1/uploads/497f6eca-6276-4993-bfeb-53cbbbba6f08"
{
  "status": 200,
  "message": "OK"
}

{
  "status": 400,
  "code": "uploads.invalid_file_extension",
  "message": "Invalid file extension"
}

{
  "status": 401,
  "message": "Unauthorized",
  "code": "common.unauthorized",
  "class": "business"
}

{
  "status": 403,
  "message": "No access to the record",
  "code": "common.rbac_no_rec_access",
  "class": "business"
}

{
  "status": 404,
  "code": "uploads.record_not_found",
  "message": "Record not found"
}

{
  "status": 429,
  "message": "Rate limit for 203.0.113.7 to /v1/uploads exceeded.",
  "code": "rate_limits_m.exceeded",
  "class": "temporary",
  "retryable": true
}

{
  "status": 500,
  "message": "Internal server error",
  "code": "common.server_error",
  "class": "business"
}

{
  "overall_status": "unhealthy",
  "message": "Service is shutting down",
  "timestamp": "2026-08-27T15:04:05Z"
}

PATCHAdjust signature count

Update document signature count

GETList a customer's uploads with search, sort and pagination

The v2 replacement for GET /v1/uploads/customer/{customer_id}. This route was registered but documented nowhere. Two differences from v1 that change how a client reads it: - it returns the SHARED LIST ENVELOPE — data, total, total_unfiltered, has_more, and keys when stacked — where v1 returns a bare array with no counts; - it takes the shared search/sort/pagination parameters, where v1 takes three flat filters (isSigned, isApproved, tag) and nothing else. Scoping is by LINK, then by grant. The uploads are those linked to the customer; a caller with read-all gets all of them, otherwise the set is intersected with the upload ids the caller may read. An empty intersection is a 200 with an empty envelope, not a 403 — so a caller who may see the customer but none of its uploads gets an empty page rather than a refusal. total_unfiltered IS ALWAYS EQUAL TO total ON THIS ROUTE — do not read it as the pre-search count. The service builds one GORM statement and reuses it: the search predicates are appended to the very object the unfiltered count is then taken from, so both counts run the same SQL. It carries useful information only when no search is given, and then it is the same number as total anyway. has_more is (offset + effective limit) < total, computed off the limit the route actually used. Filterable fields, usable as search.<field>[.operator]: id, file_name, document_type, approval_status, approval_needed, approval_made, signature_status, signature_needed, signature_made, customer_id, content_length, file_extension, metadata, created_at, created_by, modified_at, modified_by, active. Each search.<field> parameter also accepts an operator suffix — search.<field>.<operator>, e.g. search.created_at.gte=2026-01-01 or search.document_type.in=passport,id_card. The suffixed forms are not enumerated here; only the bare equality form is. The reserved search._text.<operator> filter searches the free-text expression described under the search parameter. A REJECTED search.<field> SPLITS INTO TWO OUTCOMES, and the difference is the field NAME, not whether the field exists: - a name that is not a valid identifier — search.foo-bar=1 — fails validFieldNamePattern and is a 400 query_m.invalid_field; - a well-formed name that is simply not in the list above — search.bogus=x — is a 500 carrying query_m.invalid_search_field. It is rejected, not dropped, but the route builds its total query before ApplySearchAndSort, and ApplySearchAndSort is the only place that raises that error to a 400. The same typo is a 400 on other get-all endpoints. Both checks run only when the caller has at least one readable upload: with an empty permitted set the request short-circuits to the empty 200 before the search is parsed.