{
  "openapi": "3.1.0",
  "info": {
    "title": "Rezzy Public REST API",
    "version": "1",
    "description": "Generated from public NestJS controllers, DTO validators, service response fields, and Prisma status enums. MCP uses a separate protocol; see https://docs.rezzy.dev/mcp."
  },
  "servers": [{ "url": "https://api.rezzy.dev" }],
  "security": [{ "ApiKey": [] }],
  "paths": {
    "/v1/resume/create": {
      "post": {
        "operationId": "create_resume",
        "summary": "Create resume",
        "description": "Costs 5 credits and queues generation. Not idempotent: do not automatically retry after a timeout or lost response. Save the returned ID and poll status.",
        "responses": {
          "202": {
            "description": "Generation accepted",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["success", "message", "data"],
                  "properties": {
                    "success": { "type": "boolean", "const": true },
                    "message": {
                      "type": "string",
                      "const": "Resume creation job has been successfully registered."
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "id",
                        "resume_title",
                        "status",
                        "dashboard_url"
                      ],
                      "properties": {
                        "id": { "type": "string", "format": "uuid" },
                        "resume_title": {
                          "type": "string",
                          "description": "Stored title; duplicate titles receive a suffix such as _1."
                        },
                        "status": {
                          "type": "string",
                          "enum": ["QUEUED", "IN_PROGRESS", "SUCCESS", "FAILED"]
                        },
                        "dashboard_url": { "type": "string", "format": "uri" }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error400" },
          "401": { "$ref": "#/components/responses/Error401" },
          "403": { "$ref": "#/components/responses/Error403" },
          "429": { "$ref": "#/components/responses/Error429" },
          "500": { "$ref": "#/components/responses/Error500" },
          "503": { "$ref": "#/components/responses/Error503" }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/PublicCreateResumeDto" }
            }
          }
        }
      }
    },
    "/v1/resume/{resumeId}": {
      "get": {
        "operationId": "status_resume",
        "summary": "Get resume status",
        "description": "Only documents owned by the API key account are accessible. Costs no generation credits. Poll every five seconds or slower with backoff; stop on SUCCESS or FAILED.",
        "responses": {
          "200": {
            "description": "Status retrieved",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["success", "message", "data"],
                  "properties": {
                    "success": { "type": "boolean", "const": true },
                    "message": {
                      "type": "string",
                      "const": "Resume status retrieved successfully"
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "id",
                        "resume_title",
                        "status",
                        "stage",
                        "pdf_url",
                        "dashboard_url"
                      ],
                      "properties": {
                        "id": { "type": "string", "format": "uuid" },
                        "resume_title": {
                          "type": "string",
                          "description": "Stored title; duplicate titles receive a suffix such as _1."
                        },
                        "status": {
                          "type": "string",
                          "enum": ["QUEUED", "IN_PROGRESS", "SUCCESS", "FAILED"]
                        },
                        "stage": {
                          "type": ["string", "null"],
                          "description": "Current processing stage, if available."
                        },
                        "pdf_url": {
                          "type": ["string", "null"],
                          "format": "uri",
                          "description": "Available after successful generation. Expires after one hour; read status again to refresh."
                        },
                        "dashboard_url": { "type": "string", "format": "uri" }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error400" },
          "401": { "$ref": "#/components/responses/Error401" },
          "404": { "$ref": "#/components/responses/Error404" },
          "429": { "$ref": "#/components/responses/Error429" },
          "500": { "$ref": "#/components/responses/Error500" },
          "503": { "$ref": "#/components/responses/Error503" }
        },
        "parameters": [
          {
            "name": "resumeId",
            "in": "path",
            "required": true,
            "schema": { "type": "string", "format": "uuid" }
          }
        ]
      }
    },
    "/v1/cover-letter/create": {
      "post": {
        "operationId": "create_cover_letter",
        "summary": "Create cover letter",
        "description": "Costs 3 credits and queues generation. Not idempotent: do not automatically retry after a timeout or lost response. Save the returned ID and poll status.",
        "responses": {
          "202": {
            "description": "Generation accepted",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["success", "message", "data"],
                  "properties": {
                    "success": { "type": "boolean", "const": true },
                    "message": {
                      "type": "string",
                      "const": "Cover letter creation job has been successfully registered."
                    },
                    "data": {
                      "type": "object",
                      "required": ["id", "title", "status", "dashboard_url"],
                      "properties": {
                        "id": { "type": "string", "format": "uuid" },
                        "title": {
                          "type": "string",
                          "description": "Stored title; duplicate titles receive a suffix such as _1."
                        },
                        "status": {
                          "type": "string",
                          "enum": ["QUEUED", "IN_PROGRESS", "SUCCESS", "FAILED"]
                        },
                        "dashboard_url": { "type": "string", "format": "uri" }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error400" },
          "401": { "$ref": "#/components/responses/Error401" },
          "403": { "$ref": "#/components/responses/Error403" },
          "429": { "$ref": "#/components/responses/Error429" },
          "500": { "$ref": "#/components/responses/Error500" },
          "503": { "$ref": "#/components/responses/Error503" }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicCreateCoverLetterDto"
              }
            }
          }
        }
      }
    },
    "/v1/cover-letter/{coverLetterId}": {
      "get": {
        "operationId": "status_cover_letter",
        "summary": "Get cover letter status",
        "description": "Only documents owned by the API key account are accessible. Costs no generation credits. Poll every five seconds or slower with backoff; stop on SUCCESS or FAILED.",
        "responses": {
          "200": {
            "description": "Status retrieved",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["success", "message", "data"],
                  "properties": {
                    "success": { "type": "boolean", "const": true },
                    "message": {
                      "type": "string",
                      "const": "Cover letter status retrieved successfully"
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "id",
                        "title",
                        "status",
                        "stage",
                        "pdf_url",
                        "dashboard_url"
                      ],
                      "properties": {
                        "id": { "type": "string", "format": "uuid" },
                        "title": {
                          "type": "string",
                          "description": "Stored title; duplicate titles receive a suffix such as _1."
                        },
                        "status": {
                          "type": "string",
                          "enum": ["QUEUED", "IN_PROGRESS", "SUCCESS", "FAILED"]
                        },
                        "stage": {
                          "type": ["string", "null"],
                          "description": "Current processing stage, if available."
                        },
                        "pdf_url": {
                          "type": ["string", "null"],
                          "format": "uri",
                          "description": "Available after successful generation. Expires after one hour; read status again to refresh."
                        },
                        "dashboard_url": { "type": "string", "format": "uri" }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error400" },
          "401": { "$ref": "#/components/responses/Error401" },
          "404": { "$ref": "#/components/responses/Error404" },
          "429": { "$ref": "#/components/responses/Error429" },
          "500": { "$ref": "#/components/responses/Error500" },
          "503": { "$ref": "#/components/responses/Error503" }
        },
        "parameters": [
          {
            "name": "coverLetterId",
            "in": "path",
            "required": true,
            "schema": { "type": "string", "format": "uuid" }
          }
        ]
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "Rezzy API key from the dashboard"
      }
    },
    "schemas": {
      "PublicCreateResumeDto": {
        "type": "object",
        "required": ["title", "job_description"],
        "properties": {
          "title": { "type": "string", "minLength": 1, "maxLength": "255" },
          "job_description": { "type": "string", "minLength": 1 },
          "company_url": {
            "type": ["string", "null"],
            "maxLength": "500",
            "description": "Reachable public HTTP(S) website. Bare hostnames are accepted; private network addresses are rejected."
          }
        },
        "description": "Unknown fields are stripped. Generation requires a completed profile import."
      },
      "PublicCreateCoverLetterDto": {
        "type": "object",
        "required": ["title", "job_description"],
        "properties": {
          "title": { "type": "string", "minLength": 1, "maxLength": "255" },
          "job_description": { "type": "string", "minLength": 1 },
          "company_url": {
            "type": ["string", "null"],
            "maxLength": "500",
            "description": "Reachable public HTTP(S) website. Bare hostnames are accepted; private network addresses are rejected."
          },
          "hiring_manager_name": { "type": ["string", "null"] },
          "company_street_address": { "type": ["string", "null"] },
          "company_city": { "type": ["string", "null"] },
          "company_state": { "type": ["string", "null"] },
          "company_zip": { "type": ["string", "null"] },
          "hiring_manager_email": { "type": ["string", "null"] },
          "date": {
            "type": ["string", "null"],
            "description": "Valid calendar date, normalized to YYYY-MM-DD. Omitted or blank dates are left unset."
          },
          "additional_context": { "type": ["string", "null"] }
        },
        "description": "Unknown fields are stripped. Generation requires a completed profile import."
      },
      "Error": {
        "type": "object",
        "required": ["success", "message", "data"],
        "properties": {
          "success": { "type": "boolean", "const": false },
          "message": { "type": ["string", "null"] },
          "data": {
            "type": "object",
            "required": ["error_code", "details"],
            "properties": {
              "error_code": { "type": "string" },
              "details": { "type": "object", "additionalProperties": true }
            }
          }
        }
      }
    },
    "responses": {
      "Error400": {
        "description": "Invalid input or business validation failure",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Error" }
          }
        }
      },
      "Error401": {
        "description": "Missing, invalid, expired, or revoked API key",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Error" }
          }
        }
      },
      "Error403": {
        "description": "Insufficient credits",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Error" }
          }
        }
      },
      "Error404": {
        "description": "Document missing or owned by another account",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Error" }
          }
        }
      },
      "Error429": {
        "description": "Request limit exceeded; honor Retry-After",
        "headers": {
          "Retry-After": {
            "description": "Seconds to wait before retrying",
            "schema": { "type": "integer" }
          },
          "X-RateLimit-Remaining": { "schema": { "type": "integer" } },
          "X-RateLimit-Reset": {
            "description": "Unix timestamp in seconds",
            "schema": { "type": "integer" }
          }
        },
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Error" }
          }
        }
      },
      "Error500": {
        "description": "Internal error",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Error" }
          }
        }
      },
      "Error503": {
        "description": "Required service unavailable",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Error" }
          }
        }
      }
    }
  }
}
