API REFERENCE
Beta
Add an Attachment
Uploads a document and attaches it to a finding. Unlike every other operation on this surface, the request body is multipart/form-data, not JSON — two parts, name and file.
Requires that you currently have permission to update this finding’s attachments — see Finding.editStates.attachment on List a Workflow’s Findings, which covers both this call and Remove an Attachment.
Sample
url="https://api.pointservices.com/riskinsight-services-ws/resources/v1/findings/workflows/wfpop_0000000000002082611/findings/fndg_0000000000006051384/attachments"
curl -X POST "${url}" \
-H "Authorization: Bearer your_access_token_here" \
-F "name=paystub-august.pdf" \
-F "file=@paystub-august.pdf;type=application/pdf"
The raw multipart body curl -F builds for you:
--boundary
Content-Disposition: form-data; name="name"
paystub-august.pdf
--boundary
Content-Disposition: form-data; name="file"; filename="paystub-august.pdf"
Content-Type: application/pdf
<binary bytes>
--boundary--
Header Properties
| Property | Value | Required? |
|---|---|---|
| Authorization | Bearer your token | true |
| Content-Type | multipart/form-data; boundary=… | true |
Set Content-Type to multipart/form-data, not application/json — this is the one operation on this surface that isn’t JSON. curl -F sets it for you.
Path Parameters
| Property | Description | Type |
|---|---|---|
| workflowId | The opaque handle identifying the workflow. | string |
| findingId | The opaque finding identifier (fndg_…) to attach the document to. | string |
workflowId is accepted with or without its wfpop_ prefix — a bare GUID resolves. findingId and attachmentId are not interchangeable this way: either must carry its exact prefix, or the request 404s as if that finding or attachment did not exist. There is no bare form of either that has ever been valid.
Multipart Parts
| Part | Description | Required |
|---|---|---|
| name | The document’s file name, published back as Attachment.name. Must not be blank. 255 UTF-8 bytes or fewer. | yes |
| file | The document’s raw bytes. Must not exceed 10 MiB (10,485,760 bytes). Set this part’s own Content-Type header to the document’s actual media type — it is republished verbatim on Attachment.contentType, capped at 255 UTF-8 bytes. | yes |
An oversized file is a clean 400, not a silent truncation. Sending a file over 10 MiB does not upload a truncated 10 MiB document — the whole request is rejected and no attachment is created. Check the file size client-side before uploading if you want to fail fast without spending the upload.
Set the file part’s Content-Type header accurately. It is stored exactly as sent and returned as Attachment.contentType on every later read — there is no server-side detection or correction of a wrong value.
Responses
200
The finding, re-projected — byte-identical in shape to a GET of the same finding, reflecting the new attachment. See List a Workflow’s Findings for the full Finding field table.
{
"workflowId": "wfpop_0000000000002082611",
"finding": {
"findingId": "fndg_0000000000006051384",
"code": "HP.ST",
"displayName": "High-priority stated income mismatch",
"category": ["Income"],
"severity": "HIGH",
"alertState": "Alert",
"userMessage": ["Stated income does not match the verified source document."],
"userSuggestion": ["Confirm the applicant's income against the attached document before proceeding."],
"reviewStatus": "PENDING",
"reviewNote": null,
"updatedAt": "2026-08-07T15:01:42Z",
"hasAttachments": true,
"hasHistory": false,
"links": {
"self": { "href": "https://api.pointservices.com/riskinsight-services-ws/resources/v1/findings/workflows/wfpop_0000000000002082611/findings/fndg_0000000000006051384" },
"history": { "href": "https://api.pointservices.com/riskinsight-services-ws/resources/v1/findings/workflows/wfpop_0000000000002082611/findings/fndg_0000000000006051384/history" },
"attachments": { "href": "https://api.pointservices.com/riskinsight-services-ws/resources/v1/findings/workflows/wfpop_0000000000002082611/findings/fndg_0000000000006051384/attachments" }
}
}
}
Fetch List a Finding’s Attachments afterward to see the new attachment’s attachmentId and download link — the response above signals hasAttachments only, it never embeds the attachment itself.
400
name missing/blank/over 255 UTF-8 bytes, file missing/empty, file over 10 MiB, or contentType over 255 UTF-8 bytes.
| Property | Description | Type |
|---|---|---|
| message | A human-readable explanation of what was rejected. Not a stable code — write your handling against the status code and the operation you called, not this text. | string |
{
"message": "file must not exceed 10485760 bytes"
}
403
You may not read this workflow, or may read it but currently lack permission to update this finding’s attachments.
Zero-length body, no Content-Type. Do not attempt to parse a body from this response — there is none. Branch on the status code alone.
This surface uses a bodyless 403 for every authorization failure, which is different from a problem+json 404 on the same operation. Do not assume every non-2xx on this API carries JSON — check the status first.
A 403 is also produced at the edge, before this service is reached, when a request value resembles SQL injection or cross-site scripting, and separately from the per-address rate limit (429). Both of those are also bodyless and carry no Content-Type.
404
Unknown workflowId or unknown findingId.
An RFC 9457 problem document, served as application/problem+json.
| Property | Description | Type |
|---|---|---|
| type | An absolute URI identifying the problem type. https://pointservices.com/problems/not-found is the only type this surface emits. This is the stable value to match on. | string |
| title | A short summary, written for a person. | string |
| status | The HTTP status code, repeated in the body. | number |
| detail | An explanation of this occurrence, written for your logs — never a stable code. | string |
| instance | A URI identifying this occurrence, written as urn:pps:request:<id>. Quote it when you raise a support ticket. | string |
{
"type": "https://pointservices.com/problems/not-found",
"title": "No such resource",
"status": 404,
"detail": "No finding fndg_0000000000006051384 is available to this request.",
"instance": "urn:pps:request:8d3a1f56-6c94-4e20-b7f8-0a5e9c2d4b73"
}
Branch on type, never on the text of detail.