Photo and Video Management
Endpoints for managing photos and videos within RoofLink. Photos can be attached to jobs and to individual line items across estimates, work orders, supplements, and change orders. Each photo record is created through a two-step upload flow: the first API call creates the record and returns a presigned S3 URL, the client uploads the file directly to S3, and the second API call finalizes the record. Files are stored directly in S3-compatible object storage.
Supported Photo Operations
Querying Photos
- List Photos: Retrieve a paginated list of photos with filtering options by job, line item, and related object.
- Retrieve Photo: Get full details for a specific photo, including EXIF metadata.
Creating and Managing Photos
- Create Photo: Step 1 of 2 in the upload flow. Creates a photo record and returns a presigned S3 URL for direct file upload.
- Mark Photo as Uploaded: Step 2 of 2 in the upload flow. Finalizes the photo record after the file has been uploaded to S3.
- Update Photo: Update the display name, description, and tags of an existing photo.
- Delete Photo: Permanently delete a photo, or unrelate it from a specific inspection line item without deleting it.
Photo Upload Flow
Creating a photo requires two API calls with a direct S3 upload in between. The diagram below illustrates the full sequence.
sequenceDiagram
participant Client
participant API as RoofLink API
participant S3 as S3 Compatible Storage
Client->>API: POST /light/photos/
Note right of Client: Provide name, optional job,<br/>line items, tags, and EXIF data
API-->>Client: 201 Created<br/>{ id, upload_url: { url, fields } }
Client->>S3: POST upload_url.url (multipart/form-data)
Note right of Client: Include all upload_url.fields<br/>as form fields, plus the file
S3-->>Client: 204 No Content
Client->>API: PUT /light/photos/{id}/uploaded/
API-->>Client: 200 OK — full photo record
Note left of API: Photo is now visible<br/>to other users in the company
Step 1 of 2 — Create the photo record and upload the file
Call POST /light/photos/ with the photo metadata. The server creates the record and returns a presigned POST object containing:
upload_url.url— the S3 endpoint to upload toupload_url.fields— key-value pairs that must be included as form fields in the upload request
The fields.key value contains the S3 object path. The file name is derived from the photo's display name with a random suffix appended to guarantee uniqueness.
Once you have the presigned URL, send a multipart/form-data POST request directly to upload_url.url. Include all entries from upload_url.fields as form fields, and add the file content in a field named file. No server-side proxy is involved in this step.
Step 2 of 2 — Finalize the upload
Call PUT /light/photos/{id}/uploaded/ to mark the photo as uploaded. This makes the photo visible to other users in the company. If the photo is associated with a job that has no cover photo set, this action also sets the photo as the job's cover photo.
Calling the finalize endpoint before the file upload is complete will result in a photo record with a broken URL.
Associating Photos with Jobs and Line Items
A photo can be associated with a job and with line items of various types at creation time. All referenced IDs must belong to the same company as the authenticated user.
| Field | Type | Description |
|---|---|---|
job | integer | Associates the photo with a job |
job_inspection_lineitems | integer | Links the photo to a job inspection line item |
estimate_lineitems | integer | Links the photo to an estimate line item |
supplineitems | integer | Links the photo to a supplemental line item |
change_order_lineitems | integer | Links the photo to a change order line item |
related_to | string[] | List of related object identifiers (e.g. Job101) |
EXIF Metadata and Geolocation
Photos accept EXIF metadata submitted by the client at upload time. The structure is flexible and varies by device and camera model. When location data is included, the server will attempt to geolocate the photo.
The timestamp key, when present, must be a Unix timestamp in milliseconds and is used to set the photo capture date.
Deleting and Unrelating Photos
The Delete Photo endpoint has two distinct behaviours depending on whether the job_inspection_lineitems query parameter is provided:
- Without
job_inspection_lineitems: The photo record and its associated files are permanently deleted. Returns204 No Content. - With
job_inspection_lineitems: The photo is unrelated from the specified inspection line item without being deleted. The line item's last generated report is also invalidated. Returns200 true.
Pagination
Photo lists are paginated with:
- Default page size: 10 items
- Maximum page size: 10 items
- Results include pagination metadata:
count,from_index,to_index,next,previous, andnext_page. See the responses page for details.
