openapi: 3.2.0 info: title: Phi — Protein Design Jobs API description: 'Phi is a biomodal computation platform for protein design. Submit structure-prediction and sequence-design jobs, track their status, and retrieve scored results — all via a single REST API. ## Authentication All endpoints require an API key supplied as `Authorization: Bearer ` or a Clerk session token. Organisation ID is derived automatically from Clerk tokens; static-key callers must include `X-Organization-ID`. ## Quick links - `POST /v1/phi/jobs` — submit a job - `GET /v1/phi/jobs/{job_id}/status` — poll status - `GET /v1/phi/jobs/{job_id}/scores` — download scored results ' version: 1.0.0 servers: - url: https://api.dyno-agents.app description: Production - url: http://localhost:8000 description: Local development tags: - name: jobs paths: /v1/phi/jobs/: get: tags: - jobs summary: List Jobs description: "List all jobs for an organization with pagination and filtering.\n\nArgs:\n org_id: Organization ID from header\n user_id: Optional user ID filter from header\n page: Page number (1-indexed)\n page_size: Number of results per page (max 100)\n status: Optional status filter (pending, running, completed, failed, cancelled)\n job_type: Optional job type filter (esmfold, alphafold, proteinmpnn, etc.)\n dataset_id: Optional dataset ID filter\n db: Database session\n\nReturns:\n JobListResponse with paginated job list" operationId: list_jobs_v1_phi_jobs__get parameters: - name: page in: query required: false schema: type: integer default: 1 title: Page - name: page_size in: query required: false schema: type: integer default: 50 title: Page Size - name: status in: query required: false schema: anyOf: - type: string - type: 'null' title: Status - name: job_type in: query required: false schema: anyOf: - type: string - type: 'null' title: Job Type - name: dataset_id in: query required: false schema: anyOf: - type: string - type: 'null' title: Dataset Id - name: x-api-key in: header required: false schema: anyOf: - type: string - type: 'null' description: API key for authentication title: X-Api-Key description: API key for authentication - name: X-User-ID in: header required: false schema: anyOf: - type: string - type: 'null' title: X-User-Id - name: X-Organization-ID in: header required: false schema: anyOf: - type: string - type: 'null' title: X-Organization-Id responses: '200': description: Successful Response content: application/json: schema: $ref: '#/components/schemas/JobListResponse' '422': description: Validation Error content: application/json: schema: $ref: '#/components/schemas/HTTPValidationError' post: tags: - jobs summary: Submit Job description: "Submit a biomodal job for execution.\n\nThis endpoint submits a single biomodal tool execution (e.g., ESMFold, ProteinMPNN)\nas a Temporal workflow. The job runs asynchronously and status can be polled via\nthe status endpoint.\n\nArgs:\n request: Job submission request with type and parameters\n org_id: Organization ID from header\n user_id: User ID from header\n db: Database session\n\nReturns:\n JobSubmitResponse with job_id and run_id\n\nRaises:\n HTTPException: If validation fails or submission errors occur" operationId: submit_job_v1_phi_jobs__post parameters: - name: x-api-key in: header required: false schema: anyOf: - type: string - type: 'null' description: API key for authentication title: X-Api-Key description: API key for authentication - name: X-User-ID in: header required: false schema: anyOf: - type: string - type: 'null' title: X-User-Id - name: X-Organization-ID in: header required: false schema: anyOf: - type: string - type: 'null' title: X-Organization-Id requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/JobSubmitRequest' responses: '200': description: Successful Response content: application/json: schema: $ref: '#/components/schemas/JobSubmitResponse' '422': description: Validation Error content: application/json: schema: $ref: '#/components/schemas/HTTPValidationError' /v1/phi/jobs/{job_id}/status: get: tags: - jobs summary: Get Job Status description: "Get job execution status.\n\nQueries both the database and Temporal for the most up-to-date status information.\n\nArgs:\n job_id: Job ID (UUID)\n org_id: Organization ID from header\n db: Database session\n\nReturns:\n JobStatusResponse with current status and progress\n\nRaises:\n HTTPException: If job not found or query fails" operationId: get_job_status_v1_phi_jobs__job_id__status_get parameters: - name: job_id in: path required: true schema: type: string title: Job Id - name: include_assets in: query required: false schema: type: boolean default: false title: Include Assets - name: x-api-key in: header required: false schema: anyOf: - type: string - type: 'null' description: API key for authentication title: X-Api-Key description: API key for authentication - name: X-User-ID in: header required: false schema: anyOf: - type: string - type: 'null' title: X-User-Id - name: X-Organization-ID in: header required: false schema: anyOf: - type: string - type: 'null' title: X-Organization-Id responses: '200': description: Successful Response content: application/json: schema: $ref: '#/components/schemas/JobStatusResponse' '422': description: Validation Error content: application/json: schema: $ref: '#/components/schemas/HTTPValidationError' /v1/phi/jobs/{job_id}/logs/stream: get: tags: - jobs summary: Stream Job Logs description: "Stream job logs via Server-Sent Events (SSE).\n\nThis endpoint provides real-time log streaming for a running job.\nLogs are aggregated from Temporal workflow events and GCS log files.\n\nThe stream continues until the job completes or the client disconnects.\n\nArgs:\n job_id: Job ID (UUID)\n org_id: Organization ID from header\n request: FastAPI request object (for disconnect detection)\n db: Database session\n\nReturns:\n StreamingResponse with text/event-stream content\n\nRaises:\n HTTPException: If job not found or access denied\n\nExample:\n # Using curl\n curl -N -H \"X-Organization-ID: org123\" http://api.example.com/v1/phi/jobs/{job_id}/logs/stream\n\n # Using EventSource in JavaScript\n const eventSource = new EventSource(\n `/v1/phi/jobs/${jobId}/logs/stream`,\n { headers: { 'X-Organization-ID': orgId } }\n );\n eventSource.onmessage = (event) => {\n const log = JSON.parse(event.data);\n console.log(log.message);\n };" operationId: stream_job_logs_v1_phi_jobs__job_id__logs_stream_get parameters: - name: job_id in: path required: true schema: type: string title: Job Id - name: x-api-key in: header required: false schema: anyOf: - type: string - type: 'null' description: API key for authentication title: X-Api-Key description: API key for authentication - name: X-User-ID in: header required: false schema: anyOf: - type: string - type: 'null' title: X-User-Id - name: X-Organization-ID in: header required: false schema: anyOf: - type: string - type: 'null' title: X-Organization-Id responses: '200': description: Successful Response content: application/json: schema: {} '422': description: Validation Error content: application/json: schema: $ref: '#/components/schemas/HTTPValidationError' /v1/phi/jobs/batch: post: tags: - jobs summary: Submit Batch Jobs description: "Submit multiple biomodal jobs in a batch.\n\nThis endpoint allows submitting multiple jobs at once, with partial failure handling.\nEach job is submitted independently, and failures don't prevent other jobs from being submitted.\n\nArgs:\n requests: List of job submission requests\n org_id: Organization ID from header\n user_id: User ID from header\n db: Database session\n\nReturns:\n BatchJobSubmitResponse with batch_id and per-job results\n\nExample:\n ```json\n {\n \"requests\": [\n {\n \"job_type\": \"esmfold\",\n \"params\": {\"fasta_str\": \">seq1\\nMKVLWAAS\"}\n },\n {\n \"job_type\": \"alphafold\",\n \"params\": {\"fasta_str\": \">seq2\\nGKVFWAAS\"}\n }\n ]\n }\n ```" operationId: submit_batch_jobs_v1_phi_jobs_batch_post parameters: - name: x-api-key in: header required: false schema: anyOf: - type: string - type: 'null' description: API key for authentication title: X-Api-Key description: API key for authentication - name: X-User-ID in: header required: false schema: anyOf: - type: string - type: 'null' title: X-User-Id - name: X-Organization-ID in: header required: false schema: anyOf: - type: string - type: 'null' title: X-Organization-Id requestBody: required: true content: application/json: schema: type: array items: $ref: '#/components/schemas/JobSubmitRequest' maxItems: 50 title: Requests responses: '200': description: Successful Response content: application/json: schema: $ref: '#/components/schemas/BatchJobSubmitResponse' '422': description: Validation Error content: application/json: schema: $ref: '#/components/schemas/HTTPValidationError' /v1/phi/jobs/{job_id}: delete: tags: - jobs summary: Cancel Job description: "Cancel a running job.\n\nAttempts to cancel a job by terminating its Temporal workflow.\nJobs that have already completed cannot be cancelled.\n\nArgs:\n job_id: Job ID (UUID)\n org_id: Organization ID from header\n db: Database session\n\nReturns:\n JobCancelResponse with cancellation status\n\nRaises:\n HTTPException: If job not found, access denied, or cancellation fails" operationId: cancel_job_v1_phi_jobs__job_id__delete parameters: - name: job_id in: path required: true schema: type: string title: Job Id - name: x-api-key in: header required: false schema: anyOf: - type: string - type: 'null' description: API key for authentication title: X-Api-Key description: API key for authentication - name: X-User-ID in: header required: false schema: anyOf: - type: string - type: 'null' title: X-User-Id - name: X-Organization-ID in: header required: false schema: anyOf: - type: string - type: 'null' title: X-Organization-Id responses: '200': description: Successful Response content: application/json: schema: $ref: '#/components/schemas/JobCancelResponse' '422': description: Validation Error content: application/json: schema: $ref: '#/components/schemas/HTTPValidationError' /v1/phi/jobs/{job_id}/assets/create: post: tags: - jobs summary: Manually Create Assets description: "Manually trigger asset creation for a completed job.\n\nUse this endpoint if automatic asset creation failed during job completion.\nThis is a fallback mechanism for debugging and recovery.\n\nArgs:\n job_id: Job ID\n org_id: Organization ID from header\n db: Database session\n\nReturns:\n Asset creation result with asset_group_id and assets_url\n\nRaises:\n HTTPException: If job not found, not completed, or asset creation fails" operationId: manually_create_assets_v1_phi_jobs__job_id__assets_create_post parameters: - name: job_id in: path required: true schema: type: string title: Job Id - name: x-api-key in: header required: false schema: anyOf: - type: string - type: 'null' description: API key for authentication title: X-Api-Key description: API key for authentication - name: X-User-ID in: header required: false schema: anyOf: - type: string - type: 'null' title: X-User-Id - name: X-Organization-ID in: header required: false schema: anyOf: - type: string - type: 'null' title: X-Organization-Id responses: '200': description: Successful Response content: application/json: schema: type: object additionalProperties: true title: Response Manually Create Assets V1 Phi Jobs Job Id Assets Create Post '422': description: Validation Error content: application/json: schema: $ref: '#/components/schemas/HTTPValidationError' /v1/phi/jobs/{job_id}/scores: get: tags: - jobs summary: Get Job Scores description: Return a signed download URL for the scores.csv produced by a design_pipeline job. operationId: get_job_scores_v1_phi_jobs__job_id__scores_get parameters: - name: job_id in: path required: true schema: type: string title: Job Id - name: expires_in in: query required: false schema: type: integer default: 3600 title: Expires In - name: x-api-key in: header required: false schema: anyOf: - type: string - type: 'null' description: API key for authentication title: X-Api-Key description: API key for authentication - name: X-User-ID in: header required: false schema: anyOf: - type: string - type: 'null' title: X-User-Id - name: X-Organization-ID in: header required: false schema: anyOf: - type: string - type: 'null' title: X-Organization-Id responses: '200': description: Successful Response content: application/json: schema: $ref: '#/components/schemas/ScoresDownloadResponse' '422': description: Validation Error content: application/json: schema: $ref: '#/components/schemas/HTTPValidationError' components: schemas: JobType: type: string enum: - esmfold - proteinmpnn - alphafold - rfdiffusion - ligandmpnn - chai1 - boltz - align_structures - tm_score - af2rank - rso - bindcraft - rf3 - rfdiffusion3 - boltzgen - esm2 - openfold3 - research - design_pipeline - filter_pipeline title: JobType description: Available biomodal job types. HTTPValidationError: properties: detail: items: $ref: '#/components/schemas/ValidationError' type: array title: Detail type: object title: HTTPValidationError JobCancelResponse: properties: job_id: type: string title: Job Id status: type: string title: Status message: type: string title: Message type: object required: - job_id - status - message title: JobCancelResponse description: Response for job cancellation. ScoresDownloadResponse: properties: job_id: type: string title: Job Id artifact_id: anyOf: - type: string - type: 'null' title: Artifact Id download_url: anyOf: - type: string - type: 'null' title: Download Url filename: type: string title: Filename expires_in: type: integer title: Expires In type: object required: - job_id - artifact_id - download_url - filename - expires_in title: ScoresDownloadResponse JobStatusResponse: properties: job_id: type: string title: Job Id description: Database job ID run_id: type: string title: Run Id description: Temporal workflow run ID status: $ref: '#/components/schemas/JobStatus' description: Current job status progress: anyOf: - $ref: '#/components/schemas/JobProgress' - type: 'null' description: Progress information (if job is running) output_files: anyOf: - items: additionalProperties: true type: object type: array - type: 'null' title: Output Files description: Output files (available when job completes) outputs: anyOf: - additionalProperties: true type: object - type: 'null' title: Outputs description: Inline text/structured outputs (e.g. report_md, citations for research jobs) assets_url: anyOf: - type: string - type: 'null' title: Assets Url description: URL to fetch assets for this job (e.g., /assets/runs/{run_id}/assets) asset_count: type: integer title: Asset Count description: Number of assets created for this job default: 0 asset_group: anyOf: - additionalProperties: true type: object - type: 'null' title: Asset Group description: Asset group (included when include_assets=true) assets: anyOf: - items: additionalProperties: true type: object type: array - type: 'null' title: Assets description: Assets created for this job (included when include_assets=true) error: anyOf: - type: string - type: 'null' title: Error description: Error message (if job failed) created_at: type: string format: date-time title: Created At description: Job creation timestamp started_at: anyOf: - type: string format: date-time - type: 'null' title: Started At description: Job start timestamp completed_at: anyOf: - type: string format: date-time - type: 'null' title: Completed At description: Job completion timestamp type: object required: - job_id - run_id - status - created_at title: JobStatusResponse description: Response with job status information. ValidationError: properties: loc: items: anyOf: - type: string - type: integer type: array title: Location msg: type: string title: Message type: type: string title: Error Type type: object required: - loc - msg - type title: ValidationError JobSubmitResponse: properties: job_id: type: string title: Job Id description: Database job ID (UUID) run_id: type: string title: Run Id description: Temporal workflow run ID status: type: string title: Status description: Initial job status (typically 'submitted' or 'pending') estimated_duration: anyOf: - type: integer - type: 'null' title: Estimated Duration description: Estimated execution time in seconds (if available) message: type: string title: Message description: Human-readable status message type: object required: - job_id - run_id - status - message title: JobSubmitResponse description: Response from job submission. JobStatus: type: string enum: - pending - running - completed - failed - cancelled title: JobStatus description: Job execution status. JobProgress: properties: current_step: type: string title: Current Step description: Current execution step (e.g., 'folding sequence 5/10') percent_complete: type: integer maximum: 100.0 minimum: 0.0 title: Percent Complete description: Progress percentage eta_seconds: anyOf: - type: integer - type: 'null' title: Eta Seconds description: Estimated time to completion in seconds type: object required: - current_step - percent_complete title: JobProgress description: Job execution progress information. JobListResponse: properties: jobs: items: additionalProperties: true type: object type: array title: Jobs total_count: type: integer title: Total Count total_pending: type: integer title: Total Pending total_running: type: integer title: Total Running total_completed: type: integer title: Total Completed total_failed: type: integer title: Total Failed message: anyOf: - type: string - type: 'null' title: Message type: object required: - jobs - total_count - total_pending - total_running - total_completed - total_failed title: JobListResponse description: Response for list of jobs. JobSubmitRequest: properties: job_type: $ref: '#/components/schemas/JobType' description: Type of biomodal job to execute params: additionalProperties: true type: object title: Params description: Tool-specific parameters (validated against Modal function signature) input_files: anyOf: - additionalProperties: type: string type: object - type: 'null' title: Input Files description: Input files as artifact_name -> GCS URI mapping run_id: anyOf: - type: string - type: 'null' title: Run Id description: Optional custom run_id (generated if not provided) priority: type: integer maximum: 10.0 minimum: 0.0 title: Priority description: Job priority (0=lowest, 10=highest) default: 0 context: additionalProperties: true type: object title: Context description: Additional context (e.g., project_id for asset creation) dataset_id: anyOf: - type: string - type: 'null' title: Dataset Id description: Dataset ID to run the job against (batch mode). Mutually exclusive with inline fasta_str / pdb_content in params. type: object required: - job_type title: JobSubmitRequest description: Request to submit a biomodal job. BatchJobSubmitResponse: properties: job_ids: items: type: string type: array title: Job Ids total_count: type: integer title: Total Count type: object required: - job_ids - total_count title: BatchJobSubmitResponse description: Response for batch job submission.