assets
Stable. Describes behaviour that is built and covered by tests in this repository.
POST /v1/assets/uploads #
Open a direct multipart upload session for up to 50 files
Returns, for each file, presigned S3 UploadPart URLs for its first (up to 100) parts. Upload the parts in parallel
straight to S3 (PUT, each part part_size bytes except the last), keep the ETag of each answer, then call
complete. The session lasts 24 hours. Idempotency-Key makes retries return the same session.
Request body
| Field | Type | Description |
|---|---|---|
files required | array of CreateUploadSessionFile |
Example
{
"files": [
{
"filename": "string",
"content_type": "application/pdf",
"size": 1,
"purpose": "invoice_logo"
}
]
}Responses
| Status | Meaning | Body |
|---|---|---|
201 | Created | UploadSession |
400 | Error envelope | Error |
409 | Error envelope | Error |
Example response
{
"id": "string",
"status": "OPEN",
"expire_time": "2026-11-03T10:15:00Z",
"files": [
{
"asset_id": "string",
"filename": "string",
"status": "string",
"reject_reason": "string",
"size": "string",
"part_size": "string",
"part_count": 1,
"presigned_parts": [
{
"part_number": 1,
"url": "string"
}
],
"uploaded_parts": [
{
"part_number": 1,
"size": "string",
"etag": "string"
}
]
}
]
}curl
curl -X POST https://YOUR-API-ADDRESS/v1/assets/uploads \
-H "Authorization: Bearer $PAYRUDDER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"files":[{"filename":"string","content_type":"application/pdf","size":1,"purpose":"invoice_logo"}]}'DELETE /v1/assets/uploads/{session} #
Abort a session and every unfinished file in it
Parameters
| Name | In | Type | Description |
|---|---|---|---|
session required | path | string · uuid |
Responses
| Status | Meaning | Body |
|---|---|---|
200 | OK | UploadSession |
404 | Error envelope | Error |
Example response
{
"id": "string",
"status": "OPEN",
"expire_time": "2026-11-03T10:15:00Z",
"files": [
{
"asset_id": "string",
"filename": "string",
"status": "string",
"reject_reason": "string",
"size": "string",
"part_size": "string",
"part_count": 1,
"presigned_parts": [
{
"part_number": 1,
"url": "string"
}
],
"uploaded_parts": [
{
"part_number": 1,
"size": "string",
"etag": "string"
}
]
}
]
}curl
curl -X DELETE https://YOUR-API-ADDRESS/v1/assets/uploads/<session> \
-H "Authorization: Bearer $PAYRUDDER_API_KEY"GET /v1/assets/uploads/{session}/files/{asset} #
State of one file, including the parts S3 already holds (to resume an interrupted upload)
Parameters
| Name | In | Type | Description |
|---|---|---|---|
session required | path | string · uuid | |
asset required | path | string · uuid |
Responses
| Status | Meaning | Body |
|---|---|---|
200 | OK | UploadFile |
404 | Error envelope | Error |
Example response
{
"asset_id": "string",
"filename": "string",
"status": "string",
"reject_reason": "string",
"size": "string",
"part_size": "string",
"part_count": 1,
"presigned_parts": [
{
"part_number": 1,
"url": "string"
}
],
"uploaded_parts": [
{
"part_number": 1,
"size": "string",
"etag": "string"
}
]
}curl
curl -X GET https://YOUR-API-ADDRESS/v1/assets/uploads/<session>/files/<asset> \
-H "Authorization: Bearer $PAYRUDDER_API_KEY"DELETE /v1/assets/uploads/{session}/files/{asset} #
Abort one file of a session
Parameters
| Name | In | Type | Description |
|---|---|---|---|
session required | path | string · uuid | |
asset required | path | string · uuid |
Responses
| Status | Meaning | Body |
|---|---|---|
200 | OK | UploadSession |
404 | Error envelope | Error |
Example response
{
"id": "string",
"status": "OPEN",
"expire_time": "2026-11-03T10:15:00Z",
"files": [
{
"asset_id": "string",
"filename": "string",
"status": "string",
"reject_reason": "string",
"size": "string",
"part_size": "string",
"part_count": 1,
"presigned_parts": [
{
"part_number": 1,
"url": "string"
}
],
"uploaded_parts": [
{
"part_number": 1,
"size": "string",
"etag": "string"
}
]
}
]
}curl
curl -X DELETE https://YOUR-API-ADDRESS/v1/assets/uploads/<session>/files/<asset> \
-H "Authorization: Bearer $PAYRUDDER_API_KEY"POST /v1/assets/uploads/{session}/files/{asset}/parts #
More (or refreshed) presigned part URLs of a file
Parameters
| Name | In | Type | Description |
|---|---|---|---|
session required | path | string · uuid | |
asset required | path | string · uuid | |
from | query | integer | |
count | query | integer |
Responses
| Status | Meaning | Body |
|---|---|---|
200 | OK | PresignPartsResponse |
404 | Error envelope | Error |
409 | Error envelope | Error |
Example response
{
"parts": [
{
"part_number": 1,
"url": "string"
}
]
}curl
curl -X POST https://YOUR-API-ADDRESS/v1/assets/uploads/<session>/files/<asset>/parts \
-H "Authorization: Bearer $PAYRUDDER_API_KEY"POST /v1/assets/uploads/{session}/files/{asset}/complete #
Verify the uploaded parts, assemble the object and make the asset READY
Idempotent. If the parts do not match what S3 holds (a missing part or a wrong ETag), the asset comes back
REJECTED with reject_reason: PART_MISMATCH and nothing is left in storage.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
session required | path | string · uuid | |
asset required | path | string · uuid |
Request body
| Field | Type | Description |
|---|---|---|
parts required | array of CompleteUploadFilePart |
Example
{
"parts": [
{
"part_number": 1,
"etag": "string"
}
]
}Responses
| Status | Meaning | Body |
|---|---|---|
200 | OK | Asset |
404 | Error envelope | Error |
409 | Error envelope | Error |
Example response
{
"id": "string",
"session_id": "string",
"purpose": "PURPOSE_INVOICE_LOGO",
"filename": "string",
"content_type": "string",
"size_bytes": "string",
"sha256": "string",
"status": "ASSET_STATUS_PENDING",
"reject_reason": "PART_MISMATCH",
"create_time": "2026-11-03T10:15:00Z",
"complete_time": "2026-11-03T10:15:00Z"
}curl
curl -X POST https://YOUR-API-ADDRESS/v1/assets/uploads/<session>/files/<asset>/complete \
-H "Authorization: Bearer $PAYRUDDER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"parts":[{"part_number":1,"etag":"string"}]}'GET /v1/assets #
List READY assets
Parameters
| Name | In | Type | Description |
|---|---|---|---|
purpose | query | invoice_logo | invoice_attachment | general | |
page_size | query | integer | |
page_token | query | string |
Responses
| Status | Meaning | Body |
|---|---|---|
200 | OK | ListAssetsResponse |
400 | Error envelope | Error |
Example response
{
"assets": [
{
"id": "string",
"session_id": "string",
"purpose": "PURPOSE_INVOICE_LOGO",
"filename": "string",
"content_type": "string",
"size_bytes": "string",
"sha256": "string",
"status": "ASSET_STATUS_PENDING",
"reject_reason": "PART_MISMATCH",
"create_time": "2026-11-03T10:15:00Z",
"complete_time": "2026-11-03T10:15:00Z"
}
],
"next_page_token": "string"
}curl
curl -X GET https://YOUR-API-ADDRESS/v1/assets \
-H "Authorization: Bearer $PAYRUDDER_API_KEY"POST /v1/assets #
Upload up to 20 small files in one multipart/form-data request
Files are streamed through the gateway into storage (at most 25 MiB each, 100 MiB per request); use an upload
session for larger files. An optional first part metadata picks each file's purpose:
{"files": {"logo.png": {"purpose": "invoice_logo"}}} (default general). The answer is 200 with one result per
file, in order: a bad file is rejected with an error_code and does not fail the others. The write rate limit
is charged per file.
Responses
| Status | Meaning | Body |
|---|---|---|
200 | Per-file results | UploadAssetsResponse |
400 | Error envelope | Error |
413 | Error envelope | Error |
429 | Error envelope | Error |
Example response
{
"results": [
{
"filename": "string",
"status": "created"
}
]
}curl
curl -X POST https://YOUR-API-ADDRESS/v1/assets \
-H "Authorization: Bearer $PAYRUDDER_API_KEY"GET /v1/assets/{id} #
One asset
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id required | path | string · uuid |
Responses
| Status | Meaning | Body |
|---|---|---|
200 | OK | Asset |
404 | Error envelope | Error |
Example response
{
"id": "string",
"session_id": "string",
"purpose": "PURPOSE_INVOICE_LOGO",
"filename": "string",
"content_type": "string",
"size_bytes": "string",
"sha256": "string",
"status": "ASSET_STATUS_PENDING",
"reject_reason": "PART_MISMATCH",
"create_time": "2026-11-03T10:15:00Z",
"complete_time": "2026-11-03T10:15:00Z"
}curl
curl -X GET https://YOUR-API-ADDRESS/v1/assets/<id> \
-H "Authorization: Bearer $PAYRUDDER_API_KEY"DELETE /v1/assets/{id} #
Delete a READY asset (its bytes leave the storage quota)
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id required | path | string · uuid |
Responses
| Status | Meaning | Body |
|---|---|---|
200 | OK | Asset |
404 | Error envelope | Error |
409 | Error envelope | Error |
Example response
{
"id": "string",
"session_id": "string",
"purpose": "PURPOSE_INVOICE_LOGO",
"filename": "string",
"content_type": "string",
"size_bytes": "string",
"sha256": "string",
"status": "ASSET_STATUS_PENDING",
"reject_reason": "PART_MISMATCH",
"create_time": "2026-11-03T10:15:00Z",
"complete_time": "2026-11-03T10:15:00Z"
}curl
curl -X DELETE https://YOUR-API-ADDRESS/v1/assets/<id> \
-H "Authorization: Bearer $PAYRUDDER_API_KEY"GET /v1/assets/{id}/download #
A presigned link (5 minutes) that downloads the file as an attachment
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id required | path | string · uuid |
Responses
| Status | Meaning | Body |
|---|---|---|
200 | OK | SignedUrl |
404 | Error envelope | Error |
409 | Error envelope | Error |
Example response
{
"url": "string",
"expires_at": "2026-11-03T10:15:00Z"
}curl
curl -X GET https://YOUR-API-ADDRESS/v1/assets/<id>/download \
-H "Authorization: Bearer $PAYRUDDER_API_KEY"Models
Asset
| Field | Type | Description |
|---|---|---|
id required | string | |
session_id required | string | |
purpose required | PURPOSE_INVOICE_LOGO | PURPOSE_INVOICE_ATTACHMENT | PURPOSE_GENERAL | |
filename required | string | |
content_type required | string | |
size_bytes required | string · int64 | |
sha256 required | string | |
status required | ASSET_STATUS_PENDING | ASSET_STATUS_UPLOADING | ASSET_STATUS_SCANNING | ASSET_STATUS_READY | ASSET_STATUS_REJECTED | ASSET_STATUS_ABORTED | ASSET_STATUS_CORRUPT | ASSET_STATUS_DELETED | |
reject_reason required | string | |
create_time required | string · date-time | |
complete_time required | string · date-time |
CompleteUploadFilePart
| Field | Type | Description |
|---|---|---|
part_number required | integer | |
etag required | string |
CompleteUploadFileRequest
| Field | Type | Description |
|---|---|---|
parts required | array of CompleteUploadFilePart |
CreateUploadSessionFile
| Field | Type | Description |
|---|---|---|
filename required | string | |
content_type required | string | |
size required | integer | |
purpose required | invoice_logo | invoice_attachment | general | |
sha256 | string | Optional hex sha256 of the whole file |
CreateUploadSessionRequest
| Field | Type | Description |
|---|---|---|
files required | array of CreateUploadSessionFile |
Error
| Field | Type | Description |
|---|---|---|
error required | object |
ListAssetsResponse
| Field | Type | Description |
|---|---|---|
assets required | array of Asset | |
next_page_token required | string |
PresignPartsResponse
| Field | Type | Description |
|---|---|---|
parts required | array of PresignedPart |
PresignedPart
| Field | Type | Description |
|---|---|---|
part_number required | integer | |
url required | string · uri |
SignedUrl
| Field | Type | Description |
|---|---|---|
url required | string · uri | |
expires_at required | string · date-time | RFC 3339, UTC |
UploadAssetsResponse
| Field | Type | Description |
|---|---|---|
results required | array of UploadAssetsResult |
UploadAssetsResult
| Field | Type | Description |
|---|---|---|
filename required | string | |
status required | created | rejected | |
asset | Asset | |
error_code | string | |
message | string |
UploadFile
| Field | Type | Description |
|---|---|---|
asset_id required | string | |
filename required | string | |
status required | string | |
reject_reason required | string | |
size required | string · int64 | |
part_size required | string · int64 | |
part_count required | integer | |
presigned_parts required | array of PresignedPart | |
uploaded_parts required | array of object |
UploadSession
| Field | Type | Description |
|---|---|---|
id required | string | |
status required | OPEN | COMPLETED | EXPIRED | ABORTED | |
expire_time required | string · date-time | |
files required | array of UploadFile |