# Business Made · Performance

Part of AppEngine API Documentation. Full index: https://appengine.appmint.io/documentation.md
## GET /business-made/performance/goals

**List goals**

`operationId: PerformanceController_getGoals`

Performance goals across the org.

#### Signature

```http
GET /business-made/performance/goals () -> Goals
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /business-made/performance/goals/employee/{employeeId}`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Goals |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /business-made/performance/goals

**Create a goal**

`operationId: PerformanceController_createGoal`

Creates a performance goal as a draft. Activating it is what makes it count toward a review.

#### Signature

```http
POST /business-made/performance/goals (body) -> The created goal
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /business-made/performance/goals/{id}/activate`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

The goal to create.

```json
{
  "employeeId": "EMP-4821",
  "title": "Ship the platform migration",
  "targetDate": "2026-12-31",
  "measure": "All services migrated with no customer downtime"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The created goal |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /business-made/performance/goals/{id}

**Get a goal**

`operationId: PerformanceController_getGoal`

Fetches one goal with its progress history.

#### Signature

```http
GET /business-made/performance/goals/{id} (id: string) -> The goal
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `400` | INVALID_ID | invalid id <id> | The id is not a valid record id. A well-formed id that matches nothing returns an empty 200, not a 404. | — |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /business-made/performance/goals/{id}/progress`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `id` | path | string | yes | Record id. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The goal |
| `400` | invalid id <id> — The id is not a valid record id. A well-formed id that matches nothing returns an empty 200, not a 404. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## DELETE /business-made/performance/goals/{id}

**Delete a goal**

`operationId: PerformanceController_deleteGoal`

Deletes a goal. Cancel instead where the record of what was set matters.

#### Signature

```http
DELETE /business-made/performance/goals/{id} (id: string) -> Deletion result
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /business-made/performance/goals/{id}/cancel`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `id` | path | string | yes | Record id. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Deletion result |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /business-made/performance/goals/update

**Update a goal**

`operationId: PerformanceController_updateGoal`

Updates a goal. Changing the target mid-period is worth a note — a goal quietly rewritten to match the outcome is not a goal. **Replaces the stored record** — send the whole record as read (`sk` plus `data`), not just the changed fields.

#### Signature

```http
POST /business-made/performance/goals/update (body) -> The updated goal
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /business-made/performance/goals/{id}/progress`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

The goal to update.

```json
{
  "sk": "GOL-4821",
  "data": {
    "targetDate": "2027-01-31"
  }
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The updated goal |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /business-made/performance/goals/{id}/activate

**Activate a goal**

`operationId: PerformanceController_activateGoal`

Makes a goal live and countable toward the review period.

#### Signature

```http
POST /business-made/performance/goals/{id}/activate (id: string) -> The activated goal
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | GOAL_NOT_FOUND | Goal not found | No goal has that id. | The body carries `code: "GOAL_NOT_FOUND"` and the id. |
| `400` | wrong-state | Cannot complete this plan while it is draft | The record is not in a state that allows this step; the message names the step and the current state. The body carries `reason: "wrong-state"`. | — |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /business-made/performance/goals/{id}/progress`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `id` | path | string | yes | Record id. |

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The activated goal |
| `400` | Cannot complete this plan while it is draft — The record is not in a state that allows this step; the message names the step and the current state. The body carries `reason: "wrong-state"`. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | Goal not found — No goal has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /business-made/performance/goals/{id}/progress

**Record goal progress**

`operationId: PerformanceController_updateGoalProgress`

Records progress against a goal. Regular entries are what make a review evidence-based rather than a recollection of the last month.

#### Signature

```http
POST /business-made/performance/goals/{id}/progress (id: string, body) -> The updated goal
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | GOAL_NOT_FOUND | Goal not found | No goal has that id. | The body carries `code: "GOAL_NOT_FOUND"` and the id. |
| `400` | wrong-state | Cannot complete this plan while it is draft | The record is not in a state that allows this step; the message names the step and the current state. The body carries `reason: "wrong-state"`. | — |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /business-made/performance/goals/{id}/complete`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `id` | path | string | yes | Record id. |

### Request body

The progress update.

```json
{
  "percentComplete": 60,
  "note": "Three of five services migrated"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The updated goal |
| `400` | Cannot complete this plan while it is draft — The record is not in a state that allows this step; the message names the step and the current state. The body carries `reason: "wrong-state"`. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | Goal not found — No goal has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /business-made/performance/goals/{id}/complete

**Complete a goal**

`operationId: PerformanceController_completeGoal`

Marks a goal achieved, closing it for the review.

#### Signature

```http
POST /business-made/performance/goals/{id}/complete (id: string, body) -> The completed goal
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | GOAL_NOT_FOUND | Goal not found | No goal has that id. | The body carries `code: "GOAL_NOT_FOUND"` and the id. |
| `400` | wrong-state | Cannot complete this plan while it is draft | The record is not in a state that allows this step; the message names the step and the current state. The body carries `reason: "wrong-state"`. | — |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /business-made/performance/goals/{id}/cancel`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `id` | path | string | yes | Record id. |

### Request body

Optional closing note.

```json
{
  "note": "Completed two weeks early"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The completed goal |
| `400` | Cannot complete this plan while it is draft — The record is not in a state that allows this step; the message names the step and the current state. The body carries `reason: "wrong-state"`. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | Goal not found — No goal has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /business-made/performance/goals/{id}/cancel

**Cancel a goal**

`operationId: PerformanceController_cancelGoal`

Closes a goal that is no longer relevant — priorities changed, the project was cancelled. Keeping it with a reason is fairer at review time than deleting it.

#### Signature

```http
POST /business-made/performance/goals/{id}/cancel (id: string, body) -> The cancelled goal
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | GOAL_NOT_FOUND | Goal not found | No goal has that id. | The body carries `code: "GOAL_NOT_FOUND"` and the id. |
| `400` | wrong-state | Cannot complete this plan while it is draft | The record is not in a state that allows this step; the message names the step and the current state. The body carries `reason: "wrong-state"`. | — |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `DELETE /business-made/performance/goals/{id}`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `id` | path | string | yes | Record id. |

### Request body

Why it was cancelled.

```json
{
  "reason": "Project deprioritised in Q4 planning"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The cancelled goal |
| `400` | Cannot complete this plan while it is draft — The record is not in a state that allows this step; the message names the step and the current state. The body carries `reason: "wrong-state"`. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | Goal not found — No goal has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /business-made/performance/goals/employee/{employeeId}

**Get an employee's goals**

`operationId: PerformanceController_getEmployeeGoals`

One employee's goals and how far along each is.

#### Signature

```http
GET /business-made/performance/goals/employee/{employeeId} (employeeId: string) -> The employee's goals
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /business-made/performance/goals`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `employeeId` | path | string | yes | Employee id. |
| `status` | query | string | yes |  |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The employee's goals |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /business-made/performance/reviews

**List performance reviews**

`operationId: PerformanceController_getReviews`

Reviews across the org at any stage.

#### Signature

```http
GET /business-made/performance/reviews () -> Reviews
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Review content is sensitive — restrict to HR and the relevant management line.

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /business-made/performance/reviews/employee/{employeeId}`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Reviews |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /business-made/performance/reviews

**Create a performance review**

`operationId: PerformanceController_createReview`

Opens a review for an employee and period. It moves through self-assessment, manager review, completion and acknowledgement.

#### Signature

```http
POST /business-made/performance/reviews (body) -> The created review
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /business-made/performance/reviews/{id}/start-self-review`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

The review to create.

```json
{
  "employeeId": "EMP-4821",
  "period": "2026-H2",
  "reviewerId": "EMP-4001"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The created review |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /business-made/performance/reviews/{id}

**Get a performance review**

`operationId: PerformanceController_getReview`

Fetches one review with its self-assessment, manager assessment and outcome.

#### Signature

```http
GET /business-made/performance/reviews/{id} (id: string) -> The review
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `400` | INVALID_ID | invalid id <id> | The id is not a valid record id. A well-formed id that matches nothing returns an empty 200, not a 404. | — |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /business-made/performance/reviews/{id}/complete`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `id` | path | string | yes | Record id. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The review |
| `400` | invalid id <id> — The id is not a valid record id. A well-formed id that matches nothing returns an empty 200, not a 404. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## DELETE /business-made/performance/reviews/{id}

**Delete a performance review**

`operationId: PerformanceController_deleteReview`

Deletes a review and its assessments. A completed review is part of someone's employment record — deleting one removes evidence that may be needed later.

#### Signature

```http
DELETE /business-made/performance/reviews/{id} (id: string) -> Deletion result
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /business-made/performance/reviews/employee/{employeeId}`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `id` | path | string | yes | Record id. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Deletion result |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /business-made/performance/reviews/update

**Update a performance review**

`operationId: PerformanceController_updateReview`

Updates a review's own fields. The assessment steps have their own endpoints so authorship is recorded. **Replaces the stored record** — send the whole record as read (`sk` plus `data`), not just the changed fields.

#### Signature

```http
POST /business-made/performance/reviews/update (body) -> The updated review
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /business-made/performance/reviews/{id}/manager-review`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

The review to update.

```json
{
  "sk": "REV-4821",
  "data": {
    "reviewerId": "EMP-4002"
  }
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The updated review |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /business-made/performance/reviews/{id}/start-self-review

**Start the self-review**

`operationId: PerformanceController_startSelfReview`

Opens the self-assessment stage, inviting the employee to write their own account before the manager's.

#### Signature

```http
POST /business-made/performance/reviews/{id}/start-self-review (id: string) -> The updated review
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | REVIEW_NOT_FOUND | Review not found | No review has that id. | The body carries `code: "REVIEW_NOT_FOUND"` and the id. |
| `400` | wrong-state | Cannot complete this plan while it is draft | The record is not in a state that allows this step; the message names the step and the current state. The body carries `reason: "wrong-state"`. | — |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /business-made/performance/reviews/{id}/self-assessment`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `id` | path | string | yes | Record id. |

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The updated review |
| `400` | Cannot complete this plan while it is draft — The record is not in a state that allows this step; the message names the step and the current state. The body carries `reason: "wrong-state"`. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | Review not found — No review has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /business-made/performance/reviews/{id}/self-assessment

**Submit a self-assessment**

`operationId: PerformanceController_submitSelfAssessment`

Records the employee's own assessment. Captured separately from the manager's so both perspectives sit in the record.

#### Signature

```http
POST /business-made/performance/reviews/{id}/self-assessment (id: string, body) -> The updated review
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | REVIEW_NOT_FOUND | Review not found | No review has that id. | The body carries `code: "REVIEW_NOT_FOUND"` and the id. |
| `400` | wrong-state | Cannot complete this plan while it is draft | The record is not in a state that allows this step; the message names the step and the current state. The body carries `reason: "wrong-state"`. | — |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /business-made/performance/reviews/{id}/manager-review`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `id` | path | string | yes | Record id. |

### Request body

The self-assessment.

```json
{
  "summary": "Delivered the migration; want more scope on architecture",
  "ratings": {
    "delivery": 4,
    "collaboration": 5
  }
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The updated review |
| `400` | Cannot complete this plan while it is draft — The record is not in a state that allows this step; the message names the step and the current state. The body carries `reason: "wrong-state"`. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | Review not found — No review has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /business-made/performance/reviews/{id}/manager-review

**Submit a manager review**

`operationId: PerformanceController_submitManagerReview`

Records the manager's assessment. Kept distinct from the self-assessment so a disagreement between the two remains visible.

#### Signature

```http
POST /business-made/performance/reviews/{id}/manager-review (id: string, body) -> The updated review
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | REVIEW_NOT_FOUND | Review not found | No review has that id. | The body carries `code: "REVIEW_NOT_FOUND"` and the id. |
| `400` | wrong-state | Cannot complete this plan while it is draft | The record is not in a state that allows this step; the message names the step and the current state. The body carries `reason: "wrong-state"`. | — |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /business-made/performance/reviews/{id}/complete`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `id` | path | string | yes | Record id. |

### Request body

The manager's assessment.

```json
{
  "summary": "Strong delivery, ready for more architectural ownership",
  "ratings": {
    "delivery": 4,
    "collaboration": 4
  }
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The updated review |
| `400` | Cannot complete this plan while it is draft — The record is not in a state that allows this step; the message names the step and the current state. The body carries `reason: "wrong-state"`. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | Review not found — No review has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /business-made/performance/reviews/{id}/complete

**Complete a review**

`operationId: PerformanceController_completeReview`

Finalises the review. It still needs the employee's acknowledgement — completion is the manager finishing, not the employee having seen it.

#### Signature

```http
POST /business-made/performance/reviews/{id}/complete (id: string) -> The completed review
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | REVIEW_NOT_FOUND | Review not found | No review has that id. | The body carries `code: "REVIEW_NOT_FOUND"` and the id. |
| `400` | wrong-state | Cannot complete this plan while it is draft | The record is not in a state that allows this step; the message names the step and the current state. The body carries `reason: "wrong-state"`. | — |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /business-made/performance/reviews/{id}/acknowledge`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `id` | path | string | yes | Record id. |

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The completed review |
| `400` | Cannot complete this plan while it is draft — The record is not in a state that allows this step; the message names the step and the current state. The body carries `reason: "wrong-state"`. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | Review not found — No review has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /business-made/performance/reviews/{id}/acknowledge

**Acknowledge a review**

`operationId: PerformanceController_acknowledgeReview`

Records that the employee has seen the completed review.

Acknowledgement means *seen*, not *agreed*. It is the step that matters if a review is ever relied on in a formal process, because it evidences the employee was shown it.

#### Signature

```http
POST /business-made/performance/reviews/{id}/acknowledge (id: string, body) -> The acknowledged review
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | REVIEW_NOT_FOUND | Review not found | No review has that id. | The body carries `code: "REVIEW_NOT_FOUND"` and the id. |
| `400` | wrong-state | Cannot complete this plan while it is draft | The record is not in a state that allows this step; the message names the step and the current state. The body carries `reason: "wrong-state"`. | — |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /business-made/performance/pips`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `id` | path | string | yes | Record id. |

### Request body

Optional employee comment.

```json
{
  "comment": "Agree on delivery; would like the architecture scope defined concretely"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The acknowledged review |
| `400` | Cannot complete this plan while it is draft — The record is not in a state that allows this step; the message names the step and the current state. The body carries `reason: "wrong-state"`. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | Review not found — No review has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /business-made/performance/reviews/employee/{employeeId}

**Get an employee's reviews**

`operationId: PerformanceController_getEmployeeReviews`

One employee's review history.

#### Signature

```http
GET /business-made/performance/reviews/employee/{employeeId} (employeeId: string) -> The employee's reviews
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /business-made/performance/reviews`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `employeeId` | path | string | yes | Employee id. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The employee's reviews |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /business-made/performance/pips

**List performance improvement plans**

`operationId: PerformanceController_getPIPs`

PIPs across the org. Among the most sensitive records the platform holds — restrict access tightly.

#### Signature

```http
GET /business-made/performance/pips () -> PIPs
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- A PIP is often a precursor to dismissal. Access should be narrow and auditable.

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /business-made/performance/pips/{id}`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | PIPs |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /business-made/performance/pips

**Create a PIP**

`operationId: PerformanceController_createPIP`

Creates a performance improvement plan as a draft.

A PIP is frequently the documented basis for a later dismissal, so the objectives should be specific and measurable and the review dates real. Vague objectives make the plan indefensible.

#### Signature

```http
POST /business-made/performance/pips (body) -> The created PIP
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Specific, measurable objectives with real review dates — this record may be scrutinised.

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /business-made/performance/pips/{id}/activate`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

The plan to create.

```json
{
  "employeeId": "EMP-4821",
  "startDate": "2026-10-01",
  "endDate": "2026-12-31",
  "objectives": [
    {
      "objective": "Close assigned tickets within SLA",
      "measure": "90% within SLA over the period"
    }
  ]
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The created PIP |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /business-made/performance/pips/{id}

**Get a PIP**

`operationId: PerformanceController_getPIP`

Fetches one improvement plan with its objectives and check-in history.

#### Signature

```http
GET /business-made/performance/pips/{id} (id: string) -> The PIP
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `400` | INVALID_ID | invalid id <id> | The id is not a valid record id. A well-formed id that matches nothing returns an empty 200, not a 404. | — |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /business-made/performance/pips/{id}/check-in`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `id` | path | string | yes | Record id. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The PIP |
| `400` | invalid id <id> — The id is not a valid record id. A well-formed id that matches nothing returns an empty 200, not a 404. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## DELETE /business-made/performance/pips/{id}

**Delete a PIP**

`operationId: PerformanceController_deletePIP`

Deletes an improvement plan. If it was ever active, deleting it destroys the record of a formal process — complete it instead.

#### Signature

```http
DELETE /business-made/performance/pips/{id} (id: string) -> Deletion result
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /business-made/performance/pips/{id}/complete`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `id` | path | string | yes | Record id. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Deletion result |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /business-made/performance/pips/update

**Update a PIP**

`operationId: PerformanceController_updatePIP`

Updates a plan. Changing objectives after it has started should be recorded and explained — moving the bar mid-plan undermines it. **Replaces the stored record** — send the whole record as read (`sk` plus `data`), not just the changed fields.

#### Signature

```http
POST /business-made/performance/pips/update (body) -> The updated PIP
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /business-made/performance/pips/{id}/extend`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

The plan to update.

```json
{
  "sk": "PIP-4821",
  "data": {
    "endDate": "2027-01-31"
  }
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The updated PIP |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /business-made/performance/pips/{id}/activate

**Activate a PIP**

`operationId: PerformanceController_activatePIP`

Starts the improvement plan. The employee should be told at this point — an active PIP they do not know about serves no purpose and helps nobody.

#### Signature

```http
POST /business-made/performance/pips/{id}/activate (id: string) -> The activated PIP
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | PIP_NOT_FOUND | PIP not found | No PIP has that id. | The body carries `code: "PIP_NOT_FOUND"` and the id. |
| `400` | wrong-state | Cannot complete this plan while it is draft | The record is not in a state that allows this step; the message names the step and the current state. The body carries `reason: "wrong-state"`. | — |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /business-made/performance/pips/{id}/check-in`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `id` | path | string | yes | Record id. |

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The activated PIP |
| `400` | Cannot complete this plan while it is draft — The record is not in a state that allows this step; the message names the step and the current state. The body carries `reason: "wrong-state"`. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | PIP not found — No PIP has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /business-made/performance/pips/{id}/check-in

**Record a PIP check-in**

`operationId: PerformanceController_addPIPCheckIn`

Records a review meeting during the plan — progress against each objective and what was discussed. Regular check-ins are what make the process fair and the outcome defensible.

#### Signature

```http
POST /business-made/performance/pips/{id}/check-in (id: string, body) -> The updated PIP
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | PIP_NOT_FOUND | PIP not found | No PIP has that id. | The body carries `code: "PIP_NOT_FOUND"` and the id. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /business-made/performance/pips/{id}/complete`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `id` | path | string | yes | Record id. |

### Request body

The check-in.

```json
{
  "date": "2026-11-01",
  "progress": "SLA compliance improved to 82%",
  "notes": "On track; discussed ticket triage approach"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The updated PIP |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | PIP not found — No PIP has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /business-made/performance/pips/{id}/complete

**Complete a PIP**

`operationId: PerformanceController_completePIP`

Closes an active or extended plan (status becomes `completed-successful` or `completed-unsuccessful`) with its `result` and a `summary`, plus an optional `nextAction`. This is the conclusion any subsequent decision rests on, so state it plainly.

#### Signature

```http
POST /business-made/performance/pips/{id}/complete (id: string, body) -> The completed PIP
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | PIP_NOT_FOUND | PIP not found | No PIP has that id. | The body carries `code: "PIP_NOT_FOUND"` and the id. |
| `400` | wrong-state | Cannot complete this plan while it is draft | The record is not in a state that allows this step; the message names the step and the current state. The body carries `reason: "wrong-state"`. | — |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /business-made/employees/{id}/terminate`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `id` | path | string | yes | Record id. |

### Request body

The outcome.

```json
{
  "result": "successful",
  "summary": "Sustained SLA compliance above 90% for the final six weeks"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The completed PIP |
| `400` | Cannot complete this plan while it is draft — The record is not in a state that allows this step; the message names the step and the current state. The body carries `reason: "wrong-state"`. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | PIP not found — No PIP has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /business-made/performance/pips/{id}/extend

**Extend a PIP**

`operationId: PerformanceController_extendPIP`

Extends the plan period. Record why — an extension is either a genuine second chance or a delayed decision, and the record should show which.

#### Signature

```http
POST /business-made/performance/pips/{id}/extend (id: string, body) -> The extended PIP
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | PIP_NOT_FOUND | PIP not found | No PIP has that id. | The body carries `code: "PIP_NOT_FOUND"` and the id. |
| `400` | wrong-state | Cannot complete this plan while it is draft | The record is not in a state that allows this step; the message names the step and the current state. The body carries `reason: "wrong-state"`. | — |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /business-made/performance/pips/{id}/complete`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `id` | path | string | yes | Record id. |

### Request body

The extension.

```json
{
  "newEndDate": "2027-01-31",
  "reason": "Objectives partially met; agreed further period"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The extended PIP |
| `400` | Cannot complete this plan while it is draft — The record is not in a state that allows this step; the message names the step and the current state. The body carries `reason: "wrong-state"`. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | PIP not found — No PIP has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /business-made/performance/pips/{id}/cancel

**Cancel a PIP**

`operationId: PerformanceController_cancelPIP`

Cancels a draft, active or extended plan, recording the optional reason, who and when (`cancellation`).

#### Signature

```http
POST /business-made/performance/pips/{id}/cancel (id: string, body) -> The cancelled PIP
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | PIP_NOT_FOUND | PIP not found | No PIP has that id. | The body carries `code: "PIP_NOT_FOUND"` and the id. |
| `400` | wrong-state | Cannot complete this plan while it is draft | The record is not in a state that allows this step; the message names the step and the current state. The body carries `reason: "wrong-state"`. | — |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /business-made/performance/pips/{id}/complete`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `id` | path | string | yes | Record id. |

### Request body

```json
{
  "reason": "Employee moved to a different role"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The cancelled PIP |
| `400` | Cannot complete this plan while it is draft — The record is not in a state that allows this step; the message names the step and the current state. The body carries `reason: "wrong-state"`. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | PIP not found — No PIP has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /business-made/performance/metrics

**Get performance metrics**

`operationId: PerformanceController_getPerformanceMetrics`

Aggregate performance figures — goal completion, review coverage and rating distribution.

#### Signature

```http
GET /business-made/performance/metrics () -> Performance metrics
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /business-made/performance/reviews`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Performance metrics |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

