Skip to main content
POST
Upload an attachment

Overview

Upload a file to ChainPatrol and get back a URL. Pass that URL to Create Report in attachmentUrls to attach the file as evidence. This is a two-step flow, and the two steps are separate requests:
  1. POST /attachment/upload — send the bytes, receive a URL.
  2. POST /report/create — include that URL in attachmentUrls.
See Creating Reports for the complete flow with worked examples.
You do not have to use this endpoint. attachmentUrls accepts any publicly reachable URL, so if you already host your evidence somewhere we can fetch, keep passing those links. This endpoint exists so you do not have to host them.
It is not images only. Screenshots are the most common attachment, but .eml and .msg message files, PDFs, Word documents, CSVs, and plain text are all supported — see Supported file types. Images are displayed inline on the report in the dashboard; everything else is listed as a downloadable file that our takedown team can forward to a registrar or host.
Read-only API keys cannot upload — that role exists for cross-organization reads. Uploads are recorded against the organization behind the key. See Authentication for how to send your key.

Two ways to send a file

The endpoint accepts either shape. Pick whichever your HTTP client makes easier.

Raw body

Send the file bytes as the request body and the file name as the fileName query parameter. One file per request.
fileName is required for raw uploads, and must appear exactly once. Repeating it (?fileName=a.eml&fileName=b.eml) is rejected with a 400.

Multipart form

Send multipart/form-data with one or more file parts. This is what a browser form, Postman’s file picker, or curl -F produces. The file name comes from each part’s own filename, so the fileName query parameter is ignored here. Non-file form fields are ignored, and the part names themselves do not matter — send them all as file if you like.

File name handling

  • The extension decides how we store and serve the file, so it has to be present and accepted. Matching is case-insensitive.
  • Directory components are stripped: ../../secrets/evidence.eml is stored as evidence.eml.
  • Names must contain no control characters, and are length-capped — the schema above gives the limit.
  • Your name is otherwise preserved as-is. That matters because it is the name shown on the report, and the name a registrar or hosting provider sees when our takedown team forwards the file — so phishing-email.eml is worth more than attachment1.eml.
  • Uploading two files with the same name is fine. Each upload is stored on its own path, so nothing is ever overwritten and the name you sent is what comes back.

Supported file types

The accepted extensions are enumerated in the request description above, and that list is generated from the same constants the endpoint enforces — so it is always current. The content type we serve the file with is derived from the extension, not from the Content-Type header you send, so any header your client sets is ignored. .svg and .html are deliberately excluded: they render as active content, and files we serve should not. If you need a format that is not accepted, email support@chainpatrol.io — a common workaround is to send the file inside a supported container (a PDF export, or the raw .eml).

Limits

The request body size cap and the per-request file count are stated in the schema above. Two things it does not tell you:
  • The size cap applies to the whole request body, so in a multipart request all parts share one budget. For anything larger, split it across requests and attach the resulting URLs to the same report.
  • Uploads are rate limited to 60 requests per minute per organization, or per API key for keys that are not tied to one. Exceeding it returns 429.

The returned URL

Treat the url as opaque. Store it and pass it through — do not parse it, and do not try to construct one yourself. The path layout is an implementation detail and can change.The URL is served from our CDN and is reachable by anyone who has it, which is what lets us forward evidence to registrars and hosting providers. The path is not guessable, but do not upload anything you would not want a third party to see if the link were shared.

Error responses

Every error returns a JSON body with a single error string describing what was wrong. The statuses are listed with the responses above; two things worth calling out:
  • 405 is not in the list, because it is not a response of POST. The endpoint is POST only, and any other method returns 405 Method Not Allowed.
  • Retry 429 and 502, not 400. A 4xx other than 429 means the request itself needs fixing, and retrying it unchanged will fail the same way.

Best practices

  • Upload first, report second. Nothing links the file to a report until you pass the URL to report.create. An uploaded file that is never referenced simply sits unused.
  • Attach every file to a report. Uploads are not visible in the dashboard on their own; the report is what makes them reviewable.
  • Use meaningful file names. The name follows the file into the dashboard and into outbound takedown emails.
  • Send .eml rather than a screenshot of an email when you have it. The raw message carries headers, which is what registrars and email providers act on.

Notes

  • There is no endpoint for listing, replacing, or deleting an upload. To correct a mistake, upload the right file and reference that URL instead; to remove evidence from a report, contact support@chainpatrol.io.
  • Files are not scanned for malware. Do not treat an uploaded file as safe to open just because it came through the API.

Authorizations

X-API-KEY
string
header
required

Your API key. This is required by most endpoints to access our API programatically. Reach out to us at support@chainpatrol.io to get an API key for your use.

Query Parameters

fileName
string

File name for the uploaded bytes, including the extension (for example evidence.eml). Required for raw-body uploads, and must be supplied exactly once. Ignored for multipart requests, where each part carries its own file name.

Maximum string length: 200

Body

The raw file bytes. Name the file with ?fileName=.

Response

The files were stored.

attachments
object[]
required

One entry per uploaded file, in request order.