curl --request POST \
--url https://app.withforerunner.com/api/v1/files \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: multipart/form-data' \
--form fileUpload=@example-file \
--form 'fileType=Elevation Certificate' \
--form mimeType=application/pdf \
--form 'address=123 Main St, Springfield, IL 62701' \
--form parcelId=12-34-567-890 \
--form externalSystemId=EC-2024-0417 \
--form externalDocumentURL=https://permits.example.gov/documents/EC-2024-0417 \
--form 'coordinates=[39.7817, -89.6501]'import requests
url = "https://app.withforerunner.com/api/v1/files"
files = { "fileUpload": ("example-file", open("example-file", "rb")) }
payload = {
"fileType": "Elevation Certificate",
"mimeType": "application/pdf",
"address": "123 Main St, Springfield, IL 62701",
"parcelId": "12-34-567-890",
"externalSystemId": "EC-2024-0417",
"externalDocumentURL": "https://permits.example.gov/documents/EC-2024-0417",
"coordinates": "[39.7817, -89.6501]"
}
headers = {"Authorization": "Bearer <token>"}
response = requests.post(url, data=payload, files=files, headers=headers)
print(response.text)const form = new FormData();
form.append('fileUpload', '<string>');
form.append('fileType', 'Elevation Certificate');
form.append('mimeType', 'application/pdf');
form.append('address', '123 Main St, Springfield, IL 62701');
form.append('parcelId', '12-34-567-890');
form.append('externalSystemId', 'EC-2024-0417');
form.append('externalDocumentURL', 'https://permits.example.gov/documents/EC-2024-0417');
form.append('coordinates', '[39.7817, -89.6501]');
const options = {method: 'POST', headers: {Authorization: 'Bearer <token>'}};
options.body = form;
fetch('https://app.withforerunner.com/api/v1/files', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://app.withforerunner.com/api/v1/files",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"fileUpload\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"fileType\"\r\n\r\nElevation Certificate\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"mimeType\"\r\n\r\napplication/pdf\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"address\"\r\n\r\n123 Main St, Springfield, IL 62701\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"parcelId\"\r\n\r\n12-34-567-890\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"externalSystemId\"\r\n\r\nEC-2024-0417\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"externalDocumentURL\"\r\n\r\nhttps://permits.example.gov/documents/EC-2024-0417\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"coordinates\"\r\n\r\n[39.7817, -89.6501]\r\n-----011000010111000001101001--",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: multipart/form-data"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://app.withforerunner.com/api/v1/files"
payload := strings.NewReader("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"fileUpload\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"fileType\"\r\n\r\nElevation Certificate\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"mimeType\"\r\n\r\napplication/pdf\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"address\"\r\n\r\n123 Main St, Springfield, IL 62701\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"parcelId\"\r\n\r\n12-34-567-890\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"externalSystemId\"\r\n\r\nEC-2024-0417\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"externalDocumentURL\"\r\n\r\nhttps://permits.example.gov/documents/EC-2024-0417\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"coordinates\"\r\n\r\n[39.7817, -89.6501]\r\n-----011000010111000001101001--")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://app.withforerunner.com/api/v1/files")
.header("Authorization", "Bearer <token>")
.body("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"fileUpload\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"fileType\"\r\n\r\nElevation Certificate\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"mimeType\"\r\n\r\napplication/pdf\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"address\"\r\n\r\n123 Main St, Springfield, IL 62701\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"parcelId\"\r\n\r\n12-34-567-890\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"externalSystemId\"\r\n\r\nEC-2024-0417\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"externalDocumentURL\"\r\n\r\nhttps://permits.example.gov/documents/EC-2024-0417\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"coordinates\"\r\n\r\n[39.7817, -89.6501]\r\n-----011000010111000001101001--")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.withforerunner.com/api/v1/files")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request.body = "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"fileUpload\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"fileType\"\r\n\r\nElevation Certificate\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"mimeType\"\r\n\r\napplication/pdf\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"address\"\r\n\r\n123 Main St, Springfield, IL 62701\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"parcelId\"\r\n\r\n12-34-567-890\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"externalSystemId\"\r\n\r\nEC-2024-0417\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"externalDocumentURL\"\r\n\r\nhttps://permits.example.gov/documents/EC-2024-0417\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"coordinates\"\r\n\r\n[39.7817, -89.6501]\r\n-----011000010111000001101001--"
response = http.request(request)
puts response.read_body{
"errors": [],
"file": {
"id": "f8a3b2c1-d4e5-4789-abcd-ef0123456789",
"url": "https://demoville.app.withforerunner.com/files/f8a3b2c1-d4e5-4789-abcd-ef0123456789"
}
}{
"errors": [
{
"message": "Required",
"field": "fileUpload"
}
],
"file": null
}{
"errors": [
{
"message": "Document upload already exists with external system id 2024-0417",
"field": "externalSystemId"
}
],
"file": null
}Submit File
Uploads a file and attaches it to a property.
This endpoint takes multipart/form-data, not JSON: the metadata fields below are form fields sent alongside the file, and a JSON body is rejected. Only one file is accepted per request.
At least one of address, parcelId, or coordinates is required, except for Elevation Certificates, where the location is read out of the certificate.
Supply as many as you have. Address plus parcel ID plus coordinates matches far more reliably than any one alone, and they are used together to find or create the property.
curl --request POST \
--url https://app.withforerunner.com/api/v1/files \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: multipart/form-data' \
--form fileUpload=@example-file \
--form 'fileType=Elevation Certificate' \
--form mimeType=application/pdf \
--form 'address=123 Main St, Springfield, IL 62701' \
--form parcelId=12-34-567-890 \
--form externalSystemId=EC-2024-0417 \
--form externalDocumentURL=https://permits.example.gov/documents/EC-2024-0417 \
--form 'coordinates=[39.7817, -89.6501]'import requests
url = "https://app.withforerunner.com/api/v1/files"
files = { "fileUpload": ("example-file", open("example-file", "rb")) }
payload = {
"fileType": "Elevation Certificate",
"mimeType": "application/pdf",
"address": "123 Main St, Springfield, IL 62701",
"parcelId": "12-34-567-890",
"externalSystemId": "EC-2024-0417",
"externalDocumentURL": "https://permits.example.gov/documents/EC-2024-0417",
"coordinates": "[39.7817, -89.6501]"
}
headers = {"Authorization": "Bearer <token>"}
response = requests.post(url, data=payload, files=files, headers=headers)
print(response.text)const form = new FormData();
form.append('fileUpload', '<string>');
form.append('fileType', 'Elevation Certificate');
form.append('mimeType', 'application/pdf');
form.append('address', '123 Main St, Springfield, IL 62701');
form.append('parcelId', '12-34-567-890');
form.append('externalSystemId', 'EC-2024-0417');
form.append('externalDocumentURL', 'https://permits.example.gov/documents/EC-2024-0417');
form.append('coordinates', '[39.7817, -89.6501]');
const options = {method: 'POST', headers: {Authorization: 'Bearer <token>'}};
options.body = form;
fetch('https://app.withforerunner.com/api/v1/files', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://app.withforerunner.com/api/v1/files",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"fileUpload\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"fileType\"\r\n\r\nElevation Certificate\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"mimeType\"\r\n\r\napplication/pdf\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"address\"\r\n\r\n123 Main St, Springfield, IL 62701\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"parcelId\"\r\n\r\n12-34-567-890\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"externalSystemId\"\r\n\r\nEC-2024-0417\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"externalDocumentURL\"\r\n\r\nhttps://permits.example.gov/documents/EC-2024-0417\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"coordinates\"\r\n\r\n[39.7817, -89.6501]\r\n-----011000010111000001101001--",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: multipart/form-data"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://app.withforerunner.com/api/v1/files"
payload := strings.NewReader("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"fileUpload\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"fileType\"\r\n\r\nElevation Certificate\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"mimeType\"\r\n\r\napplication/pdf\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"address\"\r\n\r\n123 Main St, Springfield, IL 62701\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"parcelId\"\r\n\r\n12-34-567-890\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"externalSystemId\"\r\n\r\nEC-2024-0417\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"externalDocumentURL\"\r\n\r\nhttps://permits.example.gov/documents/EC-2024-0417\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"coordinates\"\r\n\r\n[39.7817, -89.6501]\r\n-----011000010111000001101001--")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://app.withforerunner.com/api/v1/files")
.header("Authorization", "Bearer <token>")
.body("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"fileUpload\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"fileType\"\r\n\r\nElevation Certificate\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"mimeType\"\r\n\r\napplication/pdf\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"address\"\r\n\r\n123 Main St, Springfield, IL 62701\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"parcelId\"\r\n\r\n12-34-567-890\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"externalSystemId\"\r\n\r\nEC-2024-0417\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"externalDocumentURL\"\r\n\r\nhttps://permits.example.gov/documents/EC-2024-0417\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"coordinates\"\r\n\r\n[39.7817, -89.6501]\r\n-----011000010111000001101001--")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.withforerunner.com/api/v1/files")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request.body = "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"fileUpload\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"fileType\"\r\n\r\nElevation Certificate\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"mimeType\"\r\n\r\napplication/pdf\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"address\"\r\n\r\n123 Main St, Springfield, IL 62701\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"parcelId\"\r\n\r\n12-34-567-890\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"externalSystemId\"\r\n\r\nEC-2024-0417\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"externalDocumentURL\"\r\n\r\nhttps://permits.example.gov/documents/EC-2024-0417\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"coordinates\"\r\n\r\n[39.7817, -89.6501]\r\n-----011000010111000001101001--"
response = http.request(request)
puts response.read_body{
"errors": [],
"file": {
"id": "f8a3b2c1-d4e5-4789-abcd-ef0123456789",
"url": "https://demoville.app.withforerunner.com/files/f8a3b2c1-d4e5-4789-abcd-ef0123456789"
}
}{
"errors": [
{
"message": "Required",
"field": "fileUpload"
}
],
"file": null
}{
"errors": [
{
"message": "Document upload already exists with external system id 2024-0417",
"field": "externalSystemId"
}
],
"file": null
}Authorizations
Your account's API key, sent as Authorization: Bearer <your API key>. Keys are issued per environment, so a staging key will not work against production.
Body
The file to upload. Which media types you can send depends on the document type configured for fileType.
Each type has its own size limit, and a file over its limit is rejected:
application/pdf,image/jpeg,image/png,image/jpg— up to 30 MBapplication/json,application/geo+json,text/csv— up to 100 MBvideo/mp4,video/quicktime— up to 600 MBapplication/geopackage+vnd.sqlite3,application/zip,application/vnd.shp— up to 1000 MB
Document type name, such as Elevation Certificate, Building Permit, or Property Image. Must match a document type configured for your account; see File types for how they are set up.
"Elevation Certificate"
Media type of the file.
"application/pdf"
Street address to attach the file to, as {number} {name} {postfix}, {city}, {state} {zip}.
"123 Main St, Springfield, IL 62701"
Parcel number to attach the file to.
"12-34-567-890"
Your system's identifier for this file. Uploading a second file with an identifier already in use returns 409.
"EC-2024-0417"
Link to display this file in your system. Public website users will be directed here when viewing the file.
"https://permits.example.gov/documents/EC-2024-0417"
A JSON-encoded [latitude, longitude] tuple in EPSG:4326, to attach the file to that location.
"[39.7817, -89.6501]"
Response
Success. errors is empty.
Empty when the request succeeded. Otherwise one entry per failure, and the resource fields on the response are empty: null for single resources, [] for lists, with pageInfo omitted.
Show child attributes
Show child attributes
[]
The uploaded file. Null when the upload failed.
Show child attributes
Show child attributes
Was this page helpful?