Appearance
Get a File
Returns a short-lived download link for one file on a request you raised. Use it to download:
- the files you sent when you created the request,
- the proof of payment the cashier uploads when paying,
- the EFD receipt,
- any file people attach to the request in Johari (for example an accountant's upload),
- any file your system adds with Add Files.
Endpoint
| Method | URL |
|---|---|
GET | /api/requests/:requestID/files/:fileID |
| Path parameter | Description |
|---|---|
requestID | The request's requestID |
fileID | A files[].id from Get a Request or from a callback |
Sign it like any GET, with an empty body:
<timestamp>.GET./api/requests/6650f1a2b3c4d5e6f7a8b9e1/files/0b6f2c1e-8d4a-4f3b-9e7c-5a1d2b3c4e5f.You can only see requests raised with your API key, and their files.
Response
data on success:
| Field | Type | Description |
|---|---|---|
id | string | The file's ID |
name | string | The file name, e.g. "invoice-1042.pdf" |
type | string | null | The file type, e.g. "application/pdf", or null |
size | number | null | The size in bytes, or null |
url | string | A direct download link. Valid for 5 minutes |
expiresAt | string | When url stops working (ISO 8601, UTC) |
Downloading the file
url is a pre-signed storage link. Download it with a plain GET straight away:
- Send no Johari headers: no
x-api-key,x-timestamporx-signature. Do not sign it. - It works for 5 minutes, until
expiresAt. - Do not store
url. Ask this endpoint for a fresh link each time you need the file.
Example
bash
REQUEST_ID="6650f1a2b3c4d5e6f7a8b9e1"
FILE_ID="0b6f2c1e-8d4a-4f3b-9e7c-5a1d2b3c4e5f"
TS=$(date +%s)
SIG=$(printf '%s' "$TS.GET./api/requests/$REQUEST_ID/files/$FILE_ID." \
| openssl dgst -sha256 -hmac "$SIGNING_SECRET" \
| sed 's/^.* //')
curl "$BASE_URL/api/requests/$REQUEST_ID/files/$FILE_ID" \
-H "x-api-key: $API_KEY" \
-H "x-timestamp: $TS" \
-H "x-signature: $SIG"
# Then download the link from data.url, with no Johari headers:
# curl -o invoice-1042.pdf "<data.url>"js
const fs = require("fs");
const requestID = "6650f1a2b3c4d5e6f7a8b9e1";
const fileID = "0b6f2c1e-8d4a-4f3b-9e7c-5a1d2b3c4e5f";
// callJohari is from the Signing page
const result = await callJohari("GET", `/api/requests/${requestID}/files/${fileID}`);
if (result.httpStatus === 200) {
// A plain GET, with no Johari headers
const download = await fetch(result.data.url);
fs.writeFileSync(result.data.name, Buffer.from(await download.arrayBuffer()));
} else {
console.error(result.httpStatus, result.message);
}python
import requests # pip install requests
request_id = "6650f1a2b3c4d5e6f7a8b9e1"
file_id = "0b6f2c1e-8d4a-4f3b-9e7c-5a1d2b3c4e5f"
# call_johari is from the Signing page
result = call_johari("GET", f"/api/requests/{request_id}/files/{file_id}")
if result["httpStatus"] == 200:
# A plain GET, with no Johari headers
download = requests.get(result["data"]["url"])
with open(result["data"]["name"], "wb") as f:
f.write(download.content)
else:
print(result["httpStatus"], result["message"])Response 200:
json
{
"status": "success",
"data": {
"id": "0b6f2c1e-8d4a-4f3b-9e7c-5a1d2b3c4e5f",
"name": "invoice-1042.pdf",
"type": "application/pdf",
"size": 48213,
"url": "https://storage.example.com/...",
"expiresAt": "2026-10-30T12:05:00.000Z"
},
"message": "File link created successfully"
}The url above is shortened. Use the whole value you receive, exactly as it is.
Response 404, request not found:
json
{
"status": "error",
"data": null,
"message": "Request not found"
}You get Request not found when the request ID is wrong, when the request was raised with a different API key, or when it was deleted in Johari.
Response 404, file not found:
json
{
"status": "error",
"data": null,
"message": "File not found"
}You get File not found when the request exists but has no file with that fileID.
The usual 401 errors apply too. See Errors.
Common mistakes
Sending Johari headers to the download link
url is a pre-signed storage link, not a Johari API call. Download it with a plain GET. Do not sign it, and send no x-api-key, x-timestamp or x-signature headers. Only the call to /api/requests/:requestID/files/:fileID is signed.
Storing the link
The link stops working after 5 minutes. Store the fileID, and ask for a fresh link each time.