Appearance
Add Files
Adds up to 3 files to a request you raised. It is the same as uploading files on the request's page in Johari.
Use it, for example, when the cashier returned a request asking for a document: add the file, then respond to the return.
Endpoint
| Method | URL |
|---|---|
POST | /api/requests/:requestID/files |
| Path parameter | Description |
|---|---|
requestID | The request's requestID, from Create a Request or a callback |
Send the body as JSON with Content-Type: application/json, and sign the exact JSON text. The path you sign includes the request ID:
<timestamp>.POST./api/requests/6650f1a2b3c4d5e6f7a8b9e1/files.<the JSON body>You can only add files to a request raised with your API key (including child requests made from it). It works in any status.
Body fields
| Field | Type | Required | Description |
|---|---|---|---|
idempotencyKey | string | Yes | Your unique ID for this upload, 1 to 255 characters. A UUID is ideal. Use a new one for each new upload, and reuse it only to retry the same upload. See Idempotency |
files | array | Yes | 1 to 3 files. Each item is exactly like a files item when you create a request: name, contentType and content |
Any other field is ignored.
Rules:
- 1 to 3 files per call. Leaving
filesout, or sending[], gets400(Please provide a file). For more than 3, make another call with a new key. - Everything else is the same as when you create a request: the same 9
contentTypevalues, the check of each file's first bytes, standard base64 with nodata:prefix and no line breaks, and at most 25 MB for all files together. See Attaching files. - The signature covers the whole body, base64
contentincluded.
What happens
Exactly what happens when someone uploads files on the request's page in Johari:
- The files are added to the request. Files already on it stay.
- The request's log records that your key's user uploaded a file, with
(API)after the name, e.g.Neema Mollel (API) uploaded a file. - The status does not change, so no callback is sent for it. Nobody is notified.
- The files appear in
filesin Get a Request straight away, and in the next callbacks. Download one with Get a File.
Response
data on success:
| Field | Type | Description |
|---|---|---|
requestID | string | The request's ID |
requestNumber | string | Its number in Johari, e.g. "1042" |
files | array | Only the files this call added: [{ "id": string, "name": string, "type": string, "size": number }]. size is in bytes. Use id with Get a File |
Example
The body (the content is shortened here; send the whole file, base64-encoded):
json
{
"idempotencyKey": "e2a7c9d1-3b5f-4e8a-9c6d-7f0a1b2c3d4e",
"files": [
{
"name": "stamped-invoice.pdf",
"contentType": "application/pdf",
"content": "JVBERi0xLjQK"
}
]
}bash
REQUEST_ID="6650f1a2b3c4d5e6f7a8b9e1"
# The file as base64, on one line
FILE_B64=$(base64 < stamped-invoice.pdf | tr -d '\n')
# Build the body in a file: with a file inside, it is too long for a command-line argument
cat > body.json <<EOF
{
"idempotencyKey": "e2a7c9d1-3b5f-4e8a-9c6d-7f0a1b2c3d4e",
"files": [
{
"name": "stamped-invoice.pdf",
"contentType": "application/pdf",
"content": "$FILE_B64"
}
]
}
EOF
# Sign the exact bytes of body.json, then send that same file
TS=$(date +%s)
SIG=$( { printf '%s' "$TS.POST./api/requests/$REQUEST_ID/files."; cat body.json; } \
| openssl dgst -sha256 -hmac "$SIGNING_SECRET" \
| sed 's/^.* //')
curl -X POST "$BASE_URL/api/requests/$REQUEST_ID/files" \
-H "Content-Type: application/json" \
-H "x-api-key: $API_KEY" \
-H "x-timestamp: $TS" \
-H "x-signature: $SIG" \
--data-binary @body.jsonjs
const crypto = require("crypto");
const fs = require("fs");
const requestID = "6650f1a2b3c4d5e6f7a8b9e1";
// callJohari is from the Signing page
const result = await callJohari("POST", `/api/requests/${requestID}/files`, {
idempotencyKey: crypto.randomUUID(),
files: [
{
name: "stamped-invoice.pdf",
contentType: "application/pdf",
content: fs.readFileSync("stamped-invoice.pdf").toString("base64"),
},
],
});
if (result.httpStatus === 200) {
console.log("Added", result.data.files.map((file) => file.id));
} else {
console.error(result.httpStatus, result.message, result.data);
}python
import base64
import uuid
request_id = "6650f1a2b3c4d5e6f7a8b9e1"
# call_johari is from the Signing page
with open("stamped-invoice.pdf", "rb") as f:
content = base64.b64encode(f.read()).decode()
result = call_johari("POST", f"/api/requests/{request_id}/files", {
"idempotencyKey": str(uuid.uuid4()),
"files": [
{
"name": "stamped-invoice.pdf",
"contentType": "application/pdf",
"content": content,
}
],
})
if result["httpStatus"] == 200:
print("Added", [file["id"] for file in result["data"]["files"]])
else:
print(result["httpStatus"], result["message"], result["data"])Response 200:
json
{
"status": "success",
"data": {
"requestID": "6650f1a2b3c4d5e6f7a8b9e1",
"requestNumber": "1042",
"files": [
{
"id": "7c1e9a3f-5b2d-4e6a-8f0c-1d3b5a7c9e2f",
"name": "stamped-invoice.pdf",
"type": "application/pdf",
"size": 48213
}
]
},
"message": "File uploaded successfully"
}Response 409, same idempotencyKey sent again after it worked (data is what the first call returned):
json
{
"status": "error",
"data": {
"requestID": "6650f1a2b3c4d5e6f7a8b9e1",
"requestNumber": "1042",
"files": [
{
"id": "7c1e9a3f-5b2d-4e6a-8f0c-1d3b5a7c9e2f",
"name": "stamped-invoice.pdf",
"type": "application/pdf",
"size": 48213
}
]
},
"message": "A request with this idempotencyKey has already been processed"
}Response 400, more than 3 files:
json
{
"status": "error",
"data": "You can only upload up to 3 files",
"message": "You can only upload up to 3 files"
}Response 404, wrong ID, or the request was not raised with your key:
json
{
"status": "error",
"data": "Request not found",
"message": "Request not found"
}The usual 401 errors apply too. Every possible error is listed on the Errors page.
Common mistakes
Waiting for a callback
Adding files does not change the status, so no callback is sent. The files show up in files of Get a Request and of the next callback.
Mixing it up with Get a File
POST /api/requests/:requestID/files adds files. GET /api/requests/:requestID/files/:fileID gets a download link for one. Sign the path you call.
More than 3 files in one call
Send at most 3. For more, make another call with a new idempotencyKey.
A different file on a retry
The files are part of the signed body. A retry with the same idempotencyKey must send exactly the same files, with the same names, types and content.