Files
Sankofa/docs/phoenix/API_SPECIFICATION.md

1115 lines
23 KiB
Markdown
Raw Normal View History

# Phoenix Operating Model - API Specification
**Complete API specification for all five control planes**
This document provides detailed API specifications for the Phoenix operating model, including GraphQL schemas, REST endpoints, and integration patterns.
---
## Executive Summary
The Phoenix operating model exposes APIs for all five control planes:
1. **Commercial Plane API** - Client and billing operations
2. **Tenancy Plane API** - Tenant and identity operations
3. **Subscription Plane API** - Subscription and quota operations
4. **Environment Plane API** - Environment and deployment operations
5. **Content & DevOps Plane API** - Content and Git operations
All APIs support:
- GraphQL interface (primary)
- REST interface (alternative)
- Authentication via Keycloak
- Authorization via RBAC
- Audit logging
- Multi-region support
---
## I. Commercial Plane API
### GraphQL Schema
```graphql
# Client Management
type Client {
id: ID!
name: String!
legalEntity: LegalEntity!
contract: Contract
msa: MSA
invoicingConfig: InvoicingConfig!
paymentInstruments: [PaymentInstrument!]!
costCenters: [CostCenter!]!
tenants: [Tenant!]!
usageAggregation: UsageAggregation
chargebackRules: [ChargebackRule!]!
createdAt: DateTime!
updatedAt: DateTime!
metadata: JSON
}
type LegalEntity {
name: String!
registrationNumber: String
jurisdiction: String!
taxId: String
address: Address!
}
type InvoicingConfig {
format: InvoiceFormat!
frequency: InvoiceFrequency!
currency: String!
paymentTerms: String!
billingAddress: Address!
emailRecipients: [String!]!
}
enum InvoiceFormat {
PDF
XML
JSON
}
enum InvoiceFrequency {
MONTHLY
QUARTERLY
ANNUAL
}
# Queries
type Query {
client(id: ID!): Client
clients(filter: ClientFilter): [Client!]!
billing(clientId: ID!, timeRange: TimeRange!): BillingData!
invoices(clientId: ID!, filter: InvoiceFilter): [Invoice!]!
costCenters(clientId: ID!): [CostCenter!]!
}
# Mutations
type Mutation {
createClient(input: CreateClientInput!): Client!
updateClient(id: ID!, input: UpdateClientInput!): Client!
deleteClient(id: ID!): Boolean!
createInvoice(clientId: ID!, period: BillingPeriod!): Invoice!
processPayment(invoiceId: ID!, payment: PaymentInput!): Payment!
addPaymentInstrument(clientId: ID!, instrument: PaymentInstrumentInput!): PaymentInstrument!
removePaymentInstrument(clientId: ID!, instrumentId: ID!): Boolean!
createCostCenter(clientId: ID!, input: CreateCostCenterInput!): CostCenter!
updateCostCenter(clientId: ID!, costCenterId: ID!, input: UpdateCostCenterInput!): CostCenter!
deleteCostCenter(clientId: ID!, costCenterId: ID!): Boolean!
}
# Input Types
input CreateClientInput {
name: String!
legalEntity: LegalEntityInput!
invoicingConfig: InvoicingConfigInput!
contract: ContractInput
msa: MSAInput
}
input ClientFilter {
name: String
jurisdiction: String
status: ClientStatus
}
input TimeRange {
start: DateTime!
end: DateTime!
}
```
### REST Endpoints
```
# Client Management
POST /api/v1/commercial/clients
GET /api/v1/commercial/clients
GET /api/v1/commercial/clients/{id}
PUT /api/v1/commercial/clients/{id}
DELETE /api/v1/commercial/clients/{id}
# Billing
GET /api/v1/commercial/clients/{id}/billing
GET /api/v1/commercial/clients/{id}/invoices
POST /api/v1/commercial/clients/{id}/invoices
GET /api/v1/commercial/invoices/{id}
POST /api/v1/commercial/invoices/{id}/payments
# Cost Centers
POST /api/v1/commercial/clients/{id}/cost-centers
GET /api/v1/commercial/clients/{id}/cost-centers
PUT /api/v1/commercial/clients/{id}/cost-centers/{costCenterId}
DELETE /api/v1/commercial/clients/{id}/cost-centers/{costCenterId}
```
### Example Queries
#### Create Client
```graphql
mutation {
createClient(input: {
name: "Government Agency A"
legalEntity: {
name: "Government Agency A"
jurisdiction: "Nation A"
address: {
street: "123 Main St"
city: "Capital City"
country: "Nation A"
}
}
invoicingConfig: {
format: PDF
frequency: MONTHLY
currency: "USD"
paymentTerms: "Net 30"
billingAddress: {
street: "123 Main St"
city: "Capital City"
country: "Nation A"
}
emailRecipients: ["billing@agency.gov"]
}
}) {
id
name
legalEntity {
name
jurisdiction
}
}
}
```
#### Get Billing Data
```graphql
query {
billing(
clientId: "client-id"
timeRange: {
start: "2025-01-01T00:00:00Z"
end: "2025-01-31T23:59:59Z"
}
) {
totalCost
currency
bySubscription {
subscription {
id
name
}
cost
percentage
}
byCostCenter {
costCenter {
id
name
}
cost
percentage
}
}
}
```
---
## II. Tenancy Plane API
### GraphQL Schema
```graphql
# Tenant Management
type Tenant {
id: ID!
name: String!
primaryDomains: [String!]!
identityProvider: IdentityProvider!
rbacNamespace: String!
dataResidencyFlags: [DataResidencyFlag!]!
complianceProfile: ComplianceProfile!
client: Client!
subscriptions: [Subscription!]!
environments: [Environment!]!
regions: [Region!]!
keycloakRealmId: String
multiRegionEnabled: Boolean!
regionalDataResidency: [RegionalDataResidency!]!
crossBorderGovernance: CrossBorderGovernance
createdAt: DateTime!
updatedAt: DateTime!
metadata: JSON
}
type IdentityProvider {
type: IdentityProviderType!
config: JSON!
ssoEnabled: Boolean!
mfaRequired: Boolean!
}
enum IdentityProviderType {
KEYCLOAK
AZURE_AD
OKTA
GOOGLE_WORKSPACE
CUSTOM_SAML
CUSTOM_OIDC
}
# Queries
type Query {
tenant(id: ID!): Tenant
tenants(filter: TenantFilter): [Tenant!]!
tenantByDomain(domain: String!): Tenant
identityProvider(tenantId: ID!): IdentityProvider
complianceProfile(tenantId: ID!): ComplianceProfile
}
# Mutations
type Mutation {
createTenant(input: CreateTenantInput!): Tenant!
updateTenant(id: ID!, input: UpdateTenantInput!): Tenant!
deleteTenant(id: ID!): Boolean!
configureIdentityProvider(tenantId: ID!, provider: IdentityProviderInput!): IdentityProvider!
syncKeycloakRealm(tenantId: ID!): KeycloakRealm!
updateComplianceProfile(tenantId: ID!, profile: ComplianceProfileInput!): ComplianceProfile!
addDataResidencyFlag(tenantId: ID!, flag: DataResidencyFlagInput!): DataResidencyFlag!
removeDataResidencyFlag(tenantId: ID!, flagId: ID!): Boolean!
}
# Input Types
input CreateTenantInput {
name: String!
clientId: ID!
primaryDomains: [String!]!
identityProvider: IdentityProviderInput!
rbacNamespace: String!
complianceProfile: ComplianceProfileInput!
dataResidencyFlags: [DataResidencyFlagInput!]
multiRegionEnabled: Boolean
}
```
### REST Endpoints
```
# Tenant Management
POST /api/v1/tenancy/tenants
GET /api/v1/tenancy/tenants
GET /api/v1/tenancy/tenants/{id}
PUT /api/v1/tenancy/tenants/{id}
DELETE /api/v1/tenancy/tenants/{id}
GET /api/v1/tenancy/tenants/by-domain/{domain}
# Identity Provider
GET /api/v1/tenancy/tenants/{id}/identity-provider
PUT /api/v1/tenancy/tenants/{id}/identity-provider
POST /api/v1/tenancy/tenants/{id}/keycloak/sync
# Compliance
GET /api/v1/tenancy/tenants/{id}/compliance
PUT /api/v1/tenancy/tenants/{id}/compliance
```
### Example Queries
#### Create Tenant
```graphql
mutation {
createTenant(input: {
name: "agency-tenant"
clientId: "client-id"
primaryDomains: ["agency.gov", "agency.sankofa.nexus"]
identityProvider: {
type: KEYCLOAK
config: {}
ssoEnabled: true
mfaRequired: true
}
rbacNamespace: "agency-namespace"
complianceProfile: {
standards: [ISO_27001, SOC_2, FEDRAMP]
}
dataResidencyFlags: [{
region: "region-a"
requirement: REQUIRED
enforcement: HARD
}]
multiRegionEnabled: true
}) {
id
name
primaryDomains
keycloakRealmId
}
}
```
#### Configure Identity Provider
```graphql
mutation {
configureIdentityProvider(
tenantId: "tenant-id"
provider: {
type: AZURE_AD
config: {
tenantId: "azure-tenant-id"
clientId: "azure-client-id"
clientSecret: "azure-client-secret"
}
ssoEnabled: true
mfaRequired: true
}
) {
type
ssoEnabled
mfaRequired
}
}
```
---
## III. Subscription Plane API
### GraphQL Schema
```graphql
# Subscription Management
type Subscription {
id: ID!
name: String!
tenant: Tenant!
client: Client!
type: SubscriptionType!
serviceBundles: [ServiceBundle!]!
quotas: Quotas!
limits: Limits!
costTracking: CostTracking!
policyPacks: [PolicyPack!]!
featureEntitlements: [FeatureEntitlement!]!
environments: [Environment!]!
regions: [Region!]!
createdAt: DateTime!
updatedAt: DateTime!
metadata: JSON
}
enum SubscriptionType {
SHARED_PLATFORM
PRODUCT
SANDBOX
INNOVATION
}
type ServiceBundle {
service: ServiceType!
enabled: Boolean!
quotas: ServiceQuotas
limits: ServiceLimits
}
enum ServiceType {
COMPUTE
STORAGE
NETWORKING
DATABASE
AI_ML
ANALYTICS
SECURITY
MONITORING
BACKUP
}
# Queries
type Query {
subscription(id: ID!): Subscription
subscriptions(filter: SubscriptionFilter): [Subscription!]!
quotas(subscriptionId: ID!): Quotas!
checkQuota(subscriptionId: ID!, resource: ResourceType!): QuotaStatus!
}
# Mutations
type Mutation {
createSubscription(input: CreateSubscriptionInput!): Subscription!
updateSubscription(id: ID!, input: UpdateSubscriptionInput!): Subscription!
deleteSubscription(id: ID!): Boolean!
updateQuotas(subscriptionId: ID!, quotas: QuotasInput!): Quotas!
addServiceBundle(subscriptionId: ID!, bundle: ServiceBundleInput!): ServiceBundle!
removeServiceBundle(subscriptionId: ID!, service: ServiceType!): Boolean!
addPolicyPack(subscriptionId: ID!, pack: PolicyPackInput!): PolicyPack!
removePolicyPack(subscriptionId: ID!, packId: ID!): Boolean!
}
```
### REST Endpoints
```
# Subscription Management
POST /api/v1/subscription/subscriptions
GET /api/v1/subscription/subscriptions
GET /api/v1/subscription/subscriptions/{id}
PUT /api/v1/subscription/subscriptions/{id}
DELETE /api/v1/subscription/subscriptions/{id}
# Quotas
GET /api/v1/subscription/subscriptions/{id}/quotas
PUT /api/v1/subscription/subscriptions/{id}/quotas
GET /api/v1/subscription/subscriptions/{id}/quotas/check
# Service Bundles
POST /api/v1/subscription/subscriptions/{id}/service-bundles
DELETE /api/v1/subscription/subscriptions/{id}/service-bundles/{service}
# Policy Packs
POST /api/v1/subscription/subscriptions/{id}/policy-packs
DELETE /api/v1/subscription/subscriptions/{id}/policy-packs/{packId}
```
### Example Queries
#### Create Subscription
```graphql
mutation {
createSubscription(input: {
name: "production-subscription"
tenantId: "tenant-id"
type: PRODUCT
serviceBundles: [{
service: COMPUTE
enabled: true
quotas: {
vcpu: 100
memory: 512
instances: 50
}
}, {
service: STORAGE
enabled: true
quotas: {
total: 10000
perInstance: 500
}
}]
quotas: {
compute: {
vcpu: 100
memory: 512
instances: 50
}
storage: {
total: 10000
perInstance: 500
}
}
policyPacks: [{
name: "security-policy"
type: SECURITY
policies: []
enforcement: HARD
}]
}) {
id
name
type
serviceBundles {
service
enabled
}
}
}
```
---
## IV. Environment Plane API
### GraphQL Schema
```graphql
# Environment Management
type Environment {
id: ID!
name: String!
type: EnvironmentType!
subscription: Subscription!
networkIsolation: NetworkIsolation!
dataIsolation: DataIsolation!
deploymentPolicies: [DeploymentPolicy!]!
runtimeSecrets: [Secret!]!
complianceOverlays: [ComplianceOverlay!]!
region: Region
promotionFlow: PromotionFlow
createdAt: DateTime!
updatedAt: DateTime!
metadata: JSON
}
enum EnvironmentType {
DEV
INT
UAT
STAGING
PROD
REGULATED
SOVEREIGN
AIR_GAPPED
}
# Queries
type Query {
environment(id: ID!): Environment
environments(filter: EnvironmentFilter): [Environment!]!
promotionFlow(environmentId: ID!): PromotionFlow
deploymentPolicies(environmentId: ID!): [DeploymentPolicy!]!
}
# Mutations
type Mutation {
createEnvironment(input: CreateEnvironmentInput!): Environment!
updateEnvironment(id: ID!, input: UpdateEnvironmentInput!): Environment!
deleteEnvironment(id: ID!): Boolean!
promoteArtifact(input: PromoteArtifactInput!): PromotionResult!
approvePromotion(promotionId: ID!, approved: Boolean!): PromotionResult!
configurePromotionFlow(environmentId: ID!, flow: PromotionFlowInput!): PromotionFlow!
addDeploymentPolicy(environmentId: ID!, policy: DeploymentPolicyInput!): DeploymentPolicy!
removeDeploymentPolicy(environmentId: ID!, policyId: ID!): Boolean!
}
```
### REST Endpoints
```
# Environment Management
POST /api/v1/environment/environments
GET /api/v1/environment/environments
GET /api/v1/environment/environments/{id}
PUT /api/v1/environment/environments/{id}
DELETE /api/v1/environment/environments/{id}
# Promotion
POST /api/v1/environment/promotions
GET /api/v1/environment/promotions/{id}
POST /api/v1/environment/promotions/{id}/approve
POST /api/v1/environment/promotions/{id}/reject
# Deployment Policies
POST /api/v1/environment/environments/{id}/deployment-policies
GET /api/v1/environment/environments/{id}/deployment-policies
DELETE /api/v1/environment/environments/{id}/deployment-policies/{policyId}
```
### Example Queries
#### Create Environment
```graphql
mutation {
createEnvironment(input: {
name: "production-env"
subscriptionId: "subscription-id"
type: PROD
networkIsolation: {
vpcId: "vpc-id"
subnetIds: ["subnet-1", "subnet-2"]
firewallRules: []
}
dataIsolation: {
encryptionAtRest: true
encryptionInTransit: true
accessControls: []
}
deploymentPolicies: [{
name: "production-policy"
type: POLICY_DRIVEN
approvalRequired: true
approvers: ["release-manager-1", "release-manager-2"]
}]
region: "region-a"
}) {
id
name
type
region {
id
name
}
}
}
```
#### Promote Artifact
```graphql
mutation {
promoteArtifact(input: {
artifactId: "artifact-id"
fromEnvironmentId: "staging-env-id"
toEnvironmentId: "prod-env-id"
metadata: {
version: "1.2.3"
changelog: "Production release"
}
}) {
id
status
approvalRequired
approvers
}
}
```
---
## V. Content & DevOps Plane API
### GraphQL Schema
```graphql
# Content Hierarchy
type Enterprise {
id: ID!
name: String!
portfolios: [Portfolio!]!
ownership: Ownership!
governance: Governance!
createdAt: DateTime!
updatedAt: DateTime!
metadata: JSON
}
type Portfolio {
id: ID!
name: String!
enterprise: Enterprise!
products: [Product!]!
ownership: Ownership!
governance: Governance!
createdAt: DateTime!
updatedAt: DateTime!
metadata: JSON
}
type Product {
id: ID!
name: String!
portfolio: Portfolio!
applications: [Application!]!
ownership: Ownership!
governance: Governance!
createdAt: DateTime!
updatedAt: DateTime!
metadata: JSON
}
type Application {
id: ID!
name: String!
product: Product!
components: [Component!]!
gitRepos: [GitRepo!]!
ownership: Ownership!
governance: Governance!
createdAt: DateTime!
updatedAt: DateTime!
metadata: JSON
}
type Component {
id: ID!
name: String!
application: Application!
contentType: ContentType!
content: Content!
ownership: Ownership!
governance: Governance!
version: String!
lineage: [LineageEntry!]!
createdAt: DateTime!
updatedAt: DateTime!
metadata: JSON
}
enum ContentType {
SOURCE_CODE
IAC
PIPELINE
CONFIG_TEMPLATE
DOCUMENTATION
DATA_SCHEMA
AI_MODEL
PROMPT
}
# Queries
type Query {
enterprise(id: ID!): Enterprise
enterprises: [Enterprise!]!
portfolio(id: ID!): Portfolio
product(id: ID!): Product
application(id: ID!): Application
component(id: ID!): Component
gitRepo(id: ID!): GitRepo
gitRepos(filter: GitRepoFilter): [GitRepo!]!
}
# Mutations
type Mutation {
createEnterprise(input: CreateEnterpriseInput!): Enterprise!
createPortfolio(input: CreatePortfolioInput!): Portfolio!
createProduct(input: CreateProductInput!): Product!
createApplication(input: CreateApplicationInput!): Application!
createComponent(input: CreateComponentInput!): Component!
createGitRepo(input: CreateGitRepoInput!): GitRepo!
configureBranchProtection(repoId: ID!, branch: String!, protection: BranchProtectionInput!): BranchProtection!
}
```
### REST Endpoints
```
# Content Hierarchy
POST /api/v1/content/enterprises
GET /api/v1/content/enterprises
GET /api/v1/content/enterprises/{id}
POST /api/v1/content/portfolios
GET /api/v1/content/portfolios/{id}
POST /api/v1/content/products
GET /api/v1/content/products/{id}
POST /api/v1/content/applications
GET /api/v1/content/applications/{id}
POST /api/v1/content/components
GET /api/v1/content/components/{id}
# Git Integration
POST /api/v1/content/git-repos
GET /api/v1/content/git-repos
GET /api/v1/content/git-repos/{id}
POST /api/v1/content/git-repos/{id}/branch-protection
```
### Example Queries
#### Create Application
```graphql
mutation {
createApplication(input: {
name: "web-application"
productId: "product-id"
ownership: {
owner: "dev-team"
team: "engineering"
contact: "dev-team@agency.gov"
}
governance: {
approvalWorkflows: [{
name: "code-review"
steps: [{
approver: "tech-lead"
role: "TECH_LEAD"
}]
required: true
}]
complianceTags: ["HIPAA", "SOC_2"]
}
}) {
id
name
product {
id
name
}
}
}
```
#### Create Git Repository
```graphql
mutation {
createGitRepo(input: {
name: "web-application-repo"
applicationId: "application-id"
url: "https://git.sankofa.nexus/web-application"
branchStrategy: {
main: "main"
develop: "develop"
protectedBranches: ["main", "release/*"]
}
}) {
id
name
url
application {
id
name
}
}
}
```
---
## VI. Authentication and Authorization
### Authentication
All APIs use Keycloak for authentication:
```graphql
# Authentication via Keycloak
# Token obtained from Keycloak OAuth2/OIDC flow
# Include in Authorization header: Bearer <token>
```
### Authorization
Authorization is enforced via RBAC:
```graphql
# RBAC roles per plane:
# Commercial: Finance Admin, Billing Viewer, Cost Center Owner
# Tenancy: Tenant Owner, Security Admin, Identity Admin, Compliance Officer
# Subscription: Subscription Owner, Platform Admin, Service Operator, Auditor
# Environment: Environment Owner, Release Manager, Operator, Observer
# Content: Enterprise Architect, Portfolio Lead, Product Owner, Dev Lead, Contributor, Reviewer, Release Approver
```
### Example: Authenticated Request
```bash
curl -X POST https://api.phoenix.sankofa.nexus/graphql \
-H "Authorization: Bearer <keycloak-token>" \
-H "Content-Type: application/json" \
-d '{
"query": "query { tenant(id: \"tenant-id\") { id name } }"
}'
```
---
## VII. Error Handling
### Error Response Format
```json
{
"errors": [
{
"message": "Error message",
"extensions": {
"code": "ERROR_CODE",
"field": "fieldName",
"resource": "ResourceType",
"resourceId": "resource-id"
}
}
],
"data": null
}
```
### Common Error Codes
- `UNAUTHORIZED` - Authentication required
- `FORBIDDEN` - Insufficient permissions
- `NOT_FOUND` - Resource not found
- `VALIDATION_ERROR` - Input validation failed
- `QUOTA_EXCEEDED` - Quota limit exceeded
- `POLICY_VIOLATION` - Policy violation
- `CONFLICT` - Resource conflict
- `INTERNAL_ERROR` - Internal server error
---
## VIII. Rate Limiting
### Rate Limits
- **GraphQL**: 1000 requests per minute per tenant
- **REST**: 500 requests per minute per tenant
- **Billing Queries**: 100 requests per minute per client
- **Promotion Operations**: 50 requests per minute per environment
### Rate Limit Headers
```
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 950
X-RateLimit-Reset: 1640995200
```
---
## IX. Pagination
### GraphQL Pagination
```graphql
type Query {
tenants(
filter: TenantFilter
pagination: PaginationInput
): TenantConnection!
}
type TenantConnection {
edges: [TenantEdge!]!
pageInfo: PageInfo!
totalCount: Int!
}
type TenantEdge {
node: Tenant!
cursor: String!
}
type PageInfo {
hasNextPage: Boolean!
hasPreviousPage: Boolean!
startCursor: String
endCursor: String
}
input PaginationInput {
first: Int
after: String
last: Int
before: String
}
```
### REST Pagination
```
GET /api/v1/tenancy/tenants?page=1&pageSize=50
```
Response:
```json
{
"data": [...],
"pagination": {
"page": 1,
"pageSize": 50,
"totalPages": 10,
"totalCount": 500,
"hasNext": true,
"hasPrevious": false
}
}
```
---
## X. Webhooks and Subscriptions
### GraphQL Subscriptions
```graphql
type Subscription {
clientUpdated(clientId: ID!): Client!
tenantUpdated(tenantId: ID!): Tenant!
subscriptionUpdated(subscriptionId: ID!): Subscription!
environmentUpdated(environmentId: ID!): Environment!
promotionStatusChanged(promotionId: ID!): PromotionResult!
quotaExceeded(subscriptionId: ID!): QuotaAlert!
}
```
### REST Webhooks
```
POST /api/v1/webhooks
GET /api/v1/webhooks
PUT /api/v1/webhooks/{id}
DELETE /api/v1/webhooks/{id}
```
Webhook Events:
- `client.created`
- `client.updated`
- `tenant.created`
- `tenant.updated`
- `subscription.created`
- `subscription.updated`
- `environment.created`
- `environment.updated`
- `promotion.started`
- `promotion.approved`
- `promotion.rejected`
- `quota.exceeded`
---
## XI. Multi-Region Support
### Regional API Endpoints
```
# Primary region
https://api.phoenix.sankofa.nexus
# Regional endpoints
https://api-region-a.phoenix.sankofa.nexus
https://api-region-b.phoenix.sankofa.nexus
https://api-region-c.phoenix.sankofa.nexus
```
### Cross-Region Operations
```graphql
mutation {
createCrossRegionSubscription(input: {
name: "multi-region-sub"
tenantId: "tenant-id"
regions: ["region-a", "region-b"]
regionalQuotas: {
"region-a": {
compute: { vcpu: 50, memory: 256 }
}
"region-b": {
compute: { vcpu: 50, memory: 256 }
}
}
}) {
id
name
regions {
id
name
}
}
}
```
---
## References
- **[Operating Model](./OPERATING_MODEL.md)** - Complete operating model documentation
- **[MVP Control Plane](./MVP_CONTROL_PLANE.md)** - MVP API requirements
- **[Architecture Diagrams](./OPERATING_MODEL_DIAGRAMS.md)** - API integration diagrams
---
**Last Updated**: 2025-01-09
**Version**: 1.0
**Status**: Complete API Specification