Skip to content

Create an engagement

Opportunities module

POST/engagementsengagements.create

An external relationship: a person or external account working for an org. It cannot become Active until every blocking onboarding item passes. Creates an engagement. Requires `Idempotency-Key`; a replay returns the original response. The organization is derived from the credential or the parent row, never from the body.

  • Requires the capability opportunities.engagement.write.
  • OAuth scopes: opportunities.
  • Send an Idempotency-Key header. A replay with the same key returns the original response.
  • Error statuses: 400, 401, 409, 422, 429. Errors are RFC 9457 problem details.

Request body: EngagementCreate

engagements.create: EngagementCreate
FieldTypeRequiredDescription
application_idstring (uuid)YesIdentifier of the accepted application the engagement comes from.
worker_classificationstringYesWorker classification, from xpms.worker_classification.Constraints: pattern ^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$
pay_basisstring | nullNoPay basis; with the arrangement a permitted canon pair.Constraints: length 1 to 300
arrangementstring | nullNoArrangement; with the pay basis a permitted canon pair.Constraints: length 1 to 300
start_datestring (date)NoFirst day of the engagement; defaults to the offer's or the opportunity's.
end_datestring (date) | nullNoLast day of the engagement; defaults to the offer's or the opportunity's.
{
  "application_id": "0192f1e2-7c3a-7b4d-9e8f-1a2b3c4d5e6f",
  "worker_classification": "INDEPENDENT_CONTRACTOR",
  "pay_basis": "Day Rate",
  "arrangement": "Per Engagement",
  "start_date": "2026-10-08",
  "end_date": "2026-10-08"
}

Response 201: Engagement

engagements.create: Engagement
FieldTypeRequiredDescription
idstring (uuid)YesIdentifier of the engagement.
org_idstring (uuid)YesIdentifier of the owning organization, derived from the parent row and never accepted from the caller.
created_atstring (date-time)YesWhen the row was created.
created_bystring (uuid) | nullYesIdentifier of the person who created the row; null when a seed, platform or system process created it.
updated_atstring (date-time)YesWhen the row was last updated.
updated_bystring (uuid) | nullYesIdentifier of the person who last updated the row; null when a seed, platform or system process updated it.
person_idstring (uuid) | nullYesIdentifier of the engaged person.
organization_idstring (uuid) | nullYesIdentifier of the engaged external account.
project_idstring (uuid) | nullYesIdentifier of the project.
offer_idstring (uuid) | nullYesIdentifier of the accepted offer.
role_typeExternalRoleTypeYesExternal role type (Section 4.4.2).Constraints: one of "Client", "Vendor", "Contractor", "Crew", "Staff", "Artist", "Artist Representative", "Sponsor"
engagement_stateEngagementStateYesEngagement lifecycle state. Active requires every blocking onboarding item to pass.Constraints: one of "Onboarding", "Blocked", "Active", "Closing", "Complete", "Canceled"
activated_atstring (date-time) | nullYesWhen it became Active.
completed_atstring (date-time) | nullYesWhen it became Complete.
application_idstring (uuid) | nullYesIdentifier of the accepted application the engagement came from.
worker_classificationstring | nullYesWorker classification, from xpms.worker_classification; null for Client and Sponsor engagements.Constraints: pattern ^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$
pay_basisstring | nullYesPay basis; with the arrangement a permitted canon pair.Constraints: length 1 to 300
arrangementstring | nullYesArrangement; with the pay basis a permitted canon pair.Constraints: length 1 to 300
start_datestring (date)YesFirst day of the engagement; defaults to the offer's or the opportunity's.
end_datestring (date) | nullYesLast day of the engagement; defaults to the offer's or the opportunity's.
counterparty_idstring (uuid) | nullYesIdentifier of the counterparty (vendor) the holder is engaged through; null when direct.
{
  "id": "0192f1e2-7c3a-7b4d-9e8f-1a2b3c4d5e6f",
  "org_id": "0192f1e2-7c3a-7b4d-9e8f-1a2b3c4d5e6f",
  "created_at": "2026-10-08T14:30:00Z",
  "created_by": "0192f1e2-7c3a-7b4d-9e8f-1a2b3c4d5e6f",
  "updated_at": "2026-10-08T14:30:00Z",
  "updated_by": "0192f1e2-7c3a-7b4d-9e8f-1a2b3c4d5e6f",
  "person_id": "0192f1e2-7c3a-7b4d-9e8f-1a2b3c4d5e6f",
  "organization_id": "0192f1e2-7c3a-7b4d-9e8f-1a2b3c4d5e6f",
  "project_id": "0192f1e2-7c3a-7b4d-9e8f-1a2b3c4d5e6f",
  "offer_id": "0192f1e2-7c3a-7b4d-9e8f-1a2b3c4d5e6f",
  "role_type": "Crew",
  "engagement_state": "Onboarding",
  "activated_at": "2026-10-08T14:30:00Z",
  "completed_at": "2026-10-08T14:30:00Z",
  "application_id": "0192f1e2-7c3a-7b4d-9e8f-1a2b3c4d5e6f",
  "worker_classification": "INDEPENDENT_CONTRACTOR",
  "pay_basis": "Day Rate",
  "arrangement": "Per Engagement",
  "start_date": "2026-10-08",
  "end_date": "2026-10-08",
  "counterparty_id": "0192f1e2-7c3a-7b4d-9e8f-1a2b3c4d5e6f"
}

Code samples

curl -X POST "$XOS_BASE_URL/engagements" \
  -H "Authorization: Bearer $XOS_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"application_id":"0192f1e2-7c3a-7b4d-9e8f-1a2b3c4d5e6f","worker_classification":"INDEPENDENT_CONTRACTOR","pay_basis":"Day Rate","arrangement":"Per Engagement","start_date":"2026-10-08","end_date":"2026-10-08"}'
const { data } = await xos.engagements.create({
    "application_id": "0192f1e2-7c3a-7b4d-9e8f-1a2b3c4d5e6f",
    "worker_classification": "INDEPENDENT_CONTRACTOR",
    "pay_basis": "Day Rate",
    "arrangement": "Per Engagement",
    "start_date": "2026-10-08",
    "end_date": "2026-10-08"
  });
response = xos.engagements.create({"application_id": "0192f1e2-7c3a-7b4d-9e8f-1a2b3c4d5e6f", "worker_classification": "INDEPENDENT_CONTRACTOR", "pay_basis": "Day Rate", "arrangement": "Per Engagement", "start_date": "2026-10-08", "end_date": "2026-10-08"})
xos engagements create --data '{"application_id":"0192f1e2-7c3a-7b4d-9e8f-1a2b3c4d5e6f","worker_classification":"INDEPENDENT_CONTRACTOR","pay_basis":"Day Rate","arrangement":"Per Engagement","start_date":"2026-10-08","end_date":"2026-10-08"}'