API Reference
Offboarding Initiations

Offboarding Initiations

An initiation is a request to start offboarding an employee, submitted by a manager (or HR/admin) and optionally routed through an approval chain before the real offboarding record gets created. This is a separate, earlier step from the Offboarding API - an initiation only becomes an offboarding once it's approved (or auto-approved).

Base path: /api/offboarding-initiations

⚠️

This feature is gated behind the managerInitiation plan feature and is session-authenticated, like the rest of the app API - it is not part of the API-key-based /api/v1 surface.


Approval behavior

Whether an initiation needs approval at all depends on your org's settings and who's submitting it:

  • If HR or an admin submits the request, it's auto-approved immediately and the offboarding is created on the spot.
  • If your org has require_initiation_approval turned off, everything auto-approves the same way.
  • Otherwise, the initiation is routed through an approval chain: either the chain_id you pass explicitly, or the org's default_chain_id. If neither resolves to a real chain, there's no formal chain - the request just sits pending and PurpletGo posts an interactive notification to Slack/Teams instead of routing through named steps.

Chains are made of ordered steps, each targeting either a specific approver_id or an approver_role. Approving a step advances current_step; approving the last step creates the offboarding. Steps can also be delegated to someone else. Chain configuration itself (creating/editing chains and their steps) lives under /api/approval-chains, not documented here.


Initiation object

{
  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "org_id": "org_xyz",
  "initiated_by": "usr_mgr001",
  "initiated_by_name": "Alex Chen",
  "initiated_by_email": "alex@acme.com",
  "employee_name": "Jordan Lee",
  "employee_email": "jordan.lee@acme.com",
  "employee_role": "Senior Engineer",
  "employee_department": "Engineering",
  "exit_date": "2025-07-11",
  "separation_type": "resignation",
  "apps_to_revoke": ["github", "slack"],
  "notes": "Employee has signed their resignation letter.",
  "status": "pending",
  "chain_id": "9c1e...",
  "chain_name": "Standard Engineering Exit",
  "current_step": 2,
  "reviewed_by": null,
  "reviewed_by_name": null,
  "reviewed_at": null,
  "rejection_reason": null,
  "offboarding_id": null,
  "created_at": "2025-06-26T10:30:00.000Z",
  "updated_at": "2025-06-26T11:00:00.000Z"
}

Status values: pending · approved · rejected. There's no cancelled status - withdrawing a pending initiation deletes it outright (see Withdraw).

initiated_by_name, initiated_by_email, reviewed_by_name and chain_name are joined in by the list and get endpoints only. Submit and edit return the raw row, without them.

notes is stored sealed when the deployment has an encryption key, and every endpoint returns the column as stored - a pii:v1:... string, never the plaintext you sent. The example above shows the value before sealing. Treat notes as write-only from the API's point of view.


Endpoints

Submit an initiation

POST /api/offboarding-initiations

Restricted to managers, HR, and admins.

Request body

{
  "employee_name": "Jordan Lee",
  "employee_email": "jordan.lee@acme.com",
  "employee_role": "Senior Engineer",
  "employee_department": "Engineering",
  "exit_date": "2025-07-11",
  "separation_type": "resignation",
  "apps_to_revoke": ["github", "slack"],
  "no_apps": false,
  "notes": "Employee has signed their resignation letter.",
  "chain_id": null
}
FieldRequiredTypeDescription
employee_nameYesstringFree-text name - there's no employee lookup by ID
exit_dateYesdateISO 8601 date (YYYY-MM-DD)
employee_emailNostring
employee_roleNostring
employee_departmentNostringMust be inside the caller's department scope, if they have one (403 otherwise)
separation_typeNoenumresignation · termination · layoff · retirement · contract_end · other. Defaults to resignation
apps_to_revokeSee notestring[]Apps to revoke. Only the org's connected integrations are accepted (400 otherwise)
no_appsSee notebooleantrue confirms there is nothing to revoke for this person
notesNostringInternal notes, max 2000 characters
chain_idNouuidExplicit approval chain to use instead of the org default

You must either list at least one app in apps_to_revoke or send no_apps: true. An empty list with no no_apps is refused with 400 and { "code": "apps_choice_required" } - there's no silent empty default.

Response 201 Created - the raw initiation row (no initiated_by_name, chain_name or other joined fields). If it was auto-approved, status will already be "approved" and offboarding_id will be populated.

Other outcomes

StatusWhen
400Missing/invalid field, or no apps choice (apps_choice_required)
403Caller lacks offboardings_create, the department is outside their scope, or exit_date is already past and the caller lacks the access-revocation permission ({ "code": "past_exit_date_permission" })
409employee_email already has an open offboarding ({ "code": "duplicate" })

List initiations

GET /api/offboarding-initiations

Managers only see initiations they submitted. Reviewers (superadmin, admin and hr with offboardings_view) see the org's initiations within their scope: a reviewer limited to some departments sees initiations for those departments plus their own submissions, and one limited to their direct reports sees only their own submissions.

Query parameters

ParameterTypeDescription
statusstringpending · approved · rejected
limitintegerDefault 50, max 200
offsetintegerRow offset

Response 200 OK

{
  "rows": [ /* initiation objects */ ],
  "total": 1,
  "limit": 50,
  "offset": 0
}

Get an initiation

GET /api/offboarding-initiations/:id

Returns the initiation with a step_history array attached - one entry per approval step that's been reached, including who acted, when, and any notes or delegation.

Managers can only fetch their own initiations; HR/admins can fetch any.


Edit an initiation

PATCH /api/offboarding-initiations/:id

Only while status is pending, and only by the original submitter or HR/admin. Accepts any subset of the submit-time fields (employee_name, employee_email, employee_role, employee_department, exit_date, separation_type, apps_to_revoke, notes).


Approve an initiation

POST /api/offboarding-initiations/:id/approve

Request body

{ "notes": "Confirmed with finance. All clear to proceed." }

notes is optional. The approval that creates the offboarding also accepts apps_to_revoke (string[]) and no_apps (boolean) to override the apps chosen at submit time; the same connected-apps and apps-choice rules as Submit apply.

For chain-based initiations, only the designated approver (or role, or an active delegate) for the current step can call this - you'll get 403 otherwise, and 409 if that step was already acted on or the initiation is no longer pending. Approving the final step creates the offboarding and sets status: "approved" with offboarding_id populated. For non-chain initiations, only HR/admins can approve.

Response 200 OK - the updated initiation. On the final approval, also includes offboarding_id.

The approval that creates the offboarding can also fail with 409 when the employee already has an open offboarding ({ "code": "duplicate" }).


Reject an initiation

POST /api/offboarding-initiations/:id/reject

Request body

{
  "rejection_reason": "Incorrect employee record - please resubmit with corrected exit date.",
  "notes": "Optional - recorded on the approval chain step; falls back to rejection_reason if omitted."
}

rejection_reason is required. notes is optional. No offboarding is created; status becomes "rejected".


Delegate the current step

POST /api/offboarding-initiations/:id/delegate

Only meaningful for chain-based initiations - returns 400 if the initiation has no chain. Only the current step's designated approver can delegate, and not to the original initiator or to themself.

Request body

{ "delegate_id": "usr_hr002", "notes": "Out this week, please cover." }

Response 200 OK

{ "delegated": true, "delegate_id": "usr_hr002", "step": 2 }

Withdraw an initiation

DELETE /api/offboarding-initiations/:id

Only while status is pending, by the original submitter or HR/admin. Deletes the row outright.

Response 200 OK

{ "deleted": true }

Approval settings

GET /api/offboarding-initiations/settings

{ "require_initiation_approval": true, "default_chain_id": "9c1e..." }

PATCH /api/offboarding-initiations/settings

Needs the settings_manage permission (Super Admin and Admin by default - HR does not have it unless a custom role grants it). Body: require_initiation_approval (boolean) and/or default_chain_id (uuid or null - must belong to your org).


HRIS integration example

A typical pattern for wiring an HRIS termination webhook to PurpletGo:

app.post('/webhooks/bamboohr', async (req, res) => {
  const event = req.body;
  if (event.type !== 'employee.terminated') return res.sendStatus(200);
 
  await fetch('https://app.purpletgo.com/api/offboarding-initiations', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Cookie': sessionCookie, // this endpoint is session-authenticated, not API-key based
    },
    body: JSON.stringify({
      employee_name: event.employeeName,
      employee_email: event.employeeEmail,
      exit_date: event.lastDay,
      separation_type: 'termination',
      no_apps: true, // or apps_to_revoke: [...] - one of the two is required
      notes: `BambooHR event ID: ${event.id}`,
    }),
  });
 
  res.sendStatus(202);
});

Related

  • Offboarding API - the record that gets created once an initiation is approved
  • Checklists - tasks generated automatically when the offboarding is created