# Reviewed project clients 8 management API operations. - [GET /v1/projects/{project_id}/permission-catalogs](/docs/api/operations/catalogs_v1_projects__project_id__permission_catalogs_get): List reviewed permission catalogs - [POST /v1/projects/{project_id}/permission-catalogs](/docs/api/operations/catalog_propose_v1_projects__project_id__permission_catalogs_post): Propose an immutable permission catalog - [POST /v1/projects/{project_id}/permission-catalogs/{catalog_id}/approve](/docs/api/operations/catalog_approve_v1_projects__project_id__permission_catalogs__catalog_id__approve_post): Independently approve a catalog - [POST /v1/projects/{project_id}/permission-catalogs/{catalog_id}/revoke](/docs/api/operations/catalog_revoke_v1_projects__project_id__permission_catalogs__catalog_id__revoke_post): Revoke an approved catalog - [GET /v1/projects/{project_id}/owned-clients](/docs/api/operations/clients_v1_projects__project_id__owned_clients_get): List reviewed owned-client proposals - [POST /v1/projects/{project_id}/owned-clients](/docs/api/operations/client_propose_v1_projects__project_id__owned_clients_post): Propose an exact owned-client registration policy - [POST /v1/projects/{project_id}/owned-clients/{policy_id}/approve](/docs/api/operations/client_approve_v1_projects__project_id__owned_clients__policy_id__approve_post): Independently approve an owned-client proposal - [POST /v1/projects/{project_id}/owned-clients/{policy_id}/revoke](/docs/api/operations/client_revoke_v1_projects__project_id__owned_clients__policy_id__revoke_post): Revoke an owned-client proposal ## GET /v1/projects/{project_id}/permission-catalogs List reviewed permission catalogs List reviewed permission catalogs 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 | | --- | --- | --- | --- | --- | | `catalogs` | | CatalogRead[] | Yes | | | `_actions` | | catalog-propose[] | Yes | | #### 403 Current project authority or independent review required No fields declared in the current specification. #### 409 Current exact proposal, catalog, version or idempotency conflict No fields declared in the current specification. #### 413 Exact JSON request exceeds 64 KiB No fields declared in the current specification. #### 422 Invalid exact reviewed policy or registration No fields declared in the current specification. #### 503 Configured owned issuer authority unavailable 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/permission-catalogs' \ -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/permission-catalogs', { 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/permission-catalogs', 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/catalogs_v1_projects__project_id__permission_catalogs_get) ## POST /v1/projects/{project_id}/permission-catalogs Propose an immutable permission catalog Current project owner proposes a versioned catalog. A separate current platform project approver must approve it. Idempotency-Key replays the exact actor and body. 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; CatalogProposal | Field | Variant | Type | Required | Description | | --- | --- | --- | --- | --- | | `reason` | | string | Yes | Validation: min length 8; max length 500 | | `permissions` | | Permission[] | Yes | Validation: min items 1; max items 32 | ### Responses #### 201 Successful Response | Field | Variant | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | | string | Yes | | | `project_id` | | string | Yes | | | `revision` | | integer | Yes | | | `permissions` | | Permission[] | Yes | | | `digest` | | string | Yes | | | `status` | | pending_review \| approved \| superseded \| revoked | Yes | | | `proposer` | | string | Yes | | | `approver` | | string \| null | Yes | | | `created_at` | | string | Yes | | | `expires_at` | | string | Yes | | | `actions` | | (approve \| revoke)[] | Yes | | | `revocations` | | RevocationRead[] | No | | #### 403 Current project authority or independent review required No fields declared in the current specification. #### 409 Current exact proposal, catalog, version or idempotency conflict No fields declared in the current specification. #### 413 Exact JSON request exceeds 64 KiB No fields declared in the current specification. #### 422 Invalid exact reviewed policy or registration No fields declared in the current specification. #### 503 Configured owned issuer authority unavailable 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/permission-catalogs' \ -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \ -H 'idempotency-key: REPLACE_WITH_IDEMPOTENCY_KEY' \ -H 'Content-Type: application/json' \ --data '{ "permissions": [ { "description": "Read assigned case records", "id": "case.read" } ], "reason": "Define reviewed case access permissions" }' ``` #### TypeScript (Node.js/server-side) ```typescript const response = await fetch('https://YOUR_IDENTITY_HOST/v1/projects/REPLACE_WITH_PROJECT_ID/permission-catalogs', { method: 'POST', headers: { Authorization: `Bearer ${process.env.TAIFA_MANAGEMENT_TOKEN}`, 'idempotency-key': 'REPLACE_WITH_IDEMPOTENCY_KEY', 'Content-Type': 'application/json' }, body: JSON.stringify({ "permissions": [ { "description": "Read assigned case records", "id": "case.read" } ], "reason": "Define reviewed case access permissions" }) }); 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/permission-catalogs', headers={'Authorization': 'Bearer ' + os.environ['TAIFA_MANAGEMENT_TOKEN'], 'idempotency-key': 'REPLACE_WITH_IDEMPOTENCY_KEY'}, json=json.loads('{"permissions":[{"description":"Read assigned case records","id":"case.read"}],"reason":"Define reviewed case access permissions"}') ) response.raise_for_status() ``` ### Response example No response example in the current specification. [Request and response examples](/docs/api/operations/catalog_propose_v1_projects__project_id__permission_catalogs_post) ## POST /v1/projects/{project_id}/permission-catalogs/{catalog_id}/approve Independently approve a catalog Independently approve a catalog 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 | | | `catalog_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 | | | `revision` | | integer | Yes | | | `permissions` | | Permission[] | Yes | | | `digest` | | string | Yes | | | `status` | | pending_review \| approved \| superseded \| revoked | Yes | | | `proposer` | | string | Yes | | | `approver` | | string \| null | Yes | | | `created_at` | | string | Yes | | | `expires_at` | | string | Yes | | | `actions` | | (approve \| revoke)[] | Yes | | | `revocations` | | RevocationRead[] | No | | #### 403 Current project authority or independent review required No fields declared in the current specification. #### 409 Current exact proposal, catalog, version or idempotency conflict No fields declared in the current specification. #### 413 Exact JSON request exceeds 64 KiB No fields declared in the current specification. #### 422 Invalid exact reviewed policy or registration No fields declared in the current specification. #### 503 Configured owned issuer authority unavailable 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/permission-catalogs/REPLACE_WITH_CATALOG_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/permission-catalogs/REPLACE_WITH_CATALOG_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/permission-catalogs/REPLACE_WITH_CATALOG_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/catalog_approve_v1_projects__project_id__permission_catalogs__catalog_id__approve_post) ## POST /v1/projects/{project_id}/permission-catalogs/{catalog_id}/revoke Revoke an approved catalog Revoke an approved catalog 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 | | | `catalog_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 | | | `revision` | | integer | Yes | | | `permissions` | | Permission[] | Yes | | | `digest` | | string | Yes | | | `status` | | pending_review \| approved \| superseded \| revoked | Yes | | | `proposer` | | string | Yes | | | `approver` | | string \| null | Yes | | | `created_at` | | string | Yes | | | `expires_at` | | string | Yes | | | `actions` | | (approve \| revoke)[] | Yes | | | `revocations` | | RevocationRead[] | No | | #### 403 Current project authority or independent review required No fields declared in the current specification. #### 409 Current exact proposal, catalog, version or idempotency conflict No fields declared in the current specification. #### 413 Exact JSON request exceeds 64 KiB No fields declared in the current specification. #### 422 Invalid exact reviewed policy or registration No fields declared in the current specification. #### 503 Configured owned issuer authority unavailable 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/permission-catalogs/REPLACE_WITH_CATALOG_ID/revoke' \ -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/permission-catalogs/REPLACE_WITH_CATALOG_ID/revoke', { 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/permission-catalogs/REPLACE_WITH_CATALOG_ID/revoke', 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/catalog_revoke_v1_projects__project_id__permission_catalogs__catalog_id__revoke_post) ## GET /v1/projects/{project_id}/owned-clients List reviewed owned-client proposals List reviewed owned-client proposals 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 | | --- | --- | --- | --- | --- | | `clients` | | ClientRead[] | Yes | | | `_actions` | | client-propose[] | Yes | | #### 403 Current project authority or independent review required No fields declared in the current specification. #### 409 Current exact proposal, catalog, version or idempotency conflict No fields declared in the current specification. #### 413 Exact JSON request exceeds 64 KiB No fields declared in the current specification. #### 422 Invalid exact reviewed policy or registration No fields declared in the current specification. #### 503 Configured owned issuer authority unavailable 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/owned-clients' \ -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/owned-clients', { 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/owned-clients', 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/clients_v1_projects__project_id__owned_clients_get) ## POST /v1/projects/{project_id}/owned-clients Propose an exact owned-client registration policy Requires a controlled credential preparation and fresh private issuer custody readback. Stores the full immutable registration and versioned digest with exact accepted owner and catalog evidence for independent review. Approval does not install a client or authorize an assignment. Idempotency-Key replays the exact actor and body after current authority and fresh custody checks. 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; ClientProposal | Field | Variant | Type | Required | Description | | --- | --- | --- | --- | --- | | `reason` | | string | Yes | Validation: min length 8; max length 500 | | `target_issuer` | | string | Yes | Validation: min length 1; max length 2048 | | `client_id` | | string | Yes | Validation: min length 1; max length 128 | | `client_version` | | integer | Yes | Validation: minimum 1; maximum 9223372036854775807 | | `display_name` | | string | Yes | Validation: min length 3; max length 120 | | `catalog_id` | | string | Yes | Validation: min length 1; max length 200 | | `credential_preparation_id` | | string | Yes | Canonical preparation UUID from controlled credential delivery. Management verifies fresh private issuer readback; browser proof is reference metadata only. Validation: min length 36; max length 36 | | `permission_ids` | | string[] | Yes | Validation: min items 1; max items 32 | | `registration` | | RegistrationProposal | Yes | | ### Responses #### 201 Successful Response | Field | Variant | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | | string | Yes | | | `project_id` | | string | Yes | | | `target_issuer` | | string | Yes | | | `client_id` | | string | Yes | | | `client_version` | | integer | Yes | | | `generation` | | integer | Yes | | | `display_name` | | string | Yes | | | `catalog_id` | | string | Yes | | | `catalog_digest` | | string | Yes | | | `permission_ids` | | string[] | Yes | | | `registration` | | RegistrationRead | Yes | | | `registration_digest` | | string | Yes | | | `policy_digest` | | string | Yes | | | `credential_preparation_id` | | string \| null | No | | | `custody_binding_digest` | | string \| null | No | | | `status` | | pending_review \| approved_pending_readback \| superseded \| revoked | Yes | | | `proposer` | | string | Yes | | | `approver` | | string \| null | Yes | | | `created_at` | | string | Yes | | | `expires_at` | | string | Yes | | | `actions` | | (approve \| revoke)[] | Yes | | | `revocation` | | RevocationRead \| null | No | | #### 403 Current project authority or independent review required No fields declared in the current specification. #### 409 Current exact proposal, catalog, version or idempotency conflict No fields declared in the current specification. #### 413 Exact JSON request exceeds 64 KiB No fields declared in the current specification. #### 422 Invalid exact reviewed policy or registration No fields declared in the current specification. #### 503 Configured owned issuer authority unavailable 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/owned-clients' \ -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \ -H 'idempotency-key: REPLACE_WITH_IDEMPOTENCY_KEY' \ -H 'Content-Type: application/json' \ --data '{ "catalog_id": "00000000-0000-4000-8000-000000000001", "client_id": "case-app-test", "client_version": 1, "credential_preparation_id": "00000000-0000-4000-8000-000000000002", "display_name": "Case application test", "permission_ids": [ "case.read" ], "reason": "Review an owned case application registration", "registration": { "enabled": true, "management_access": false, "post_logout_redirect_uris": [ "https://case.example.test/signed-out" ], "redirect_uris": [ "https://case.example.test/callback" ], "refresh_allowed": false, "resource_audiences": [ "case-api-test" ], "secret_hash_fingerprint": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" }, "target_issuer": "https://owned-issuer.example.test" }' ``` #### TypeScript (Node.js/server-side) ```typescript const response = await fetch('https://YOUR_IDENTITY_HOST/v1/projects/REPLACE_WITH_PROJECT_ID/owned-clients', { method: 'POST', headers: { Authorization: `Bearer ${process.env.TAIFA_MANAGEMENT_TOKEN}`, 'idempotency-key': 'REPLACE_WITH_IDEMPOTENCY_KEY', 'Content-Type': 'application/json' }, body: JSON.stringify({ "catalog_id": "00000000-0000-4000-8000-000000000001", "client_id": "case-app-test", "client_version": 1, "credential_preparation_id": "00000000-0000-4000-8000-000000000002", "display_name": "Case application test", "permission_ids": [ "case.read" ], "reason": "Review an owned case application registration", "registration": { "enabled": true, "management_access": false, "post_logout_redirect_uris": [ "https://case.example.test/signed-out" ], "redirect_uris": [ "https://case.example.test/callback" ], "refresh_allowed": false, "resource_audiences": [ "case-api-test" ], "secret_hash_fingerprint": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" }, "target_issuer": "https://owned-issuer.example.test" }) }); 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/owned-clients', headers={'Authorization': 'Bearer ' + os.environ['TAIFA_MANAGEMENT_TOKEN'], 'idempotency-key': 'REPLACE_WITH_IDEMPOTENCY_KEY'}, json=json.loads('{"catalog_id":"00000000-0000-4000-8000-000000000001","client_id":"case-app-test","client_version":1,"credential_preparation_id":"00000000-0000-4000-8000-000000000002","display_name":"Case application test","permission_ids":["case.read"],"reason":"Review an owned case application registration","registration":{"enabled":true,"management_access":false,"post_logout_redirect_uris":["https://case.example.test/signed-out"],"redirect_uris":["https://case.example.test/callback"],"refresh_allowed":false,"resource_audiences":["case-api-test"],"secret_hash_fingerprint":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"},"target_issuer":"https://owned-issuer.example.test"}') ) response.raise_for_status() ``` ### Response example No response example in the current specification. [Request and response examples](/docs/api/operations/client_propose_v1_projects__project_id__owned_clients_post) ## POST /v1/projects/{project_id}/owned-clients/{policy_id}/approve Independently approve an owned-client proposal Obtains fresh private custody readback before source locks and records an independent current approver with the exact proposal and approved catalog evidence. The approved_pending_readback state still requires separate reviewed installation and product acknowledgement. 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 | | | `policy_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 | | | `target_issuer` | | string | Yes | | | `client_id` | | string | Yes | | | `client_version` | | integer | Yes | | | `generation` | | integer | Yes | | | `display_name` | | string | Yes | | | `catalog_id` | | string | Yes | | | `catalog_digest` | | string | Yes | | | `permission_ids` | | string[] | Yes | | | `registration` | | RegistrationRead | Yes | | | `registration_digest` | | string | Yes | | | `policy_digest` | | string | Yes | | | `credential_preparation_id` | | string \| null | No | | | `custody_binding_digest` | | string \| null | No | | | `status` | | pending_review \| approved_pending_readback \| superseded \| revoked | Yes | | | `proposer` | | string | Yes | | | `approver` | | string \| null | Yes | | | `created_at` | | string | Yes | | | `expires_at` | | string | Yes | | | `actions` | | (approve \| revoke)[] | Yes | | | `revocation` | | RevocationRead \| null | No | | #### 403 Current project authority or independent review required No fields declared in the current specification. #### 409 Current exact proposal, catalog, version or idempotency conflict No fields declared in the current specification. #### 413 Exact JSON request exceeds 64 KiB No fields declared in the current specification. #### 422 Invalid exact reviewed policy or registration No fields declared in the current specification. #### 503 Configured owned issuer authority unavailable 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/owned-clients/REPLACE_WITH_POLICY_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/owned-clients/REPLACE_WITH_POLICY_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/owned-clients/REPLACE_WITH_POLICY_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/client_approve_v1_projects__project_id__owned_clients__policy_id__approve_post) ## POST /v1/projects/{project_id}/owned-clients/{policy_id}/revoke Revoke an owned-client proposal Revoke an owned-client proposal 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 | | | `policy_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 | | | `target_issuer` | | string | Yes | | | `client_id` | | string | Yes | | | `client_version` | | integer | Yes | | | `generation` | | integer | Yes | | | `display_name` | | string | Yes | | | `catalog_id` | | string | Yes | | | `catalog_digest` | | string | Yes | | | `permission_ids` | | string[] | Yes | | | `registration` | | RegistrationRead | Yes | | | `registration_digest` | | string | Yes | | | `policy_digest` | | string | Yes | | | `credential_preparation_id` | | string \| null | No | | | `custody_binding_digest` | | string \| null | No | | | `status` | | pending_review \| approved_pending_readback \| superseded \| revoked | Yes | | | `proposer` | | string | Yes | | | `approver` | | string \| null | Yes | | | `created_at` | | string | Yes | | | `expires_at` | | string | Yes | | | `actions` | | (approve \| revoke)[] | Yes | | | `revocation` | | RevocationRead \| null | No | | #### 403 Current project authority or independent review required No fields declared in the current specification. #### 409 Current exact proposal, catalog, version or idempotency conflict No fields declared in the current specification. #### 413 Exact JSON request exceeds 64 KiB No fields declared in the current specification. #### 422 Invalid exact reviewed policy or registration No fields declared in the current specification. #### 503 Configured owned issuer authority unavailable 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/owned-clients/REPLACE_WITH_POLICY_ID/revoke' \ -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/owned-clients/REPLACE_WITH_POLICY_ID/revoke', { 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/owned-clients/REPLACE_WITH_POLICY_ID/revoke', 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/client_revoke_v1_projects__project_id__owned_clients__policy_id__revoke_post)