{"openapi":"3.1.0","info":{"title":"Honest MRR metrics API","version":"1","description":"Read your organization's subscription metrics, and import revenue and ad-spend CSVs. Every request authenticates with an API key created in the app (Settings → API & sharing); keys are read-only unless created with the write scope. Errors are JSON — `{ \"error\": \"…\" }` — including 429s, which also carry `Retry-After`."},"servers":[{"url":"https://honestmrr.com"}],"externalDocs":{"description":"API documentation","url":"https://honestmrr.com/docs/api"},"paths":{"/api/v1/overview":{"get":{"operationId":"get_overview","summary":"Headline numbers: MRR, 30-day movements, customers, churn and growth.","tags":["Reports"],"security":[{"apiKey":[]}],"responses":{"200":{"description":"The overview report for the API key's organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Report"},"examples":{"overview":{"summary":"Illustrative values — series arrays shortened","value":{"report":"overview","generatedAt":"2026-10-05T09:30:00.000Z","data":{"series":[{"day":"2026-10-03","mrr":2481500},{"day":"2026-10-04","mrr":2483000}],"currentMrr":2483000,"mrr30dAgo":2295000,"growth30dPct":0.0819,"newMrr30d":124000,"churnedMrr30d":31000,"expansionMrr30d":61000,"contractionMrr30d":9000,"reactivationMrr30d":43000,"daily30":[{"day":"2026-10-04","newMrr":4900,"churnedMrr":0,"activeCustomers":314}],"newMrrPrev30d":98000,"churnedMrrPrev30d":27000,"activeCustomers":314,"activeCustomers30dAgo":296,"activeSubscriptions":331,"logoChurnRate30d":0.018,"basis":"net","hasData":true}}}}}}},"401":{"description":"Missing, invalid or revoked API key.","headers":{"WWW-Authenticate":{"description":"`Bearer`.","schema":{"type":"string"}},"Link":{"description":"Where to learn how to authenticate: the API docs (rel=\"help\"), this description (rel=\"service-desc\") and the API catalog (rel=\"api-catalog\").","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited — 60 requests a minute per key, 240 per IP.","headers":{"Retry-After":{"description":"Seconds until the current one-minute window resets.","schema":{"type":"integer","minimum":1}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/mrr":{"get":{"operationId":"get_mrr","summary":"The MRR series with each month's new, expansion, contraction, churn and reactivation.","tags":["Reports"],"security":[{"apiKey":[]}],"responses":{"200":{"description":"The mrr report for the API key's organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Report"},"examples":{"mrr":{"summary":"Illustrative values — series arrays shortened","value":{"report":"mrr","generatedAt":"2026-10-05T09:30:00.000Z","data":{"series":[{"day":"2026-10-04","mrr":2483000}],"currentMrr":2483000,"last30":{"newMrr":124000,"expansionMrr":61000,"contractionMrr":9000,"churnedMrr":31000,"reactivationMrr":43000},"monthly":[{"month":"2026-09","startMrr":2252000,"newMrr":118000,"expansionMrr":57000,"contractionMrr":11000,"churnedMrr":29000,"reactivationMrr":38000,"endMrr":2425000}],"basis":"net","hasData":true}}}}}}},"401":{"description":"Missing, invalid or revoked API key.","headers":{"WWW-Authenticate":{"description":"`Bearer`.","schema":{"type":"string"}},"Link":{"description":"Where to learn how to authenticate: the API docs (rel=\"help\"), this description (rel=\"service-desc\") and the API catalog (rel=\"api-catalog\").","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited — 60 requests a minute per key, 240 per IP.","headers":{"Retry-After":{"description":"Seconds until the current one-minute window resets.","schema":{"type":"integer","minimum":1}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/churn":{"get":{"operationId":"get_churn","summary":"Logo churn, gross and net revenue churn, month by month.","tags":["Reports"],"security":[{"apiKey":[]}],"responses":{"200":{"description":"The churn report for the API key's organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Report"},"examples":{"churn":{"summary":"Illustrative values — series arrays shortened","value":{"report":"churn","generatedAt":"2026-10-05T09:30:00.000Z","data":{"monthly":[{"month":"2026-09","startMrr":2252000,"churnedMrr":29000,"contractionMrr":11000,"expansionMrr":57000,"grossRevenueChurn":0.0178,"netRevenueChurn":-0.0075,"logoChurnRate":0.016}],"atRisk":[{"provider":"stripe","customerId":"cus_Q4x9Lk2","email":"billing@example.com","mrr":4900,"at":"2026-10-02T09:14:00.000Z"}],"recentlyChurned":[{"provider":"paddle","customerId":"ctm_01h8z3","email":null,"mrr":2900,"at":"2026-09-29T00:00:00.000Z"}],"delinquentMrr":9800,"hasData":true}}}}}}},"401":{"description":"Missing, invalid or revoked API key.","headers":{"WWW-Authenticate":{"description":"`Bearer`.","schema":{"type":"string"}},"Link":{"description":"Where to learn how to authenticate: the API docs (rel=\"help\"), this description (rel=\"service-desc\") and the API catalog (rel=\"api-catalog\").","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited — 60 requests a minute per key, 240 per IP.","headers":{"Retry-After":{"description":"Seconds until the current one-minute window resets.","schema":{"type":"integer","minimum":1}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/revenue":{"get":{"operationId":"get_revenue","summary":"Realized revenue — cash collected, net of refunds — month by month.","tags":["Reports"],"security":[{"apiKey":[]}],"responses":{"200":{"description":"The revenue report for the API key's organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Report"},"examples":{"revenue":{"summary":"Illustrative values — series arrays shortened","value":{"report":"revenue","generatedAt":"2026-10-05T09:30:00.000Z","data":{"monthly":[{"month":"2026-09","bySource":{"subscriptions":2391000,"youtube":41250},"total":2432250}],"otherLast30d":41250,"otherBySourceLast30d":{"youtube":41250},"hasOther":true,"hasData":true}}}}}}},"401":{"description":"Missing, invalid or revoked API key.","headers":{"WWW-Authenticate":{"description":"`Bearer`.","schema":{"type":"string"}},"Link":{"description":"Where to learn how to authenticate: the API docs (rel=\"help\"), this description (rel=\"service-desc\") and the API catalog (rel=\"api-catalog\").","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited — 60 requests a minute per key, 240 per IP.","headers":{"Retry-After":{"description":"Seconds until the current one-minute window resets.","schema":{"type":"integer","minimum":1}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/acquisition":{"get":{"operationId":"get_acquisition","summary":"Ad spend, new customers, CAC, payback and LTV:CAC (LTV fields are null below Pro).","tags":["Reports"],"security":[{"apiKey":[]}],"responses":{"200":{"description":"The acquisition report for the API key's organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Report"},"examples":{"acquisition":{"summary":"Illustrative values — series arrays shortened","value":{"report":"acquisition","generatedAt":"2026-10-05T09:30:00.000Z","data":{"monthly":[{"month":"2026-09","spendCents":414000,"spendByPlatform":{"google_ads":289000,"facebook_ads":125000},"newCustomers":23,"newMrr":115000,"cac":18000,"paybackMonths":3.6}],"blendedCac":18000,"ltv":270000,"ltvToCac":15,"topCampaigns":[{"platform":"google_ads","campaignId":"20581234567","campaignName":"Search — brand","spendCents":96000,"clicks":812,"reportedConversions":9}],"currency":"usd","hasSpend":true,"hasData":true}}}}}}},"401":{"description":"Missing, invalid or revoked API key.","headers":{"WWW-Authenticate":{"description":"`Bearer`.","schema":{"type":"string"}},"Link":{"description":"Where to learn how to authenticate: the API docs (rel=\"help\"), this description (rel=\"service-desc\") and the API catalog (rel=\"api-catalog\").","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited — 60 requests a minute per key, 240 per IP.","headers":{"Retry-After":{"description":"Seconds until the current one-minute window resets.","schema":{"type":"integer","minimum":1}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/import/revenue":{"post":{"operationId":"import_revenue","summary":"Import a revenue CSV (affiliate or creator payouts) — kept out of MRR, on its own line.","tags":["Imports"],"security":[{"apiKey":[]}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["source","file"],"properties":{"source":{"type":"string","enum":["amazon_associates","youtube","tiktok_creator","instagram_creator","facebook_creator","onlyfans"]},"file":{"type":"string","format":"binary","description":"The CSV export, at most 8 MB."}}}}}},"responses":{"200":{"description":"Imported. Re-importing the same file is idempotent — duplicates are counted, not added.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Not multipart/form-data, an unknown or missing `source`, or no `file` (or an empty one).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid or revoked API key.","headers":{"WWW-Authenticate":{"description":"`Bearer`.","schema":{"type":"string"}},"Link":{"description":"Where to learn how to authenticate: the API docs (rel=\"help\"), this description (rel=\"service-desc\") and the API catalog (rel=\"api-catalog\").","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key is read-only — imports need a key created with the write scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"File larger than 8 MB.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"The file couldn't be read as that source's CSV — the message says why.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited — 60 requests a minute per key, 240 per IP.","headers":{"Retry-After":{"description":"Seconds until the current one-minute window resets.","schema":{"type":"integer","minimum":1}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"An internal error while importing (logged on our side; the message is generic on purpose). Retrying the same file is safe — imports are idempotent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/import/ad-spend":{"post":{"operationId":"import_ad_spend","summary":"Import an ad-spend CSV for CAC and payback.","tags":["Imports"],"security":[{"apiKey":[]}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["platform","file"],"properties":{"platform":{"type":"string","enum":["google_ads","facebook_ads","instagram_ads","tiktok_ads","microsoft_ads"]},"file":{"type":"string","format":"binary","description":"The CSV export, at most 8 MB."}}}}}},"responses":{"200":{"description":"Imported. Re-importing the same file is idempotent — duplicates are counted, not added.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Not multipart/form-data, an unknown or missing `platform`, or no `file` (or an empty one).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid or revoked API key.","headers":{"WWW-Authenticate":{"description":"`Bearer`.","schema":{"type":"string"}},"Link":{"description":"Where to learn how to authenticate: the API docs (rel=\"help\"), this description (rel=\"service-desc\") and the API catalog (rel=\"api-catalog\").","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key is read-only — imports need a key created with the write scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"File larger than 8 MB.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"The file couldn't be read as that source's CSV — the message says why.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited — 60 requests a minute per key, 240 per IP.","headers":{"Retry-After":{"description":"Seconds until the current one-minute window resets.","schema":{"type":"integer","minimum":1}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"An internal error while importing (logged on our side; the message is generic on purpose). Retrying the same file is safe — imports are idempotent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"components":{"securitySchemes":{"apiKey":{"type":"http","scheme":"bearer","description":"An API key (hm_live_…) from Settings → API & sharing, sent as `Authorization: Bearer <key>`."}},"schemas":{"Report":{"type":"object","required":["report","generatedAt","data"],"properties":{"report":{"type":"string","enum":["overview","mrr","churn","revenue","acquisition"]},"generatedAt":{"type":"string","format":"date-time"},"data":{"type":"object","additionalProperties":true,"description":"The report's figures, in the organization's reporting currency's minor units unless a field says otherwise; rates and growth are fractions (0.018 = 1.8%). Each report's example shows its fields."}}},"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"string"}}}}}}