{
  "openapi": "3.1.0",
  "info": {
    "title": "Dovly AI marketing site API",
    "version": "1.1.0",
    "description": "Public endpoints of www.dovly.com (the marketing site). Dovly AI is an AI-powered credit improvement platform; the member product itself lives at app.dovly.com and its API is not public. No authentication is required for the endpoints below. There is no GraphQL endpoint anywhere on this domain — the only GraphQL-adjacent thing is the auth-gated Sanity Studio CMS admin at /studio, which is not an API. Rate limiting: every API response carries the IETF draft RateLimit and RateLimit-Policy headers; 429 responses additionally carry Retry-After (seconds). Reads on /api/reviews/ allow 60 requests/minute per client at the origin (CDN-cached responses replay a header snapshot; RateLimit-Policy is the stable field); /api/partner-inquiry/ allows 5 submissions per 10 minutes.",
    "contact": {
      "name": "Dovly AI support",
      "email": "support@dovly.com",
      "url": "https://www.dovly.com/contact/"
    }
  },
  "servers": [
    {
      "url": "https://www.dovly.com"
    }
  ],
  "paths": {
    "/api/reviews/": {
      "get": {
        "operationId": "listGoogleReviews",
        "summary": "List verified Google reviews",
        "description": "Paged window over the pool of verified Google Business Profile reviews shown across the site (rating 4+, newest first). Use offset/limit to page. Unauthenticated.",
        "parameters": [
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "Zero-based start index. Clamped to 0..5000.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 5000,
              "default": 0
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Page size. Clamped server-side.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 12
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of reviews plus the pool total. Carries RateLimit and RateLimit-Policy headers (IETF draft ratelimit-headers).",
            "headers": {
              "RateLimit-Policy": {
                "schema": {
                  "type": "string"
                },
                "description": "Origin policy, e.g. \"60;w=60\"."
              },
              "RateLimit": {
                "schema": {
                  "type": "string"
                },
                "description": "limit/remaining/reset snapshot for the current window."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "reviews",
                    "total"
                  ],
                  "properties": {
                    "reviews": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "required": [
                          "id",
                          "rating",
                          "reviewerName",
                          "text"
                        ],
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "rating": {
                            "type": "integer",
                            "minimum": 1,
                            "maximum": 5
                          },
                          "reviewerName": {
                            "type": "string"
                          },
                          "text": {
                            "type": "string"
                          },
                          "reviewCreatedAt": {
                            "type": "string",
                            "format": "date-time"
                          }
                        }
                      }
                    },
                    "total": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited (60 requests/minute per client at the origin). Retry after Retry-After seconds.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait."
              },
              "RateLimit-Policy": {
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      }
    },
    "/api/partner-inquiry/": {
      "post": {
        "operationId": "submitPartnerInquiry",
        "summary": "Submit a B2B partnership inquiry",
        "description": "Sends a partnership inquiry to the Dovly AI partnerships team. Intended for businesses (employers, credit unions, affiliates) — not for consumer support, which is support@dovly.com. Rate limited per client; a 429 carries Retry-After.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "interest",
                  "companyName",
                  "firstName",
                  "lastName",
                  "email",
                  "phone",
                  "website"
                ],
                "properties": {
                  "interest": {
                    "type": "string",
                    "description": "What kind of partnership."
                  },
                  "companyName": {
                    "type": "string",
                    "maxLength": 160
                  },
                  "firstName": {
                    "type": "string"
                  },
                  "lastName": {
                    "type": "string"
                  },
                  "email": {
                    "type": "string",
                    "format": "email",
                    "maxLength": 200
                  },
                  "phone": {
                    "type": "string"
                  },
                  "website": {
                    "type": "string"
                  },
                  "message": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Inquiry accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "description": "Rate limited. Retry after the number of seconds in the Retry-After header.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "ErrorBody": {
        "type": "object",
        "properties": {
          "error": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "object",
                "properties": {
                  "code": {
                    "type": "string"
                  },
                  "message": {
                    "type": "string"
                  },
                  "hint": {
                    "type": "string"
                  },
                  "docs": {
                    "type": "string",
                    "format": "uri"
                  }
                }
              }
            ]
          }
        }
      }
    },
    "responses": {
      "Error": {
        "description": "Structured JSON error.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorBody"
            }
          }
        }
      }
    }
  },
  "x-machine-readable-content": {
    "description": "Non-API machine-readable resources on this site.",
    "resources": [
      {
        "url": "https://www.dovly.com/llms.txt",
        "contentType": "text/plain",
        "purpose": "LLM site guide (llmstxt.org)"
      },
      {
        "url": "https://www.dovly.com/llms-full.txt",
        "contentType": "text/plain",
        "purpose": "Expanded product facts for LLMs"
      },
      {
        "url": "https://www.dovly.com/pricing.md",
        "contentType": "text/markdown",
        "purpose": "Pricing in markdown"
      },
      {
        "url": "https://www.dovly.com/home.md",
        "contentType": "text/markdown",
        "purpose": "Homepage in markdown (also served for Accept: text/markdown on /)"
      },
      {
        "url": "https://www.dovly.com/sitemap.xml",
        "contentType": "application/xml",
        "purpose": "Full URL inventory"
      }
    ]
  }
}