{
    "openapi": "3.1.0",
    "info": {
        "title": "eduardocruz.com",
        "summary": "Public read API for hiring Eduardo Cruz — senior Laravel engineer and fractional CTO.",
        "description": "Unauthenticated, read-only endpoints describing who Eduardo Cruz is, what he is hired for, and the current engagement terms, plus one write endpoint for submitting a hiring inquiry.\n\nThe same facts are available over MCP (Streamable HTTP) at https://eduardocruz.com/mcp, and as prose at https://eduardocruz.com/llms.txt.\n\nErrors use RFC 9457 problem details with a stable `code` and a `resolution` hint.",
        "version": "1.0.0",
        "contact": {
            "name": "Eduardo Cruz",
            "email": "eduardo@eduardocruz.com",
            "url": "https://eduardocruz.com/contact"
        },
        "license": {
            "name": "Proprietary",
            "url": "https://eduardocruz.com/terms"
        }
    },
    "servers": [
        {
            "url": "https://eduardocruz.com",
            "description": "Production"
        }
    ],
    "externalDocs": {
        "description": "Agent and API documentation",
        "url": "https://eduardocruz.com/docs"
    },
    "tags": [
        {
            "name": "profile",
            "description": "Read-only facts about the engineer and the engagement."
        },
        {
            "name": "hiring",
            "description": "Opening an engagement."
        },
        {
            "name": "ferramentas",
            "description": "Standalone tools for the Brazilian market. Unrelated to hiring: each answers a question of its own and needs no authentication."
        }
    ],
    "paths": {
        "/api/v1/profile": {
            "get": {
                "operationId": "getProfile",
                "summary": "Get profile",
                "description": "Who Eduardo Cruz is: positioning, the experience ladder with real start years, location and time zone, languages, and profile links. Includes a `disambiguation` field — two other public people share the name.",
                "tags": [
                    "profile"
                ],
                "security": [],
                "responses": {
                    "200": {
                        "description": "Get profile.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Profile"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limit exceeded. Honor Retry-After.",
                        "content": {
                            "application/problem+json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Problem"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/v1/services": {
            "get": {
                "operationId": "listServices",
                "summary": "List services and products",
                "description": "The services Eduardo is hired for, each with a `best_for` line stating the situation it fits, plus the products he builds. Use `best_for` to decide fit — including deciding against.",
                "tags": [
                    "profile"
                ],
                "security": [],
                "responses": {
                    "200": {
                        "description": "List services and products.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ServicesResponse"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limit exceeded. Honor Retry-After.",
                        "content": {
                            "application/problem+json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Problem"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/v1/engagement": {
            "get": {
                "operationId": "getEngagement",
                "summary": "Get engagement terms",
                "description": "Current hourly rate, hours available per week, billing method and period, working hours, and how to open an engagement. Availability changes; read this rather than quoting a cached number.",
                "tags": [
                    "profile"
                ],
                "security": [],
                "responses": {
                    "200": {
                        "description": "Get engagement terms.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Engagement"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limit exceeded. Honor Retry-After.",
                        "content": {
                            "application/problem+json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Problem"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/v1/when-to-use": {
            "get": {
                "operationId": "getWhenToUse",
                "summary": "Get agent guidance",
                "description": "When an agent should reach for this domain and — the half that makes it guidance rather than marketing — when it should not.",
                "tags": [
                    "profile"
                ],
                "security": [],
                "responses": {
                    "200": {
                        "description": "Get agent guidance.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/WhenToUse"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limit exceeded. Honor Retry-After.",
                        "content": {
                            "application/problem+json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Problem"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/v1/ferramentas/reajuste-aluguel": {
            "get": {
                "operationId": "calcularReajusteAluguel",
                "summary": "Adjust a Brazilian rent by a monthly index",
                "description": "Adjusts a rent by the IGP-M over the twelve months of the contract year that just ended, and returns the working: the window used, the compounded factor, and every monthly index inside it.\n\nThe window is the point. For a contract signed on 2025-05-25, the first anniversary uses May 2025 through April 2026 — the month of signing is included, the anniversary month is not. It is NOT the most recently published rolling twelve months, which is the mistake that produces a different amount that still reproduces on the Banco Central's own calculator: that shifted window drops months the tenant already lived through and pulls in months belonging to the next anniversary, which would then be charged twice.\n\nTwo things this endpoint will not do. It never composes a partial window: if the window needs a month that has not been published, it answers 422 `index_not_published_yet` naming the month, because eleven of twelve months yields a plausible and wrong amount. And when its own copy of the series is stale it answers 503 `source_unreachable` rather than claiming a month was not published, which it cannot know.\n\nSource: Banco Central SGS series 28655 (IGP-M, full precision). Series 189 is the same index rounded to two decimals and drifts from the Banco Central's answer once compounded.",
                "tags": [
                    "ferramentas"
                ],
                "security": [],
                "parameters": [
                    {
                        "name": "valor",
                        "in": "query",
                        "required": true,
                        "description": "The current amount, before adjustment. Must be greater than zero.",
                        "schema": {
                            "type": "number",
                            "format": "double",
                            "exclusiveMinimum": 0,
                            "example": 3800
                        }
                    },
                    {
                        "name": "data_inicio",
                        "in": "query",
                        "required": true,
                        "description": "The date the contract was signed, as YYYY-MM-DD. Not the date of the last adjustment.",
                        "schema": {
                            "type": "string",
                            "format": "date",
                            "example": "2025-05-25"
                        }
                    },
                    {
                        "name": "aniversarios",
                        "in": "query",
                        "required": false,
                        "description": "Which anniversary to compute: 1 is the first adjustment, one year after signing.",
                        "schema": {
                            "type": "integer",
                            "minimum": 1,
                            "maximum": 30,
                            "default": 1
                        }
                    },
                    {
                        "name": "indice",
                        "in": "query",
                        "required": false,
                        "description": "Index code. Only `igpm` is supported today.",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "igpm"
                            ],
                            "default": "igpm"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "The adjusted amount and the working behind it.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ReajusteAluguel"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "A parameter is missing or not usable. `detail` names which.",
                        "content": {
                            "application/problem+json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Problem"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "The window needs a month that has not been published yet. Extension member `missing_month` names it; retry after publication.",
                        "content": {
                            "application/problem+json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Problem"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limit exceeded. Honor Retry-After.",
                        "content": {
                            "application/problem+json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Problem"
                                }
                            }
                        }
                    },
                    "503": {
                        "description": "The index series could not be refreshed, so whether the month exists cannot be determined. This is a fault on this side.",
                        "content": {
                            "application/problem+json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Problem"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/hire-leads": {
            "post": {
                "operationId": "createHiringInquiry",
                "summary": "Submit a hiring inquiry",
                "description": "Send a hiring inquiry. This creates a message, not a commitment: Eduardo replies before any engagement or billing exists. Rate limited to 5 requests per minute per IP.\n\nSubmit only details the person you represent has agreed to send. `problem` should describe the actual problem — a generic message gets a generic reply.",
                "tags": [
                    "hiring"
                ],
                "security": [],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/HiringInquiry"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Inquiry received.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/HiringInquiryReceipt"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "Validation failed.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ValidationError"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limit exceeded. Honor Retry-After.",
                        "content": {
                            "application/problem+json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Problem"
                                }
                            }
                        }
                    },
                    "500": {
                        "description": "Server error.",
                        "content": {
                            "application/problem+json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Problem"
                                }
                            }
                        }
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "ReajusteAluguel": {
                "type": "object",
                "description": "An adjusted amount together with everything needed to reproduce it independently.",
                "properties": {
                    "indice": {
                        "type": "string",
                        "example": "igpm"
                    },
                    "valor_original": {
                        "type": "number",
                        "format": "double",
                        "example": 3800
                    },
                    "valor_corrigido": {
                        "type": "number",
                        "format": "double",
                        "description": "Rounded to cents once, at the end. Never rounded mid-calculation.",
                        "example": 3823.14
                    },
                    "fator": {
                        "type": "number",
                        "format": "double",
                        "description": "The compounded factor, unrounded: the product of (1 + monthly percent / 100) across the window.",
                        "example": 1.00608927
                    },
                    "aniversario": {
                        "type": "integer",
                        "example": 1
                    },
                    "janela": {
                        "type": "object",
                        "description": "The twelve months of the contract year that ended at this anniversary, inclusive.",
                        "properties": {
                            "de": {
                                "type": "string",
                                "example": "2025-05"
                            },
                            "ate": {
                                "type": "string",
                                "example": "2026-04"
                            }
                        }
                    },
                    "meses": {
                        "type": "array",
                        "description": "Every monthly index used, in order, so the factor can be recomputed by hand.",
                        "items": {
                            "type": "object",
                            "properties": {
                                "month": {
                                    "type": "string",
                                    "example": "2025-05"
                                },
                                "percent": {
                                    "type": "number",
                                    "format": "double",
                                    "example": -0.4881646067
                                }
                            }
                        }
                    },
                    "serie": {
                        "type": "object",
                        "description": "Provenance of the index data, including whether it is a cached fallback.",
                        "properties": {
                            "id": {
                                "type": "integer",
                                "description": "Banco Central SGS series id.",
                                "example": 28655
                            },
                            "series_through": {
                                "type": "string",
                                "description": "The most recent month the series carries.",
                                "example": "2026-07"
                            },
                            "fetched_at": {
                                "type": "string",
                                "format": "date-time"
                            },
                            "stale": {
                                "type": "boolean",
                                "description": "True when served from a local copy because the source could not be refreshed. A stale series is still correct for any window that closed before `series_through`."
                            }
                        }
                    }
                }
            },
            "Problem": {
                "type": "object",
                "description": "RFC 9457 problem details. `code` is stable across releases; `resolution` names the next move.",
                "required": [
                    "status",
                    "code",
                    "detail"
                ],
                "properties": {
                    "type": {
                        "type": "string",
                        "format": "uri",
                        "description": "URI identifying the problem type."
                    },
                    "title": {
                        "type": "string",
                        "description": "Short human-readable summary."
                    },
                    "status": {
                        "type": "integer",
                        "description": "HTTP status code.",
                        "examples": [
                            404
                        ]
                    },
                    "code": {
                        "type": "string",
                        "description": "Stable machine-readable error code.",
                        "examples": [
                            "not_found"
                        ]
                    },
                    "detail": {
                        "type": "string",
                        "description": "What went wrong with this specific request."
                    },
                    "resolution": {
                        "type": "string",
                        "description": "Concrete next step to resolve it."
                    },
                    "instance": {
                        "type": "string",
                        "description": "The request path that produced the error."
                    },
                    "documentation_url": {
                        "type": "string",
                        "format": "uri"
                    }
                }
            },
            "ValidationError": {
                "type": "object",
                "description": "Laravel's standard validation shape. Kept as-is because the site's own hire form reads it.",
                "properties": {
                    "message": {
                        "type": "string"
                    },
                    "errors": {
                        "type": "object",
                        "description": "Field name => list of messages.",
                        "additionalProperties": {
                            "type": "array",
                            "items": {
                                "type": "string"
                            }
                        }
                    }
                }
            },
            "Profile": {
                "type": "object",
                "properties": {
                    "name": {
                        "type": "string"
                    },
                    "headline": {
                        "type": "string"
                    },
                    "summary": {
                        "type": "string"
                    },
                    "location": {
                        "type": "object",
                        "properties": {
                            "city": {
                                "type": "string"
                            },
                            "country": {
                                "type": "string",
                                "description": "ISO 3166-1 alpha-2."
                            },
                            "timezone": {
                                "type": "string",
                                "description": "IANA time zone."
                            },
                            "utc_offset": {
                                "type": "string"
                            }
                        }
                    },
                    "remote": {
                        "type": "boolean"
                    },
                    "languages": {
                        "type": "array",
                        "items": {
                            "type": "string"
                        }
                    },
                    "experience": {
                        "type": "array",
                        "description": "Start years, not durations — so the numbers stay true without edits.",
                        "items": {
                            "type": "object",
                            "properties": {
                                "area": {
                                    "type": "string"
                                },
                                "since": {
                                    "type": "integer"
                                }
                            }
                        }
                    },
                    "disambiguation": {
                        "type": "string",
                        "description": "Who this person is NOT."
                    },
                    "urls": {
                        "type": "object",
                        "additionalProperties": {
                            "type": "string",
                            "format": "uri"
                        }
                    }
                }
            },
            "Service": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string"
                    },
                    "name": {
                        "type": "string"
                    },
                    "description": {
                        "type": "string"
                    },
                    "best_for": {
                        "type": "string",
                        "description": "The situation this service fits."
                    },
                    "docs": {
                        "type": "string",
                        "format": "uri"
                    }
                }
            },
            "Product": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string"
                    },
                    "name": {
                        "type": "string"
                    },
                    "url": {
                        "type": "string",
                        "format": "uri"
                    },
                    "description": {
                        "type": "string"
                    },
                    "free_tier": {
                        "type": "string"
                    }
                }
            },
            "ServicesResponse": {
                "type": "object",
                "properties": {
                    "services": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/Service"
                        }
                    },
                    "products": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/Product"
                        }
                    }
                }
            },
            "Engagement": {
                "type": "object",
                "properties": {
                    "rate": {
                        "type": "object",
                        "properties": {
                            "amount": {
                                "type": "number",
                                "examples": [
                                    60
                                ]
                            },
                            "currency": {
                                "type": "string",
                                "examples": [
                                    "USD"
                                ]
                            },
                            "unit": {
                                "type": "string",
                                "examples": [
                                    "hour"
                                ]
                            }
                        }
                    },
                    "availability": {
                        "type": "object",
                        "properties": {
                            "hours_per_week": {
                                "type": "integer",
                                "examples": [
                                    20
                                ]
                            },
                            "description": {
                                "type": "string"
                            }
                        }
                    },
                    "billing": {
                        "type": "object",
                        "properties": {
                            "method": {
                                "type": "string"
                            },
                            "period": {
                                "type": "string"
                            },
                            "checkout_url": {
                                "type": "string",
                                "format": "uri"
                            }
                        }
                    },
                    "working_hours": {
                        "type": "string"
                    },
                    "how_to_start": {
                        "type": "object",
                        "properties": {
                            "description": {
                                "type": "string"
                            },
                            "endpoint": {
                                "type": "string"
                            },
                            "human_url": {
                                "type": "string",
                                "format": "uri"
                            }
                        }
                    }
                }
            },
            "WhenToUse": {
                "type": "object",
                "properties": {
                    "use_when": {
                        "type": "array",
                        "items": {
                            "type": "string"
                        }
                    },
                    "do_not_use_when": {
                        "type": "array",
                        "items": {
                            "type": "string"
                        }
                    },
                    "how_to_call": {
                        "type": "object",
                        "additionalProperties": {
                            "type": "string"
                        }
                    }
                }
            },
            "HiringInquiry": {
                "type": "object",
                "required": [
                    "name",
                    "email",
                    "path",
                    "problem"
                ],
                "properties": {
                    "name": {
                        "type": "string",
                        "maxLength": 120,
                        "description": "Full name of the person inquiring."
                    },
                    "email": {
                        "type": "string",
                        "format": "email",
                        "maxLength": 180,
                        "description": "Where the reply goes."
                    },
                    "path": {
                        "type": "string",
                        "enum": [
                            "a",
                            "b",
                            "c",
                            "w"
                        ],
                        "description": "Which kind of engagement: `a` AI agent work, `b` senior Laravel work, `c` fractional CTO, `w` unsure / other."
                    },
                    "problem": {
                        "type": "string",
                        "minLength": 10,
                        "maxLength": 5000,
                        "description": "The actual problem, in the inquirer's own words."
                    }
                }
            },
            "HiringInquiryReceipt": {
                "type": "object",
                "properties": {
                    "ok": {
                        "type": "boolean"
                    },
                    "ref": {
                        "type": "string",
                        "description": "Reference for this inquiry.",
                        "examples": [
                            "hire-a1b2c3"
                        ]
                    },
                    "path": {
                        "type": "string"
                    }
                }
            }
        }
    },
    "security": []
}