attachFile() from its ctx.flight.attachToPirepSubmission handler. This page is for whoever maintains the airline’s PIREP-receiving backend, not the plugin author.
What changes
Only one thing changes the PIREP submission: a plugin returningattachFile() from its attachToPirepSubmission handler. When that happens for a flight, that flight’s submission is sent as multipart/form-data instead of application/json.
Everything else leaves the submission exactly as it has always been, byte-identical JSON. That includes plugins that handle files some other way. A screenshot plugin that uploads each screenshot to its own endpoint as it is taken, for example, never touches the PIREP submission, so your completion endpoint receives the same JSON it always has.
If none of your installed plugins return
attachFile() from a submission
handler, nothing on this page applies to you.Wire format
The PIREP travels as a single form field namedpayload, holding exactly the JSON body your backend already receives when no file is attached. Each attached file travels as its own part, named <pluginId>_<n>, numbered from 0 per plugin. Inside the JSON, every attachment is replaced with { "$file": "<part name>" } pointing at its part.
So a submission that would otherwise be:
payload carrying that JSON verbatim as a string, plus ground-ops_0 and ground-ops_1 carrying the files, each with its own filename and content type.
Recovering it is one step:
Because the PIREP is one field rather than one field per value, types survive
exactly as they do on the JSON path: booleans stay booleans,
null stays
null, and an empty array stays an empty array. Nothing about the body
changes when a file is attached except that it is wrapped in a payload
field.history[0][lat], was deliberately avoided. It emits one field per leaf value, and a two-hour flight produces over 1300 of them. PHP parses a multipart body itself, so max_input_vars (default 1000) applies and silently discards everything past the limit. A JSON body is read in userland and is exempt. Under that encoding, attaching a file to a long flight would have quietly truncated the route, the flight log and the attachment references themselves, leaving the uploaded files with nothing pointing at them.
What your backend needs to do
- Accept
multipart/form-dataon the PIREP completion endpoint, alongside theapplication/jsonit already accepts, and read the PIREP from thepayloadfield with a JSON decode. - Walk the decoded body for
$filereferences and match each{ "$file": "<part name>" }object to the uploaded file part of that name, to reassemble which attachment belongs where. - Check
max_file_uploads(PHP default20) if you expect plugins to attach many files at once. The PIREP itself is one field regardless of flight length, somax_input_varsis not a concern, but each file is still a separate upload. - Return a status you can stand behind if you reject the submission. See the fallback below for which statuses Stratos treats as “reject the attachments” versus “something went wrong.”
- Accept a chunked request body. Because the submission is streamed, Stratos sends no
Content-Lengthheader, so the request arrives chunked. A proxy or web server in front of your backend that refuses chunked uploads will reject it with 411 or 400 before your application code ever sees it.