Large event file uploads
Send usage events to Solvimon in files of millions of lines. You create a file record through the API, upload a gzipped CSV to a short-lived signed URL, and get back an acknowledgement file and a per-line result file.
Why this matters
The event ingestion API handles usage as it happens, and event file uploads carry a CSV inside the request body for files up to 20 MB. Neither fits a nightly export of a million lines or more.
Large file uploads take a different route. The file itself never travels through the API: it goes straight to file storage over a signed URL, so there is no request size limit to work around and no retry of a multi-gigabyte request body. You still need nothing but your normal Solvimon API key, and no Google Cloud account or service account of your own.
Solvimon answers with two files. An ACK arrives within minutes and tells you whether the file was accepted and how many lines it holds. A RESULT arrives when processing finishes and gives one line per input line, so you can resend exactly the lines that failed.
How it works
- One file record per upload. The
FILEresource is your handle for status, line counts and downloads. - Signed URLs only. Upload and download links are valid for 60 minutes, and you can ask for a new one at any time with your API key.
- Nothing starts until you say so. The upload alone processes nothing; the
processcall does. - Webhooks, not polling. Subscribe to
FILE.STATUS_UPDATEDand you are told at every step.
Implementation
Via API
Create the file record
Create the file with the create file endpoint, setting source to BUCKET:
A BUCKET file takes no file_name and no content. Its files are named after the file id and reference instead.
upload is returned only here, on the create. Send exactly the headers it gives: they are part of the signature.
Upload the file
The link is checked when the upload starts, so an upload that runs past the 60 minutes still completes. For very large files or unstable connections, use a resumable upload: POST to the same URL with the header x-goog-resumable: start, then upload to the session URL you get back. A session stays valid for 7 days and survives a dropped connection. Google’s client libraries handle this for you.
Uploaded the wrong file? While the file record is CREATED you can upload as often as you like. Each upload replaces the previous one, and only the last upload before you call process is used.
Get a new upload link if yours expired
GET /v1/files/{id}/upload-url returns a fresh link, as often as needed, for as long as the file record is CREATED:
After process the call returns 409. To abandon an upload instead, POST /v1/files/{id}/cancel with no body moves a CREATED file to CANCELLED.
Start processing
When the upload has finished, tell Solvimon with POST /v1/files/{id}/process and no body. The response is the file record, now UPLOADED.
- If the file is not in storage yet, the call returns
409. Finish or redo the upload, then call again. - Calling it again before the ACK exists is safe: it answers
200and re-sends theUPLOADEDwebhook, and nothing is processed twice. Once the ACK exists it returns409. - Content already uploaded under another file record, or a file over the size limit, is
REJECTEDstraight away with the reason in the ACK.
Read the ACK
Solvimon checks every line first, with the same validation as the event ingestion API, and against duplicates both inside the file and among events already received. Within minutes the file record moves to VALIDATED or REJECTED, and you get a FILE.STATUS_UPDATED webhook for each change.
Follow progress
The file status endpoint shows the line counts growing while the status is PROCESSING:
bucket_files lists only the files that exist, so the RESULT is missing here. It is left out entirely until the upload is accepted by process. not_matched and duplicate are only known at the end, so they stay 0 until then.
Read the RESULT and resend what failed
When the file record reaches DONE or DONE_WITH_ERRORS, bucket_files.result is filled at the same moment. Download it with GET /v1/files/{id}/result/download-url.
Put the lines whose status is ERROR, corrected, into a new file with a new reference. Do not resend lines that are DONE, NOT_MATCHED or DUPLICATE.
Via Desk
Creating a bucket file stays API-only, but everything after that is visible in Desk under Files. The list filters on several statuses at once, so you can pull up everything that is still PROCESSING, or everything that ended REJECTED or DONE_WITH_ERRORS.
Opening a file shows:
- File details. Reference, name, description, source, meter, upload time, record count and
message. A bucket file has no file name, so the page is titled by its reference. - Lines. The counters from
line_counts: processed, done, not matched, duplicate and error. - Downloads. Buttons for Original, ACK and Result, each appearing only once that file has been written. A download fetches a fresh signed link and saves under the file’s own name.
- Actions. Process on a file that is still
CREATED, and Cancel file, which asks for confirmation first. Neither is offered once processing has started, because a run cannot be stopped or undone. - The line table. One row per line with its number, status, reference, event, meter, customer and message, plus the raw CSV line for a line that failed. Meter and customer are links for users who hold
METER.VIEWandCUSTOMER.VIEW. The file’s header columns are shown in a tooltip, and the status filter takes several statuses at once, which is what makes a file of a million lines workable: filter toERRORandDUPLICATEand you see only what needs attention.
Input file format
The input is a gzipped CSV: UTF-8, comma-separated, RFC 4180 quoting, with a header row, one event per line. A byte order mark at the start of the file, as Excel’s “CSV UTF-8” export writes, is ignored. A file with bytes that are not valid UTF-8 is rejected as NOT_UTF8. Once the file has been checked, column_headers on the file record lists the header’s column names.
The meter data file endpoint returns a CSV header template for a meter. Add a meter_id or meter_reference column when the file holds more than one meter.
ACK and RESULT files
Both are UTF-8 CSV with a header row and UTC timestamps. The ACK is plain CSV; the RESULT is gzipped. GET /v1/files/{id}/original/download-url returns the file you uploaded.
Each entry in bucket_files carries its file_name, and a download saves under that name: <file id>_<reference>.csv.gz for the original, <file id>_<reference>_ack.csv and <file id>_<reference>_result.csv.gz. The names follow the file record’s current reference, while the ACK’s content keeps the reference it had when the ACK was written.
The ACK
One line, written after the file has been checked and before it is processed.
statusisVALIDATED, meaning the file will be processed, orREJECTED, meaning nothing is processed.invalid_linesare lines that fail the event API’s validation, for example an unknown customer or meter, or a missing reference. They are reported asERRORin the RESULT, with the reason. The rest of the file is processed normally.duplicate_linesare lines whose reference appears earlier in the file, or was already received. They are reported asDUPLICATEand not processed.- The ACK counts the duplicates known at validation:
0when there are none, and empty for a rejected file. The final count is inline_counts.duplicateand the RESULT, and it can differ from the ACK when an event with the same reference arrives after the ACK was written.
A rejected file is final: none of its lines is processed and it gets no RESULT. Fix the file and upload it as a new file record with a new reference. The reason column holds the code, and message on the file record repeats it in words, for example MISSING_COLUMN:reference: the header has no reference column.
The RESULT
One line per input line, in the same order.
line_item_number counts data lines, starting at 1 after the header. resource_id is the Solvimon id of the stored event, and it is empty for ERROR.
These per-line outcomes are also available as JSON through the file lines endpoint, where a line that is still being processed shows as IMPORTED. Filter with statuses[], which takes several values: ?statuses[]=ERROR&statuses[]=DUPLICATE. The older single-valued status parameter is deprecated. Each line also carries reference, event_id, meter_id and customer_id, and the raw CSV line in data, base64 encoded, for a line that failed.
File statuses and webhooks
Subscribe to the FILE.STATUS_UPDATED webhook to be told about every status change. Progress updates send no webhook. A final status and its file always arrive together: when you receive DONE or DONE_WITH_ERRORS, the RESULT can be downloaded straight away.
The webhook carries no download links. Call the download-url endpoint with your API key when you receive it.
Limits and retention
Edge cases
- Forgetting the
processcall. Nothing is processed. The file record staysCREATEDand becomesEXPIREDafter 7 days. You can callprocessat any point before that. - Replacing a file after
process. The upload is fixed onceprocesshas been called. Create a new file record with the corrected data. If some events were already stored, contact Solvimon about correcting them. - Resending a line that was already
DONE. It comes back asDUPLICATEand is not processed again, so resend only theERRORlines. - Uploading several files at once. Each file needs its own file record. They are processed independently.
- Changing the reference.
PATCH /v1/files/{id}changesreference,nameanddescriptionat any status. Every other field is read-only, and a status change is refused and points atprocess.
Only the last upload before the process call is used, and an upload after that call is ignored. If you are retrying an upload, make sure it has finished before you call process.
See also: Event ingestion API for real-time usage, Event file uploads for files up to 20 MB, Usage file uploads for the Desk walkthrough, and Meters for the columns a meter expects.