# Repository · Workflow

Part of AppEngine API Documentation. Full index: https://appengine.appmint.io/documentation.md
## GET /repository/request-approval/{datatype}/{id}

**Request approval for a record**

`operationId: RepositoryController_requestApproval`

Submits a record into its approval workflow.

Note this is mounted on `GET` despite changing state, so it can be triggered by anything that follows a link. Do not expose the URL where it may be prefetched.

#### Signature

```http
GET /repository/request-approval/{datatype}/{id} (datatype: string, id: string) -> The approval request result
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`). Required role(s): `content:read`.

#### Notes

- A state change on `GET` — and it needs only `read` permission, not `approve`.

#### Errors

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

#### See also

- `POST /repository/approve/{datatype}/{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. |
| `datatype` | path | string | yes | The collection to act on, e.g. `sf_product`, `customer`, `category`. Determines the shape of `data`. |
| `id` | path | string | yes | Record `sk`. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The approval request 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 /repository/approve/{datatype}/{id}

**Approve a record**

`operationId: RepositoryController_approve`

Approves a record that is awaiting review, advancing it through its workflow. Requires the `approve` permission, which is separate from `update`.

#### Signature

```http
POST /repository/approve/{datatype}/{id} (datatype: string, id: string, body) -> The approved record
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`). Required role(s): `content:approve`.

#### Errors

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

#### See also

- `POST /repository/reject/{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. |
| `datatype` | path | string | yes | The collection to act on, e.g. `sf_product`, `customer`, `category`. Determines the shape of `data`. |
| `id` | path | string | yes | Record `sk`. |

### Request body

Optional approval notes.

```json
{
  "notes": "Checked against the brand guidelines"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The approved record |
| `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 /repository/reject/{id}

**Reject a record**

`operationId: RepositoryController_reject`

Rejects a record awaiting approval.

**Known defect:** the handler reads a `datatype` path parameter, but the route declares only `{id}` — so `datatype` is always `undefined` here. The other workflow endpoints take `{datatype}/{id}`; this one does not, and behaves differently as a result. Verify the outcome rather than assuming symmetry with `approve`.

#### Signature

```http
POST /repository/reject/{id} (id: string, body) -> The rejection result
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`). Required role(s): `content:approve`.

#### Notes

- Asymmetric with `approve`, which takes a datatype. The missing parameter is a defect, not a design choice.

#### Errors

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

#### See also

- `POST /repository/approve/{datatype}/{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. |
| `datatype` | path | string | yes |  |
| `id` | path | string | yes | Record `sk`. |

### Request body

Optional rejection notes.

```json
{
  "notes": "Copy does not match the approved messaging"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The rejection 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 /repository/publish/{datatype}/{id}

**Publish a record**

`operationId: RepositoryController_publish`

Makes a record publicly visible. Requires `create` permission rather than a dedicated publish right.

#### Signature

```http
POST /repository/publish/{datatype}/{id} (datatype: string, id: string) -> The published record
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`). Required role(s): `content:create`.

#### Errors

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

#### See also

- `POST /repository/unpublish/{datatype}/{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. |
| `datatype` | path | string | yes | The collection to act on, e.g. `sf_product`, `customer`, `category`. Determines the shape of `data`. |
| `id` | path | string | yes | Record `sk`. |

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The published record |
| `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 /repository/unpublish/{datatype}/{id}

**Unpublish a record**

`operationId: RepositoryController_unpublish`

Withdraws a record from public visibility without deleting it. Requires `delete` permission — a heavier right than publishing needs, so an account able to publish may be unable to reverse it.

#### Signature

```http
POST /repository/unpublish/{datatype}/{id} (datatype: string, id: string) -> The unpublished record
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`). Required role(s): `content:delete`.

#### Notes

- Publishing needs `create`; unpublishing needs `delete`. The asymmetry is deliberate but surprising.

#### Errors

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

#### See also

- `POST /repository/publish/{datatype}/{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. |
| `datatype` | path | string | yes | The collection to act on, e.g. `sf_product`, `customer`, `category`. Determines the shape of `data`. |
| `id` | path | string | yes | Record `sk`. |

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The unpublished record |
| `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. |

