{
  "openapi": "3.1.0",
  "info": {
    "title": "Wisprs API",
    "version": "1.0.0",
    "description": "Versioned public API for Wisprs media ingestion, transcription, exports, and transcript repurposing.\n\nVersioning & deprecation policy: all endpoints live under the current major\nprefix `/api/v1/`. Breaking changes ship only under a new major prefix; the\nprevious major stays reachable for at least 6 months. Removed or renamed\nfields are announced in advance and deprecated operations return a\n`Deprecation` and `Sunset` HTTP header while active.\n"
  },
  "servers": [
    {
      "url": "https://wisprs.co",
      "description": "Production"
    },
    {
      "url": "http://localhost:2222",
      "description": "Local development"
    }
  ],
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "wisprs_sk_*"
      },
      "oauth2": {
        "type": "oauth2",
        "description": "OAuth 2.0 authorization-code flow (PKCE) via Clerk for agent/MCP clients.\nIssued tokens carry a subset of the scopes below; the server intersects\nthem with this canonical registry and drops unknown scopes. Production\nOAuth enablement is rollout-gated — bearer API keys work everywhere today.\nDiscovery: https://clerk.wisprs.co/.well-known/openid-configuration\nResource metadata: https://wisprs.co/.well-known/oauth-protected-resource/api/mcp\n",
        "flows": {
          "authorizationCode": {
            "authorizationUrl": "https://clerk.wisprs.co/oauth/authorize",
            "tokenUrl": "https://clerk.wisprs.co/oauth/token",
            "refreshUrl": "https://clerk.wisprs.co/oauth/token",
            "scopes": {
              "transcripts:read": "View transcripts and transcription status in your Wisprs workspace.",
              "transcripts:write": "Create transcriptions and translations in your Wisprs workspace.",
              "transcripts:export": "Export transcripts from your Wisprs workspace.",
              "library:search": "Search your Wisprs transcript library.",
              "ai:transform": "Generate content from transcripts in your Wisprs workspace."
            }
          }
        }
      }
    },
    "schemas": {
      "SuccessEnvelope": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "const": true
          },
          "data": {
            "type": "object"
          }
        },
        "required": [
          "success",
          "data"
        ]
      },
      "JobEnvelope": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "const": true
          },
          "data": {
            "type": "object",
            "properties": {
              "jobId": {
                "type": "integer"
              },
              "status": {
                "type": "string",
                "enum": [
                  "queued",
                  "processing",
                  "completed",
                  "failed"
                ]
              }
            },
            "required": [
              "jobId",
              "status"
            ]
          }
        },
        "required": [
          "success",
          "data"
        ]
      },
      "TranscriptionEnvelope": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "const": true
          },
          "data": {
            "type": "object",
            "properties": {
              "id": {
                "type": "integer"
              },
              "status": {
                "type": "string",
                "enum": [
                  "pending",
                  "processing",
                  "completed",
                  "failed"
                ]
              },
              "text": {
                "type": "string"
              },
              "language": {
                "type": "string"
              },
              "durationSeconds": {
                "type": "number"
              },
              "fileName": {
                "type": "string"
              },
              "createdAt": {
                "type": "string",
                "format": "date-time"
              }
            },
            "required": [
              "id",
              "status"
            ]
          }
        },
        "required": [
          "success",
          "data"
        ]
      },
      "TranscriptListEnvelope": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "const": true
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TranscriptionEnvelope/properties/data"
            }
          }
        },
        "required": [
          "success",
          "data"
        ]
      },
      "ExportFile": {
        "type": "string",
        "format": "binary"
      },
      "ErrorEnvelope": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "const": false
          },
          "error": {
            "type": "string"
          }
        },
        "required": [
          "success",
          "error"
        ]
      }
    }
  },
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "paths": {
    "/api/v1/media/ingest": {
      "post": {
        "operationId": "ingestMediaFromUrl",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "oauth2": [
              "transcripts:write"
            ]
          }
        ],
        "description": "Downloads media from sourceUrl, stores it and enqueues transcription; returns the created job id.",
        "summary": "Ingest media from a public URL and create a transcription job",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "sourceUrl": {
                    "type": "string",
                    "format": "uri"
                  },
                  "fileName": {
                    "type": "string"
                  },
                  "fileType": {
                    "type": "string"
                  },
                  "fileSize": {
                    "type": "integer"
                  },
                  "webhookUrl": {
                    "type": "string",
                    "format": "uri"
                  },
                  "webhookSecret": {
                    "type": "string"
                  }
                },
                "required": [
                  "sourceUrl"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JobEnvelope"
                }
              }
            },
            "description": "Job created"
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/transcriptions": {
      "post": {
        "operationId": "createTranscription",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "oauth2": [
              "transcripts:write"
            ]
          }
        ],
        "description": "Creates a transcription job from a URL source; poll /api/v1/jobs/{id} until complete.",
        "summary": "Create a transcription job from a URL source",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "source": {
                    "type": "object",
                    "properties": {
                      "url": {
                        "type": "string",
                        "format": "uri"
                      }
                    },
                    "required": [
                      "url"
                    ]
                  },
                  "fileName": {
                    "type": "string"
                  },
                  "fileType": {
                    "type": "string"
                  },
                  "fileSize": {
                    "type": "integer"
                  },
                  "webhookUrl": {
                    "type": "string",
                    "format": "uri"
                  },
                  "webhookSecret": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JobEnvelope"
                }
              }
            },
            "description": "Transcription created"
          }
        }
      }
    },
    "/api/v1/transcriptions/{id}": {
      "get": {
        "operationId": "getTranscription",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "oauth2": [
              "transcripts:read"
            ]
          }
        ],
        "description": "Returns the transcript text, metadata and status for one transcription id.",
        "summary": "Fetch one transcription",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TranscriptionEnvelope"
                }
              }
            },
            "description": "Transcription returned"
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/transcriptions/{id}/export": {
      "get": {
        "operationId": "exportTranscript",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "oauth2": [
              "transcripts:export"
            ]
          }
        ],
        "description": "Renders the transcript as txt, srt, vtt, json, md or docx and streams the file.",
        "summary": "Export a transcript in multiple formats",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "integer"
            }
          },
          {
            "in": "query",
            "name": "format",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "txt",
                "srt",
                "vtt",
                "json",
                "md",
                "docx"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/octet-stream": {
                "schema": {
                  "$ref": "#/components/schemas/ExportFile"
                }
              }
            },
            "description": "Export file"
          }
        }
      }
    },
    "/api/v1/transcriptions/{id}/summary": {
      "post": {
        "operationId": "getTranscriptSummary",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "oauth2": [
              "ai:transform"
            ]
          }
        ],
        "description": "Generates (first call) then returns a structured summary of the transcript.",
        "summary": "Generate or fetch a structured summary",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessEnvelope"
                }
              }
            },
            "description": "Summary returned"
          }
        }
      }
    },
    "/api/v1/transcriptions/{id}/chapters": {
      "post": {
        "operationId": "getTranscriptChapters",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "oauth2": [
              "ai:transform"
            ]
          }
        ],
        "description": "Generates (first call) then returns timestamped chapters for the transcript.",
        "summary": "Generate chapters for a completed transcript",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessEnvelope"
                }
              }
            },
            "description": "Chapters returned"
          }
        }
      }
    },
    "/api/v1/transcriptions/{id}/quotes": {
      "post": {
        "operationId": "getTranscriptQuotes",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "oauth2": [
              "ai:transform"
            ]
          }
        ],
        "description": "Generates (first call) then returns notable pull-quotes with timestamps.",
        "summary": "Extract pull-quotes from a completed transcript",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessEnvelope"
                }
              }
            },
            "description": "Quotes returned"
          }
        }
      }
    },
    "/api/v1/transcriptions/{id}/repurpose": {
      "post": {
        "operationId": "repurposeTranscript",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "oauth2": [
              "ai:transform"
            ]
          }
        ],
        "description": "Transforms the transcript into show notes, a thread, a blog draft and more by mode.",
        "summary": "Generate a repurposed artifact from a transcript",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "mode": {
                    "type": "string",
                    "enum": [
                      "summary",
                      "chapters",
                      "quotes",
                      "show-notes",
                      "thread",
                      "blog"
                    ]
                  }
                },
                "required": [
                  "mode"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessEnvelope"
                }
              }
            },
            "description": "Repurposed artifact returned"
          }
        }
      }
    },
    "/api/v1/jobs/{id}": {
      "get": {
        "operationId": "getJobStatus",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "oauth2": [
              "transcripts:read"
            ]
          }
        ],
        "description": "Lightweight polling endpoint for async job state: queued, processing, completed or failed.",
        "summary": "Poll transcription job status",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JobEnvelope"
                }
              }
            },
            "description": "Job status returned"
          }
        }
      }
    },
    "/api/v1/usage": {
      "get": {
        "operationId": "getApiUsage",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "description": "Returns request counts and recent per-request logs scoped to the authenticated API key.",
        "summary": "View API usage and recent request logs for the current key owner",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessEnvelope"
                }
              }
            },
            "description": "Usage returned"
          }
        }
      }
    },
    "/api/v1/library/search": {
      "get": {
        "operationId": "searchLibrary",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "oauth2": [
              "library:search"
            ]
          }
        ],
        "description": "Full-text search across the key owner's transcript library; returns ranked matches.",
        "summary": "Search a user's transcript library",
        "parameters": [
          {
            "in": "query",
            "name": "q",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "limit",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 25
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TranscriptListEnvelope"
                }
              }
            },
            "description": "Matching transcripts returned"
          }
        }
      }
    },
    "/api/v1/webhooks/test": {
      "post": {
        "operationId": "sendTestWebhook",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "description": "Signs and delivers a test event to url so receivers can verify verification logic.",
        "summary": "Send a signed test webhook to a target URL",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "url": {
                    "type": "string",
                    "format": "uri"
                  },
                  "eventType": {
                    "type": "string"
                  },
                  "signingSecret": {
                    "type": "string"
                  }
                },
                "required": [
                  "url"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessEnvelope"
                }
              }
            },
            "description": "Test delivered"
          },
          "502": {
            "description": "Downstream webhook failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/webhooks/endpoints": {
      "get": {
        "operationId": "listWebhookEndpoints",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "description": "Lists webhook endpoints configured for the authenticated API key.",
        "summary": "List configured webhook endpoints",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessEnvelope"
                }
              }
            },
            "description": "Webhook endpoints returned"
          }
        }
      },
      "post": {
        "operationId": "createWebhookEndpoint",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "description": "Registers a new webhook endpoint that will receive signed events.",
        "summary": "Create a webhook endpoint",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "url": {
                    "type": "string",
                    "format": "uri"
                  },
                  "apiKeyId": {
                    "type": "integer"
                  }
                },
                "required": [
                  "url"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessEnvelope"
                }
              }
            },
            "description": "Webhook endpoint created"
          }
        }
      }
    },
    "/api/v1/webhooks/endpoints/{id}": {
      "patch": {
        "operationId": "updateWebhookEndpoint",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "description": "Partially updates a webhook endpoint's target url, key binding or active flag.",
        "summary": "Update a webhook endpoint",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "url": {
                    "type": "string",
                    "format": "uri"
                  },
                  "apiKeyId": {
                    "type": "integer",
                    "nullable": true
                  },
                  "isActive": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessEnvelope"
                }
              }
            },
            "description": "Webhook endpoint updated"
          }
        }
      }
    },
    "/api/v1/webhooks/deliveries": {
      "get": {
        "operationId": "listWebhookDeliveries",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "description": "Returns recent delivery attempts with status, response code and timestamps.",
        "summary": "List recent webhook deliveries",
        "parameters": [
          {
            "in": "query",
            "name": "endpointId",
            "schema": {
              "type": "integer"
            }
          },
          {
            "in": "query",
            "name": "status",
            "schema": {
              "type": "string",
              "enum": [
                "success",
                "failed"
              ]
            }
          },
          {
            "in": "query",
            "name": "limit",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessEnvelope"
                }
              }
            },
            "description": "Delivery history returned"
          }
        }
      }
    },
    "/api/v1/webhooks/deliveries/{id}/retry": {
      "post": {
        "operationId": "retryWebhookDelivery",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "description": "Re-enqueues a failed delivery attempt with a fresh signature.",
        "summary": "Retry a failed webhook delivery",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessEnvelope"
                }
              }
            },
            "description": "Delivery retried"
          },
          "502": {
            "description": "Retry attempt failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/media/uploads/init": {
      "post": {
        "operationId": "initChunkedUpload",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "oauth2": [
              "transcripts:write"
            ]
          }
        ],
        "description": "Starts a chunked upload session and returns upload URLs/parameters.",
        "summary": "Initialize a chunked upload session",
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessEnvelope"
                }
              }
            },
            "description": "Session created"
          }
        }
      }
    },
    "/api/v1/media/uploads/complete": {
      "post": {
        "operationId": "completeChunkedUpload",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "oauth2": [
              "transcripts:write"
            ]
          }
        ],
        "description": "Finalizes a finished chunked upload session and enqueues assembly + transcription.",
        "summary": "Finalize a chunked upload session and enqueue assembly",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JobEnvelope"
                }
              }
            },
            "description": "Assembly queued"
          }
        }
      }
    }
  }
}
