{"openapi":"3.1.0","info":{"title":"Fordeal.ai API","version":"0.1.0","summary":"Order services, consultations and goods from software.","description":"Fordeal is a marketplace where people and AI agents order real-world services (tradespeople, cleaning, salons), book online consultations (doctors, lawyers, advisors) and buy or sell goods. Everything a human can do on the website an agent can do through this MCP server or the REST API: no UI, no scraping, no human in the loop.\n\nThe same operations are available over MCP (Streamable HTTP) at https://fordeal.ai/mcp.","contact":{"name":"Fordeal agents","email":"agents@fordeal.ai","url":"https://fordeal.ai/agents"}},"servers":[{"url":"https://fordeal.ai","description":"Production"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"Agent API key from https://fordeal.ai/agents."},"adminKey":{"type":"http","scheme":"bearer","description":"The platform admin key (ADMIN_API_KEY). One person, the founder; not issued to agents."},"cronSecret":{"type":"http","scheme":"bearer","description":"CRON_SECRET, sent by the scheduler (Vercel Cron). `x-cron-secret: <secret>` works as well."}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["unauthorized","forbidden","not_found","validation","invalid_state","conflict","budget_exceeded","rate_limited","payment_failed","country_not_supported","geocoding_failed","feature_disabled","minor_rule","internal"],"description":"Stable machine-readable error code."},"message":{"type":"string","description":"What went wrong."},"fix":{"type":"string","description":"What to do about it, written for an autonomous caller."},"details":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["code","message","fix"]}},"required":["error"],"description":"Every 4xx and 5xx response has this shape."},"Success":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}},"paths":{"/api/v1/categories":{"get":{"operationId":"listCategories","summary":"List categories","description":"Call this first when you do not know the exact category slug for a request.","tags":["categories"],"security":[{},{"bearerAuth":[]}],"parameters":[{"name":"locale","in":"query","required":false,"description":"BCP 47 locale for human-readable strings, e.g. \"en\", \"cs\", \"sk\". Defaults to the country's default locale.","schema":{"type":"string","minLength":2,"maxLength":10}},{"name":"pillar","in":"query","required":false,"description":"Only return categories of this pillar.","schema":{"type":"string","enum":["services","consultations","goods","work","tasks"]}}],"responses":{"200":{"description":"Success. The payload always carries next_actions[].","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation or geocoding error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this agent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Wrong state or a taken slot.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/providers":{"get":{"operationId":"searchProviders","summary":"Search providers","description":"Find tradespeople, cleaners, salons and other service providers near a place.","tags":["providers"],"security":[{},{"bearerAuth":[]}],"parameters":[{"name":"address","in":"query","required":false,"description":"Free-text address, e.g. \"Vinohradská 10, Praha 2\" or just a city name. Fordeal geocodes it and derives the country, currency and local providers from it.","schema":{"type":"string","minLength":2}},{"name":"location","in":"query","required":false,"description":"WGS84 coordinates. Use this when you already know them; otherwise pass address.","schema":{"type":"object","properties":{"lat":{"type":"number","minimum":-90,"maximum":90},"lng":{"type":"number","minimum":-180,"maximum":180}},"required":["lat","lng"]}},{"name":"country","in":"query","required":false,"description":"ISO 3166-1 alpha-2 country code, e.g. \"CZ\". Optional: normally derived from the address.","schema":{"type":"string","minLength":2,"maxLength":2}},{"name":"category","in":"query","required":false,"description":"Category slug from list_categories.","schema":{"type":"string"}},{"name":"text","in":"query","required":false,"description":"What the customer needs, in any language. Used to infer the category when `category` is not given.","schema":{"type":"string"}},{"name":"radius_km","in":"query","required":false,"description":"Search radius in kilometres. Default 25.","schema":{"type":"number","exclusiveMinimum":0,"maximum":300}},{"name":"date","in":"query","required":false,"description":"Day the customer needs the work done. Reserved for availability filtering.","schema":{"type":"string"}},{"name":"instant_only","in":"query","required":false,"description":"Only providers with instant booking (book_service works without waiting for an offer).","schema":{"type":"boolean"}},{"name":"max_price","in":"query","required":false,"description":"Maximum hourly rate, in the currency of the resolved country.","schema":{"type":"number","exclusiveMinimum":0}},{"name":"language","in":"query","required":false,"description":"Only providers who speak this language code.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":50}}],"responses":{"200":{"description":"Success. The payload always carries next_actions[].","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation or geocoding error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this agent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Wrong state or a taken slot.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/price-estimate":{"post":{"operationId":"estimatePrice","summary":"Estimate a price","description":"Get a realistic price range for a job before creating it, so you can tell the user what it will cost and set a sensible budget_max.","tags":["price-estimate"],"security":[{},{"bearerAuth":[]}],"parameters":[],"responses":{"200":{"description":"Success. The payload always carries next_actions[].","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation or geocoding error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this agent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Wrong state or a taken slot.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"address":{"type":"string","minLength":2,"description":"Free-text address, e.g. \"Vinohradská 10, Praha 2\" or just a city name. Fordeal geocodes it and derives the country, currency and local providers from it."},"location":{"type":"object","properties":{"lat":{"type":"number","minimum":-90,"maximum":90},"lng":{"type":"number","minimum":-180,"maximum":180}},"required":["lat","lng"],"description":"WGS84 coordinates. Use this when you already know them; otherwise pass address."},"country":{"type":"string","minLength":2,"maxLength":2,"description":"ISO 3166-1 alpha-2 country code, e.g. \"CZ\". Optional: normally derived from the address."},"category":{"type":"string","description":"Category slug from list_categories."},"description":{"type":"string","minLength":3,"description":"What needs doing, in the customer's own words. More detail gives a tighter range."},"photo_url":{"description":"Public URL of a photo of the problem. Improves the estimate.","type":"string"}},"required":["category","description"],"additionalProperties":false}}}}}},"/api/v1/jobs":{"post":{"operationId":"createJob","summary":"Create a job","description":"Post a job. Fordeal classifies it, estimates the price, picks the best 3-5 providers nearby and messages them on WhatsApp; they reply with a firm price and a time.","tags":["jobs"],"security":[{"bearerAuth":[]}],"parameters":[],"responses":{"200":{"description":"Success. The payload always carries next_actions[].","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation or geocoding error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this agent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Wrong state or a taken slot.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"address":{"type":"string","minLength":2,"description":"Free-text address, e.g. \"Vinohradská 10, Praha 2\" or just a city name. Fordeal geocodes it and derives the country, currency and local providers from it."},"location":{"type":"object","properties":{"lat":{"type":"number","minimum":-90,"maximum":90},"lng":{"type":"number","minimum":-180,"maximum":180}},"required":["lat","lng"],"description":"WGS84 coordinates. Use this when you already know them; otherwise pass address."},"country":{"type":"string","minLength":2,"maxLength":2,"description":"ISO 3166-1 alpha-2 country code, e.g. \"CZ\". Optional: normally derived from the address."},"idempotency_key":{"type":"string","minLength":8,"maxLength":200,"description":"Client-generated key. Retrying with the same key returns the first result instead of creating a second job, booking or order."},"description":{"type":"string","minLength":3,"description":"What needs doing, in the customer's own words."},"category":{"description":"Category slug. Omit to let Fordeal classify the description.","type":"string"},"title":{"description":"Short title providers see. Omit to let Fordeal write one.","type":"string","maxLength":120},"photos":{"description":"Public URLs of photos of the problem.","maxItems":10,"type":"array","items":{"type":"string"}},"time_window_start":{"description":"Earliest acceptable start.","type":"string"},"time_window_end":{"description":"Latest acceptable finish.","type":"string"},"budget_max":{"description":"Maximum the customer will pay, in the currency of the resolved country.","type":"number","exclusiveMinimum":0}},"required":["description"],"additionalProperties":false}}}}},"get":{"operationId":"listJobs","summary":"List your own jobs","description":"Every job you created, newest first, with its status, agreed price and time window. Needs an API key (agent) or a customer access token. Next: get_offers on an open job, or get_status for one job in full.","tags":["jobs"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"limit","in":"query","required":false,"description":"How many jobs to return. Default 50.","schema":{"type":"integer","minimum":1,"maximum":100}}],"responses":{"200":{"description":"Success. The payload always carries next_actions[].","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation or geocoding error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this agent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Wrong state or a taken slot.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/jobs/{id}":{"get":{"operationId":"getJob","summary":"Read a job","description":"Everything about one job: status, agreed price, schedule, the message log with the provider, and the proof (photos, GPS) the provider submitted.","tags":["jobs"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Job id returned by create_job, book_service, book_consultation or book_lesson.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success. The payload always carries next_actions[].","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation or geocoding error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this agent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Wrong state or a taken slot.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/jobs/{id}/offers":{"get":{"operationId":"getJobOffers","summary":"List offers on a job","description":"List the firm offers providers have sent for a job: price with currency, ETA, the provider's stats and any note.","tags":["jobs"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Job id returned by create_job, book_service, book_consultation or book_lesson.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success. The payload always carries next_actions[].","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation or geocoding error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this agent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Wrong state or a taken slot.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/jobs/{id}/accept":{"post":{"operationId":"acceptJobOffer","summary":"Accept an offer","description":"Accept a provider's offer. The payment is authorized (not captured) into escrow, the other offers are rejected, and the provider is confirmed on WhatsApp.","tags":["jobs"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Job id returned by create_job, book_service, book_consultation or book_lesson.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success. The payload always carries next_actions[].","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation or geocoding error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this agent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Wrong state or a taken slot.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"idempotency_key":{"type":"string","minLength":8,"maxLength":200,"description":"Client-generated key. Retrying with the same key returns the first result instead of creating a second job, booking or order."},"offer_id":{"type":"string","description":"Offer id from get_offers."}},"required":["offer_id"],"additionalProperties":false}}}}}},"/api/v1/jobs/{id}/confirm":{"post":{"operationId":"confirmJob","summary":"Confirm or dispute completion","description":"Call this when the job is in status done_by_provider. approve=true captures the escrow, takes the platform commission (8 % from the provider) and pays the provider out; the job ends in status \"paid\".","tags":["jobs"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Job id returned by create_job, book_service, book_consultation or book_lesson.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success. The payload always carries next_actions[].","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation or geocoding error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this agent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Wrong state or a taken slot.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"idempotency_key":{"type":"string","minLength":8,"maxLength":200,"description":"Client-generated key. Retrying with the same key returns the first result instead of creating a second job, booking or order."},"approve":{"type":"boolean","description":"true releases the payment; false opens a dispute."},"note":{"description":"Required in practice when approve=false: what is wrong.","type":"string","maxLength":2000}},"required":["approve"],"additionalProperties":false}}}}}},"/api/v1/jobs/{id}/cancel":{"post":{"operationId":"cancelJob","summary":"Cancel a job","description":"Cancel a job that has not been completed. Free while no offer is accepted; after acceptance the authorized payment is released and cancellation terms apply.","tags":["jobs"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Job id returned by create_job, book_service, book_consultation or book_lesson.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success. The payload always carries next_actions[].","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation or geocoding error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this agent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Wrong state or a taken slot.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"description":"Why it is being cancelled. Shown to the provider.","type":"string","maxLength":500}},"additionalProperties":false}}}}}},"/api/v1/jobs/{id}/review":{"post":{"operationId":"reviewJob","summary":"Review a paid job","description":"Leave a verified review after a job reaches status \"paid\". Only jobs actually paid through Fordeal can be reviewed, which is why the provider stats are trustworthy.","tags":["jobs"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Job id returned by create_job, book_service, book_consultation or book_lesson.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success. The payload always carries next_actions[].","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation or geocoding error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this agent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Wrong state or a taken slot.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"rating":{"type":"integer","minimum":1,"maximum":5,"description":"1 = bad, 5 = excellent."},"text":{"description":"What happened, in the customer's words.","type":"string","maxLength":2000}},"required":["rating"],"additionalProperties":false}}}}}},"/api/v1/bookings":{"post":{"operationId":"bookService","summary":"Book a fixed-price service","description":"Book a specific service in a specific slot, with no offer round.","tags":["bookings"],"security":[{"bearerAuth":[]}],"parameters":[],"responses":{"200":{"description":"Success. The payload always carries next_actions[].","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation or geocoding error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this agent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Wrong state or a taken slot.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"idempotency_key":{"type":"string","minLength":8,"maxLength":200,"description":"Client-generated key. Retrying with the same key returns the first result instead of creating a second job, booking or order."},"service_id":{"type":"string","description":"Service id from search_providers -> providers[].services[].id."},"slot":{"type":"string","description":"Start of the slot to book."},"address":{"description":"Where the service happens, when the provider comes to the customer.","type":"string","minLength":2},"note":{"description":"Anything the provider should know.","type":"string","maxLength":1000}},"required":["service_id","slot"],"additionalProperties":false}}}}}},"/api/v1/requests":{"post":{"operationId":"requestAnything","summary":"Request anything in free text","description":"Use when you do not know which category fits, or the need spans several trades.","tags":["requests"],"security":[{"bearerAuth":[]}],"parameters":[],"responses":{"200":{"description":"Success. The payload always carries next_actions[].","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation or geocoding error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this agent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Wrong state or a taken slot.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"text":{"type":"string","minLength":5,"maxLength":4000,"description":"What is needed, in the customer's own words. Anything: a leaking tap, a piano tuner, someone to queue for a permit, a maths tutor on Saturday."},"address":{"type":"string","minLength":2,"description":"Free-text address, e.g. \"Vinohradská 10, Praha 2\" or just a city name. Fordeal geocodes it and derives the country, currency and local providers from it."},"location":{"type":"object","properties":{"lat":{"type":"number","minimum":-90,"maximum":90},"lng":{"type":"number","minimum":-180,"maximum":180}},"required":["lat","lng"],"description":"WGS84 coordinates. Use this when you already know them; otherwise pass address."},"country":{"type":"string","minLength":2,"maxLength":2,"description":"ISO 3166-1 alpha-2 country code, e.g. \"CZ\". Optional: normally derived from the address."},"budget_max":{"description":"Maximum the customer will pay, in the currency of the resolved country.","type":"number","exclusiveMinimum":0},"deadline":{"description":"When it has to be done by.","type":"string"},"photos":{"description":"Public URLs of photos that help providers understand the request.","maxItems":10,"type":"array","items":{"type":"string"}},"locale":{"type":"string","minLength":2,"maxLength":10,"description":"BCP 47 locale for human-readable strings, e.g. \"en\", \"cs\", \"sk\". Defaults to the country's default locale."},"idempotency_key":{"type":"string","minLength":8,"maxLength":200,"description":"Client-generated key. Retrying with the same key returns the first result instead of creating a second job, booking or order."}},"required":["text"],"additionalProperties":false}}}}}},"/api/v1/requests/open":{"get":{"operationId":"listOpenRequests","summary":"List open requests near a place","description":"For providers, and for agents acting for a provider: free-form requests near a place that no category fit, which any verified local provider may answer with an offer.","tags":["requests"],"security":[{},{"bearerAuth":[]}],"parameters":[{"name":"address","in":"query","required":false,"description":"Free-text address, e.g. \"Vinohradská 10, Praha 2\" or just a city name. Fordeal geocodes it and derives the country, currency and local providers from it.","schema":{"type":"string","minLength":2}},{"name":"location","in":"query","required":false,"description":"WGS84 coordinates. Use this when you already know them; otherwise pass address.","schema":{"type":"object","properties":{"lat":{"type":"number","minimum":-90,"maximum":90},"lng":{"type":"number","minimum":-180,"maximum":180}},"required":["lat","lng"]}},{"name":"country","in":"query","required":false,"description":"ISO 3166-1 alpha-2 country code, e.g. \"CZ\". Optional: normally derived from the address.","schema":{"type":"string","minLength":2,"maxLength":2}},{"name":"radius_km","in":"query","required":false,"description":"Search radius in km. Default 25.","schema":{"type":"integer","minimum":1,"maximum":200}},{"name":"limit","in":"query","required":false,"description":"How many requests to return. Default 20.","schema":{"type":"integer","minimum":1,"maximum":100}}],"responses":{"200":{"description":"Success. The payload always carries next_actions[].","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation or geocoding error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this agent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Wrong state or a taken slot.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/classify":{"post":{"operationId":"classifyRequest","summary":"Classify a request into a category","description":"What Fordeal would make of a request before it is sent: the best category slug (null when nothing fits), a confidence 0-1 and a short title. Public, no side effects. The website's request wizard uses it to offer the category or the open-request path; an agent can use it to decide between create_job and request_anything.","tags":["classify"],"security":[{},{"bearerAuth":[]}],"parameters":[],"responses":{"200":{"description":"Success. The payload always carries next_actions[].","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation or geocoding error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this agent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Wrong state or a taken slot.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"text":{"type":"string","minLength":3,"maxLength":4000,"description":"The request, in the customer's own words."},"locale":{"type":"string","minLength":2,"maxLength":10,"description":"BCP 47 locale for human-readable strings, e.g. \"en\", \"cs\", \"sk\". Defaults to the country's default locale."}},"required":["text"],"additionalProperties":false}}}}}},"/api/v1/tasks":{"post":{"operationId":"createTask","summary":"Create a micro-task","description":"Hire a human for a short physical task an agent cannot do itself: take a photo on site, verify that something exists, pick something up, deliver, stand in a queue, get a document signed.","tags":["tasks"],"security":[{"bearerAuth":[]}],"parameters":[],"responses":{"200":{"description":"Success. The payload always carries next_actions[].","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation or geocoding error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this agent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Wrong state or a taken slot.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"address":{"type":"string","minLength":2,"description":"Free-text address, e.g. \"Vinohradská 10, Praha 2\" or just a city name. Fordeal geocodes it and derives the country, currency and local providers from it."},"location":{"type":"object","properties":{"lat":{"type":"number","minimum":-90,"maximum":90},"lng":{"type":"number","minimum":-180,"maximum":180}},"required":["lat","lng"],"description":"WGS84 coordinates. Use this when you already know them; otherwise pass address."},"country":{"type":"string","minLength":2,"maxLength":2,"description":"ISO 3166-1 alpha-2 country code, e.g. \"CZ\". Optional: normally derived from the address."},"idempotency_key":{"type":"string","minLength":8,"maxLength":200,"description":"Client-generated key. Retrying with the same key returns the first result instead of creating a second job, booking or order."},"description":{"type":"string","minLength":3,"description":"Exactly what the person must do. Be literal: they read this on a phone."},"deadline":{"type":"string","description":"When the task must be finished."},"pay":{"type":"number","exclusiveMinimum":0,"description":"Fixed payment, in the currency of the resolved country."},"proof_required":{"description":"What the worker must submit. Default [\"photo\",\"gps\"].","type":"array","items":{"type":"string","enum":["photo","gps","signature"]}},"category":{"description":"Task category slug (pillar \"tasks\"). Default \"verify-on-site\".","type":"string"},"photos":{"description":"Reference photos for the worker.","maxItems":10,"type":"array","items":{"type":"string"}}},"required":["description","deadline","pay"],"additionalProperties":false}}}}}},"/api/v1/postings":{"post":{"operationId":"postJob","summary":"Post a work opening","description":"Publish a work opening in the Work section: a temp job, a full-time role, seasonal work or an agreement.","tags":["postings"],"security":[{"bearerAuth":[]}],"parameters":[],"responses":{"200":{"description":"Success. The payload always carries next_actions[].","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation or geocoding error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this agent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Wrong state or a taken slot.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"address":{"type":"string","minLength":2,"description":"Free-text address, e.g. \"Vinohradská 10, Praha 2\" or just a city name. Fordeal geocodes it and derives the country, currency and local providers from it."},"location":{"type":"object","properties":{"lat":{"type":"number","minimum":-90,"maximum":90},"lng":{"type":"number","minimum":-180,"maximum":180}},"required":["lat","lng"],"description":"WGS84 coordinates. Use this when you already know them; otherwise pass address."},"country":{"type":"string","minLength":2,"maxLength":2,"description":"ISO 3166-1 alpha-2 country code, e.g. \"CZ\". Optional: normally derived from the address."},"idempotency_key":{"type":"string","minLength":8,"maxLength":200,"description":"Client-generated key. Retrying with the same key returns the first result instead of creating a second job, booking or order."},"title":{"type":"string","minLength":3,"maxLength":120,"description":"Role title as a candidate would search for it."},"type":{"type":"string","enum":["temp","full_time","agreement","micro_task"],"description":"Kind of engagement."},"description":{"description":"Duties, requirements, shift pattern.","type":"string","maxLength":5000},"pay":{"description":"Pay amount in the currency of the resolved country.","type":"number","exclusiveMinimum":0},"pay_unit":{"description":"What the pay is per.","type":"string","enum":["hour","day","month","task"]},"start_date":{"description":"When the work starts.","type":"string"}},"required":["title","type"],"additionalProperties":false}}}}},"get":{"operationId":"listPostings","summary":"List work openings","description":"Open work and temp-job postings, newest first. Public.","tags":["postings"],"security":[{},{"bearerAuth":[]}],"parameters":[{"name":"country","in":"query","required":false,"description":"ISO 3166-1 alpha-2 country code, e.g. \"CZ\". Optional: normally derived from the address.","schema":{"type":"string","minLength":2,"maxLength":2}},{"name":"type","in":"query","required":false,"schema":{"type":"string","enum":["temp","full_time","agreement","micro_task"]}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100}}],"responses":{"200":{"description":"Success. The payload always carries next_actions[].","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation or geocoding error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this agent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Wrong state or a taken slot.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/medical/explain":{"post":{"operationId":"explainMedicalReport","summary":"Explain a medical report","description":"Turn a lab result or medical report into plain language: what each value means, which values sit outside the printed reference range, three questions to ask the doctor, and which specialty to consult.","tags":["medical"],"security":[{},{"bearerAuth":[]}],"parameters":[],"responses":{"200":{"description":"Success. The payload always carries next_actions[].","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation or geocoding error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this agent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Wrong state or a taken slot.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"text":{"description":"The report as text. Either this or file_url is required.","type":"string"},"file_url":{"description":"Public URL of a photo or PDF of the report.","type":"string"},"locale":{"description":"Language of the explanation.","type":"string","minLength":2,"maxLength":10},"store":{"description":"Keep the document in the account (explicit consent). Requires an API key.","type":"boolean"},"country":{"description":"Country to look for consultants in.","type":"string","minLength":2,"maxLength":2}},"additionalProperties":false}}}}}},"/api/v1/consultants":{"get":{"operationId":"searchConsultants","summary":"Search consultants","description":"Find doctors, lawyers, tax advisors, psychologists and other consultants who take online appointments.","tags":["consultants"],"security":[{},{"bearerAuth":[]}],"parameters":[{"name":"category","in":"query","required":true,"description":"Consultation category slug, e.g. \"general-practitioner\", \"lawyer\".","schema":{"type":"string"}},{"name":"date","in":"query","required":false,"description":"Earliest slot you want. Default: now.","schema":{"type":"string"}},{"name":"language","in":"query","required":false,"description":"Language the consultant must speak.","schema":{"type":"string"}},{"name":"country","in":"query","required":false,"description":"ISO 3166-1 alpha-2 country code, e.g. \"CZ\". Optional: normally derived from the address.","schema":{"type":"string","minLength":2,"maxLength":2}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":50}}],"responses":{"200":{"description":"Success. The payload always carries next_actions[].","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation or geocoding error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this agent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Wrong state or a taken slot.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/consultations":{"post":{"operationId":"bookConsultation","summary":"Book a consultation","description":"Book one free slot with a consultant found through search_consultants.","tags":["consultations"],"security":[{"bearerAuth":[]}],"parameters":[],"responses":{"200":{"description":"Success. The payload always carries next_actions[].","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation or geocoding error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this agent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Wrong state or a taken slot.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"idempotency_key":{"type":"string","minLength":8,"maxLength":200,"description":"Client-generated key. Retrying with the same key returns the first result instead of creating a second job, booking or order."},"provider_id":{"type":"string","description":"Consultant id from search_consultants."},"slot":{"type":"string","description":"Start of one of the consultant's free slots."},"channel":{"description":"Preferred channel. Must be one the consultant offers.","type":"string","enum":["video","chat","phone"]},"note":{"description":"What the consultation is about. The consultant reads it beforehand.","type":"string","maxLength":2000}},"required":["provider_id","slot"],"additionalProperties":false}}}}}},"/api/v1/consultations/{id}/link":{"get":{"operationId":"getConsultationLink","summary":"Get the meeting link","description":"Return the meeting URL, channel and exact slot for a consultation booked with book_consultation, plus the disclaimer that an online consultation is not an examination and no prescriptions are issued.","tags":["consultations"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Job id returned by book_consultation.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success. The payload always carries next_actions[].","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation or geocoding error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this agent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Wrong state or a taken slot.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/tutors":{"get":{"operationId":"searchTutors","summary":"Search tutors","description":"Find tutors for one subject, ranked by how well they fit the student: subject and level taught, online or in person, price against the ceiling, and how the tutor describes their teaching style against what the student asks for in `style`.","tags":["tutors"],"security":[{},{"bearerAuth":[]}],"parameters":[{"name":"subject","in":"query","required":true,"description":"Subject slug from GET /api/v1/tutoring/subjects, e.g. \"math\", \"english\", \"programming\".","schema":{"type":"string","minLength":1}},{"name":"level","in":"query","required":false,"description":"Level the student needs: primary, secondary, university, languages or it. GET /api/v1/tutoring/subjects lists the levels per subject.","schema":{"type":"string","enum":["primary","secondary","university","languages","it"]}},{"name":"mode","in":"query","required":false,"description":"\"online\" (video lesson, meeting link from get_consultation_link) or \"in_person\" (address required).","schema":{"type":"string","enum":["online","in_person"]}},{"name":"address","in":"query","required":false,"description":"Free-text address, e.g. \"Vinohradská 10, Praha 2\" or just a city name. Fordeal geocodes it and derives the country, currency and local providers from it.","schema":{"type":"string","minLength":2}},{"name":"location","in":"query","required":false,"description":"WGS84 coordinates. Use this when you already know them; otherwise pass address.","schema":{"type":"object","properties":{"lat":{"type":"number","minimum":-90,"maximum":90},"lng":{"type":"number","minimum":-180,"maximum":180}},"required":["lat","lng"]}},{"name":"country","in":"query","required":false,"description":"ISO 3166-1 alpha-2 country code, e.g. \"CZ\". Optional: normally derived from the address.","schema":{"type":"string","minLength":2,"maxLength":2}},{"name":"max_price_per_hour","in":"query","required":false,"description":"Most the student pays for a 60-minute lesson, in the currency of the resolved country.","schema":{"type":"number","exclusiveMinimum":0}},{"name":"language","in":"query","required":false,"description":"Language the lessons must be taught in (BCP 47 code).","schema":{"type":"string","minLength":2,"maxLength":10}},{"name":"style","in":"query","required":false,"description":"What the student wants from the tutor, e.g. \"patient, exam drills, lots of speaking\". Used for ranking.","schema":{"type":"string","maxLength":300}},{"name":"date","in":"query","required":false,"description":"Earliest slot wanted. Default: now.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"How many tutors to return. Default 10.","schema":{"type":"integer","minimum":1,"maximum":50}},{"name":"locale","in":"query","required":false,"description":"BCP 47 locale for human-readable strings, e.g. \"en\", \"cs\", \"sk\". Defaults to the country's default locale.","schema":{"type":"string","minLength":2,"maxLength":10}}],"responses":{"200":{"description":"Success. The payload always carries next_actions[].","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation or geocoding error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this agent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Wrong state or a taken slot.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/lessons":{"post":{"operationId":"bookLesson","summary":"Book a lesson","description":"Book a 60-minute (or 30-180 minute) lesson with a tutor from search_tutors, in one of the listed slot starts.","tags":["lessons"],"security":[{"bearerAuth":[]}],"parameters":[],"responses":{"200":{"description":"Success. The payload always carries next_actions[].","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation or geocoding error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this agent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Wrong state or a taken slot.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"idempotency_key":{"type":"string","minLength":8,"maxLength":200,"description":"Client-generated key. Retrying with the same key returns the first result instead of creating a second job, booking or order."},"provider_id":{"type":"string","description":"Tutor id from search_tutors -> tutors[].id."},"slot_start":{"type":"string","description":"Start of the lesson: one of search_tutors -> tutors[].slots[].start."},"subject":{"type":"string","minLength":1,"description":"Subject slug from GET /api/v1/tutoring/subjects, e.g. \"math\", \"english\", \"programming\"."},"level":{"type":"string","enum":["primary","secondary","university","languages","it"],"description":"Level the student needs: primary, secondary, university, languages or it. GET /api/v1/tutoring/subjects lists the levels per subject."},"mode":{"description":"Default: online when the tutor offers it.","type":"string","enum":["online","in_person"]},"duration_min":{"description":"Lesson length in minutes. Default 60; package lessons are always 60.","type":"integer","minimum":30,"maximum":180},"package_id":{"description":"Draw this lesson from a package bought with buy_lesson_package (same tutor, subject and level).","type":"string"},"student_is_adult":{"type":"boolean","description":"True when the student is 18 or older. False only together with `guardian`, and only while the minor mode is on (adults_only=false in search_tutors)."},"guardian":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":120,"description":"The guardian's full name."},"email":{"type":"string","format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$","description":"The guardian's e-mail; the lesson record and the receipt go there."},"consent_at":{"type":"string","description":"When the guardian agreed to this lesson."}},"required":["name","email","consent_at"],"description":"Required when student_is_adult is false: the parent or legal guardian who consents to the lesson."},"address":{"description":"Where an in-person lesson takes place. Required when mode is in_person.","type":"string","minLength":2},"note":{"description":"What the student wants to work on. The tutor reads it before the lesson.","type":"string","maxLength":2000}},"required":["provider_id","slot_start","subject","level","student_is_adult"],"additionalProperties":false}}}}}},"/api/v1/lesson-packages":{"post":{"operationId":"buyLessonPackage","summary":"Buy a lesson package","description":"Create a package of 5 or 10 lessons with one tutor for one subject and level.","tags":["lesson-packages"],"security":[{"bearerAuth":[]}],"parameters":[],"responses":{"200":{"description":"Success. The payload always carries next_actions[].","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation or geocoding error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this agent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Wrong state or a taken slot.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"idempotency_key":{"type":"string","minLength":8,"maxLength":200,"description":"Client-generated key. Retrying with the same key returns the first result instead of creating a second job, booking or order."},"provider_id":{"type":"string","description":"Tutor id from search_tutors."},"lessons":{"anyOf":[{"type":"number","const":5},{"type":"number","const":10}],"description":"Package size: 5 or 10 lessons."},"subject":{"type":"string","minLength":1,"description":"Subject slug from GET /api/v1/tutoring/subjects, e.g. \"math\", \"english\", \"programming\"."},"level":{"type":"string","enum":["primary","secondary","university","languages","it"],"description":"Level the student needs: primary, secondary, university, languages or it. GET /api/v1/tutoring/subjects lists the levels per subject."}},"required":["provider_id","lessons","subject","level"],"additionalProperties":false}}}}}},"/api/v1/lesson-packages/{id}":{"get":{"operationId":"getLessonPackage","summary":"Read a lesson package","description":"One package bought with buy_lesson_package: lessons_total, lessons_used, lessons_left, the locked price_per_lesson, status (active, completed when every lesson is booked, cancelled) and every lesson booked from it as a job with its status.","tags":["lesson-packages"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Package id from buy_lesson_package.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success. The payload always carries next_actions[].","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation or geocoding error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this agent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Wrong state or a taken slot.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/tutoring/subjects":{"get":{"operationId":"listTutoringSubjects","summary":"List tutoring subjects and levels","description":"Every subject a tutor can teach (slug, localized names, the levels it is taught at, group) plus the level, mode and package-size vocabularies the tutoring tools accept. Seeded from packages/db; adding a subject is one row. Public. `adults_only` is true while the minor mode is switched off (students must be 18+) and false when a guardian may book for a student under 18. Next: search_tutors with one of the slugs.","tags":["tutoring"],"security":[{},{"bearerAuth":[]}],"parameters":[{"name":"locale","in":"query","required":false,"description":"BCP 47 locale for human-readable strings, e.g. \"en\", \"cs\", \"sk\". Defaults to the country's default locale.","schema":{"type":"string","minLength":2,"maxLength":10}}],"responses":{"200":{"description":"Success. The payload always carries next_actions[].","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation or geocoding error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this agent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Wrong state or a taken slot.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/items":{"get":{"operationId":"searchItems","summary":"Search items","description":"Search items people and agents are selling. Filter by free text, category slug (pillar \"goods\"), maximum price and location.","tags":["items"],"security":[{},{"bearerAuth":[]}],"parameters":[{"name":"address","in":"query","required":false,"description":"Free-text address, e.g. \"Vinohradská 10, Praha 2\" or just a city name. Fordeal geocodes it and derives the country, currency and local providers from it.","schema":{"type":"string","minLength":2}},{"name":"location","in":"query","required":false,"description":"WGS84 coordinates. Use this when you already know them; otherwise pass address.","schema":{"type":"object","properties":{"lat":{"type":"number","minimum":-90,"maximum":90},"lng":{"type":"number","minimum":-180,"maximum":180}},"required":["lat","lng"]}},{"name":"country","in":"query","required":false,"description":"ISO 3166-1 alpha-2 country code, e.g. \"CZ\". Optional: normally derived from the address.","schema":{"type":"string","minLength":2,"maxLength":2}},{"name":"text","in":"query","required":false,"description":"What to look for, in any language.","schema":{"type":"string"}},{"name":"category","in":"query","required":false,"description":"Goods category slug, e.g. \"phones\".","schema":{"type":"string"}},{"name":"max_price","in":"query","required":false,"description":"Maximum price in the currency of the resolved country.","schema":{"type":"number","exclusiveMinimum":0}},{"name":"radius_km","in":"query","required":false,"schema":{"type":"number","exclusiveMinimum":0,"maximum":2000}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":50}}],"responses":{"200":{"description":"Success. The payload always carries next_actions[].","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation or geocoding error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this agent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Wrong state or a taken slot.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"listItem","summary":"List an item for sale","description":"Publish something for sale. Pass address (free text) or location {lat,lng}.","tags":["items"],"security":[{"bearerAuth":[]}],"parameters":[],"responses":{"200":{"description":"Success. The payload always carries next_actions[].","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation or geocoding error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this agent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Wrong state or a taken slot.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"address":{"type":"string","minLength":2,"description":"Free-text address, e.g. \"Vinohradská 10, Praha 2\" or just a city name. Fordeal geocodes it and derives the country, currency and local providers from it."},"location":{"type":"object","properties":{"lat":{"type":"number","minimum":-90,"maximum":90},"lng":{"type":"number","minimum":-180,"maximum":180}},"required":["lat","lng"],"description":"WGS84 coordinates. Use this when you already know them; otherwise pass address."},"country":{"type":"string","minLength":2,"maxLength":2,"description":"ISO 3166-1 alpha-2 country code, e.g. \"CZ\". Optional: normally derived from the address."},"idempotency_key":{"type":"string","minLength":8,"maxLength":200,"description":"Client-generated key. Retrying with the same key returns the first result instead of creating a second job, booking or order."},"title":{"description":"Omit to let Fordeal draft it from the photos.","type":"string","maxLength":120},"description":{"type":"string","maxLength":5000},"price":{"description":"Asking price in the currency of the resolved country. Omit to let Fordeal suggest one from the photos.","type":"number","exclusiveMinimum":0},"photos":{"description":"Public URLs. Required when title or price is omitted.","maxItems":10,"type":"array","items":{"type":"string"}},"category":{"description":"Goods category slug. Default \"other-goods\".","type":"string"},"condition":{"type":"string","enum":["new","like_new","used","for_parts"]},"negotiable":{"description":"Allow buyers to call make_offer. Default false.","type":"boolean"},"delivery_options":{"description":"How the buyer can get it. Default [\"pickup\"].","type":"array","items":{"type":"string"}}},"additionalProperties":false}}}}}},"/api/v1/items/{id}":{"get":{"operationId":"getItem","summary":"Read an item and its order","description":"Full state of one item: the listing, the offers buyers made, and the order if it has been bought (paid -> shipped -> delivered -> confirmed -> paid_out).","tags":["items"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Item id returned by list_item or search_items.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success. The payload always carries next_actions[].","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation or geocoding error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this agent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Wrong state or a taken slot.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"updateItem","summary":"Change or withdraw a listing","description":"Change the price, title, description or negotiability of an item you listed, or set status=\"removed\" to withdraw it.","tags":["items"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Item id returned by list_item or search_items.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success. The payload always carries next_actions[].","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation or geocoding error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this agent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Wrong state or a taken slot.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","maxLength":120},"description":{"type":"string","maxLength":5000},"price":{"description":"New asking price in the item's currency.","type":"number","exclusiveMinimum":0},"negotiable":{"type":"boolean"},"status":{"description":"\"removed\" takes it off the marketplace.","type":"string","enum":["active","removed"]}},"additionalProperties":false}}}}}},"/api/v1/items/{id}/buy":{"post":{"operationId":"buyItem","summary":"Buy an item","description":"Buy an item immediately. The money goes into escrow: it is only released to the seller after confirm_item_received, so a buyer is never exposed.","tags":["items"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Item id returned by list_item or search_items.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success. The payload always carries next_actions[].","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation or geocoding error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this agent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Wrong state or a taken slot.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"idempotency_key":{"type":"string","minLength":8,"maxLength":200,"description":"Client-generated key. Retrying with the same key returns the first result instead of creating a second job, booking or order."},"delivery":{"type":"string","description":"One of the item's delivery_options, e.g. \"pickup\", \"parcel_locker\", \"courier\"."},"delivery_address":{"description":"Where to send it, when delivery is not pickup.","type":"string","minLength":2},"price":{"description":"Only for an agreed price below the listing (after make_offer).","type":"number","exclusiveMinimum":0}},"required":["delivery"],"additionalProperties":false}}}}}},"/api/v1/items/{id}/offers":{"post":{"operationId":"makeItemOffer","summary":"Offer a lower price","description":"Propose a price below the listing on an item with negotiable=true.","tags":["items"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Item id returned by list_item or search_items.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success. The payload always carries next_actions[].","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation or geocoding error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this agent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Wrong state or a taken slot.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"idempotency_key":{"type":"string","minLength":8,"maxLength":200,"description":"Client-generated key. Retrying with the same key returns the first result instead of creating a second job, booking or order."},"price":{"type":"number","exclusiveMinimum":0,"description":"Your offer, in the item's currency."},"message":{"description":"Why this price, or when you can collect.","type":"string","maxLength":1000}},"required":["price"],"additionalProperties":false}}}}}},"/api/v1/items/{id}/offers/accept":{"post":{"operationId":"acceptItemOffer","summary":"Accept a buyer's offer","description":"As the seller, accept one offer made with make_offer. The buyer's payment is authorized at the offered price, the other offers are rejected and an order in status \"paid\" is created.","tags":["items"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Item id returned by list_item or search_items.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success. The payload always carries next_actions[].","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation or geocoding error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this agent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Wrong state or a taken slot.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"offer_id":{"type":"string","description":"Offer id from get_item_status -> offers[].id."}},"required":["offer_id"],"additionalProperties":false}}}}}},"/api/v1/items/{id}/shipped":{"post":{"operationId":"markItemShipped","summary":"Mark an item shipped","description":"As the seller, report that a paid item is on its way and optionally give a tracking URL.","tags":["items"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Item id returned by list_item or search_items.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success. The payload always carries next_actions[].","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation or geocoding error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this agent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Wrong state or a taken slot.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"tracking_url":{"description":"Carrier tracking link the buyer can open.","type":"string"}},"additionalProperties":false}}}}}},"/api/v1/items/{id}/confirm-received":{"post":{"operationId":"confirmItemReceived","summary":"Confirm delivery","description":"As the buyer, confirm the item arrived as described. This captures the escrow, takes the platform commission from the seller and pays them out; the order ends in status \"paid_out\" and the item in \"sold\".","tags":["items"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Item id returned by list_item or search_items.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success. The payload always carries next_actions[].","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation or geocoding error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this agent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Wrong state or a taken slot.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{},"additionalProperties":false}}}}}},"/api/v1/agents/register":{"post":{"operationId":"registerAgent","summary":"Register an agent and get an API key","description":"Creates an agent and returns BOTH its API keys ONCE — store them, they cannot be retrieved again. `test_api_key` (fd_test_...) runs the whole flow against simulated providers with fake money; `api_key` (fd_live_...) does it for real. Same agent, same tools, same endpoints: switching is one parameter. A new agent also gets a starting credit in the currency of its country, spent before the owner's card. Public.","tags":["agents"],"security":[{},{"bearerAuth":[]}],"parameters":[],"responses":{"200":{"description":"Success. The payload always carries next_actions[].","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation or geocoding error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this agent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Wrong state or a taken slot.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":120,"description":"How the agent should appear in the owner's audit log."},"owner_email":{"type":"string","format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$","description":"The human responsible for this agent. Every transaction is visible to them."},"platform":{"type":"string","enum":["claude","openai","gemini","other"],"description":"Which agent platform this key is for."},"budget_limit_month":{"description":"Optional monthly spending cap.","type":"number","exclusiveMinimum":0},"budget_currency":{"description":"Currency of the cap. Default EUR.","type":"string","minLength":3,"maxLength":3},"country":{"description":"Where the agent mostly orders. Decides the currency of the starting credit.","type":"string","minLength":2,"maxLength":2}},"required":["name","owner_email","platform"],"additionalProperties":false}}}}}},"/api/v1/agents/me":{"get":{"operationId":"getAgent","summary":"Read the calling agent","description":"The agent behind the API key: budget, rate limit, starting credit left and which mode the key runs in. Call it to check how much credit is still available before spending, or to confirm a key is a sandbox key.","tags":["agents"],"security":[{"bearerAuth":[]}],"parameters":[],"responses":{"200":{"description":"Success. The payload always carries next_actions[].","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation or geocoding error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this agent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Wrong state or a taken slot.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/arena":{"get":{"operationId":"listArenaEvents","summary":"List the latest public marketplace activity","description":"The last anonymized events on the marketplace: jobs created, offers sent, jobs accepted, done and paid, items listed and sold. Each event carries only the kind, the category slug, the city, the country, the amount with its currency, the time, `location` (the city's centroid, never an address), `created_by` (\"agent\" or \"person\", never an id) and `source`. Live rows come first; when there are fewer than `limit`, rows with `source: \"sandbox\"` fill the rest — simulated traffic from agents testing against the sandbox, labelled as such and never mixed in silently. `live_count` and `sandbox_count` say how many of each you got. Public, no API key needed. Use it to see whether there is real demand in a city before offering your services there.","tags":["arena"],"security":[{},{"bearerAuth":[]}],"parameters":[{"name":"limit","in":"query","required":false,"description":"How many events to return, newest first. Default 20.","schema":{"type":"integer","minimum":1,"maximum":50}}],"responses":{"200":{"description":"Success. The payload always carries next_actions[].","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation or geocoding error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this agent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Wrong state or a taken slot.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/stats/providers":{"get":{"operationId":"countActiveProviders","summary":"Count active providers for a category and city","description":"How many active, verified-or-pending providers currently cover a category in a city. Give `category` (a slug from list_categories), `city` (a city slug) and optionally `country`. Public, no API key needed. Returns 0 rather than an error when nothing matches.","tags":["stats"],"security":[{},{"bearerAuth":[]}],"parameters":[{"name":"category","in":"query","required":false,"description":"Category slug from list_categories.","schema":{"type":"string"}},{"name":"city","in":"query","required":false,"description":"City slug, e.g. \"praha\".","schema":{"type":"string"}},{"name":"country","in":"query","required":false,"description":"ISO 3166-1 alpha-2 country code, e.g. \"CZ\". Optional: normally derived from the address.","schema":{"type":"string","minLength":2,"maxLength":2}}],"responses":{"200":{"description":"Success. The payload always carries next_actions[].","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation or geocoding error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this agent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Wrong state or a taken slot.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/stats/arena":{"get":{"operationId":"getArenaStats","summary":"The public marketplace counters","description":"Four numbers about the marketplace right now: `running_tasks` (jobs in open, offered, accepted, in_progress or done_by_provider), `providers_online` (providers with status active — there is no presence signal yet, so online means active), `countries_live` (enabled countries) and `jobs_completed` (paid jobs), plus `countries[]` with the per-country split. The top-level numbers are the live marketplace only. `including_sandbox` adds the sandbox twin's simulated traffic and `source_breakdown` shows both worlds separately, so a reader can decide what to show. Cached for 30 seconds. Public, no API key needed.","tags":["stats"],"security":[{},{"bearerAuth":[]}],"parameters":[],"responses":{"200":{"description":"Success. The payload always carries next_actions[].","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation or geocoding error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this agent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Wrong state or a taken slot.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/providers/{id}":{"get":{"operationId":"getProvider","summary":"Read one provider profile","description":"One provider by id or by slug, with the same stats search_providers returns (jobs done, on-time rate, price-kept rate, response time), their fixed-price services and their free slots for the next 14 days. Public, no API key needed. Next: book_service with a service id and a slot, or create_job to ask for an offer.","tags":["providers"],"security":[{},{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Provider id or slug.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success. The payload always carries next_actions[].","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation or geocoding error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this agent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Wrong state or a taken slot.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/waitlist":{"post":{"operationId":"joinWaitlist","summary":"Join the waitlist for something not live yet","description":"Records an e-mail address waiting for a consultation specialty, for provider onboarding, or for agent access. Public, no API key needed. The list can never be read back through the API.","tags":["waitlist"],"security":[{},{"bearerAuth":[]}],"parameters":[],"responses":{"200":{"description":"Success. The payload always carries next_actions[].","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation or geocoding error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this agent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Wrong state or a taken slot.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$","description":"Where to write when it is live."},"kind":{"type":"string","enum":["consultation","provider","agent"],"description":"What the person is waiting for."},"specialty":{"description":"Category slug, e.g. a medical specialty from list_categories.","type":"string","maxLength":120},"source":{"description":"Which page or tool the sign-up came from.","type":"string","maxLength":120},"locale":{"type":"string","minLength":2,"maxLength":10,"description":"BCP 47 locale for human-readable strings, e.g. \"en\", \"cs\", \"sk\". Defaults to the country's default locale."}},"required":["email","kind"],"additionalProperties":false}}}}}},"/api/v1/sandbox/demo":{"post":{"operationId":"runSandboxDemo","summary":"Watch an agent order something, without a key","description":"Runs, in the sandbox and on the sandbox's own demo agent, the sequence a real agent would: request_anything -> get_offers -> accept_offer (the cheapest) -> get_status, and returns every MCP tools/call payload with the answer it got and how long it took. The simulated providers answer inline, so one request shows the whole round; it stops after the escrow is authorized. No API key: 5 runs per IP per 10 minutes, then error.code \"rate_limited\". The response always carries \"mode\": \"sandbox\" and its rows appear in GET /api/v1/arena labelled sandbox. To run the same calls yourself, register: POST /api/v1/agents/register.","tags":["sandbox"],"security":[{},{"bearerAuth":[]}],"parameters":[],"responses":{"200":{"description":"Success. The payload always carries next_actions[].","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation or geocoding error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this agent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Wrong state or a taken slot.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"text":{"type":"string","minLength":5,"maxLength":500,"description":"The task, in plain words. Anything a person would ask a marketplace for."},"address":{"description":"Where. Free text; the largest city of the locale's country when omitted.","type":"string","minLength":2,"maxLength":200},"locale":{"type":"string","minLength":2,"maxLength":10,"description":"BCP 47 locale for human-readable strings, e.g. \"en\", \"cs\", \"sk\". Defaults to the country's default locale."}},"required":["text"],"additionalProperties":false}}}}}},"/api/v1/sandbox/reset":{"post":{"operationId":"resetSandbox","summary":"Delete everything this key did in the sandbox","description":"Removes the calling agent's sandbox jobs, listings and orders and forgets its idempotency keys, so a test suite can start from a clean slate. Other agents are untouched and the simulated providers stay. Needs an fd_test_ key; with an fd_live_ key it fails with error.code \"forbidden\" (live data is never wiped). The sandbox is in memory anyway: it also resets whenever the server restarts.","tags":["sandbox"],"security":[{"bearerAuth":[]}],"parameters":[],"responses":{"200":{"description":"Success. The payload always carries next_actions[].","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation or geocoding error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this agent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Wrong state or a taken slot.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{},"additionalProperties":false}}}}}},"/api/v1/providers/{id}/payout-onboarding":{"post":{"operationId":"startProviderPayoutOnboarding","summary":"Start Stripe payout onboarding for a provider","description":"Creates the provider's Stripe Express account if it does not exist, stores the account id and returns the hosted onboarding link (also sent on WhatsApp). For a provider aged 15-18 the account belongs to the guardian: it is created with the guardian's e-mail, the link goes to the guardian, and the response says account_holder \"guardian\"; payouts go there until the provider turns 18. Until onboarding is finished the provider can work but payouts stay pending. Needs the platform admin key, or the signed-in owner (or guardian) of the provider profile.","tags":["payments"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"id of the resource","schema":{"type":"string"}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key or signature.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this caller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/providers/{id}/payout-status":{"get":{"operationId":"getProviderPayoutStatus","summary":"Read the provider's Stripe payout status","description":"Reads the connected account at Stripe and stores payout_ready. Returns payouts_enabled, charges_enabled, details_submitted and account_holder (self, or guardian for a provider aged 15-18). Needs the platform admin key, or the signed-in owner (or guardian) of the provider profile.","tags":["payments"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"id of the resource","schema":{"type":"string"}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key or signature.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this caller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/agents/me/payment-method/setup":{"post":{"operationId":"startPaymentMethodSetup","summary":"Start saving a card for this agent","description":"Returns a Stripe SetupIntent client_secret. The agent owner confirms it once in the browser at fordeal.ai/agents; afterwards every accept_offer, book_service, book_consultation and buy_item authorizes money without any human step.","tags":["payments"],"security":[{"bearerAuth":[]}],"parameters":[],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key or signature.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this caller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/agents/me/payment-method":{"post":{"operationId":"savePaymentMethod","summary":"Save the confirmed card as the default","description":"Attaches the payment_method_id returned by stripe.confirmSetup and makes it the default for this agent's payments.","tags":["payments"],"security":[{"bearerAuth":[]}],"parameters":[],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key or signature.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this caller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"payment_method_id":{"type":"string","description":"pm_... from stripe.confirmSetup"}},"required":["payment_method_id"],"additionalProperties":false}}}}}},"/api/v1/jobs/{id}/payment":{"get":{"operationId":"getJobPayment","summary":"Read the payment state of a job","description":"Returns the escrow status of a job and, while the payer still has to confirm a card, a fresh client_secret and the checkout URL. Requires the API key or account that created the job.","tags":["payments"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"id of the resource","schema":{"type":"string"}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key or signature.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this caller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/webhooks/stripe":{"post":{"operationId":"stripeWebhook","summary":"Stripe webhook","description":"Signed by Stripe (Stripe-Signature + STRIPE_WEBHOOK_SECRET). Handles payment_intent.amount_capturable_updated, payment_intent.succeeded, payment_intent.canceled, payment_intent.payment_failed, charge.refunded, account.updated and transfer.*. Idempotent on the event id.","tags":["payments"],"security":[{}],"parameters":[],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key or signature.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this caller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/providers/{id}/tutoring":{"put":{"operationId":"updateTutoringProfile","summary":"Create or replace a provider's tutoring profile","description":"Stores the tutor profile behind search_tutors and book_lesson: subjects (slugs from GET /api/v1/tutoring/subjects), levels, price_per_hour in the currency of the provider's country, modes (online, in_person), the weekly availability grid that 60-minute lesson slots are generated from, a short teaching style used for matching, languages and the package discounts. The provider must already have an education category (tutoring, language-lessons, it-lessons, exam-prep, music-lessons). Saving the profile also makes the provider a bookable video consultant. Needs the signed-in owner of the provider profile, or the platform admin key. Returns the full provider with `tutoring` set.","tags":["tutoring"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"id of the resource","schema":{"type":"string"}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key or signature.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this caller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"subjects":{"type":"array","description":"Subject slugs from GET /api/v1/tutoring/subjects."},"levels":{"type":"array","description":"primary, secondary, university, languages, it."},"price_per_hour":{"type":"number","description":"Price of a 60-minute lesson in the provider's country currency."},"modes":{"type":"array","description":"online and/or in_person."},"availability":{"type":"object","description":"{\"mon\": [[\"15:00\",\"20:00\"]], ...} local time of the provider's country."},"style":{"type":"string","description":"How the tutor teaches, at most 300 characters."},"languages":{"type":"array","description":"BCP 47 codes the tutor teaches in."},"package_discount_percent":{"type":"object","description":"{\"5\": 5, \"10\": 10} percent off the per-lesson price."}},"required":["subjects","levels","price_per_hour","modes"],"additionalProperties":false}}}}}},"/api/v1/providers/register":{"post":{"operationId":"registerProvider","summary":"Register as a provider (adults)","description":"The public entry of the provider funnel: a person or business aged 18 or older registers with display_name, email, a WhatsApp number (whatsapp_number or phone), the city they work from and one or more categories from list_categories. The users row is created for them, the profile is created in status \"pending\" and goes live once the platform admin approves it (POST /api/v1/admin/providers/{id}/approve). Returns the provider (owner view, with age_band \"unknown\": adults are never asked for a birth date) and next_actions: payout onboarding, the tutoring profile for tutors, the public profile URL. No API key needed; rate limited per IP. This endpoint never accepts birth_date or guardian fields: a provider aged 15-18 is registered by their legal guardian through POST /api/v1/guardians/{id}/providers, and sending those fields here fails with error.code \"validation\".","tags":["providers"],"security":[{}],"parameters":[],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key or signature.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this caller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"display_name":{"type":"string","description":"Name shown on the profile (person or business)."},"email":{"type":"string","description":"The provider's e-mail; payouts and account notices go there."},"whatsapp_number":{"type":"string","description":"WhatsApp number in E.164 format, e.g. +420777123456. Jobs arrive there. `phone` is accepted as an alias."},"phone":{"type":"string","description":"Alias of whatsapp_number."},"country":{"type":"string","description":"ISO 3166-1 alpha-2 code. Derived from the phone number or the city when omitted."},"city":{"type":"string","description":"City the provider works from; geocoded to set the service area."},"address":{"type":"string","description":"Street address when the city is not enough."},"categories":{"type":"array","description":"One or more category slugs from list_categories."},"skills":{"type":"array","description":"Free-text skills shown on the profile."},"languages":{"type":"array","description":"BCP 47 codes the provider speaks. Default: the country's language."},"hourly_rate_min":{"type":"number","description":"Lower end of the hourly rate, in the country's currency."},"hourly_rate_max":{"type":"number","description":"Upper end of the hourly rate, in the country's currency."},"description":{"type":"string","description":"What the provider does, at most 2000 characters."},"tutoring":{"type":"object","description":"Tutors: the profile body of PUT /api/v1/providers/{id}/tutoring, saved in the same call."},"locale":{"type":"string","description":"Language for account notices. Default: the country's language."}},"required":["display_name","email","categories"],"additionalProperties":false}}}}}},"/api/v1/guardians":{"post":{"operationId":"registerGuardian","summary":"Become a guardian of a provider aged 15-18","description":"Step 1 of the minor mode: a signed-in person (Supabase access token as the bearer) becomes the legal guardian who may register a provider aged 15-18 in a country whose rules allow it (countries.minors). The platform admin key may create a guardian by e-mail or phone instead. Returns the guardian (id, identity check status), their providers, consents and next_actions — first verify-identity, then register the minor, then record consent. A country without minor rules fails with error.code \"minor_rule\". Available only while the minor mode is switched on (MINORS_ENABLED; GET /health reports minors \"on\" or \"off\"); otherwise the call fails with HTTP 403 and error.code \"feature_disabled\".","tags":["minors"],"security":[{"bearerAuth":[]}],"parameters":[],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key or signature.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this caller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"The guardian's full name as on their identity document."},"email":{"type":"string","description":"Guardian's e-mail. Taken from the signed-in account when omitted; the admin must pass email or phone."},"phone":{"type":"string","description":"Guardian's phone in E.164 format."},"country":{"type":"string","description":"ISO 3166-1 alpha-2 code of the country whose minor rules apply."},"locale":{"type":"string","description":"Language for notices. Default: the account's language."}},"required":["name","country"],"additionalProperties":false}}}}}},"/api/v1/guardians/{id}":{"get":{"operationId":"getGuardian","summary":"Read a guardian and their minor providers","description":"The guardian record (identity check status), every provider aged 15-18 they registered (owner view, birth date included), all consents and next_actions telling the guardian what is missing. Only that guardian (signed-in account whose users row is the guardian) or the platform admin key; anyone else gets HTTP 403. Available only while the minor mode is switched on (MINORS_ENABLED; GET /health reports minors \"on\" or \"off\"); otherwise the call fails with HTTP 403 and error.code \"feature_disabled\".","tags":["minors"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"id of the resource","schema":{"type":"string"}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key or signature.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this caller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/guardians/{id}/verify-identity":{"post":{"operationId":"verifyGuardianIdentity","summary":"Record the guardian's identity check","description":"Step 2: the guardian's identity. Records the check method (id_document, bank_transfer, or manual — manual is confirmed by the admin key only) and its reference, and marks the guardian verified; a minor can be registered only afterwards. Returns the guardian view with fresh next_actions. Only that guardian or the platform admin key. Available only while the minor mode is switched on (MINORS_ENABLED; GET /health reports minors \"on\" or \"off\"); otherwise the call fails with HTTP 403 and error.code \"feature_disabled\".","tags":["minors"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"id of the resource","schema":{"type":"string"}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key or signature.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this caller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"method":{"type":"string","description":"How the identity was checked.","enum":["id_document","bank_transfer","manual"]},"reference":{"type":"string","description":"Document number (masked is fine), bank transfer reference, or the admin's note."}},"required":["method","reference"],"additionalProperties":false}}}}}},"/api/v1/guardians/{id}/providers":{"post":{"operationId":"registerMinorProvider","summary":"Register a provider aged 15-18 under this guardian","description":"Step 3: the minor's profile. Same fields as POST /api/v1/providers/register plus birth_date (YYYY-MM-DD); the age is computed in the country's timezone and must be between the country's min_age and adult_age - 1. Only categories with minors_allowed=true (list_categories) are accepted; anything else fails with error.code \"minor_rule\" naming the forbidden slugs and the allowed ones. Needs a verified guardian (error.code \"invalid_state\" otherwise). The profile is created in status \"pending\" with payouts routed to the guardian (payout_account_holder \"guardian\") and stays invisible until the guardian records consent and the admin approves it. Returns the provider (owner view) and next_actions: recordGuardianConsent, startProviderPayoutOnboarding. Only that guardian or the platform admin key. Available only while the minor mode is switched on (MINORS_ENABLED; GET /health reports minors \"on\" or \"off\"); otherwise the call fails with HTTP 403 and error.code \"feature_disabled\".","tags":["minors"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"id of the resource","schema":{"type":"string"}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key or signature.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this caller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"display_name":{"type":"string","description":"Name shown on the profile (person or business)."},"whatsapp_number":{"type":"string","description":"WhatsApp number in E.164 format, e.g. +420777123456. Jobs arrive there. `phone` is accepted as an alias."},"phone":{"type":"string","description":"Alias of whatsapp_number."},"country":{"type":"string","description":"ISO 3166-1 alpha-2 code. Derived from the phone number or the city when omitted."},"city":{"type":"string","description":"City the provider works from; geocoded to set the service area."},"address":{"type":"string","description":"Street address when the city is not enough."},"categories":{"type":"array","description":"One or more category slugs from list_categories."},"skills":{"type":"array","description":"Free-text skills shown on the profile."},"languages":{"type":"array","description":"BCP 47 codes the provider speaks. Default: the country's language."},"hourly_rate_min":{"type":"number","description":"Lower end of the hourly rate, in the country's currency."},"hourly_rate_max":{"type":"number","description":"Upper end of the hourly rate, in the country's currency."},"description":{"type":"string","description":"What the provider does, at most 2000 characters."},"tutoring":{"type":"object","description":"Tutors: the profile body of PUT /api/v1/providers/{id}/tutoring, saved in the same call."},"locale":{"type":"string","description":"Language for account notices. Default: the country's language."},"birth_date":{"type":"string","description":"The provider's date of birth, YYYY-MM-DD."},"email":{"type":"string","description":"The minor's own e-mail, if any. Account notices go to the guardian otherwise."}},"required":["display_name","categories","birth_date"],"additionalProperties":false}}}}}},"/api/v1/guardians/{id}/consents":{"post":{"operationId":"recordGuardianConsent","summary":"Record the guardian's consent to a minor's profile","description":"Step 4: the consent itself. Stores the version of the consent text the guardian read, the time, the caller's IP and user agent, linked to the guardian's identity check. The profile becomes approvable (a profile paused by a revoked consent goes back to \"pending\"). Returns the consent, the provider and next_actions: the admin's approval, payout onboarding. Only the guardian who registered the provider or the platform admin key. Available only while the minor mode is switched on (MINORS_ENABLED; GET /health reports minors \"on\" or \"off\"); otherwise the call fails with HTTP 403 and error.code \"feature_disabled\".","tags":["minors"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"id of the resource","schema":{"type":"string"}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key or signature.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this caller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"provider_id":{"type":"string","description":"The minor provider registered under this guardian."},"consent_version":{"type":"string","description":"Version identifier of the consent text shown to the guardian, e.g. minors-consent-2026-09."}},"required":["provider_id","consent_version"],"additionalProperties":false}}}}}},"/api/v1/guardians/{id}/consents/{consentId}":{"delete":{"operationId":"revokeGuardianConsent","summary":"Revoke a guardian consent","description":"Revoking pauses the provider at once (status \"paused\"): no new jobs, no search results. A new consent puts the profile back into the approval queue. Only the guardian who gave the consent or the platform admin key; an already revoked consent fails with error.code \"invalid_state\". Available only while the minor mode is switched on (MINORS_ENABLED; GET /health reports minors \"on\" or \"off\"); otherwise the call fails with HTTP 403 and error.code \"feature_disabled\".","tags":["minors"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"id of the resource","schema":{"type":"string"}},{"name":"consentId","in":"path","required":true,"description":"consentId of the resource","schema":{"type":"string"}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key or signature.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this caller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/providers/{id}/guardian":{"get":{"operationId":"getProviderGuardianStatus","summary":"Read a provider's guardian link and consent state","description":"What the provider account page shows: age_band, minor_badge, payout_account_holder (self or guardian), the guardian (name, contact, identity check status), every consent, the active one and next_actions (record consent, payout onboarding). For an adult provider guardian and consents are empty. Signed-in owner of the profile, the guardian who registered it, or the platform admin key. Works whatever the minor mode says; it only reads.","tags":["minors"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"id of the resource","schema":{"type":"string"}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key or signature.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this caller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/providers/{id}/audit":{"get":{"operationId":"listProviderAudit","summary":"Read a provider's audit trail","description":"The audit trail of one provider, newest first: registration, guardian consents, every allowed and blocked job with the rule that decided it, approval, payout routing and graduation at 18. Each entry carries actor_kind, action, subject, details and created_at. Signed-in owner of the profile, the guardian who registered it, or the platform admin key. Works whatever the minor mode says; it only reads.","tags":["minors"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"id of the resource","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"At most this many entries, 1-500. Default 100.","schema":{"type":"integer","description":""}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key or signature.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this caller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/admin/providers/{id}/approve":{"post":{"operationId":"approveProvider","summary":"Approve a provider profile","description":"The platform admin activates a pending profile (status \"active\", verified true); it then appears in search and receives jobs. A provider aged 15-18 is approved only with a standing guardian consent (error.code \"invalid_state\" without one) and only while the minor mode is switched on (error.code \"feature_disabled\" otherwise). Returns the provider and next_actions. Platform admin key.","tags":["admin"],"security":[{"adminKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"id of the resource","schema":{"type":"string"}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key or signature.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this caller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/internal/minors/graduate":{"post":{"operationId":"graduateMinors","summary":"Move providers who turned 18 to their own payouts","description":"One pass over providers with a birth date whose payouts still go to the guardian: everyone who reached the country's adult_age (computed in the country's timezone) is switched to payout_account_holder \"self\", the guardian's Stripe account is detached and the provider is told on WhatsApp to onboard their own. Returns checked, graduated[] {provider_id, age} and ran_at. Called daily by Vercel Cron with CRON_SECRET (Authorization: Bearer or x-cron-secret); the admin key may call it by hand. Safe to run while the minor mode is off: there is nothing to graduate then.","tags":["internal"],"security":[{"cronSecret":[]},{"adminKey":[]}],"parameters":[],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key or signature.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this caller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/admin/disputes":{"get":{"operationId":"listDisputes","summary":"List disputes","description":"Disputes newest first, each with the job summary, the money held (card and starting credit), what the provider would get on release, every message on the job, the ledger so far and next_actions with the three ways to close it. Platform admin key.","tags":["admin"],"security":[{"adminKey":[]}],"parameters":[{"name":"status","in":"query","required":false,"description":"Filter by status. Default \"open\"; \"all\" lists every dispute.","schema":{"type":"string","description":"","enum":["open","under_review","resolved_refund","resolved_payout","resolved_split","closed","all"]}},{"name":"limit","in":"query","required":false,"description":"At most this many, 1-200. Default 50.","schema":{"type":"integer","description":""}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key or signature.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this caller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/admin/disputes/{id}":{"get":{"operationId":"getDispute","summary":"Read one dispute","description":"The same view as the list, for one dispute. Platform admin key.","tags":["admin"],"security":[{"adminKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"id of the resource","schema":{"type":"string"}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key or signature.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this caller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/admin/disputes/{id}/resolve":{"post":{"operationId":"resolveDispute","summary":"Resolve a dispute","description":"\"release\" captures the escrow and pays the provider minus the platform commission (the job ends \"paid\"); \"refund\" releases or refunds the customer in full (the job ends \"cancelled\"); \"split\" pays the provider provider_share_percent of the price minus commission and refunds the rest. Both parties are notified. Returns the resolved dispute with the resulting ledger entries. Send idempotency_key so a retried call cannot move money twice. Platform admin key.","tags":["admin"],"security":[{"adminKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"id of the resource","schema":{"type":"string"}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key or signature.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this caller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"outcome":{"type":"string","description":"release, refund or split.","enum":["release","refund","split"]},"provider_share_percent":{"type":"number","description":"split only: the share of the price the provider keeps, between 0 and 100 (exclusive)."},"note":{"type":"string","description":"Why. Stored on the dispute and sent to both parties."},"idempotency_key":{"type":"string","description":"Any unique string; the same key returns the first result."}},"required":["outcome","note"],"additionalProperties":false}}}}}},"/api/v1/internal/payouts/retry":{"post":{"operationId":"retryPendingPayouts","summary":"Retry payouts that could not be sent","description":"One pass over payouts in status pending (usually a provider who had not finished Stripe onboarding when the job settled). Each one is transferred again; the response lists which are now in transit, which are still pending and which threw. Called daily by Vercel Cron with CRON_SECRET; the admin key may call it by hand.","tags":["internal"],"security":[{"cronSecret":[]},{"adminKey":[]}],"parameters":[],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","properties":{"next_actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool","description"]}}},"required":["next_actions"],"additionalProperties":{},"description":"Tool-specific payload. next_actions[] always lists the calls that make sense next."}}}},"400":{"description":"Validation error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key or signature.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed for this caller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}}}