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, and address.countryCode is required inside the address.

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": "US-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": "US-CA",
    "postalCode": "95814",
    "countryCode": "US"
  },
  "isPrimary": true,
  "events": { "createdAt": "2026-09-25T15:00:00Z" }
}
FieldWhat it's for
nameRequired.
addressRequired. line1, line2, city, subdivision (an ISO 3166-2 code such as US-CA), postalCode, and countryCode (ISO 3166-1 alpha-2, required). The address can't be changed later.
isPrimaryMakes this your Account's primary worksite. Defaults to false.
externalIdYour own ID for the location. A duplicate returns 409 ResourceConflict. Create is never an upsert.
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. Send an empty string to clear it.
  • 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 409 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
409 ResourceConflict on createThe externalId is already used by another worksite.Look it up with filter[externalId][eq].
409 on deleteThe worksite is primary, or an engagement still uses it.Promote another worksite or reassign the engagements first.
422 ValidationError on createA required field is missing, such as address.countryCode, or you sent a field the endpoint doesn't accept.Read errors[].
422 ValidationError on updateYou sent isPrimary: false or an address.Promote another worksite, or create a new one for a new address.

Webhooks

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

Related


Did this page help you?