POST /v1/files/public
Uploads an asset to your tenant's public bucket and returns a direct URL that can be embedded in public-facing content such as knowledge base article images.
When to use this
- Embedding an image in a public knowledge base article (
KBPUBLICcontent field). - Attaching a logo, diagram, or screenshot to a public portal page.
- Generating the target URL for any
<img>tag that must be reachable without a login.
How it works
Uploads are a two-step presigned POST flow. The REST API never sees the file bytes itself.
- Your code calls
POST /v1/files/publicwith the filename. The server returns a short-lived presigned S3 POST form and the final public URL the file will have once uploaded. - Your code POSTs the file bytes directly to the returned S3 endpoint, with the form fields and the file attached as
file. S3 stores the object in your tenant's public bucket. - The public URL returned in step 1 is now live. Use it as the
srcof an<img>tag, or anywhere else a public HTTPS URL is expected.
Authentication
Standard PAT bearer token in the Authorization header, like every other endpoint under rest.demandflow.com.
Request body
{
"filename": "network-diagram.png"
}
filename(optional): the name to use when storing the object. Non-alphanumeric characters other than. _ -are replaced with underscores, and the name is truncated to 120 characters. If omitted,fileis used.
Response
{
"url": "https://<your-sub-id>-public.s3.eu-west-2.amazonaws.com/",
"fields": {
"key": "<your-sub-id>/a1b2c3d4-.../network-diagram.png",
"bucket": "<your-sub-id>-public",
"X-Amz-Algorithm": "...",
"X-Amz-Credential": "...",
"X-Amz-Date": "...",
"Policy": "...",
"X-Amz-Signature": "..."
},
"fileKey": "<your-sub-id>/a1b2c3d4-.../network-diagram.png",
"fileUrl": "https://<your-sub-id>-public.s3.eu-west-2.amazonaws.com/<your-sub-id>/a1b2c3d4-.../network-diagram.png"
}
url: the S3 endpoint you POST the file bytes to in step 2.fields: an opaque map of form fields returned by S3. Submit every one of them as part of the upload form, before the file itself.fileKey: the object's key within the bucket. Useful for audit logs or for constructing the URL yourself.fileUrl: the final public URL. Store this value, not the presignedurl, in any record that needs to reference the file after upload.
Limits
- Maximum file size: 10 MB per upload.
- Presigned URL validity: 10 minutes from issue. Upload must complete within that window.
- Content type is inferred by S3 from the file bytes or the
Content-Typeheader you pass on the POST. For browser uploads of<input type="file">this is set automatically.
Error responses
401: noAuthorizationheader.403: invalid or expired token.400: malformed JSON body.405: the endpoint only accepts POST.500: internal error. The S3 presign failed for example because the bucket is misconfigured. Retry after a short delay. If it persists, contact support.
Example: curl
Two requests. The first asks the API for a presigned form. The second uploads the file directly to S3.
# Step 1: request a presigned POST
curl -s -X POST "https://rest.demandflow.com/v1/files/public" \
-H "Authorization: Bearer <your-pat>" \
-H "Content-Type: application/json" \
-d '{"filename":"diagram.png"}' \
-o presign.json
# Step 2: upload to S3. jq reads the form fields out of the response.
UPLOAD_URL=$(jq -r '.url' presign.json)
FIELDS=$(jq -r '.fields | to_entries[] | "-F \(.key)=\(.value)"' presign.json | tr '\n' ' ')
eval curl -s $FIELDS -F 'file=@./diagram.png' "$UPLOAD_URL"
# Step 3: the file is now public at
jq -r '.fileUrl' presign.json
Example: Node
async function uploadPublic(pat, file) {
const presign = await fetch('https://rest.demandflow.com/v1/files/public', {
method: 'POST',
headers: { Authorization: `Bearer ${pat}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ filename: file.name }),
}).then(r => r.json());
const form = new FormData();
for (const [k, v] of Object.entries(presign.fields)) form.append(k, v);
form.append('file', file);
const upload = await fetch(presign.url, { method: 'POST', body: form });
if (!upload.ok) throw new Error(`Upload failed: ${upload.status}`);
return presign.fileUrl;
}
Using the URL in an article
<img src="https://<your-sub-id>-public.s3.eu-west-2.amazonaws.com/<key>" alt="Network diagram">
Paste the fileUrl directly into your article's HTML. No further server-side rewriting is needed. The URL stays valid indefinitely unless the object is deleted.
Safety reminder
The bucket behind this endpoint is configured for anonymous public read. Uploading a file here is equivalent to publishing it on the open internet. Review every upload before calling this endpoint, and prefer the private-upload routes for anything else.