{"openapi":"3.1.0","info":{"title":"Tenpace Review Router Agent Setup API","version":"1.1.1","description":"Create a declarative Review Router setup plan, send one short-lived URL to the person completing setup, then monitor and apply the exact plan locked by their sign-in. Provider credentials never pass through the agent."},"servers":[{"url":"https://api.tenpace.com","description":"Tenpace production agent API"}],"tags":[{"name":"Review Router setup","description":"Plan, authorize, apply, and verify a Review Router connection without exposing provider credentials to the calling agent."}],"paths":{"/v1/review-router/setup-sessions":{"post":{"tags":["Review Router setup"],"operationId":"createReviewRouterSetupSession","summary":"Create an inert setup plan","description":"GitHub Actions should provide an OIDC token whose repository claim matches intent.repository. Other clients may create anonymous, rate-limited sessions. Neither method authorizes provider changes.","security":[{},{"GitHubActionsOidc":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","schema":{"type":"string","minLength":8,"maxLength":200},"description":"Stable for one logical setup request."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["intent"],"properties":{"source":{"$ref":"#/components/schemas/SetupSource"},"intent":{"$ref":"#/components/schemas/SetupIntent"}}}}}},"responses":{"201":{"description":"Setup created. agentToken is returned only by creation/replay. Direct API, CLI, and MCP setupUrl values carry a browser-only claim token in the URL fragment; GitHub Action URLs contain no claim secret and are bound to the OIDC actor.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatedSetupSession"}}}},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/review-router/setup-sessions/{setupId}":{"get":{"summary":"Get setup state and next human action","security":[{},{"SetupToken":[]},{"TenpaceSession":[]},{"SetupClaimToken":[]}],"parameters":[{"name":"setupId","in":"path","required":true,"schema":{"type":"string","pattern":"^rrs_"}}],"responses":{"200":{"description":"Current setup state","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetupSession"}}}},"409":{"$ref":"#/components/responses/Conflict"}},"operationId":"getReviewRouterSetupSession","tags":["Review Router setup"]},"delete":{"summary":"Cancel an unapplied setup","security":[{"SetupToken":[]},{"TenpaceSession":[]}],"parameters":[{"name":"setupId","in":"path","required":true,"schema":{"type":"string","pattern":"^rrs_"}}],"responses":{"200":{"description":"Current setup state","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetupSession"}}}},"409":{"$ref":"#/components/responses/Conflict"}},"operationId":"cancelReviewRouterSetupSession","tags":["Review Router setup"]}},"/v1/review-router/setup-sessions/{setupId}/intent":{"put":{"summary":"Edit the setup intent","security":[{"SetupToken":[]},{"TenpaceSession":[]}],"parameters":[{"name":"setupId","in":"path","required":true,"schema":{"type":"string","pattern":"^rrs_"}}],"responses":{"200":{"description":"Current setup state","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetupSession"}}}},"409":{"$ref":"#/components/responses/Conflict"}},"description":"The machine token can edit only before claim. The person who claimed the setup can edit afterward; saving creates and locks the new intent version atomically.","operationId":"updateReviewRouterSetupIntent","tags":["Review Router setup"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetupIntent"}}}}}},"/v1/review-router/setup-sessions/{setupId}/plan":{"get":{"summary":"Preview the exact intent version, plan, and next human action","security":[{},{"SetupToken":[]},{"TenpaceSession":[]},{"SetupClaimToken":[]}],"parameters":[{"name":"setupId","in":"path","required":true,"schema":{"type":"string","pattern":"^rrs_"}}],"responses":{"200":{"description":"Current setup state","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetupSession"}}}},"409":{"$ref":"#/components/responses/Conflict"}},"operationId":"previewReviewRouterSetupSession","tags":["Review Router setup"]}},"/v1/review-router/setup-sessions/{setupId}/claim":{"post":{"summary":"Claim and lock the setup as a signed-in Tenpace user","security":[{"TenpaceSession":[],"SetupClaimToken":[]},{"TenpaceSession":[]}],"parameters":[{"name":"setupId","in":"path","required":false,"description":"Required for non-GitHub-Action setup sessions.","schema":{"type":"string","pattern":"^rrs_"}},{"name":"X-Tenpace-Setup-Claim","in":"header","required":false,"schema":{"type":"string","pattern":"^rr_claim_"}}],"responses":{"200":{"description":"Current setup state","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetupSession"}}}},"409":{"$ref":"#/components/responses/Conflict"}},"description":"Claiming locks the exact current intent version. Direct API, CLI, and MCP sessions require X-Tenpace-Setup-Claim on first claim. GitHub Action sessions instead require the signed-in user's GitHub ID to match the OIDC workflow actor.","operationId":"claimReviewRouterSetupSession","tags":["Review Router setup"]}},"/v1/review-router/setup-sessions/{setupId}/apply":{"post":{"summary":"Idempotently apply the locked route","security":[{"SetupToken":[]},{"TenpaceSession":[]}],"parameters":[{"name":"setupId","in":"path","required":true,"schema":{"type":"string","pattern":"^rrs_"}}],"responses":{"200":{"description":"Current setup state","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetupSession"}}}},"409":{"$ref":"#/components/responses/Conflict"}},"operationId":"applyReviewRouterSetupSession","tags":["Review Router setup"]}},"/v1/review-router/setup-sessions/{setupId}/test":{"post":{"summary":"Send one real Slack setup delivery","security":[{"SetupToken":[]},{"TenpaceSession":[]}],"parameters":[{"name":"setupId","in":"path","required":true,"schema":{"type":"string","pattern":"^rrs_"}}],"responses":{"200":{"description":"Current setup state","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetupSession"}}}},"409":{"$ref":"#/components/responses/Conflict"}},"operationId":"testReviewRouterSetupSession","tags":["Review Router setup"]}},"/v1/review-router/setup-sessions/{setupId}/connections/github":{"post":{"summary":"Create the GitHub App installation URL for the claimed team","security":[{"TenpaceSession":[]}],"parameters":[{"name":"setupId","in":"path","required":true,"schema":{"type":"string","pattern":"^rrs_"}}],"responses":{"200":{"description":"Short-lived GitHub installation destination","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectionUrl"}}}}},"operationId":"createReviewRouterGitHubConnectionUrl","tags":["Review Router setup"]}},"/v1/review-router/setup-sessions/{setupId}/connections/slack":{"post":{"summary":"Create a one-time Slack OAuth handoff for the claimed team","security":[{"TenpaceSession":[]}],"parameters":[{"name":"setupId","in":"path","required":true,"schema":{"type":"string","pattern":"^rrs_"}}],"responses":{"200":{"description":"One-time Slack OAuth handoff URL","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectionUrl"}}}}},"operationId":"createReviewRouterSlackConnectionUrl","tags":["Review Router setup"]}}},"components":{"securitySchemes":{"GitHubActionsOidc":{"type":"http","scheme":"bearer","bearerFormat":"GitHub Actions OIDC JWT"},"SetupToken":{"type":"http","scheme":"bearer","bearerFormat":"rr_setup_ token"},"TenpaceSession":{"type":"http","scheme":"bearer","bearerFormat":"Tenpace session"},"SetupClaimToken":{"type":"apiKey","in":"header","name":"X-Tenpace-Setup-Claim"}},"schemas":{"SetupSource":{"type":"string","enum":["api","github_action","mcp","cli","review_health_audit"],"default":"api"},"SetupIntent":{"type":"object","additionalProperties":false,"required":["repository","slackChannel"],"properties":{"repository":{"type":"string","pattern":"^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$"},"slackChannel":{"type":"string","description":"Name with or without a leading #."},"slackWorkspace":{"type":"string","description":"Optional Tenpace workspace ID, Slack team ID, or exact workspace name."},"preset":{"type":"string","enum":["repo_watch","full_coverage","team_activity"],"default":"repo_watch"},"reviewerMentions":{"type":"string","enum":["all","connected_only","none"],"default":"all"}}},"SetupSession":{"type":"object","required":["id","status","intent","intentVersion","lockedIntentVersion","intentLocked","setupUrl","plan","connections","result"],"properties":{"id":{"type":"string"},"status":{"type":"string","enum":["awaiting_human","awaiting_billing","awaiting_github","awaiting_slack","awaiting_slack_workspace","awaiting_slack_channel","ready_to_apply","applying","test_pending","complete","failed","cancelled","expired"]},"source":{"$ref":"#/components/schemas/SetupSource"},"intent":{"$ref":"#/components/schemas/SetupIntent"},"intentVersion":{"type":"integer","minimum":1},"lockedIntentVersion":{"type":["integer","null"]},"intentLocked":{"type":"boolean"},"approvedIntentVersion":{"type":["integer","null"],"deprecated":true,"description":"Compatibility alias for lockedIntentVersion."},"approvalValid":{"type":"boolean","deprecated":true,"description":"Compatibility alias for intentLocked."},"setupUrl":{"type":"string","format":"uri","description":"Human handoff. GitHub Action URLs contain no secret and are actor-bound; other creation sources return a claim capability in the URL fragment only on creation/replay."},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"expiresAt":{"type":"string","format":"date-time"},"plan":{"type":"array","items":{"type":"object"}},"humanAction":{"type":["object","null"]},"connections":{"type":"object"},"result":{"type":"object"},"error":{"type":["object","null"]}}},"CreatedSetupSession":{"allOf":[{"$ref":"#/components/schemas/SetupSession"},{"type":"object","required":["agentToken"],"properties":{"agentToken":{"type":"string","writeOnly":true}}}]},"ConnectionUrl":{"type":"object","additionalProperties":false,"required":["url"],"properties":{"url":{"type":"string","format":"uri"}}},"Error":{"type":"object","required":["error","message"],"properties":{"error":{"type":"string"},"message":{"type":"string"},"retryable":{"type":"boolean"}}}},"responses":{"Conflict":{"description":"The request conflicts with the current setup state.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"RateLimited":{"description":"Too many public setup requests.","headers":{"Retry-After":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}