{"openapi":"3.1.0","info":{"title":"Delphy API","version":"0.1","description":"The @identity for the agentic web. Discover, inspect, and onboard any entity — businesses, professionals, services, organizations, and more."},"servers":[{"url":"https://delphy.network","description":"Production"},{"url":"http://localhost:3000","description":"Local development"}],"paths":{"/api/search":{"get":{"summary":"Search capabilities","description":"Full-text search with optional filters. At least one parameter is required.","parameters":[{"name":"q","in":"query","schema":{"type":"string"},"description":"Full-text search query"},{"name":"category","in":"query","schema":{"type":"string"},"description":"Filter by category"},{"name":"kind","in":"query","schema":{"type":"string","enum":["business","service","api","mcp","cli","workflow","skill","knowledge_source","person","professional","organization","city_service"]},"description":"Filter by kind"},{"name":"near","in":"query","schema":{"type":"string"},"description":"Filter by location (matches country or state)"},{"name":"limit","in":"query","schema":{"type":"integer","default":10,"maximum":50},"description":"Max results to return"}],"responses":{"200":{"description":"Search results","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchResponse"}}}},"400":{"description":"No search parameters provided"}}}},"/api/capabilities/{slug}":{"get":{"summary":"Get capability profile","description":"Fetch a structured capability profile by slug.","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"},"description":"Capability profile slug (e.g., kalizo-limestone)"}],"responses":{"200":{"description":"Capability profile","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CapabilityProfile"}}}},"404":{"description":"Capability not found"}}}},"/@{slug}/delphy.json":{"get":{"summary":"Get raw delphy.json manifest","description":"Fetch the canonical delphy.json for a capability.","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Raw delphy.json manifest","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Capability not found"}}}},"/api/discover":{"get":{"summary":"Discover nearby entities","description":"Geocodes a location via Nominatim and searches OpenStreetMap for entities. Merges with Delphy registry results.","parameters":[{"name":"q","in":"query","required":true,"schema":{"type":"string"},"description":"What to find (e.g., restaurants, dentist, cafe)"},{"name":"near","in":"query","required":true,"schema":{"type":"string"},"description":"Location text (e.g., Katy, TX)"},{"name":"radius","in":"query","schema":{"type":"integer","default":3000,"maximum":10000},"description":"Search radius in meters"},{"name":"limit","in":"query","schema":{"type":"integer","default":20,"maximum":50},"description":"Max results to return"}],"responses":{"200":{"description":"Discover results from OpenStreetMap and Delphy","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiscoverResponse"}}}},"400":{"description":"Missing q or near, or unknown location"},"502":{"description":"Geocoding service unavailable"}}}},"/api/discover/import":{"post":{"summary":"Import a discovered entity as a draft profile","description":"Creates a draft Delphy profile from OpenStreetMap data. Requires Bearer authorization.","security":[{"BearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiscoverImportRequest"}}}},"responses":{"200":{"description":"Profile created or existing draft returned","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiscoverImportResponse"}}}},"400":{"description":"Missing required fields"},"401":{"description":"Missing or invalid Bearer token"},"409":{"description":"Published profile already exists"}}}},"/oauth/token":{"post":{"summary":"Exchange credentials for a Bearer token","description":"Two grant types: (1) claim_secret — provide slug + claim_secret. (2) authorization_code — provide code + redirect_uri from the OAuth authorize flow.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenRequest"}}}},"responses":{"200":{"description":"Bearer token issued","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenResponse"}}}},"400":{"description":"Missing or invalid fields"},"401":{"description":"Invalid credentials or authorization code"}}}},"/api/oauth/authorize":{"post":{"summary":"Generate an OAuth authorization code","description":"Validates claim_secret credentials and returns an authorization code for the OAuth Authorization Code flow. The code can be exchanged at POST /oauth/token.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthorizeRequest"}}}},"responses":{"200":{"description":"Authorization code generated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthorizeResponse"}}}},"400":{"description":"Missing fields, invalid redirect_uri, or unsafe scheme"},"401":{"description":"Invalid credentials"}}}},"/api/profile/{slug}":{"patch":{"summary":"Edit a capability profile","description":"Update fields on an existing profile. Requires a Bearer token that belongs to the profile's slug.","security":[{"BearerAuth":[]}],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"},"description":"Profile slug"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfileEditRequest"}}}},"responses":{"200":{"description":"Profile updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CapabilityProfile"}}}},"400":{"description":"Invalid data (schema validation failed)"},"401":{"description":"Missing or invalid token"},"403":{"description":"Token does not belong to this profile"},"404":{"description":"Profile not found"}}}},"/api/onboard":{"post":{"summary":"Validate or create a capability profile","description":"dry_run mode validates and returns a normalized preview. create mode creates a public draft profile (no auth required, rate-limited to 10/hour per IP).","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardRequest"}}}},"responses":{"200":{"description":"Validation/creation result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardResponse"}}}},"400":{"description":"Invalid request body"},"409":{"description":"Slug already taken (draft or published)"},"429":{"description":"Rate limit exceeded"}}}}},"components":{"schemas":{"SearchResponse":{"type":"object","properties":{"query":{"type":"string"},"results":{"type":"array","items":{"$ref":"#/components/schemas/SearchResult"}}}},"SearchResult":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string"},"summary":{"type":"string"},"categories":{"type":"array","items":{"type":"string"}},"phone":{"type":"string","nullable":true},"location":{"type":"object","nullable":true},"profile_url":{"type":"string"},"delphy_json_url":{"type":"string"}}},"CapabilityProfile":{"type":"object","properties":{"slug":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string"},"summary":{"type":"string"},"categories":{"type":"array","items":{"type":"string"}},"location":{"type":"object","nullable":true,"description":"Coarse discovery location (country, state, city)"},"address":{"type":"object","nullable":true,"description":"Structured postal address (street, city, state, postal_code, country)"},"phone":{"type":"string","nullable":true},"email":{"type":"string","nullable":true},"website":{"type":"string","nullable":true},"opening_hours":{"type":"string","nullable":true},"contact":{"type":"object","nullable":true,"description":"Reachability declaration (method + value)"},"interfaces":{"type":"array","nullable":true},"capabilities":{"type":"array"},"agent_instructions":{"type":"string","nullable":true},"metadata":{"type":"object","nullable":true,"description":"Kind-specific fields (specialties, credentials, cuisine, etc.)"},"status":{"type":"string"},"visibility":{"type":"string"},"profile_url":{"type":"string"},"delphy_json_url":{"type":"string"}}},"OnboardRequest":{"type":"object","required":["profile"],"properties":{"mode":{"type":"string","enum":["dry_run","create"],"default":"dry_run"},"profile":{"type":"object","description":"A delphy.json manifest to validate or create"}}},"OnboardResponse":{"type":"object","properties":{"valid":{"type":"boolean"},"mode":{"type":"string"},"slug":{"type":"string","description":"Profile slug (create mode only)"},"claim_secret":{"type":"string","description":"Claim secret for this profile (create mode only). Format: dph_claim_<32hex>. Shown only once — save it immediately."},"claim_secret_warning":{"type":"string"},"profile":{"type":"object"},"profile_url":{"type":"string"},"skill_url":{"type":"string"},"delphy_json_url":{"type":"string"},"normalized":{"type":"object"},"errors":{"type":"array","items":{"type":"string"}},"warnings":{"type":"array","items":{"type":"string"}}}},"DiscoverResponse":{"type":"object","properties":{"query":{"type":"string"},"location":{"type":"object","properties":{"input":{"type":"string"},"resolved":{"type":"string"},"lat":{"type":"number"},"lon":{"type":"number"}}},"warnings":{"type":"array","items":{"type":"string"}},"results":{"type":"array"}}},"DiscoverImportRequest":{"type":"object","required":["name","lat","lon"],"properties":{"name":{"type":"string"},"amenity":{"type":"string"},"lat":{"type":"number"},"lon":{"type":"number"},"address":{"type":"object"},"phone":{"type":"string"},"website":{"type":"string"},"cuisine":{"type":"string"},"opening_hours":{"type":"string"}}},"DiscoverImportResponse":{"type":"object","properties":{"created":{"type":"boolean"},"slug":{"type":"string"},"profile_url":{"type":"string"},"delphy_json_url":{"type":"string"},"message":{"type":"string"}}},"TokenRequest":{"type":"object","description":"Either claim_secret grant (slug + claim_secret) or authorization_code grant (grant_type + code + redirect_uri)","properties":{"grant_type":{"type":"string","enum":["authorization_code"],"description":"Set to 'authorization_code' for code exchange. Omit for claim_secret grant."},"slug":{"type":"string","description":"Profile slug (claim_secret grant)"},"claim_secret":{"type":"string","description":"Claim secret (claim_secret grant)"},"code":{"type":"string","description":"Authorization code (authorization_code grant)"},"redirect_uri":{"type":"string","description":"Must match the redirect_uri used at /api/oauth/authorize (authorization_code grant)"}}},"TokenResponse":{"type":"object","properties":{"access_token":{"type":"string","description":"Bearer token (format: dph_tk_<32hex>)"},"token_type":{"type":"string","enum":["bearer"]},"expires_in":{"type":"integer","description":"Token lifetime in seconds (default: 86400)"},"slug":{"type":"string"}}},"AuthorizeRequest":{"type":"object","required":["slug","claim_secret","redirect_uri"],"properties":{"slug":{"type":"string"},"claim_secret":{"type":"string"},"redirect_uri":{"type":"string","description":"Must be http or https scheme"},"state":{"type":"string","description":"Opaque state value passed through to the redirect"}}},"AuthorizeResponse":{"type":"object","properties":{"redirect_uri":{"type":"string","description":"The redirect_uri with code and state appended as query params"},"code":{"type":"string","description":"Authorization code (format: dph_code_<32hex>)"}}},"ProfileEditRequest":{"type":"object","description":"Partial update — include only the fields you want to change","properties":{"name":{"type":"string"},"summary":{"type":"string"},"categories":{"type":"array","items":{"type":"string"}},"capabilities":{"type":"array"},"location":{"type":"object"},"contact":{"type":"object"},"interfaces":{"type":"array"},"phone":{"type":"string"},"email":{"type":"string"},"website":{"type":"string"},"address":{"type":"object"},"opening_hours":{"type":"string"},"metadata":{"type":"object"},"agent_instructions":{"type":"string"}}}},"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer"}}}}