uploads.prepare
Prepare a private receipt or original email upload. Supply filename, mimeType, sizeBytes, sha256, idempotencyKey. If alreadyUploaded is true, the immutable original was verified: skip PUT and still confirm the returned submissionId. Otherwise upload unchanged bytes to uploadUrl, then confirm. Reuse the same idempotency key and payload on retry; changed payloads conflict. Authenticated identity is retained regardless of email headers. To add the receipt for one purchase, pass receiptFor with that entry id: it must still need a receipt or invoice (contributors: a purchase on their own card), the upload goes on its account, and matching compares the receipt with that purchase only.
/api/v1/accounting/uploads.preparePermissions
Who can call it
Retries
MCP
accounting_prepare_uploadFields
filenamestringRequiredThe file's name, including its extension.
1–255 characters
mimeTypeenumRequiredThe file's type, such as image/jpeg or application/pdf.
image/jpegimage/pngimage/webpimage/heicimage/heifapplication/pdfmessage/rfc822sizeBytesintegerRequiredThe file's size in bytes.
1 to 52428800
claimedMetadatamapsha256stringRequiredThe SHA-256 hash of the file's exact bytes, as 64 lowercase hex characters.
SHA-256 hash as 64 lowercase hex characters
idempotencyKeystringRequiredAny unique text you generate once per intended change, so a retried request only happens once. Send it as the Idempotency-Key header instead if you prefer; if you send both they must match.
8–160 characters
paymentAccountIdstring (ID)The card or account the purchase was paid with, from accounts.list.
receiptForstring (ID)The ID of the purchase this receipt is for, from attention.mine or entries.list. The upload is refused unless that purchase still needs a receipt.
receiptBatchIdstring (ID)The ID of the related record.
Example
curl https://app.getoatmilk.com/api/v1/accounting/uploads.prepare \
-H "Authorization: Bearer $OATMILK_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"filename": "receipt.jpg",
"mimeType": "image/jpeg",
"sizeBytes": 1,
"sha256": "9f2b5c1d7e3a4b6c8d0e2f4a6b8c0d2e4f6a8b0c2d4e6f8a0b2c4d6e8f0a2b4c"
}'{
"data": {
"submissionId": "4d5e6f7a-8b9c-4d0e-8f1a-2b3c4d5e6f7a",
"uploadUrl": "https://storage.example.com/upload/sign/accounting/receipt.jpg?token=synthetic",
"uploadToken": "synthetic-upload-token",
"storagePath": "org_synthetic/4d5e6f7a-8b9c-4d0e-8f1a-2b3c4d5e6f7a/upload/9f2b5c1d7e3a4b6c8d0e2f4a6b8c0d2e4f6a8b0c2d4e6f8a0b2c4d6e8f0a2b4c/receipt.jpg",
"expiresIn": 7200,
"alreadyUploaded": false
}
}Try it
Try it
Checks your input with this action’s real schema and answers like the API, with synthetic data. No key needed, and nothing changes.
curl https://app.getoatmilk.com/api/v1/accounting/uploads.prepare \
-H "Authorization: Bearer $OATMILK_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"filename": "receipt.jpg",
"mimeType": "image/jpeg",
"sizeBytes": 1,
"sha256": "9f2b5c1d7e3a4b6c8d0e2f4a6b8c0d2e4f6a8b0c2d4e6f8a0b2c4d6e8f0a2b4c"
}'More in Inbox and uploads.