File Uploads

DayZero uses S3-backed file storage for bill attachments, bank statements, CSV/Excel imports, and other documents. Uploading is a two-step pattern: put the file in storage to get an s3_key, then pass that key to the endpoint that consumes it.

The /api/v1/upload/* endpoints work with an API token but are not listed in the public API Reference. The endpoints that consume an s3_key (bills, bulk uploads, reconciliations, reports…) are all public and documented there.

Presigned Upload (Recommended)

Get a presigned upload URL, then upload the file directly to S3 from the client:

Step 1: Request a presigned URL

bash
curl -X POST "https://api.ondayzero.com/api/v1/upload" \
  -H "Authorization: Bearer dz_your_token_here" \
  -H "x-business-id: YOUR_BUSINESS_ID" \
  -H "Content-Type: application/json" \
  -d '{"filename": "receipt.pdf"}'

Returns s3_upload_url (a presigned S3 PUT URL, valid for one hour), the s3_key to reference the file with, and the content_type DayZero inferred from the filename. Supported extensions: pdf, csv, xls, xlsx, doc, docx, md, and common image formats (png, jpg, jpeg, gif, webp, heic, heif, bmp, tiff, avif); anything else is rejected with 400.

Step 2: Upload to S3

bash
curl -X PUT "{s3_upload_url}" \
  -H "Content-Type: application/pdf" \
  --data-binary @receipt.pdf

Send the same Content-Type the presign response returned — S3 rejects the upload if it differs.

Step 3: Use the s3_key

Pass the s3_key to whichever endpoint consumes it. Common ones:

Use Endpoint and field
Attach a document to a bill s3_key on POST /api/v1/bills, POST /api/v1/bills/received, PUT /api/v1/bills/{bill_id} — see Bills
Create bills / invoices from PDFs with AI single_bill_s3_keys / multi_bill_s3_key on POST /api/v1/bills/ai-create; single_invoice_s3_keys / multi_invoice_s3_key on POST /api/v1/invoices/ai-create
Import bank transactions from CSV/Excel s3_key on POST /api/v1/transactions/bulk-upload/headers → /preview → /bulk-upload — see Transactions
Bulk-import invoices, bills or journal entries s3_key on POST /api/v1/invoices/bulk, POST /api/v1/bills/bulk, POST /api/v1/journal-entries/bulk-upload/preview and /post
Upload a bank statement for reconciliation statement_s3_key on POST /api/v1/reconciliations — see Reconciliation
Feed a spreadsheet to a report file_s3_key / s3_keys on POST /api/v1/reports — see Reports
Vendor contracts and note attachments s3_key on POST /api/v1/vendor-contracts, POST /api/v1/notes/{note_id}/attachments

Direct Upload

Upload a file through the API in one call (simpler, but the bytes transit DayZero's servers, so prefer presigned URLs for large files):

bash
curl -X POST "https://api.ondayzero.com/api/v1/upload/direct" \
  -H "Authorization: Bearer dz_your_token_here" \
  -H "x-business-id: YOUR_BUSINESS_ID" \
  -F "file=@receipt.pdf"

Returns the s3_key, filename and file_size. Oversized files are rejected with 413.

Some workflows have their own multipart shortcut that uploads and processes in one request, e.g. POST /api/v1/bills/upload (bill document) and POST /api/v1/reconciliations/upload (bank statement).

Download a File

Get a presigned download URL:

bash
curl "https://api.ondayzero.com/api/v1/upload/download?s3_key=path/to/file.pdf" \
  -H "Authorization: Bearer dz_your_token_here" \
  -H "x-business-id: YOUR_BUSINESS_ID"

Returns download_url, a time-limited S3 link that needs no DayZero headers. Or stream the file through the API (avoids CORS issues with presigned URLs in browsers):

bash
curl "https://api.ondayzero.com/api/v1/upload/stream?s3_key=path/to/file.pdf&filename=receipt.pdf" \
  -H "Authorization: Bearer dz_your_token_here" \
  -H "x-business-id: YOUR_BUSINESS_ID" \
  -o downloaded-file.pdf

filename is optional and sets the download's Content-Disposition name. Only keys belonging to the business in x-business-id can be downloaded.

List Uploaded Files

bash
curl "https://api.ondayzero.com/api/v1/upload/files" \
  -H "Authorization: Bearer dz_your_token_here" \
  -H "x-business-id: YOUR_BUSINESS_ID"

Returns items of {id, name, s3_key, type, source, created_at}. Filter with ?source=user_upload or ?source=ai_generated to separate files you uploaded from ones DayZero generated.

CSV Templates

Download templates for bulk imports. GET /api/v1/upload/templates lists the names — currently rec-txns (bank transactions), bulk-invoice-upload, bulk-bill-upload and bulk-journal-entries:

bash
curl "https://api.ondayzero.com/api/v1/upload/templates/bulk-invoice-upload" \
  -H "Authorization: Bearer dz_your_token_here" \
  -H "x-business-id: YOUR_BUSINESS_ID"

The response carries the template as csv_content_stringified (plain CSV text), csv_content_object (rows as JSON) and csv_content_base64; the journal-entries template is also returned as xls_content_base64, pre-filled with the business's own ledger names.