{
  "openapi": "3.1.0",
  "info": {
    "title": "Clidelity Public API",
    "version": "2026-08-25",
    "summary": "The public HTTP endpoints behind Clidelity's intake, screening, and testimonial pages.",
    "description": "Clidelity is an AI sales system for women coaches and consultants. These endpoints power the product's own public pages: prospect intake, the screening chat bootstrap, testimonial and approval links, and invite-gated signup. They are rate limited per IP and addressed by capability tokens or public slugs carried in the request body, so no Authorization header is used here. They are not a general-purpose CRUD API. An agent working on a coach's behalf should prefer the MCP server at https://clidelity.com/mcp, which exposes read-only tools over her workspace behind OAuth. Every error response is JSON with the shape in components.schemas.Error. Versioning: the API is versioned by date. Every response carries the current version in the Clidelity-Api-Version header. A client may pin a version by sending the same header on the request, and an unknown pin is refused with a 400 naming the supported versions, so a pin never drifts silently. Breaking changes ship under a new version date. A deprecated version or operation keeps working for at least 90 days after the replacement ships, is marked deprecated in this document, and signals retirement in responses with the Deprecation header and a Sunset header carrying the retirement date, per RFC 8594. Nothing is deprecated today. Rate limiting: every response carries the RateLimit and RateLimit-Policy header fields from the IETF RateLimit headers draft, with the legacy RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset names alongside, and a 429 carries Retry-After in seconds. Limits are per IP on a fixed one-hour window, with each operation's budget in its description.",
    "contact": {
      "name": "Clidelity",
      "email": "hello@khudco.com",
      "url": "https://clidelity.com/contact"
    },
    "termsOfService": "https://clidelity.com/terms"
  },
  "externalDocs": {
    "description": "Clidelity agent integration guide",
    "url": "https://clidelity.com/docs/agents.md"
  },
  "servers": [
    {
      "url": "https://clidelity.com"
    }
  ],
  "tags": [
    {
      "name": "intake",
      "description": "The public prospect intake flow"
    },
    {
      "name": "testimonials",
      "description": "Token-addressed testimonial and approval links"
    },
    {
      "name": "voice",
      "description": "Token-addressed voice recording management"
    },
    {
      "name": "account",
      "description": "Invite-gated signup"
    }
  ],
  "paths": {
    "/api/public/get-coach": {
      "post": {
        "operationId": "getCoachBySlug",
        "tags": [
          "intake"
        ],
        "summary": "Resolve a coach slug to intake-page display fields",
        "description": "Returns the display data the public intake page needs for one coach, resolved from her public slug. Rate limited to 60 requests per hour per IP.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "slug"
                ],
                "properties": {
                  "slug": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "pattern": "^[a-z0-9-]+$",
                    "description": "The coach's public booking slug, the path segment of her intake link"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Coach display fields",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "name": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "business_name": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "one_liner": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "logo_url": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Public logo URL, or null when hidden or absent"
                    },
                    "intake_ground": {
                      "type": "string",
                      "description": "The intake page's background theme key"
                    },
                    "calendar_connected": {
                      "type": "boolean",
                      "description": "True when a healthy calendar connection makes manual booking fields unnecessary"
                    }
                  }
                }
              }
            },
            "headers": {
              "Clidelity-Api-Version": {
                "$ref": "#/components/headers/ClidelityApiVersion"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "400": {
            "description": "Invalid JSON or input",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Clidelity-Api-Version": {
                "$ref": "#/components/headers/ClidelityApiVersion"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "404": {
            "description": "No coach carries that slug",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Clidelity-Api-Version": {
                "$ref": "#/components/headers/ClidelityApiVersion"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "429": {
            "description": "Rate limit reached",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Clidelity-Api-Version": {
                "$ref": "#/components/headers/ClidelityApiVersion"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            }
          },
          "500": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Clidelity-Api-Version": {
                "$ref": "#/components/headers/ClidelityApiVersion"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/ClidelityApiVersion"
          }
        ]
      }
    },
    "/api/public/create-prospect": {
      "post": {
        "operationId": "createProspect",
        "tags": [
          "intake"
        ],
        "summary": "Create a prospect for a coach and start her intake",
        "description": "Creates the prospect row the screening chat runs against. The returned id is the credential for the screening flow, so treat it as a secret. An active prospect with the same email for the same coach is archived first, which keeps the coach's pipeline to one live row per person. Rate limited to 10 requests per hour per IP.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "coach_slug",
                  "name",
                  "email"
                ],
                "properties": {
                  "coach_slug": {
                    "type": "string",
                    "description": "The coach's public slug"
                  },
                  "name": {
                    "type": "string",
                    "maxLength": 200
                  },
                  "email": {
                    "type": "string",
                    "format": "email",
                    "maxLength": 255
                  },
                  "appointment_at": {
                    "type": "string",
                    "description": "Optional booked call time, as entered",
                    "maxLength": 64
                  },
                  "appointment_timezone": {
                    "type": "string",
                    "description": "Optional IANA timezone for the booked call",
                    "maxLength": 64
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The new prospect",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "id"
                  ],
                  "properties": {
                    "id": {
                      "type": "string",
                      "format": "uuid",
                      "description": "The prospect id, which addresses the screening chat"
                    }
                  }
                }
              }
            },
            "headers": {
              "Clidelity-Api-Version": {
                "$ref": "#/components/headers/ClidelityApiVersion"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "400": {
            "description": "Invalid JSON or input, details carries field errors when present",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Clidelity-Api-Version": {
                "$ref": "#/components/headers/ClidelityApiVersion"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "404": {
            "description": "No coach carries that slug",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Clidelity-Api-Version": {
                "$ref": "#/components/headers/ClidelityApiVersion"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "429": {
            "description": "Rate limit reached",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Clidelity-Api-Version": {
                "$ref": "#/components/headers/ClidelityApiVersion"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            }
          },
          "500": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Clidelity-Api-Version": {
                "$ref": "#/components/headers/ClidelityApiVersion"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/ClidelityApiVersion"
          }
        ]
      }
    },
    "/api/public/get-prospect": {
      "post": {
        "operationId": "getProspect",
        "tags": [
          "intake"
        ],
        "summary": "Bootstrap the screening chat for one prospect",
        "description": "Returns the screening page's data for a prospect id. The id itself is the credential, returned by createProspect or carried in the intake link the coach shared. Rate limited to 60 requests per hour per IP.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "prospect_id"
                ],
                "properties": {
                  "prospect_id": {
                    "type": "string",
                    "format": "uuid"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Prospect screening state",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "name": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "appointment_at": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "appointment_timezone": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "transcript": {
                      "type": [
                        "array",
                        "null"
                      ],
                      "items": {
                        "type": "object"
                      },
                      "description": "The screening conversation so far"
                    },
                    "flags": {
                      "type": [
                        "array",
                        "null"
                      ],
                      "items": {
                        "type": "string"
                      }
                    },
                    "status": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "summary": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "coach_name": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "coach_headshot_url": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "intake_ground": {
                      "type": "string"
                    }
                  }
                }
              }
            },
            "headers": {
              "Clidelity-Api-Version": {
                "$ref": "#/components/headers/ClidelityApiVersion"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "400": {
            "description": "Invalid JSON or input",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Clidelity-Api-Version": {
                "$ref": "#/components/headers/ClidelityApiVersion"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "404": {
            "description": "No prospect carries that id",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Clidelity-Api-Version": {
                "$ref": "#/components/headers/ClidelityApiVersion"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "429": {
            "description": "Rate limit reached",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Clidelity-Api-Version": {
                "$ref": "#/components/headers/ClidelityApiVersion"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            }
          },
          "500": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Clidelity-Api-Version": {
                "$ref": "#/components/headers/ClidelityApiVersion"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/ClidelityApiVersion"
          }
        ]
      }
    },
    "/api/public/signup": {
      "post": {
        "operationId": "redeemInviteSignup",
        "tags": [
          "account"
        ],
        "summary": "Create a coach account from an invitation",
        "description": "Signup is invite-gated during the founding cohort. The invite token reserves a seat atomically, the account is created, and the seat is released if creation fails. Rate limited to 10 requests per hour per IP, and this limiter fails closed.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "invite",
                  "name",
                  "email",
                  "password",
                  "accepted"
                ],
                "properties": {
                  "invite": {
                    "type": "string",
                    "description": "The invitation token"
                  },
                  "name": {
                    "type": "string",
                    "maxLength": 200
                  },
                  "business_name": {
                    "type": "string",
                    "maxLength": 200
                  },
                  "email": {
                    "type": "string",
                    "format": "email"
                  },
                  "password": {
                    "type": "string",
                    "minLength": 12
                  },
                  "accepted": {
                    "type": "boolean",
                    "const": true,
                    "description": "Must be true, records Terms and Privacy acceptance"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Account created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    }
                  }
                }
              }
            },
            "headers": {
              "Clidelity-Api-Version": {
                "$ref": "#/components/headers/ClidelityApiVersion"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "400": {
            "description": "Invalid JSON or input, or the invitation is not valid",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Clidelity-Api-Version": {
                "$ref": "#/components/headers/ClidelityApiVersion"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "429": {
            "description": "Rate limit reached",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Clidelity-Api-Version": {
                "$ref": "#/components/headers/ClidelityApiVersion"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            }
          },
          "500": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Clidelity-Api-Version": {
                "$ref": "#/components/headers/ClidelityApiVersion"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/ClidelityApiVersion"
          }
        ]
      }
    },
    "/api/public/testimonial": {
      "post": {
        "operationId": "testimonialGetOrSubmit",
        "tags": [
          "testimonials"
        ],
        "summary": "Read or submit a testimonial by request token",
        "description": "One endpoint, two actions. get returns the page state for the token, including any voice transcript once transcription lands. submit closes the testimonial once, with the client's words, name choice, and consent scope. Rate limited to 300 requests per hour per IP, sized for transcript polling.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "token",
                  "action"
                ],
                "properties": {
                  "token": {
                    "type": "string",
                    "format": "uuid",
                    "description": "The request token from the link the coach shared"
                  },
                  "action": {
                    "type": "string",
                    "enum": [
                      "get",
                      "submit"
                    ]
                  },
                  "content": {
                    "type": "string",
                    "description": "submit only, the testimonial text"
                  },
                  "client_name": {
                    "type": "string",
                    "description": "submit only, required unless anonymous"
                  },
                  "consent_scope": {
                    "type": "string",
                    "enum": [
                      "full_name",
                      "first_name",
                      "anonymous"
                    ],
                    "description": "submit only"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Page state for get, or ok true for submit",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "type": "object",
                      "properties": {
                        "status": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "submitted": {
                          "type": "boolean"
                        },
                        "coach_name": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "business_name": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "client_first_name": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "transcript": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "capture_status": {
                          "type": [
                            "string",
                            "null"
                          ]
                        }
                      }
                    },
                    {
                      "type": "object",
                      "required": [
                        "ok"
                      ],
                      "properties": {
                        "ok": {
                          "type": "boolean"
                        }
                      }
                    }
                  ]
                }
              }
            },
            "headers": {
              "Clidelity-Api-Version": {
                "$ref": "#/components/headers/ClidelityApiVersion"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "400": {
            "description": "Invalid input, missing consent fields, or the testimonial was already submitted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Clidelity-Api-Version": {
                "$ref": "#/components/headers/ClidelityApiVersion"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "404": {
            "description": "The token does not address a testimonial request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Clidelity-Api-Version": {
                "$ref": "#/components/headers/ClidelityApiVersion"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "429": {
            "description": "Rate limit reached",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Clidelity-Api-Version": {
                "$ref": "#/components/headers/ClidelityApiVersion"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            }
          },
          "500": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Clidelity-Api-Version": {
                "$ref": "#/components/headers/ClidelityApiVersion"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/ClidelityApiVersion"
          }
        ]
      }
    },
    "/api/public/feedback-approval": {
      "post": {
        "operationId": "feedbackApprovalDecide",
        "tags": [
          "testimonials"
        ],
        "summary": "Approve or decline sharing a mined quote, by permission token",
        "description": "One endpoint, three actions. get returns the quote and its state. approve promotes the quote to an approved testimonial with the client's name choice. decline is terminal and is never asked about again. A decided request answers 400 to further decisions. Rate limited to 30 requests per hour per IP.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "token",
                  "action"
                ],
                "properties": {
                  "token": {
                    "type": "string",
                    "format": "uuid",
                    "description": "The permission token from the may-I-share email"
                  },
                  "action": {
                    "type": "string",
                    "enum": [
                      "get",
                      "approve",
                      "decline"
                    ]
                  },
                  "client_name": {
                    "type": "string",
                    "description": "approve only, required unless anonymous"
                  },
                  "consent_scope": {
                    "type": "string",
                    "enum": [
                      "full_name",
                      "first_name",
                      "anonymous"
                    ],
                    "description": "approve only"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Quote state for get, or the decision receipt",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "type": "object",
                      "properties": {
                        "quote": {
                          "type": "string"
                        },
                        "coach_name": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "client_first_name": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "decided": {
                          "type": "boolean"
                        },
                        "declined": {
                          "type": "boolean"
                        }
                      }
                    },
                    {
                      "type": "object",
                      "properties": {
                        "ok": {
                          "type": "boolean"
                        },
                        "approved": {
                          "type": "boolean"
                        },
                        "declined": {
                          "type": "boolean"
                        }
                      }
                    }
                  ]
                }
              }
            },
            "headers": {
              "Clidelity-Api-Version": {
                "$ref": "#/components/headers/ClidelityApiVersion"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "400": {
            "description": "Invalid input, missing consent fields, or the request was already answered",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Clidelity-Api-Version": {
                "$ref": "#/components/headers/ClidelityApiVersion"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "404": {
            "description": "The token does not address a share request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Clidelity-Api-Version": {
                "$ref": "#/components/headers/ClidelityApiVersion"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "429": {
            "description": "Rate limit reached",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Clidelity-Api-Version": {
                "$ref": "#/components/headers/ClidelityApiVersion"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            }
          },
          "500": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Clidelity-Api-Version": {
                "$ref": "#/components/headers/ClidelityApiVersion"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/ClidelityApiVersion"
          }
        ]
      }
    },
    "/api/public/voice-capture": {
      "post": {
        "operationId": "voiceCaptureManage",
        "tags": [
          "voice"
        ],
        "summary": "Read or delete a voice recording, by manage token",
        "description": "The recorder returns a manage token to the person who recorded. get returns playback and transcription state with a one-hour signed playback URL. delete schedules audio removal within a day, and the transcript text stays by design. Rate limited to 600 requests per hour per IP, sized for transcription polling.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "token",
                  "action"
                ],
                "properties": {
                  "token": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "action": {
                    "type": "string",
                    "enum": [
                      "get",
                      "delete"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Capture state for get, or the deletion receipt",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "type": "object",
                      "properties": {
                        "created_at": {
                          "type": "string"
                        },
                        "expires_at": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "audio_removed": {
                          "type": "boolean"
                        },
                        "playback_url": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "status": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "transcript": {
                          "type": [
                            "string",
                            "null"
                          ]
                        }
                      }
                    },
                    {
                      "type": "object",
                      "properties": {
                        "status": {
                          "type": "string",
                          "enum": [
                            "deletion_scheduled"
                          ]
                        }
                      }
                    }
                  ]
                }
              }
            },
            "headers": {
              "Clidelity-Api-Version": {
                "$ref": "#/components/headers/ClidelityApiVersion"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "400": {
            "description": "Invalid JSON or input",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Clidelity-Api-Version": {
                "$ref": "#/components/headers/ClidelityApiVersion"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "404": {
            "description": "The token does not address a recording",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Clidelity-Api-Version": {
                "$ref": "#/components/headers/ClidelityApiVersion"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "429": {
            "description": "Rate limit reached",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Clidelity-Api-Version": {
                "$ref": "#/components/headers/ClidelityApiVersion"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            }
          },
          "500": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Clidelity-Api-Version": {
                "$ref": "#/components/headers/ClidelityApiVersion"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/ClidelityApiVersion"
          }
        ]
      }
    }
  },
  "components": {
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "string",
            "description": "A human-readable sentence naming what went wrong and what to do next. Machine codes appear here for a few cases, for example trial_limit_reached."
          },
          "details": {
            "description": "Field-level validation errors when input parsing failed",
            "type": [
              "object",
              "null"
            ]
          }
        },
        "description": "Every non-2xx response from these endpoints is JSON in this shape. Unknown paths under /api/ answer 404 with this shape and a hint listing the discoverable resources. A 400 can also mean the request pinned an unsupported Clidelity-Api-Version, and the error sentence names the supported versions."
      }
    },
    "parameters": {
      "ClidelityApiVersion": {
        "name": "Clidelity-Api-Version",
        "in": "header",
        "required": false,
        "description": "Optional version pin. Send the API version date this client was built against. A supported value is honored, an unknown value answers 400 with an error naming the supported versions, and omitting the header means the current version.",
        "schema": {
          "type": "string",
          "enum": [
            "2026-08-25"
          ]
        }
      }
    },
    "headers": {
      "ClidelityApiVersion": {
        "description": "The API version date this response was served under. Present on every response.",
        "schema": {
          "type": "string"
        }
      },
      "RateLimit": {
        "description": "IETF draft structured field for the active limit partition. r is the requests remaining in the window and t is the seconds until it resets. Example: \"per-ip\";r=42;t=1800",
        "schema": {
          "type": "string"
        }
      },
      "RateLimitPolicy": {
        "description": "IETF draft structured field naming the limit policy. q is the request quota and w is the window in seconds. Example: \"per-ip\";q=60;w=3600",
        "schema": {
          "type": "string"
        }
      },
      "RateLimitLimit": {
        "description": "Legacy name for the request quota in the window.",
        "schema": {
          "type": "string"
        }
      },
      "RateLimitRemaining": {
        "description": "Legacy name for the requests remaining in the window.",
        "schema": {
          "type": "string"
        }
      },
      "RateLimitReset": {
        "description": "Legacy name for the seconds until the window resets.",
        "schema": {
          "type": "string"
        }
      },
      "RetryAfter": {
        "description": "Seconds to wait before retrying. Sent with every 429.",
        "schema": {
          "type": "string"
        }
      },
      "Deprecation": {
        "description": "Marks a deprecated operation or version. Absent today. When a deprecation is announced this carries its date, with Sunset naming the retirement date.",
        "schema": {
          "type": "string"
        }
      },
      "Sunset": {
        "description": "RFC 8594 retirement date for a deprecated operation or version. Absent today. Retirement comes no sooner than 90 days after the Deprecation announcement.",
        "schema": {
          "type": "string"
        }
      }
    }
  }
}
