Worksites

Record the physical locations where your employees work, mark a primary worksite, and assign worksites to Employee engagements in the V3 API.

A worksite is a physical work location your Account owns, such as an office, a clinic, or a warehouse. This page shows you how to create worksites, choose a primary one, and assign them to Employee engagements.

What a worksite is for

Worksites apply to Employee work. When an Employee engagement names a worksite, Wingspan uses that worksite for state income tax assignment on the employee's pay statements. An Employee engagement with no worksite is treated as remote work.

Contractor engagements don't need a worksite.

Where you set itFieldWhat it means
An Engagement templateworksiteId or isRemoteThe default location for Employee work on that template.
A PayeeEngagementworksiteIdWhere this employee works. Leave it out, or set it to null, for remote work.

Create a worksite

POST /v3/payments/worksites creates one. name and address are required. Each worksite name must be unique in your Account.

curl -X POST https://api.wingspan.app/v3/payments/worksites \
  -H "Authorization: Bearer $WINGSPAN_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "name": "Northwind Sacramento clinic",
    "externalId": "site-sac-01",
    "address": {
      "line1": "200 Example Way",
      "city": "Sacramento",
      "subdivision": "CA",
      "postalCode": "95814",
      "countryCode": "US"
    },
    "isPrimary": true
  }'
// 201 Created (trimmed)
{
  "id": "Wk4sT9pLq2Xn7Rb3Vd8HcA",
  "accountId": "z9uv0jPAxTqSLs5UKwv1DE",
  "externalId": "site-sac-01",
  "name": "Northwind Sacramento clinic",
  "address": {
    "line1": "200 Example Way",
    "city": "Sacramento",
    "subdivision": "CA",
    "postalCode": "95814",
    "countryCode": "US"
  },
  "isPrimary": true,
  "events": { "createdAt": "2026-09-25T15:00:00Z" }
}
FieldWhat it's for
nameRequired.
addressRequired. line1, city, subdivision (the two-letter state code, such as CA), postalCode, and countryCode (ISO 3166-1 alpha-2) are all required. line2 is optional. The address can't be changed later.
isPrimaryMakes this your Account's primary worksite. Defaults to false, except that your first worksite is always primary.
externalIdYour own ID for the location. Wingspan doesn't check it for uniqueness on worksites, so use a value you keep unique.
metadataUp to 50 keys of your own data.

The worksite belongs to the Account you're acting as. To create one for a child Account, send X-Wingspan-Account. See Acting on behalf of Accounts.

List and read worksites

curl -G https://api.wingspan.app/v3/payments/worksites \
  -H "Authorization: Bearer $WINGSPAN_TOKEN" \
  --data-urlencode "filter[externalId][eq]=site-sac-01"

Update a worksite

PATCH /v3/payments/worksites/{worksiteId} changes name, isPrimary, externalId, and metadata. Fields you leave out stay the same.

curl -X PATCH https://api.wingspan.app/v3/payments/worksites/Wk4sT9pLq2Xn7Rb3Vd8HcA \
  -H "Authorization: Bearer $WINGSPAN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "name": "Northwind Sacramento clinic (Midtown)" }'
  • Address. You can't change it. If a location moves, create a new worksite and point engagements at it.
  • Primary. Send "isPrimary": true to make a worksite primary. The previous primary is demoted. You can't send false; to move the primary flag, promote another worksite instead.
  • externalId. You can set or replace it, but not clear it. An empty string returns 422.
  • metadata. Sending it replaces the stored metadata. You can't clear metadata through this endpoint.

Delete a worksite

DELETE /v3/payments/worksites/{worksiteId} returns 204. It returns 422 if the worksite is your primary worksite or if any engagement still references it. Move those engagements to another worksite, or promote another worksite to primary, then delete.

Assign a worksite to an employee

Set worksiteId when you create the PayeeEngagement, or change it later with PATCH:

curl -X PATCH https://api.wingspan.app/v3/payments/payee-engagements/ru9zEafz6i4WRlIOA10wAk \
  -H "Authorization: Bearer $WINGSPAN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "worksiteId": "Wk4sT9pLq2Xn7Rb3Vd8HcA" }'

Send "worksiteId": null to switch the engagement to remote work. See Engagements and Payroll runs.

What can go wrong

Status and codeCauseFix
422 ValidationError on createA required field is missing, such as address.countryCode, the name is already used by another worksite, or you sent a field the endpoint doesn't accept.Read errors[].
422 ValidationError on updateYou sent isPrimary: false, an address, an empty externalId, or a name another worksite already uses.Promote another worksite, or create a new one for a new address.
422 ValidationError when you assign a worksite to an Employee PayeeEngagementThe worksite's country or state isn't supported for W-2 payroll (payments.WorksiteCountryUnsupported, payments.WorksiteJurisdictionUnsupported), or the state isn't enabled on your employer payroll profile (payments.WorksiteJurisdictionNotEnabled).Choose a worksite in an enabled state, or enable the state on your payroll profile.
422 ValidationError on deleteThe worksite is primary, or an engagement still uses it.Promote another worksite or reassign the engagements first.

Webhooks

Worksites don't emit webhook events. Read the worksite after each change.

Related


Did this page help you?