Skip to content

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 ​

MethodURL
POST/api/requests/:requestID/files
Path parameterDescription
requestIDThe 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 ​

FieldTypeRequiredDescription
idempotencyKeystringYesYour 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
filesarrayYes1 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 files out, or sending [], gets 400 (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 contentType values, the check of each file's first bytes, standard base64 with no data: prefix and no line breaks, and at most 25 MB for all files together. See Attaching files.
  • The signature covers the whole body, base64 content included.

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 files in Get a Request straight away, and in the next callbacks. Download one with Get a File.

Response ​

data on success:

FieldTypeDescription
requestIDstringThe request's ID
requestNumberstringIts number in Johari, e.g. "1042"
filesarrayOnly 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.json
js
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.