DevelopersAPI reference

Weather API

REST endpoints for weather in ServFlo: 6 operations with parameters, request and response fields, permissions and curl examples.

Base URL: https://app.servflo.ai/api. Every call needs Authorization: Bearer sfk_… (Authentication); {organizationId} ($ORGANIZATION_ID in the examples) is your business's id.

OperationEndpointRisk
Get the weather settingsGET /organizations/{organizationId}/weather/settingsread
Change the weather settingsPATCH /organizations/{organizationId}/weather/settingswrite
Get a job's weatherGET /organizations/{organizationId}/jobs/{jobId}/weatherread
Check the weather for a time at a propertyGET /organizations/{organizationId}/weather/forecastread
Get the weather for the scheduleGET /organizations/{organizationId}/weather/scheduleread
Move a visit for the weatherPOST /organizations/{organizationId}/jobs/{jobId}/weather/reschedulesensitive

Get the weather settings

GET /organizations/{organizationId}/weather/settings

Weather-aware scheduling settings: whether the office is alerted when an outdoor visit's forecast turns bad, how many days ahead, the units people see, where forecasts come from and whether the business address has a map location. Read-only.

Permission: jobs.read (Owner, Admin, Dispatcher, Technician (own jobs), Member); risk read (OAuth scope servflo.read).

Permissionjobs.read
Riskread, OAuth scope servflo.read. Read: reads only.
MCP toolweather_settings (toolset scheduling)

Example

curl "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/weather/settings" \
  -H "Authorization: Bearer $SERVFLO_API_KEY"

Response

200: the answer's fields
FieldTypeDescription
alertsEnabledbooleanAlert the office when an outdoor visit's forecast turns bad.
alertDaysAheadintegerHow many days ahead visits are watched for alerts.
unitsSettingenum or nullThe chosen units; null = by the business's country. One of imperial, metric.
unitsenumHow people see it: imperial (°F, mph, in) or metric (°C, km/h, mm). Numbers in answers are always imperial. One of imperial, metric.
modeenumWhere forecasts come from: nws (US National Weather Service, about 7 days), open-meteo (16 days), fake (scripted) or off. One of nws, open-meteo, fake, off.
hasBusinessLocationbooleanThe business address has a map location (the dispatch board's daily forecast).

Change the weather settings

PATCH /organizations/{organizationId}/weather/settings

Turn weather alerts on or off, set how many days ahead (1-7) outdoor visits are watched, and the units (imperial, metric, or null for the business's country). Which work is outdoor and its limits are set per service type (PATCH /service-types/{serviceTypeId}: weatherSensitive and the weather limits). Owners and admins.

Permissionorganization.manage (Owner, Admin)
Riskwrite, OAuth scope servflo.write. Write: creates or changes records inside the business; nothing leaves it.
MCP toolweather_updateSettings (toolset scheduling)

Request body

FieldTypeRequiredDescription
alertsEnabledbooleanNo
alertDaysAheadintegerNo1–7.
unitsenum or nullNoHow people see it: imperial (°F, mph, in) or metric (°C, km/h, mm). Numbers in answers are always imperial. One of imperial, metric.

Example

curl -X PATCH "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/weather/settings" \
  -H "Authorization: Bearer $SERVFLO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"alertsEnabled":true,"alertDaysAhead":1,"units":"imperial"}'

Response

200: the answer's fields
FieldTypeDescription
alertsEnabledbooleanAlert the office when an outdoor visit's forecast turns bad.
alertDaysAheadintegerHow many days ahead visits are watched for alerts.
unitsSettingenum or nullThe chosen units; null = by the business's country. One of imperial, metric.
unitsenumHow people see it: imperial (°F, mph, in) or metric (°C, km/h, mm). Numbers in answers are always imperial. One of imperial, metric.
modeenumWhere forecasts come from: nws (US National Weather Service, about 7 days), open-meteo (16 days), fake (scripted) or off. One of nws, open-meteo, fake, off.
hasBusinessLocationbooleanThe business address has a map location (the dispatch board's daily forecast).

Get a job's weather

GET /organizations/{organizationId}/jobs/{jobId}/weather

The forecast at the job's property and each open visit checked against its service type's limits (GOOD, WATCH, BAD or UNKNOWN, with reasons), whether the job plans around the weather, and the next clear days for its next open visit. Use it before booking or moving outdoor work; to move a visit for the weather call POST /jobs/{jobId}/weather/reschedule. Technicians: their own jobs. Read-only.

Permission: jobs.read (Owner, Admin, Dispatcher, Technician (own jobs), Member); risk read (OAuth scope servflo.read).

Permissionjobs.read
Riskread, OAuth scope servflo.read. Read: reads only.
MCP toolweather_forJob (toolset scheduling)

Parameters

NameInTypeRequiredDescription
jobIdpathstringYes

Example

curl "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/jobs/{jobId}/weather" \
  -H "Authorization: Bearer $SERVFLO_API_KEY"

Response

200: the answer's fields
FieldTypeDescription
weatherSensitivebooleanThe job plans around the weather (alerts, the banner).
sourceenumjob = the job's own switch; serviceType = its service type is outdoor work; none = neither. One of job, serviceType, none.
serviceTypeNamestring or null
limitsobject
limits.maxRainChancenumberBAD at or above this chance of rain (%).
limits.maxWindMphnumberBAD at or above this wind (gusts count at 75 %).
limits.minTempFnumber or nullBAD below this; null = no limit.
limits.maxTempFnumber or nullBAD above this; null = no limit.
unitsenumHow people see it: imperial (°F, mph, in) or metric (°C, km/h, mm). Numbers in answers are always imperial. One of imperial, metric.
hasLocationbooleanThe property has a map location (needed for a forecast).
forecastErrorstring or null
fetchedAtstring or null
forecastThroughstring or nullThe last day the forecast reaches.
daysarray of objectThe daily forecast at the property from today.
days[].datestring
days[].conditionenumThe worst sky between 07:00 and 19:00. One of clear, partly_cloudy, cloudy, fog, drizzle, rain, snow, storm.
days[].highFnumber
days[].lowFnumber
days[].rainPctnumberHighest chance of precipitation between 07:00 and 19:00.
days[].windMphnumber
days[].gustMphnumber or null
days[].precipInnumber or null
days[].hourCountinteger
visitsarray of object
visits[].visitIdstring
visits[].scheduledDatestring or null
visits[].scheduledTimestring or null
visits[].durationMinutesinteger
visits[].statusstring
visits[].assessmentobject or nullNull when the visit is not scheduled.
visits[].assessment.statusenumGood: within every limit; WATCH: close to a limit; BAD: past a limit, or thunderstorms or snow; UNKNOWN: the forecast does not reach this time yet (or no map location). One of GOOD, WATCH, BAD, UNKNOWN.
visits[].assessment.summarystringOne line, in the business's units.
visits[].assessment.reasonsarray of object
visits[].assessment.rainPctnumber or null
visits[].assessment.windMphnumber or null
visits[].assessment.gustMphnumber or null
visits[].assessment.lowFnumber or null
visits[].assessment.highFnumber or null
visits[].assessment.conditionenum or nullOne of clear, partly_cloudy, cloudy, fog, drizzle, rain, snow, storm.
visits[].assessment.hoursarray of objectThe forecast hours the visit covers.
suggestionsarray of objectThe next clear days for the job's next open visit (up to 3), as far as the forecast reaches.
suggestions[].datestringA day the same visit (same time and length) would be GOOD.
suggestions[].summarystring

Check the weather for a time at a property

GET /organizations/{organizationId}/weather/forecast

For booking a job that does not exist yet: the daily forecast at a property, a day and time (and length, default the service type's) checked against the service type's limits, and the next clear days after it. Without a date, only the forecast and the next clear days from today. Find the property with GET /customers/{customerId}. Read-only.

Permission: jobs.read (Owner, Admin, Dispatcher, Technician (own jobs), Member); risk read (OAuth scope servflo.read).

Permissionjobs.read
Riskread, OAuth scope servflo.read. Read: reads only.
MCP toolweather_forSlot (toolset scheduling)

Parameters

NameInTypeRequiredDescription
propertyIdquerystringYes
datequerystringNoA calendar date in the business's own calendar, YYYY-MM-DD.
timequerystringNoA local time of day, HH:MM (24-hour). Blank means 09:00 on new jobs.
durationMinutesqueryintegerNo1–1440.
serviceTypeIdquerystringNoIts weather limits apply; default limits without one.

Example

curl "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/weather/forecast?propertyId=property_id" \
  -H "Authorization: Bearer $SERVFLO_API_KEY"

Response

200: the answer's fields
FieldTypeDescription
serviceTypeWeatherSensitiveboolean
limitsobject
limits.maxRainChancenumberBAD at or above this chance of rain (%).
limits.maxWindMphnumberBAD at or above this wind (gusts count at 75 %).
limits.minTempFnumber or nullBAD below this; null = no limit.
limits.maxTempFnumber or nullBAD above this; null = no limit.
unitsenumHow people see it: imperial (°F, mph, in) or metric (°C, km/h, mm). Numbers in answers are always imperial. One of imperial, metric.
hasLocationboolean
forecastErrorstring or null
forecastThroughstring or null
daysarray of object
days[].datestring
days[].conditionenumThe worst sky between 07:00 and 19:00. One of clear, partly_cloudy, cloudy, fog, drizzle, rain, snow, storm.
days[].highFnumber
days[].lowFnumber
days[].rainPctnumberHighest chance of precipitation between 07:00 and 19:00.
days[].windMphnumber
days[].gustMphnumber or null
days[].precipInnumber or null
days[].hourCountinteger
assessmentobject or nullThe asked slot checked; null without a date.
assessment.statusenumGood: within every limit; WATCH: close to a limit; BAD: past a limit, or thunderstorms or snow; UNKNOWN: the forecast does not reach this time yet (or no map location). One of GOOD, WATCH, BAD, UNKNOWN.
assessment.summarystringOne line, in the business's units.
assessment.reasonsarray of object
assessment.reasons[].kindenumOne of rain, wind, cold, heat, storm, snow.
assessment.reasons[].levelenumOne of BAD, WATCH.
assessment.reasons[].textstring
assessment.reasons[].valuenumber or nullThe number behind it, imperial: rain %, wind mph, low or high °F; null for storms and snow.
assessment.reasons[].gustMphnumber or nullWind only: the gusts, when worth naming.
assessment.rainPctnumber or null
assessment.windMphnumber or null
assessment.gustMphnumber or null
assessment.lowFnumber or null
assessment.highFnumber or null
assessment.conditionenum or nullOne of clear, partly_cloudy, cloudy, fog, drizzle, rain, snow, storm.
assessment.hoursarray of objectThe forecast hours the visit covers.
assessment.hours[].tstringLocal hour at the property, YYYY-MM-DDTHH:00.
assessment.hours[].tempFnumber
assessment.hours[].rainPctnumberChance of precipitation, 0-100.
assessment.hours[].precipInnumber or null
assessment.hours[].windMphnumber
assessment.hours[].gustMphnumber or null
assessment.hours[].conditionenumOne of clear, partly_cloudy, cloudy, fog, drizzle, rain, snow, storm.
suggestionsarray of object
suggestions[].datestringA day the same visit (same time and length) would be GOOD.
suggestions[].summarystring

Get the weather for the schedule

GET /organizations/{organizationId}/weather/schedule

For the dispatch board and calendar: the daily forecast at the business's address for a date range (at most 31 days; forecasts reach about 7-16 days), and every weather-sensitive open visit in the range checked at its own property. Technicians: their own visits. Read-only.

Permissionschedule.read (Owner, Admin, Dispatcher, Technician, Member)
Riskread, OAuth scope servflo.read. Read: reads only.
MCP toolweather_schedule (toolset scheduling)

Parameters

NameInTypeRequiredDescription
fromquerystringYesA calendar date in the business's own calendar, YYYY-MM-DD.
toquerystringYesA calendar date in the business's own calendar, YYYY-MM-DD.

Example

curl "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/weather/schedule?from=2026-11-03&to=2026-11-03" \
  -H "Authorization: Bearer $SERVFLO_API_KEY"

Response

200: the answer's fields
FieldTypeDescription
unitsenumHow people see it: imperial (°F, mph, in) or metric (°C, km/h, mm). Numbers in answers are always imperial. One of imperial, metric.
hasBusinessLocationboolean
daysarray of objectThe daily forecast at the business's address.
days[].datestring
days[].conditionenumThe worst sky between 07:00 and 19:00. One of clear, partly_cloudy, cloudy, fog, drizzle, rain, snow, storm.
days[].highFnumber
days[].lowFnumber
days[].rainPctnumberHighest chance of precipitation between 07:00 and 19:00.
days[].windMphnumber
days[].gustMphnumber or null
days[].precipInnumber or null
days[].hourCountinteger
visitsarray of object
visits[].visitIdstring
visits[].jobIdstring
visits[].identifierstring
visits[].scheduledDatestring or null
visits[].scheduledTimestring or null
visits[].durationMinutesinteger
visits[].statusstring
visits[].hasLocationboolean
visits[].assessmentobject or null
visits[].assessment.statusenumGood: within every limit; WATCH: close to a limit; BAD: past a limit, or thunderstorms or snow; UNKNOWN: the forecast does not reach this time yet (or no map location). One of GOOD, WATCH, BAD, UNKNOWN.
visits[].assessment.summarystringOne line, in the business's units.
visits[].assessment.reasonsarray of object
visits[].assessment.rainPctnumber or null
visits[].assessment.windMphnumber or null
visits[].assessment.gustMphnumber or null
visits[].assessment.lowFnumber or null
visits[].assessment.highFnumber or null
visits[].assessment.conditionenum or nullOne of clear, partly_cloudy, cloudy, fog, drizzle, rain, snow, storm.

Move a visit for the weather

POST /organizations/{organizationId}/jobs/{jobId}/weather/reschedule

Moves the job's visit (visitId, default its next scheduled one) to another day and optionally time, like any reschedule (reminders follow the new time). SENDS TO THE CUSTOMER when notifyCustomer is true (default): a text (else an email) saying the visit moved because of the weather; message replaces the default wording. Consent rules apply. Pick the day from GET /jobs/{jobId}/weather suggestions and confirm it with the person first. Returns the new slot and whether the customer was told.

Permissionjobs.write (Owner, Admin, Dispatcher)
Risksensitive, OAuth scope servflo.sensitive. Sensitive: moves money, deletes, sends or shows something to a customer, or grants or revokes access.
MCP toolweather_reschedule (toolset scheduling)
ApprovalOver MCP, this tool asks for your OK first (in the AI app when it supports it, otherwise in ServFlo). See Approvals.

Parameters

NameInTypeRequiredDescription
jobIdpathstringYes

Request body

FieldTypeRequiredDescription
visitIdstringNo
scheduledDatestringYesA calendar date in the business's own calendar, YYYY-MM-DD.
scheduledTimestringNoA local time of day, HH:MM (24-hour). Blank means 09:00 on new jobs.
notifyCustomerbooleanNoDefault true.
messagestringNoThe text to send instead of the default weather message. Up to 1000 characters.

Example

curl -X POST "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/jobs/{jobId}/weather/reschedule" \
  -H "Authorization: Bearer $SERVFLO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"scheduledDate":"2026-11-03"}'

Response

200: the answer's fields
FieldTypeDescription
visitIdstring
fromDatestring or null
scheduledDatestring
scheduledTimestring or null
customerNotifiedboolean
channelenum or nullOne of SMS, EMAIL.
messagestring or nullWhat was sent to the customer.
notifyProblemstring or nullWhy the customer could not be told (no consent, no number).

On this page