{
  "openapi": "3.1.0",
  "info": {
    "title": "Unformal API",
    "version": "1.0.0",
    "description": "Create and manage Conversations (Pulses) programmatically. Unformal replaces forms with adaptive AI Conversations. Authenticate with a Bearer API key (`unf_*`). Get a key via POST /signup with no prior auth.",
    "contact": {
      "name": "Unformal",
      "email": "hello@unformal.ai",
      "url": "https://unformal.ai/contact"
    },
    "x-logo": "https://unformal.ai/pulse-screenshot.png"
  },
  "servers": [
    {
      "url": "https://unformal.ai/api/v1",
      "description": "Production"
    }
  ],
  "tags": [
    {
      "name": "Auth",
      "description": "Account creation and API key management"
    },
    {
      "name": "Pulses",
      "description": "Create and manage Pulses (Conversations)"
    },
    {
      "name": "Conversations",
      "description": "Read transcripts and Echo structured data"
    },
    {
      "name": "Usage",
      "description": "Credits and usage stats"
    }
  ],
  "paths": {
    "/signup": {
      "post": {
        "operationId": "createAccount",
        "summary": "Create account and API key",
        "description": "No authentication required. Returns a Bearer API key and 50 free credits.",
        "tags": [
          "Auth"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email"
                  },
                  "workspaceName": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Account created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SignupResponse"
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "409": {
            "description": "Email already registered",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/verify": {
      "post": {
        "operationId": "verifyEmail",
        "summary": "Verify signup email code",
        "description": "Complete email verification after signup.",
        "tags": [
          "Auth"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email",
                  "code"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email"
                  },
                  "code": {
                    "type": "string",
                    "description": "6-digit verification code"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Email verified"
          },
          "400": {
            "description": "Invalid code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/login": {
      "post": {
        "operationId": "requestLoginCode",
        "summary": "Request login code",
        "description": "Send a 6-digit code to an existing account email.",
        "tags": [
          "Auth"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Code sent if account exists"
          }
        }
      }
    },
    "/login/verify": {
      "post": {
        "operationId": "verifyLoginCode",
        "summary": "Verify login code and mint API key",
        "description": "Returns a fresh Bearer API key.",
        "tags": [
          "Auth"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email",
                  "code"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email"
                  },
                  "code": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Fresh API key returned"
          },
          "400": {
            "description": "Invalid code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/pulses": {
      "get": {
        "operationId": "listPulses",
        "summary": "List Pulses",
        "description": "List all Pulses in the authenticated workspace.",
        "tags": [
          "Pulses"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Pulse list"
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createPulse",
        "summary": "Create a Pulse",
        "description": "Create a Pulse from an intention string. Auto-generates interview config and returns a shareable URL.",
        "tags": [
          "Pulses"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreatePulseRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Pulse created"
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "402": {
            "description": "Out of credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/pulses/{id}": {
      "get": {
        "operationId": "getPulse",
        "summary": "Get Pulse",
        "description": "Get Pulse details and configuration.",
        "tags": [
          "Pulses"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Pulse details"
          },
          "404": {
            "description": "Pulse not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": {
                    "code": "NOT_FOUND",
                    "message": "Pulse not found"
                  }
                }
              }
            }
          }
        }
      },
      "patch": {
        "operationId": "updatePulse",
        "summary": "Update Pulse",
        "description": "Update Pulse configuration fields.",
        "tags": [
          "Pulses"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdatePulseRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Pulse updated"
          },
          "404": {
            "description": "Pulse not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "archivePulse",
        "summary": "Archive Pulse",
        "description": "Archive a Pulse.",
        "tags": [
          "Pulses"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Pulse archived"
          },
          "404": {
            "description": "Pulse not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/pulses/{id}/publish": {
      "post": {
        "operationId": "publishPulse",
        "summary": "Publish Pulse",
        "description": "Publish a draft Pulse.",
        "tags": [
          "Pulses"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Pulse published"
          },
          "404": {
            "description": "Pulse not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/pulses/{id}/conversations": {
      "get": {
        "operationId": "listConversations",
        "summary": "List conversations",
        "description": "List completed conversations for a Pulse.",
        "tags": [
          "Conversations"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Conversation list"
          },
          "404": {
            "description": "Pulse not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/pulses/{id}/export": {
      "get": {
        "operationId": "exportConversations",
        "summary": "Export conversations",
        "description": "Export conversations as CSV or JSON.",
        "tags": [
          "Conversations"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Export file"
          },
          "404": {
            "description": "Pulse not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/pulses/{id}/stream": {
      "get": {
        "operationId": "streamConversations",
        "summary": "Stream conversation events",
        "description": "Server-sent events when conversations complete.",
        "tags": [
          "Conversations"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "text/event-stream"
          }
        }
      }
    },
    "/conversations/{id}": {
      "get": {
        "operationId": "getConversation",
        "summary": "Get conversation",
        "description": "Full transcript plus Echo structured extraction.",
        "tags": [
          "Conversations"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Conversation details"
          },
          "404": {
            "description": "Conversation not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/usage": {
      "get": {
        "operationId": "getUsage",
        "summary": "Get usage",
        "description": "Credit balance and usage statistics.",
        "tags": [
          "Usage"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Usage stats"
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "unf_*",
        "description": "Bearer API key. Obtain via POST /signup (no auth) or POST /login/verify. Not OAuth — machine clients use API keys."
      }
    },
    "parameters": {
      "PulseId": {
        "name": "id",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        },
        "description": "Pulse ID"
      },
      "ConversationId": {
        "name": "id",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        },
        "description": "Conversation ID"
      }
    },
    "schemas": {
      "ErrorResponse": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string",
                "description": "Machine-readable error code"
              },
              "message": {
                "type": "string",
                "description": "Human-readable error message"
              },
              "hint": {
                "type": "string",
                "description": "How to resolve the error"
              }
            }
          }
        }
      },
      "SignupResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "object",
            "properties": {
              "api_key": {
                "type": "string"
              },
              "workspace_id": {
                "type": "string"
              },
              "email": {
                "type": "string"
              },
              "credits": {
                "type": "integer"
              }
            }
          }
        }
      },
      "CreatePulseRequest": {
        "type": "object",
        "required": [
          "intention"
        ],
        "properties": {
          "intention": {
            "type": "string",
            "description": "What the AI should learn from the respondent"
          },
          "slug": {
            "type": "string"
          },
          "context": {
            "type": "string"
          },
          "mode": {
            "type": "string",
            "enum": [
              "interview",
              "extract"
            ]
          },
          "tone": {
            "type": "string"
          },
          "maxDurationMin": {
            "type": "integer"
          },
          "maxQuestions": {
            "type": "integer"
          },
          "webhookUrl": {
            "type": "string",
            "format": "uri"
          },
          "outputFields": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string"
                },
                "type": {
                  "type": "string"
                },
                "description": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "UpdatePulseRequest": {
        "type": "object",
        "properties": {
          "intention": {
            "type": "string"
          },
          "context": {
            "type": "string"
          },
          "webhookUrl": {
            "type": "string"
          }
        }
      }
    }
  },
  "x-auth": {
    "type": "bearer_api_key",
    "signup": "https://unformal.ai/api/v1/signup",
    "documentation": "https://unformal.ai/docs/api.md",
    "openapi": "https://unformal.ai/openapi.json"
  }
}