Custom fields

Define your own typed fields on Wingspan payees, line items, and engagements, then set, read, and search their values through the V3 API.

This page shows you how to store your own data on Wingspan records, such as an internal contractor ID on a payee or a cost center on a payable's line items. You define each custom field once for your Account, then set values on the records it applies to.

Custom fields are typed and validated. If you only need free-form tags, use metadata instead. Custom fields are for data you want checked on write, required on import, and searchable.

Define a field

Create a custom field with a display name, a machine key, a data type, and the kind of record it applies to:

curl -X POST "https://api.wingspan.app/v3/platform/custom-fields" \
  -H "Authorization: Bearer $WINGSPAN_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "name": "Contractor ID",
    "key": "contractorId",
    "dataType": "String",
    "resourceType": "Payee",
    "isRequired": false
  }'
// (trimmed)
{
  "id": "Xa2Lk8Pq5Rt9Vm3Wz7NcYd",
  "name": "Contractor ID",
  "key": "contractorId",
  "dataType": "String",
  "resourceType": "Payee",
  "isRequired": false
}
FieldValues
nameThe label people see.
keyThe machine name you use in API calls. For payee fields, keys may use letters, digits, _, and - only.
dataTypeString, Number, Boolean, Datetime, or ValueSet (a list of strings).
resourceTypePayee, LineItem, or Engagement.
isRequiredWhen true, imports must include a value for this field. Defaults to false.

Custom field definitions belong to the Account. To define fields for a child Account, send X-Wingspan-Account. See Acting on behalf of Accounts.

Set and read values on a payee

Each payee has a map of custom field values keyed by the field's key.

Update a payee's custom fields with the keys you want to change:

curl -X PATCH "https://api.wingspan.app/v3/payments/payees/Rw5Nc2Hk8LqZ4tVp9XmBsa/custom-fields" \
  -H "Authorization: Bearer $WINGSPAN_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "contractorId": "RN-04821",
    "startedAt": "2026-01-15",
    "badgeNumber": null
  }'
  • A key with a value sets it. The value is checked against the field's dataType.
  • A key set to null clears that value.
  • Keys you leave out keep their values.
  • An empty object ({}) is rejected.
  • ValueSet values can be read here but can't be written through this endpoint.
  • A key with no custom field definition for payees is rejected with 422 ValidationError; errors[].field is values.{key} and errors[].code is UnsupportedValue. This applies to clearing a key with null too. Nothing in the request is saved.

Get a payee's custom fields returns the same map. A payee with no values returns {}.

Payee custom fields are the payer's own data about the relationship.

Set values on line items

Set line item custom field values when you import payables with a PayableImport batch. Each item's data.customFields takes values keyed by the LineItem field's key, and every required LineItem field must be present. See Batches and bulk operations.

A PayeeImport batch sets payee custom field values the same way, through each item's data.customFields.

Setting values on engagement custom fields isn't available in the V3 API yet. Contact support if you need it.

Search by custom field

The payee search rows can filter on payee custom fields with filter[customFields.{key}][eq]=..., as well as ne, anyOf, noneOf, and contains:

curl -g "https://api.wingspan.app/v3/search/payee-rows?filter[customFields.contractorId][eq]=RN-04821" \
  -H "Authorization: Bearer $WINGSPAN_TOKEN"

Matching on custom fields in search is by analyzed terms, not exact string equality, and it's case-insensitive. A key that isn't defined matches no rows. See Search.

Manage definitions

TaskEndpoint
List definitions, optionally by filter[resourceType][eq] or filter[resourceType][anyOf][]GET /v3/platform/custom-fields
Read one definitionGET /v3/platform/custom-fields/{fieldId}
Change a definition's name, key, isRequired, or other fieldsPATCH /v3/platform/custom-fields/{fieldId}
Delete a definitionDELETE /v3/platform/custom-fields/{fieldId}

Important: Deleting a definition also deletes every value stored for it, on every record. Export the values first if you need them.

Renaming a key changes the name you use in API calls and imports. Update your integration at the same time.

From V1

V1V3
Custom collaborator fieldsCustom fields with resourceType: Payee
Custom line item fieldsCustom fields with resourceType: LineItem
Columns named after the field in the bulk payable uploaddata.customFields on PayableImport batch items
Editing fields on a collaborator or through the collaborator bulk uploadPATCH /v3/payments/payees/{payeeId}/custom-fields, or data.customFields on PayeeImport batch items
payerOwnedData.customFields.{key} search filterfilter[customFields.{key}][eq] on /v3/search/payee-rows

What can go wrong

ResponseCauseFix
422 ValidationError on a valueThe value doesn't match the field's dataTypeCheck the definition with GET /v3/platform/custom-fields
422 ValidationError on a keyA payee field key uses characters other than letters, digits, _, and -Rename the key
422 ValidationError on an empty bodyPATCH with {}Send at least one key
Batch item rejectedA required custom field is missing from data.customFieldsAdd the value, or make the field optional

Related pages


Did this page help you?