{"openapi":"3.1.0","info":{"title":"Habitcore","version":"1.0.0","description":"Behavioural analytics for habit and routine data. Scores adherence and consistency, measures streaks and momentum, flags lapse risk, correlates mood and energy against completion, and produces ranked next-best actions and multi-week plans. Use it for habit tracking, routine optimisation, adherence monitoring, engagement and churn-risk signals, streak analysis, consistency scoring, and coaching recommendations. Exposed two ways from one engine: a pay-per-call x402 surface for autonomous agents under /agent/v1 (USDC on Base, no account, no API key, from $0.03 per call), and a JWT-authenticated surface for human applications under /v1. Agent endpoints are stateless: they operate only on the summaries supplied in the request body and cannot read, list or infer any stored user history. Deterministic and CPU-only unless a model is explicitly configured, so results are reproducible for the same input.","contact":{"url":"https://api.mydev-tools.tech"},"license":{"name":"Proprietary","url":"https://api.mydev-tools.tech/"},"termsOfService":"https://api.mydev-tools.tech/","x-guidance":"This API scores and plans habits. Two surfaces share one engine:\n\nAGENT SURFACE (/agent/v1/*) — pay per call over x402, no account needed.\nPrices: analyze $0.05, plan $0.10, insights $0.05, recommend $0.03. Settled in USDC on eip155:8453.\n\nHow to call a paid endpoint:\n1. POST the endpoint with no X-PAYMENT header. You get 402 and a PAYMENT-REQUIRED response header (base64 JSON) plus a JSON body describing the scheme, network, atomic amount, asset and payTo address.\n2. Sign that authorization with your own wallet and retry the identical request with the resulting payload in the X-PAYMENT header.\n3. On success you get 200 and the analysis. A 502 means payment verification was briefly unreachable; nothing was charged, retry after Retry-After.\n\nRequest shape: every agent endpoint takes the same body — habits (1-25 summaries, each with name, completion_rate 0-1, current_streak, best_streak, optional average_mood, mood_correlation, energy_trend, risk_score) plus optional horizon_days (7-180), persona and locale. Batch habits into one call rather than issuing one call per habit; the price is per request, not per habit.\n\nChoosing an endpoint: /recommend is deterministic and cheapest — use it for high-frequency loops. /analyze and /insights score and explain. /plan is the most compute-intensive and produces a scheduled, horizon-bounded plan.\n\nPrivacy boundary: agent endpoints are stateless. They read only the habits in your request body. There is no parameter, identifier or query that lets an agent reach a stored human user's history, and none will be added — do not attempt to pass user IDs.\n\nHUMAN SURFACE (/v1/*) — JWT only, for the habit application. Not payable and not usable by agents; an x402 payment will not authorize it.\n\nLimits: requests are rate limited per caller and request bodies are size capped; both return 429/413 with a JSON error of the shape { error, message }. Retry with backoff and honour Retry-After."},"servers":[{"url":"https://api.mydev-tools.tech","description":"Production"}],"security":[],"tags":[{"name":"agent","description":"x402 pay-per-call endpoints for autonomous agents. USDC on Base, no account required."},{"name":"analytics","description":"Behavioural analytics: adherence, consistency, streaks, momentum and lapse risk."},{"name":"behavioural-intelligence","description":"Pattern detection, correlation and planning over habit and routine data."},{"name":"reliability","description":"Operational reliability scoring for recurring tasks, jobs and pipelines."},{"name":"human","description":"JWT-authenticated endpoints for the habit application."},{"name":"billing","description":"Subscription plans, entitlements and provider webhooks for the human application."},{"name":"meta","description":"Discovery and health."},{"name":"discovery","description":"Free, unauthenticated endpoints an agent reads before deciding to buy: the capability catalogue, the price list and the volume-rebate terms."},{"name":"admin","description":"Operator-only revenue reporting. Requires X-Admin-Token."}],"x-x402":{"version":1,"scheme":"exact","network":"eip155:8453","asset":"USDC","payTo":"0x9333e2b421A33428D71b7E03cc050C297d85BDA6","facilitator":"https://api.cdp.coinbase.com/platform/v2/x402","discovery":"/openapi.json"},"paths":{"/agent/v1/reliability/analyze":{"get":{"operationId":"agentReliabilityAnalyzeProbe","summary":"Operational reliability analysis — discovery probe","description":"Always answers 402 with the payment challenge, for directory crawlers that probe with GET. Never accepts payment and never returns a result; the resource is invoked with POST.","tags":["discovery","agent"],"security":[],"responses":{"402":{"description":"Payment challenge in the PAYMENT-REQUIRED header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"agentAnalyzeReliability","summary":"Score reliability of recurring tasks, jobs and pipelines","description":"Reliability analysis over up to 25 recurring tasks in one call: success rate, streak recovery, lapse risk, latency-trend signals and ranked remediation ordered by priority. Use for pipeline and cron monitoring, SLA and uptime adherence, flaky-job triage, agent task reliability, and deciding what to fix first. Deterministic threshold analysis over the figures supplied — no model, no log parsing, no root-cause inference, so the same input always yields the same output. Stateless: no identifier of any stored record is accepted.","tags":["agent","analytics","reliability"],"security":[],"x-payment-info":{"price":{"mode":"fixed","currency":"USD","amount":"0.080000"},"protocols":[{"x402":{}}]},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["tasks"],"properties":{"system":{"type":"string","maxLength":120,"description":"Optional label to correlate the response with a system."},"tasks":{"type":"array","minItems":1,"maxItems":25,"description":"Price is per request, not per task — batch aggressively.","items":{"type":"object","required":["name","success_rate","current_streak","best_streak"],"properties":{"name":{"type":"string"},"success_rate":{"type":"number","minimum":0,"maximum":1},"current_streak":{"type":"integer","minimum":0,"description":"Consecutive successful runs right now."},"best_streak":{"type":"integer","minimum":0},"runs":{"type":"integer","minimum":0,"description":"Total runs observed. Fewer than 10 marks the assessment provisional."},"latency_trend":{"type":"string","enum":["rising","stable","falling"],"description":"Rising is the degradation signal."},"p95_latency_ms":{"type":"number","minimum":0},"risk_score":{"type":"number","minimum":0,"maximum":1,"description":"Caller prior; blended, never overriding."},"cadence":{"type":"string","enum":["continuous","hourly","daily","weekly","ad_hoc"]},"critical":{"type":"boolean","description":"Raises severity and recommendation priority."}}}}}}}}},"responses":{"200":{"description":"Reliability assessment with ranked remediation.","content":{"application/json":{"schema":{"type":"object","required":["summary","assessments"],"properties":{"system":{"type":["string","null"]},"summary":{"type":"object"},"assessments":{"type":"array","items":{"type":"object"}},"watchouts":{"type":"array","items":{"type":"string"}},"recommendations":{"type":"array","items":{"type":"object"}},"method":{"type":"string","description":"States that the analysis is deterministic and model-free."}}}}}},"400":{"description":"Validation failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Payment required. Terms in the PAYMENT-REQUIRED header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentRequired"}}}}}}},"/v1/habits/{habitId}/logs":{"post":{"operationId":"logHabitEvent","summary":"Record a habit completion","description":"Logs one occurrence of a habit with optional mood, energy, stress and context. These signals are what the intelligence engine correlates against completion; raw notes stay in the database and never cross the LLM boundary.","tags":["human"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"habitId","in":"path","required":true,"description":"Habit to log against. Must belong to the authenticated user.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["occurredAt","status"],"properties":{"occurredAt":{"type":"string","format":"date-time"},"status":{"type":"string","enum":["COMPLETED","SKIPPED","PARTIAL"]},"completionRate":{"type":"number","minimum":0,"maximum":1},"durationMinutes":{"type":"integer","minimum":0,"maximum":1440},"moodScore":{"type":"integer","minimum":1,"maximum":10},"energyScore":{"type":"integer","minimum":1,"maximum":10},"stressScore":{"type":"integer","minimum":1,"maximum":10},"contextTags":{"type":"array","maxItems":12,"items":{"type":"string","maxLength":32}},"note":{"type":"string","maxLength":1024}}}}}},"responses":{"201":{"description":"Log entry created.","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid access token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Habit not found, or not owned by this user.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/auth/me":{"get":{"operationId":"getProfile","summary":"Current user profile","description":"Profile and tier of the authenticated user.","tags":["human"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Profile.","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid access token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/auth/token/rotate":{"post":{"operationId":"rotateAccessToken","summary":"Rotate the access token","description":"Issues a fresh access token for an already-authenticated session. Distinct from /v1/auth/refresh, which exchanges a refresh token.","tags":["human"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"New access token.","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid access token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/admin/revenue/summary":{"get":{"operationId":"adminRevenueSummary","summary":"Revenue summary (window, today, all-time)","description":"Gross revenue, attributed cost and net margin over a rolling window, the current UTC day, and all time. Sourced from the AgentUsageDaily rollup so it cannot disagree with the per-endpoint breakdown.","tags":["admin"],"security":[{"adminToken":[]}],"parameters":[{"name":"days","in":"query","required":false,"description":"Rolling window length in days. Clamped to 1-365. Defaults to 30.","schema":{"type":"integer","minimum":1,"maximum":365,"default":30}}],"responses":{"200":{"description":"Revenue figures. Money is returned both rounded to cents and at full precision.","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid X-Admin-Token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"ADMIN_API_TOKEN is not configured, so the capability is switched off.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/admin/revenue/endpoints":{"get":{"operationId":"adminRevenueEndpoints","summary":"Per-endpoint revenue breakdown","description":"Which paid route actually earns. Endpoints with zero traffic are still listed — a route earning nothing is a signal, not something to hide.","tags":["admin"],"security":[{"adminToken":[]}],"parameters":[{"name":"days","in":"query","required":false,"description":"Rolling window length in days. Clamped to 1-365. Defaults to 30.","schema":{"type":"integer","minimum":1,"maximum":365,"default":30}}],"responses":{"200":{"description":"Revenue figures. Money is returned both rounded to cents and at full precision.","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid X-Admin-Token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"ADMIN_API_TOKEN is not configured, so the capability is switched off.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/admin/revenue/timeseries":{"get":{"operationId":"adminRevenueTimeseries","summary":"Daily revenue timeseries","description":"One zero-filled point per UTC day, for charting. Gaps are made explicit because a gap in a revenue chart reads as missing data rather than a genuine zero.","tags":["admin"],"security":[{"adminToken":[]}],"parameters":[{"name":"days","in":"query","required":false,"description":"Rolling window length in days. Clamped to 1-365. Defaults to 30.","schema":{"type":"integer","minimum":1,"maximum":365,"default":30}}],"responses":{"200":{"description":"Revenue figures. Money is returned both rounded to cents and at full precision.","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid X-Admin-Token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"ADMIN_API_TOKEN is not configured, so the capability is switched off.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/admin/revenue/payments":{"get":{"operationId":"adminRecentPayments","summary":"Recent settled payments","description":"Most recent verified payments, newest first, with payer wallet and the on-chain transaction hash when the facilitator returned one.","tags":["admin"],"security":[{"adminToken":[]}],"parameters":[{"name":"limit","in":"query","required":false,"description":"Maximum rows to return.","schema":{"type":"integer","minimum":1,"maximum":200,"default":25}}],"responses":{"200":{"description":"Revenue figures. Money is returned both rounded to cents and at full precision.","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid X-Admin-Token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"ADMIN_API_TOKEN is not configured, so the capability is switched off.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/admin/revenue/customers":{"get":{"operationId":"adminRevenueCustomers","summary":"Paying wallets, tier mix and rebate liability","description":"Wallets ranked by lifetime spend, tier distribution, rebate issued, and the face value of credits issued but not yet redeemed — an obligation against future capacity.","tags":["admin"],"security":[{"adminToken":[]}],"parameters":[{"name":"limit","in":"query","required":false,"description":"Maximum rows to return.","schema":{"type":"integer","minimum":1,"maximum":200,"default":25}}],"responses":{"200":{"description":"Revenue figures. Money is returned both rounded to cents and at full precision.","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid X-Admin-Token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"ADMIN_API_TOKEN is not configured, so the capability is switched off.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/agent/v1/pricing":{"get":{"operationId":"getAgentPricing","summary":"Price list and volume-rebate terms","description":"Machine-readable prices for every paid endpoint, the volume-rebate tier ladder, and the calling wallet own standing when a payment payload or wallet hint is presented. Free: charging for the price list would be self-defeating.","tags":["discovery","agent"],"security":[],"responses":{"200":{"description":"Prices, rebate tiers and caller standing.","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/v1/capabilities":{"get":{"operationId":"getCapabilityManifest","summary":"Capability manifest","description":"Capability-oriented catalogue: each capability this platform provides, with its JSON Schema for input and output, the price an external caller pays, and the paid endpoint that serves it. Intended for orchestrators matching on a needed capability rather than on a product name. Also served at /.well-known/capabilities.","tags":["discovery"],"security":[],"responses":{"200":{"description":"Capabilities with schemas, prices and limits.","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/.well-known/capabilities":{"get":{"operationId":"getCapabilityManifestWellKnown","summary":"Capability manifest (well-known alias)","description":"Identical to /v1/capabilities, at the conventional well-known path.","tags":["discovery"],"security":[],"responses":{"200":{"description":"Capabilities with schemas, prices and limits.","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/llms.txt":{"get":{"operationId":"getLlmsTxt","summary":"Plain-text capability pitch for LLM crawlers","description":"The plain-text analogue of robots.txt for capabilities: what is offered, what it costs, how to pay, and the rebate programme. Read by agent frameworks and LLM crawlers that do not parse OpenAPI.","tags":["discovery"],"security":[],"responses":{"200":{"description":"Plain text.","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/dashboard":{"get":{"operationId":"getRevenueDashboard","summary":"Operator revenue dashboard (HTML)","description":"Self-contained HTML page. Holds no secret: it prompts for the admin token in-browser and calls the gated /v1/admin/revenue/* API with it. Served with X-Robots-Tag noindex.","tags":["admin"],"security":[],"responses":{"200":{"description":"HTML dashboard.","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/":{"get":{"operationId":"getServiceDescriptor","summary":"Service descriptor","description":"Machine-readable index of the paid agent endpoints and their prices.","tags":["meta"],"security":[],"responses":{"200":{"description":"Service descriptor"},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/health":{"get":{"operationId":"getHealth","summary":"Health check","description":"Liveness probe. Returns service status without authentication.","tags":["meta"],"security":[],"responses":{"200":{"description":"OK"},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/openapi.json":{"get":{"operationId":"getOpenApi","summary":"This document","description":"Returns this OpenAPI 3.1 document, including agent pricing metadata.","tags":["meta"],"security":[],"responses":{"200":{"description":"OpenAPI 3.1 document"},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/agent/v1/habits/analyze":{"get":{"operationId":"agentAnalyzeHabitsProbe","summary":"Analyse behavioural adherence, consistency and streak momentum — discovery probe","description":"Always answers 402 with the payment challenge, for directory crawlers that probe with GET. Never accepts payment and never returns a result: the resource is invoked with POST. Paying and retrying a GET moves no funds.","tags":["discovery","agent"],"security":[],"responses":{"402":{"description":"Payment challenge in the PAYMENT-REQUIRED header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"agentAnalyzeHabits","summary":"Analyse behavioural adherence, consistency and streak momentum","description":"Behavioural analysis over up to 25 habits in one call: adherence and consistency scores, streak momentum, lapse-risk flags, plus aggregate summary, highlights, watchouts and recommendations. Stateless: operates only on the supplied payload.","tags":["agent","analytics","behavioural-intelligence"],"security":[{"x402Payment":[]}],"x-payment-info":{"price":{"mode":"fixed","currency":"USD","amount":"0.05"},"protocols":[{"x402":{}}]},"x-x402":{"scheme":"exact","network":"eip155:8453","price":"$0.05","asset":"USDC","payTo":"0x9333e2b421A33428D71b7E03cc050C297d85BDA6","facilitator":"https://api.cdp.coinbase.com/platform/v2/x402"},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentAnalysisInput"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentAnalysisResult"}}}},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Payment Required. The response body carries the x402 payment requirements; retry with an X-PAYMENT header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentRequired"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"Payment verification is temporarily unavailable. No charge was made; retry after the Retry-After interval.","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/agent/v1/habits/plan":{"get":{"operationId":"agentPlanHabitsProbe","summary":"Generate a multi-week routine plan with weekly targets and milestones — discovery probe","description":"Always answers 402 with the payment challenge, for directory crawlers that probe with GET. Never accepts payment and never returns a result: the resource is invoked with POST. Paying and retrying a GET moves no funds.","tags":["discovery","agent"],"security":[],"responses":{"402":{"description":"Payment challenge in the PAYMENT-REQUIRED header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"agentPlanHabits","summary":"Generate a multi-week routine plan with weekly targets and milestones","description":"Produces a scheduled, horizon-bounded plan across the supplied habits. The most compute-intensive endpoint in the catalogue, hence the higher price.","tags":["agent","analytics","behavioural-intelligence"],"security":[{"x402Payment":[]}],"x-payment-info":{"price":{"mode":"fixed","currency":"USD","amount":"0.10"},"protocols":[{"x402":{}}]},"x-x402":{"scheme":"exact","network":"eip155:8453","price":"$0.10","asset":"USDC","payTo":"0x9333e2b421A33428D71b7E03cc050C297d85BDA6","facilitator":"https://api.cdp.coinbase.com/platform/v2/x402"},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentAnalysisInput"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentPlanResult"}}}},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Payment Required. The response body carries the x402 payment requirements; retry with an X-PAYMENT header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentRequired"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"Payment verification is temporarily unavailable. No charge was made; retry after the Retry-After interval.","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/agent/v1/habits/insights":{"get":{"operationId":"agentHabitInsightsProbe","summary":"Extract behavioural patterns, correlations and lapse-risk signals — discovery probe","description":"Always answers 402 with the payment challenge, for directory crawlers that probe with GET. Never accepts payment and never returns a result: the resource is invoked with POST. Paying and retrying a GET moves no funds.","tags":["discovery","agent"],"security":[],"responses":{"402":{"description":"Payment challenge in the PAYMENT-REQUIRED header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"agentHabitInsights","summary":"Extract behavioural patterns, correlations and lapse-risk signals","description":"Surfaces patterns, correlations and risk signals across the supplied habit summaries.","tags":["agent","analytics","behavioural-intelligence"],"security":[{"x402Payment":[]}],"x-payment-info":{"price":{"mode":"fixed","currency":"USD","amount":"0.05"},"protocols":[{"x402":{}}]},"x-x402":{"scheme":"exact","network":"eip155:8453","price":"$0.05","asset":"USDC","payTo":"0x9333e2b421A33428D71b7E03cc050C297d85BDA6","facilitator":"https://api.cdp.coinbase.com/platform/v2/x402"},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentAnalysisInput"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentAnalysisResult"}}}},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Payment Required. The response body carries the x402 payment requirements; retry with an X-PAYMENT header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentRequired"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"Payment verification is temporarily unavailable. No charge was made; retry after the Retry-After interval.","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/agent/v1/habits/recommend":{"get":{"operationId":"agentRecommendActionsProbe","summary":"Rank next-best actions per habit with rationale and priority — discovery probe","description":"Always answers 402 with the payment challenge, for directory crawlers that probe with GET. Never accepts payment and never returns a result: the resource is invoked with POST. Paying and retrying a GET moves no funds.","tags":["discovery","agent"],"security":[],"responses":{"402":{"description":"Payment challenge in the PAYMENT-REQUIRED header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"agentRecommendActions","summary":"Rank next-best actions per habit with rationale and priority","description":"Deterministic, CPU-only ranking of the next-best action per habit. Cheapest endpoint in the catalogue; suitable for high-frequency agent loops.","tags":["agent","analytics","behavioural-intelligence"],"security":[{"x402Payment":[]}],"x-payment-info":{"price":{"mode":"fixed","currency":"USD","amount":"0.03"},"protocols":[{"x402":{}}]},"x-x402":{"scheme":"exact","network":"eip155:8453","price":"$0.03","asset":"USDC","payTo":"0x9333e2b421A33428D71b7E03cc050C297d85BDA6","facilitator":"https://api.cdp.coinbase.com/platform/v2/x402"},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentAnalysisInput"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentRecommendResult"}}}},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Payment Required. The response body carries the x402 payment requirements; retry with an X-PAYMENT header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentRequired"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"Payment verification is temporarily unavailable. No charge was made; retry after the Retry-After interval.","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/auth/register":{"post":{"operationId":"registerUser","summary":"Register user","tags":["human"],"security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email","password"],"properties":{"email":{"type":"string","format":"email"},"password":{"type":"string","minLength":8},"displayName":{"type":"string"}}}}}},"responses":{"201":{"description":"Created"},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Email already registered","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/auth/login":{"post":{"operationId":"loginUser","summary":"Exchange credentials for an access token","tags":["human"],"security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email","password"],"properties":{"email":{"type":"string","format":"email"},"password":{"type":"string"}}}}}},"responses":{"200":{"description":"Access token issued"},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Invalid credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/habits":{"get":{"operationId":"listOwnHabits","summary":"List the authenticated user's active habits","tags":["human"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Habit list"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"createOwnHabit","summary":"Create a habit","description":"Subject to the plan's active-habit cap: Free allows 3, Premium is unlimited. Archived habits do not occupy a slot.","tags":["human"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","minLength":2},"description":{"type":"string","maxLength":512},"category":{"type":"string","maxLength":64},"cadence":{"type":"string","enum":["DAILY","WEEKLY","CUSTOM"]},"targetPerWeek":{"type":"integer","minimum":1,"maximum":14},"targetDaysMask":{"type":"integer","minimum":0,"maximum":127},"startDate":{"type":"string","format":"date-time"}}}}}},"responses":{"201":{"description":"Created"},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"$ref":"#/components/responses/QuotaExceeded"}}}},"/v1/habits/analyze":{"post":{"operationId":"analyzeOwnHabits","summary":"Analyse the authenticated user's habits","description":"Metered on Free (5 per calendar month, reported in the X-Quota-* response headers) and unmetered on Premium. Mood correlation fields are Premium-only: on Free they are absent from the response rather than null, and a `redacted` object names what was withheld.","tags":["human"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Analysis payload","headers":{"X-Quota-Limit":{"schema":{"type":"integer"},"description":"Monthly allowance, omitted when unlimited"},"X-Quota-Used":{"schema":{"type":"integer"}},"X-Quota-Remaining":{"schema":{"type":"integer"}},"X-Quota-Period":{"schema":{"type":"string"},"description":"Billing period, e.g. 2026-07"}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"$ref":"#/components/responses/QuotaExceeded"},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/habits/insights":{"post":{"operationId":"getOwnInsights","summary":"Fetch the authenticated user's insights","description":"Free returns at most the latest 5 insights and only rows marked Free-readable; a larger requested limit is clamped rather than rejected. Premium returns the full history.","tags":["human"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Insights list"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/habits/plan":{"post":{"operationId":"planOwnHabits","summary":"Generate a plan for the authenticated user","description":"Premium only. Free callers receive 402 with code `premium_required`.","tags":["human"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Plan generated"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"$ref":"#/components/responses/PremiumRequired"},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/habits/recommend":{"post":{"operationId":"recommendOwnHabits","summary":"Recommendations for the authenticated user","description":"Available on every tier. The suggestions themselves are never withheld — only the Premium metric fields in the accompanying `metrics` object are.","tags":["human"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Recommendation payload"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Habit not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/billing/plans":{"get":{"operationId":"listBillingPlans","summary":"Plan catalogue and prices","description":"Public: pricing is not a secret, and the app needs it before a user has an account. `purchasable` is false for any plan with no live provider price configured, so a client can show the price without offering a checkout that would fail.","tags":["billing"],"security":[],"responses":{"200":{"description":"Plan catalogue","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlanCatalogue"}}}}}}},"/v1/billing/me":{"get":{"operationId":"getOwnBillingState","summary":"Entitlements, subscription and usage for the authenticated user","description":"The entitlements reported here are the ones being enforced: they are resolved from the database, not from the tier claim in the access token, so a cancellation takes effect immediately rather than when the token expires.","tags":["billing"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Billing state","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BillingState"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/billing/checkout":{"post":{"operationId":"createCheckoutSession","summary":"Start a provider-hosted checkout","description":"Returns a URL hosted by the payment provider; no card data ever reaches this API. This call grants nothing on its own — a user who abandons the provider page is exactly as unentitled as before it. Entitlements change only when the provider sends a signed webhook. 501 means no provider is configured, which is reported honestly rather than simulated.","tags":["billing"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["plan"],"properties":{"plan":{"type":"string","enum":["premium_monthly","premium_yearly"],"description":"Plan code from GET /v1/billing/plans."}}}}}},"responses":{"201":{"description":"Checkout session created","content":{"application/json":{"schema":{"type":"object","properties":{"provider":{"type":"string"},"plan":{"type":"string"},"checkout_url":{"type":"string","format":"uri"},"session_id":{"type":"string"}}}}}},"400":{"description":"Unknown or non-purchasable plan","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"No billing provider configured (`provider_not_configured`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/billing/webhook/{provider}":{"post":{"operationId":"receiveBillingWebhook","summary":"Provider webhook (machine-to-machine)","description":"Called by the payment provider, not by clients. The signature over the exact request bytes is the authentication, so no bearer token applies. Events are idempotent: a redelivery is acknowledged with 200 and applied once. A signature that does not verify returns 400 — not 500, which would invite an endless retry of a payload that can never verify.","tags":["billing"],"security":[{"stripeSignature":[]}],"parameters":[{"name":"provider","in":"path","required":true,"schema":{"type":"string","enum":["stripe"]}}],"requestBody":{"required":true,"description":"Raw provider event. Read as bytes so the signature stays verifiable.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Event verified. `applied` is false for a duplicate or an event type we ignore.","content":{"application/json":{"schema":{"type":"object","properties":{"received":{"type":"boolean"},"applied":{"type":"boolean"},"reason":{"type":"string","nullable":true}}}}}},"400":{"description":"Signature verification failed, or an unknown provider (`invalid_signature`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"Webhooks are not configured (`provider_not_configured`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"components":{"securitySchemes":{"adminToken":{"type":"apiKey","in":"header","name":"X-Admin-Token","description":"Operator token gating /v1/admin/*. Set ADMIN_API_TOKEN server-side; the routes answer 501 when it is unset rather than exposing revenue with no auth."},"bearerAuth":{"type":"apiKey","in":"header","name":"Authorization","description":"JWT access token from POST /v1/auth/login, sent as `Bearer <token>`. Human application surface only; these routes are never reachable with an x402 payment."},"x402Payment":{"type":"apiKey","in":"header","name":"X-PAYMENT","description":"Base64-encoded x402 payment payload. Obtain the requirements from the 402 response."},"stripeSignature":{"type":"apiKey","in":"header","name":"Stripe-Signature","description":"HMAC-SHA256 over `<timestamp>.<raw request body>`, set by the payment provider. Not obtainable by API clients — this scheme documents how the webhook authenticates its caller, not a way to call it."}},"responses":{"QuotaExceeded":{"description":"A plan allowance is exhausted (`quota_exceeded`). This is an upgrade prompt, not an x402 payment requirement — there is no X-PAYMENT header that settles it. `details` carries the feature, the usage, the limit and the upgrade path.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"PremiumRequired":{"description":"The feature is Premium-only (`premium_required`). As above: an account upgrade, not an x402 payment. Purchase at POST /v1/billing/checkout.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"schemas":{"AgentHabit":{"type":"object","required":["name","completion_rate","current_streak","best_streak"],"properties":{"name":{"type":"string"},"completion_rate":{"type":"number","minimum":0,"maximum":1},"current_streak":{"type":"integer","minimum":0},"best_streak":{"type":"integer","minimum":0},"average_mood":{"type":"number","minimum":1,"maximum":10},"mood_correlation":{"type":"number","minimum":-1,"maximum":1},"energy_trend":{"type":"string","enum":["rising","stable","falling"]},"risk_score":{"type":"number","minimum":0,"maximum":1},"metadata":{"type":"object","additionalProperties":true}}},"AgentAnalysisInput":{"type":"object","required":["habits"],"description":"Caller-supplied habit summaries. No identifiers of any stored user are accepted or resolved; send only data you own.","properties":{"habits":{"type":"array","minItems":1,"maxItems":25,"items":{"$ref":"#/components/schemas/AgentHabit"}},"horizon_days":{"type":"integer","minimum":7,"maximum":180,"default":35},"persona":{"type":"string"},"locale":{"type":"string"}}},"AgentAnalysisResult":{"type":"object","properties":{"aggregate_summary":{"type":"object","additionalProperties":true},"highlights":{"type":"array","items":{"type":"string"}},"watchouts":{"type":"array","items":{"type":"string"}},"recommendations":{"type":"array","items":{"type":"string"}}}},"AgentPlanResult":{"type":"object","additionalProperties":true},"AgentRecommendResult":{"type":"object","properties":{"recommendations":{"type":"array","items":{"type":"object","properties":{"habit":{"type":"string"},"action":{"type":"string"},"rationale":{"type":"string"},"priority":{"type":"number","minimum":0,"maximum":1}}}},"generated_for_habits":{"type":"integer"}}},"PaymentRequired":{"type":"object","description":"x402 payment requirements returned with HTTP 402.","properties":{"x402Version":{"type":"integer"},"accepts":{"type":"array","items":{"type":"object","additionalProperties":true}},"error":{"type":"string"}}},"Error":{"type":"object","properties":{"error":{"type":"string","description":"Stable machine-readable code, e.g. `quota_exceeded`."},"message":{"type":"string"},"details":{"description":"Present on some errors — quota errors carry feature/used/limit/upgrade.","additionalProperties":true}}},"PlanCatalogue":{"type":"object","description":"Public pricing. A plan is listed whether or not it can be bought right now, so the app can show what Premium costs even while billing is switched off; `purchasable` is the flag that decides whether checkout will succeed.","properties":{"currency":{"type":"string","description":"ISO 4217 code, uppercase."},"plans":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","enum":["free","premium_monthly","premium_yearly"]},"name":{"type":"string"},"tier":{"type":"string","enum":["FREE","PREMIUM"]},"interval":{"type":"string","enum":["month","year"],"nullable":true,"description":"null for the non-recurring Free plan."},"price":{"type":"object","properties":{"amount_cents":{"type":"integer","description":"Authoritative minor-unit amount."},"amount":{"type":"string","description":"Decimal string, e.g. \"4.99\"."},"currency":{"type":"string"},"display":{"type":"string","description":"Preformatted, e.g. \"USD 4.99\" or \"Free\"."}}},"purchasable":{"type":"boolean","description":"False when no provider price is configured for this plan; checkout returns 501."},"features":{"type":"array","items":{"type":"string"}}}}},"billing":{"type":"object","properties":{"provider":{"type":"string","description":"`none` when no provider is configured."},"configured":{"type":"boolean"}}}}},"BillingState":{"type":"object","description":"The entitlements actually being enforced, resolved from the database rather than the access token, plus the subscription behind them and usage against the metered quota.","properties":{"tier":{"type":"string","enum":["FREE","PREMIUM"]},"premium_until":{"type":"string","format":"date-time","nullable":true},"limits":{"type":"object","description":"null means unlimited.","properties":{"max_habits":{"type":"integer","nullable":true},"analyses_per_month":{"type":"integer","nullable":true},"insight_history":{"type":"integer","nullable":true}}},"features":{"type":"object","properties":{"habit_plans":{"type":"boolean"},"mood_correlation":{"type":"boolean"},"full_insight_history":{"type":"boolean"}}},"subscription":{"type":"object","nullable":true,"description":"null for a user who has never subscribed.","properties":{"provider":{"type":"string","enum":["STRIPE","APPLE_APP_STORE","GOOGLE_PLAY","MANUAL"]},"plan_code":{"type":"string","nullable":true},"status":{"type":"string","enum":["INCOMPLETE","TRIALING","ACTIVE","PAST_DUE","CANCELED","EXPIRED"]},"current_period_end":{"type":"string","format":"date-time","nullable":true},"cancel_at_period_end":{"type":"boolean","description":"True once cancellation is scheduled; access continues until current_period_end."}}},"usage":{"type":"object","properties":{"period":{"type":"string","description":"Calendar month, e.g. \"2026-07\"."},"analyses":{"type":"object","properties":{"used":{"type":"integer"},"limit":{"type":"integer","nullable":true}}}}},"billing":{"type":"object","properties":{"provider":{"type":"string"}}}}}}}}