# Project lifecycle 6 management API operations. - [GET /v1/projects/{project_id}/lifecycle](/docs/api/operations/read_v1_projects__project_id__lifecycle_get): Read project lifecycle and issuer removal state - [POST /v1/projects/{project_id}/lifecycle/suspend](/docs/api/operations/suspend_route_v1_projects__project_id__lifecycle_suspend_post): Suspend a project - [POST /v1/projects/{project_id}/lifecycle/resume](/docs/api/operations/resume_route_v1_projects__project_id__lifecycle_resume_post): Resume a suspended project - [POST /v1/projects/{project_id}/lifecycle/decommission](/docs/api/operations/decommission_request_v1_projects__project_id__lifecycle_decommission_post): Request irreversible decommission - [POST /v1/projects/{project_id}/lifecycle/decommission/{action_id}/approve](/docs/api/operations/decommission_approve_v1_projects__project_id__lifecycle_decommission__action_id__approve_post): Approve irreversible decommission - [POST /v1/projects/{project_id}/lifecycle/decommission/{action_id}/cancel](/docs/api/operations/decommission_cancel_v1_projects__project_id__lifecycle_decommission__action_id__cancel_post): Cancel a pending decommission request ## GET /v1/projects/{project_id}/lifecycle Read project lifecycle and issuer removal state Scoped to a current owner or project approver. Revocation state is Management ledger state plus authenticated Go receipts. local_sessions is always unobserved. Authentication: bearer access token with audience `taifa-management`. Endpoint roles and eligibility are reviewed separately from the OpenAPI bearer scheme. No operation-specific scopes are declared in the OpenAPI document. Bearer authentication and endpoint authorization requirements still apply. ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `project_id` | path | string | Yes | | ### Request body This operation has no request body. ### Responses #### 200 Successful Response | Field | Variant | Type | Required | Description | | --- | --- | --- | --- | --- | | `project_id` | | string | Yes | | | `name` | | string | Yes | | | `status` | | string | Yes | | | `downstream` | | DownstreamRead | Yes | | | `actions` | | ActionRead[] | Yes | | | `revocations` | | RevocationDetail[] | Yes | | | `allowed` | | (suspend \| resume \| decommission-request \| decommission-approve \| decommission-cancel)[] | Yes | | #### 403 Current scoped authority, independent review or recent strong authentication required No fields declared in the current specification. #### 409 Current project state, target set or idempotency conflict No fields declared in the current specification. #### 422 Invalid exact request No fields declared in the current specification. ### Request examples Illustrative only. Replace placeholders and keep management tokens on the server. #### cURL ```sh curl -X GET 'https://YOUR_IDENTITY_HOST/v1/projects/REPLACE_WITH_PROJECT_ID/lifecycle' \ -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' ``` #### TypeScript (Node.js/server-side) ```typescript const response = await fetch('https://YOUR_IDENTITY_HOST/v1/projects/REPLACE_WITH_PROJECT_ID/lifecycle', { method: 'GET', headers: { Authorization: `Bearer ${process.env.TAIFA_MANAGEMENT_TOKEN}` } }); const result = await response.json(); ``` #### Python ```python import os import requests response = requests.request( 'GET', 'https://YOUR_IDENTITY_HOST/v1/projects/REPLACE_WITH_PROJECT_ID/lifecycle', headers={'Authorization': 'Bearer ' + os.environ['TAIFA_MANAGEMENT_TOKEN']} ) response.raise_for_status() ``` ### Response example No response example in the current specification. [Request and response examples](/docs/api/operations/read_v1_projects__project_id__lifecycle_get) ## POST /v1/projects/{project_id}/lifecycle/suspend Suspend a project Reversible. Blocks new authority, revokes workforce access through the ordered lifecycle feed and leaves issuer clients installed. Resume does not restore access. Authentication: bearer access token with audience `taifa-management`. Endpoint roles and eligibility are reviewed separately from the OpenAPI bearer scheme. No operation-specific scopes are declared in the OpenAPI document. Bearer authentication and endpoint authorization requirements still apply. ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `project_id` | path | string | Yes | | | `idempotency-key` | header | string | Yes | | ### Request body #### application/json Required; identity__owned_client_router__Reason | Field | Variant | Type | Required | Description | | --- | --- | --- | --- | --- | | `reason` | | string | Yes | Validation: min length 8; max length 500 | ### Responses #### 200 Successful Response | Field | Variant | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | | string | Yes | | | `project_id` | | string | Yes | | | `kind` | | suspend \| resume \| decommission | Yes | | | `status` | | requested \| effective \| cancelled | Yes | | | `requested_by` | | string | Yes | | | `decided_by` | | string \| null | Yes | | | `reason` | | string | Yes | | | `created_at` | | string | Yes | | | `expires_at` | | string \| null | Yes | | | `effective_at` | | string \| null | Yes | | | `completed_at` | | string \| null | Yes | | | `project_status` | | string | Yes | | | `access_revoked` | | integer | Yes | | | `lifecycle_head` | | integer | Yes | | | `revocations` | | RevocationRead[] | Yes | | #### 403 Current scoped authority, independent review or recent strong authentication required No fields declared in the current specification. #### 409 Current project state, target set or idempotency conflict No fields declared in the current specification. #### 422 Invalid exact request No fields declared in the current specification. ### Request examples Illustrative only. Replace placeholders and keep management tokens on the server. #### cURL ```sh curl -X POST 'https://YOUR_IDENTITY_HOST/v1/projects/REPLACE_WITH_PROJECT_ID/lifecycle/suspend' \ -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \ -H 'idempotency-key: REPLACE_WITH_IDEMPOTENCY_KEY' \ -H 'Content-Type: application/json' \ --data '{ "reason": "REPLACE_WITH_REASON" }' ``` #### TypeScript (Node.js/server-side) ```typescript const response = await fetch('https://YOUR_IDENTITY_HOST/v1/projects/REPLACE_WITH_PROJECT_ID/lifecycle/suspend', { method: 'POST', headers: { Authorization: `Bearer ${process.env.TAIFA_MANAGEMENT_TOKEN}`, 'idempotency-key': 'REPLACE_WITH_IDEMPOTENCY_KEY', 'Content-Type': 'application/json' }, body: JSON.stringify({ "reason": "REPLACE_WITH_REASON" }) }); const result = await response.json(); ``` #### Python ```python import os import json import requests response = requests.request( 'POST', 'https://YOUR_IDENTITY_HOST/v1/projects/REPLACE_WITH_PROJECT_ID/lifecycle/suspend', headers={'Authorization': 'Bearer ' + os.environ['TAIFA_MANAGEMENT_TOKEN'], 'idempotency-key': 'REPLACE_WITH_IDEMPOTENCY_KEY'}, json=json.loads('{"reason":"REPLACE_WITH_REASON"}') ) response.raise_for_status() ``` ### Response example No response example in the current specification. [Request and response examples](/docs/api/operations/suspend_route_v1_projects__project_id__lifecycle_suspend_post) ## POST /v1/projects/{project_id}/lifecycle/resume Resume a suspended project Requires a current project approver other than the suspender. Workforce access must be granted again through the normal reviewed workflow. Authentication: bearer access token with audience `taifa-management`. Endpoint roles and eligibility are reviewed separately from the OpenAPI bearer scheme. No operation-specific scopes are declared in the OpenAPI document. Bearer authentication and endpoint authorization requirements still apply. ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `project_id` | path | string | Yes | | | `idempotency-key` | header | string | Yes | | ### Request body #### application/json Required; identity__owned_client_router__Reason | Field | Variant | Type | Required | Description | | --- | --- | --- | --- | --- | | `reason` | | string | Yes | Validation: min length 8; max length 500 | ### Responses #### 200 Successful Response | Field | Variant | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | | string | Yes | | | `project_id` | | string | Yes | | | `kind` | | suspend \| resume \| decommission | Yes | | | `status` | | requested \| effective \| cancelled | Yes | | | `requested_by` | | string | Yes | | | `decided_by` | | string \| null | Yes | | | `reason` | | string | Yes | | | `created_at` | | string | Yes | | | `expires_at` | | string \| null | Yes | | | `effective_at` | | string \| null | Yes | | | `completed_at` | | string \| null | Yes | | | `project_status` | | string | Yes | | | `access_revoked` | | integer | Yes | | | `lifecycle_head` | | integer | Yes | | | `revocations` | | RevocationRead[] | Yes | | #### 403 Current scoped authority, independent review or recent strong authentication required No fields declared in the current specification. #### 409 Current project state, target set or idempotency conflict No fields declared in the current specification. #### 422 Invalid exact request No fields declared in the current specification. ### Request examples Illustrative only. Replace placeholders and keep management tokens on the server. #### cURL ```sh curl -X POST 'https://YOUR_IDENTITY_HOST/v1/projects/REPLACE_WITH_PROJECT_ID/lifecycle/resume' \ -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \ -H 'idempotency-key: REPLACE_WITH_IDEMPOTENCY_KEY' \ -H 'Content-Type: application/json' \ --data '{ "reason": "REPLACE_WITH_REASON" }' ``` #### TypeScript (Node.js/server-side) ```typescript const response = await fetch('https://YOUR_IDENTITY_HOST/v1/projects/REPLACE_WITH_PROJECT_ID/lifecycle/resume', { method: 'POST', headers: { Authorization: `Bearer ${process.env.TAIFA_MANAGEMENT_TOKEN}`, 'idempotency-key': 'REPLACE_WITH_IDEMPOTENCY_KEY', 'Content-Type': 'application/json' }, body: JSON.stringify({ "reason": "REPLACE_WITH_REASON" }) }); const result = await response.json(); ``` #### Python ```python import os import json import requests response = requests.request( 'POST', 'https://YOUR_IDENTITY_HOST/v1/projects/REPLACE_WITH_PROJECT_ID/lifecycle/resume', headers={'Authorization': 'Bearer ' + os.environ['TAIFA_MANAGEMENT_TOKEN'], 'idempotency-key': 'REPLACE_WITH_IDEMPOTENCY_KEY'}, json=json.loads('{"reason":"REPLACE_WITH_REASON"}') ) response.raise_for_status() ``` ### Response example No response example in the current specification. [Request and response examples](/docs/api/operations/resume_route_v1_projects__project_id__lifecycle_resume_post) ## POST /v1/projects/{project_id}/lifecycle/decommission Request irreversible decommission Records a request that expires after 72 hours. It changes no project authority until an independent approver approves it. Authentication: bearer access token with audience `taifa-management`. Endpoint roles and eligibility are reviewed separately from the OpenAPI bearer scheme. No operation-specific scopes are declared in the OpenAPI document. Bearer authentication and endpoint authorization requirements still apply. ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `project_id` | path | string | Yes | | | `idempotency-key` | header | string | Yes | | ### Request body #### application/json Required; identity__owned_client_router__Reason | Field | Variant | Type | Required | Description | | --- | --- | --- | --- | --- | | `reason` | | string | Yes | Validation: min length 8; max length 500 | ### Responses #### 201 Successful Response | Field | Variant | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | | string | Yes | | | `project_id` | | string | Yes | | | `kind` | | suspend \| resume \| decommission | Yes | | | `status` | | requested \| effective \| cancelled | Yes | | | `requested_by` | | string | Yes | | | `decided_by` | | string \| null | Yes | | | `reason` | | string | Yes | | | `created_at` | | string | Yes | | | `expires_at` | | string \| null | Yes | | | `effective_at` | | string \| null | Yes | | | `completed_at` | | string \| null | Yes | | | `project_status` | | string | Yes | | | `access_revoked` | | integer | Yes | | | `lifecycle_head` | | integer | Yes | | | `revocations` | | RevocationRead[] | Yes | | #### 403 Current scoped authority, independent review or recent strong authentication required No fields declared in the current specification. #### 409 Current project state, target set or idempotency conflict No fields declared in the current specification. #### 422 Invalid exact request No fields declared in the current specification. ### Request examples Illustrative only. Replace placeholders and keep management tokens on the server. #### cURL ```sh curl -X POST 'https://YOUR_IDENTITY_HOST/v1/projects/REPLACE_WITH_PROJECT_ID/lifecycle/decommission' \ -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \ -H 'idempotency-key: REPLACE_WITH_IDEMPOTENCY_KEY' \ -H 'Content-Type: application/json' \ --data '{ "reason": "REPLACE_WITH_REASON" }' ``` #### TypeScript (Node.js/server-side) ```typescript const response = await fetch('https://YOUR_IDENTITY_HOST/v1/projects/REPLACE_WITH_PROJECT_ID/lifecycle/decommission', { method: 'POST', headers: { Authorization: `Bearer ${process.env.TAIFA_MANAGEMENT_TOKEN}`, 'idempotency-key': 'REPLACE_WITH_IDEMPOTENCY_KEY', 'Content-Type': 'application/json' }, body: JSON.stringify({ "reason": "REPLACE_WITH_REASON" }) }); const result = await response.json(); ``` #### Python ```python import os import json import requests response = requests.request( 'POST', 'https://YOUR_IDENTITY_HOST/v1/projects/REPLACE_WITH_PROJECT_ID/lifecycle/decommission', headers={'Authorization': 'Bearer ' + os.environ['TAIFA_MANAGEMENT_TOKEN'], 'idempotency-key': 'REPLACE_WITH_IDEMPOTENCY_KEY'}, json=json.loads('{"reason":"REPLACE_WITH_REASON"}') ) response.raise_for_status() ``` ### Response example No response example in the current specification. [Request and response examples](/docs/api/operations/decommission_request_v1_projects__project_id__lifecycle_decommission_post) ## POST /v1/projects/{project_id}/lifecycle/decommission/{action_id}/approve Approve irreversible decommission Requires an independent current project approver. Queues exact issuer revoke commands. The project becomes decommissioned only after every removal is acknowledged or was never installed. Authentication: bearer access token with audience `taifa-management`. Endpoint roles and eligibility are reviewed separately from the OpenAPI bearer scheme. No operation-specific scopes are declared in the OpenAPI document. Bearer authentication and endpoint authorization requirements still apply. ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `project_id` | path | string | Yes | | | `action_id` | path | string | Yes | | | `idempotency-key` | header | string | Yes | | ### Request body #### application/json Required; identity__owned_client_router__Reason | Field | Variant | Type | Required | Description | | --- | --- | --- | --- | --- | | `reason` | | string | Yes | Validation: min length 8; max length 500 | ### Responses #### 200 Successful Response | Field | Variant | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | | string | Yes | | | `project_id` | | string | Yes | | | `kind` | | suspend \| resume \| decommission | Yes | | | `status` | | requested \| effective \| cancelled | Yes | | | `requested_by` | | string | Yes | | | `decided_by` | | string \| null | Yes | | | `reason` | | string | Yes | | | `created_at` | | string | Yes | | | `expires_at` | | string \| null | Yes | | | `effective_at` | | string \| null | Yes | | | `completed_at` | | string \| null | Yes | | | `project_status` | | string | Yes | | | `access_revoked` | | integer | Yes | | | `lifecycle_head` | | integer | Yes | | | `revocations` | | RevocationRead[] | Yes | | #### 403 Current scoped authority, independent review or recent strong authentication required No fields declared in the current specification. #### 409 Current project state, target set or idempotency conflict No fields declared in the current specification. #### 422 Invalid exact request No fields declared in the current specification. ### Request examples Illustrative only. Replace placeholders and keep management tokens on the server. #### cURL ```sh curl -X POST 'https://YOUR_IDENTITY_HOST/v1/projects/REPLACE_WITH_PROJECT_ID/lifecycle/decommission/REPLACE_WITH_ACTION_ID/approve' \ -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \ -H 'idempotency-key: REPLACE_WITH_IDEMPOTENCY_KEY' \ -H 'Content-Type: application/json' \ --data '{ "reason": "REPLACE_WITH_REASON" }' ``` #### TypeScript (Node.js/server-side) ```typescript const response = await fetch('https://YOUR_IDENTITY_HOST/v1/projects/REPLACE_WITH_PROJECT_ID/lifecycle/decommission/REPLACE_WITH_ACTION_ID/approve', { method: 'POST', headers: { Authorization: `Bearer ${process.env.TAIFA_MANAGEMENT_TOKEN}`, 'idempotency-key': 'REPLACE_WITH_IDEMPOTENCY_KEY', 'Content-Type': 'application/json' }, body: JSON.stringify({ "reason": "REPLACE_WITH_REASON" }) }); const result = await response.json(); ``` #### Python ```python import os import json import requests response = requests.request( 'POST', 'https://YOUR_IDENTITY_HOST/v1/projects/REPLACE_WITH_PROJECT_ID/lifecycle/decommission/REPLACE_WITH_ACTION_ID/approve', headers={'Authorization': 'Bearer ' + os.environ['TAIFA_MANAGEMENT_TOKEN'], 'idempotency-key': 'REPLACE_WITH_IDEMPOTENCY_KEY'}, json=json.loads('{"reason":"REPLACE_WITH_REASON"}') ) response.raise_for_status() ``` ### Response example No response example in the current specification. [Request and response examples](/docs/api/operations/decommission_approve_v1_projects__project_id__lifecycle_decommission__action_id__approve_post) ## POST /v1/projects/{project_id}/lifecycle/decommission/{action_id}/cancel Cancel a pending decommission request Cancel a pending decommission request Authentication: bearer access token with audience `taifa-management`. Endpoint roles and eligibility are reviewed separately from the OpenAPI bearer scheme. No operation-specific scopes are declared in the OpenAPI document. Bearer authentication and endpoint authorization requirements still apply. ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `project_id` | path | string | Yes | | | `action_id` | path | string | Yes | | | `idempotency-key` | header | string | Yes | | ### Request body #### application/json Required; identity__owned_client_router__Reason | Field | Variant | Type | Required | Description | | --- | --- | --- | --- | --- | | `reason` | | string | Yes | Validation: min length 8; max length 500 | ### Responses #### 200 Successful Response | Field | Variant | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | | string | Yes | | | `project_id` | | string | Yes | | | `kind` | | suspend \| resume \| decommission | Yes | | | `status` | | requested \| effective \| cancelled | Yes | | | `requested_by` | | string | Yes | | | `decided_by` | | string \| null | Yes | | | `reason` | | string | Yes | | | `created_at` | | string | Yes | | | `expires_at` | | string \| null | Yes | | | `effective_at` | | string \| null | Yes | | | `completed_at` | | string \| null | Yes | | | `project_status` | | string | Yes | | | `access_revoked` | | integer | Yes | | | `lifecycle_head` | | integer | Yes | | | `revocations` | | RevocationRead[] | Yes | | #### 403 Current scoped authority, independent review or recent strong authentication required No fields declared in the current specification. #### 409 Current project state, target set or idempotency conflict No fields declared in the current specification. #### 422 Invalid exact request No fields declared in the current specification. ### Request examples Illustrative only. Replace placeholders and keep management tokens on the server. #### cURL ```sh curl -X POST 'https://YOUR_IDENTITY_HOST/v1/projects/REPLACE_WITH_PROJECT_ID/lifecycle/decommission/REPLACE_WITH_ACTION_ID/cancel' \ -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \ -H 'idempotency-key: REPLACE_WITH_IDEMPOTENCY_KEY' \ -H 'Content-Type: application/json' \ --data '{ "reason": "REPLACE_WITH_REASON" }' ``` #### TypeScript (Node.js/server-side) ```typescript const response = await fetch('https://YOUR_IDENTITY_HOST/v1/projects/REPLACE_WITH_PROJECT_ID/lifecycle/decommission/REPLACE_WITH_ACTION_ID/cancel', { method: 'POST', headers: { Authorization: `Bearer ${process.env.TAIFA_MANAGEMENT_TOKEN}`, 'idempotency-key': 'REPLACE_WITH_IDEMPOTENCY_KEY', 'Content-Type': 'application/json' }, body: JSON.stringify({ "reason": "REPLACE_WITH_REASON" }) }); const result = await response.json(); ``` #### Python ```python import os import json import requests response = requests.request( 'POST', 'https://YOUR_IDENTITY_HOST/v1/projects/REPLACE_WITH_PROJECT_ID/lifecycle/decommission/REPLACE_WITH_ACTION_ID/cancel', headers={'Authorization': 'Bearer ' + os.environ['TAIFA_MANAGEMENT_TOKEN'], 'idempotency-key': 'REPLACE_WITH_IDEMPOTENCY_KEY'}, json=json.loads('{"reason":"REPLACE_WITH_REASON"}') ) response.raise_for_status() ``` ### Response example No response example in the current specification. [Request and response examples](/docs/api/operations/decommission_cancel_v1_projects__project_id__lifecycle_decommission__action_id__cancel_post)