Reinstate a suspended app
The platform.apps.reinstate operation: POST /api/v1/platform/apps/{id}/reinstate in the REST API and the platform_apps_reinstate tool in the MCP server.
/api/v1/platform/apps/{id}/reinstatePlatform admins: lifts the platform's suspension of an app (platform.apps.suspend), with a reason. The app
can get tokens, be authorized and be installed again.
It doesn't resume any installation: each one stays paused until its organization resumes it
(app_installations.resume, their decision), after which the app asks for authorization again. The
organization that registered the app and every organization with it installed get an app.reinstated event, and
their owners and admins an email saying so, with the reason. Reinstating an app that isn't suspended changes
nothing.
Security tier; needs a sign-in within the last 15 minutes.
At a glance
- REST:
POST /api/v1/platform/apps/{id}/reinstate - MCP tool:
platform_apps_reinstate - Operation ID:
platform.apps.reinstate - Scope: Platform
- Permission:
platform:admin - Risk tier:
security - Dry run: Supported (send
Ownrecord-Dry-Run: true) - Idempotency:
Idempotency-Keyrequired - Modes: Test and live
- Authentication: API key with the
platform:adminscope - Fresh sign-in: In the console, a sign-in within the last 15 minutes
- Since: M13
Request
Path parameters
| Field | Type | Description |
|---|---|---|
id | ocl_… ID |
Body
A JSON object (Content-Type: application/json):
| Field | Type | Required | Description |
|---|---|---|---|
reason | string | Yes | Why the suspension ends. The app's organization and every organization that installed it read it. |
Response
200 OK with a JSON object:
| Field | Type | Description |
|---|---|---|
id | ocl_… ID | |
object | "platform_app" | |
name | string | |
publisher | string | |
org | object | |
org.id | org_… ID | |
org.slug | string | |
org.name | string | |
visibility | one of private, listed | |
listed | boolean | |
reviewStatus | one of not_submitted, pending, changes_requested, approved, rejected | |
status | one of active, disabled | |
suspension | object or null | |
createdAt | date-time | |
updatedAt | date-time | |
logoUrl | string or null | |
websiteUrl | string or null | |
installations | object | |
installations.organizations | integer | |
installations.active | integer | |
installations.paused | integer | |
installations.pausedBySuspension | integer | |
installations.revoked | integer | |
history | array of object | |
history[].action | one of suspended, reinstated | |
history[].at | date-time | |
history[].by | usr_… ID | |
history[].reason | string | |
history[].organizations | integer | |
history[].installationsPaused | integer or null | |
version | integer |
Examples
Reinstate once the partner fixed it
POST /api/v1/platform/apps/ocl_01m4ttwd3veh9apbewxheq5xha/reinstate
Authorization: Bearer or_test_…
Idempotency-Key: 3f1c9a52-7d0e-4b8f-9a61-0c2d5e8b7f14
Content-Type: application/json
{
"reason": "The partner rotated its secret and confirmed the leak is closed."
}
Response (200):
{
"id": "ocl_01m4ttwd3veh9apbewxheq5xha",
"object": "platform_app",
"name": "Ledgerly AI",
"publisher": "Ledgerly AI B.V.",
"org": {
"id": "org_01m4ttwd3veh9apbewxheq5xhb",
"slug": "ledgerly",
"name": "Ledgerly"
},
"visibility": "listed",
"listed": true,
"reviewStatus": "approved",
"status": "active",
"suspension": {
"status": "reinstated",
"reason": "Its client secret was published in a public repository; tokens were used from unknown networks.",
"suspendedAt": "2026-11-01T08:30:00.000Z",
"reinstatedAt": "2026-11-03T16:00:00.000Z",
"reinstateReason": "The partner rotated its secret and confirmed the leak is closed.",
"suspendedBy": "usr_01m4ttwd3veh9apbewxheq5xhg",
"reinstatedBy": "usr_01m4ttwd3veh9apbewxheq5xhg"
},
"createdAt": "2026-10-25T09:00:00.000Z",
"updatedAt": "2026-11-03T16:00:00.000Z",
"logoUrl": null,
"websiteUrl": "https://ledgerly.example",
"installations": {
"organizations": 12,
"active": 0,
"paused": 12,
"pausedBySuspension": 12,
"revoked": 2
},
"history": [
{
"action": "suspended",
"at": "2026-11-01T08:30:00.000Z",
"by": "usr_01m4ttwd3veh9apbewxheq5xhg",
"reason": "Its client secret was published in a public repository; tokens were used from unknown networks.",
"organizations": 12,
"installationsPaused": 12
},
{
"action": "reinstated",
"at": "2026-11-03T16:00:00.000Z",
"by": "usr_01m4ttwd3veh9apbewxheq5xhg",
"reason": "The partner rotated its secret and confirmed the leak is closed.",
"organizations": 12,
"installationsPaused": null
}
],
"version": 6
}
Errors
| Code | HTTP status | When | What to do |
|---|---|---|---|
fresh_auth_required | 403 | Your last sign-in is older than 15 minutes: sign in again first. | Sign in again, then repeat the action within 15 minutes. |
validation_failed | 400 | No reason, or one longer than 2,000 characters. | Fix the fields listed in details.issues and send the request again. |
resource_not_found | 404 | No registered app has this ID. | Check the ID and that your credentials are scoped to the right organization, entity, brand and mode. |
version_conflict | 409 | The app changed at the same moment; retry. | Fetch the object again and retry the change. |
permission_denied | 403 | You aren't a platform admin. | Ask an organization owner or admin for a role or scope that allows this action. |
It can also return these common errors: api_version_unsupported, invalid_json, unsupported_media_type, authentication_required, api_key_invalid, idempotency_key_required, idempotency_key_reused, idempotency_in_progress, rate_limited, internal_error.