Properties
| Name | Type | Description |
|---|---|---|
| pulledAt | string | When the snapshot behind these figures was taken. |
| currency | string | |
| plan | string | |
| historyDays | integer | The window the trend actually covers, which on a free plan is shorter than the one requested. Label charts from this, not from what you asked for. |
| windowNote | string | Present only when the plan shortened the window. |
| portfolio | object | |
| trend | array | Portfolio net over the window, one point per pull. |
| earnedYear | integernull | |
| earnedThisYearUsd | object | |
| earnedTotalUsd | object | |
| earnedThisMonthSoFarUsd | object | The month still running, deliberately kept out of the two totals above. Null means nothing in scope reports before a month closes. |
| earnedThisMonthMissingRails | array | Rails that report nothing until a month closes, so the month-to-date figure is known to be incomplete and says which parts are absent. |
| earnedSeries | objectnull | Twelve slots per year, null where nothing was measured. Null and zero differ: an unreported month is unknown, not a month of no money. |
| projects | array | Worst net margin first; unknown net sorts last. |
JSON Schema
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://artifacts.apis.io/devmargin-app/json-schema/devmargin-app-portfolio-schema.json",
"title": "Portfolio",
"x-generated": "2026-11-05",
"x-method": "derived",
"x-generator": "derive-json-schema.py",
"x-source": "openapi/_original/devmargin-app-openapi-openapi.yml#/components/schemas/Portfolio",
"type": "object",
"properties": {
"pulledAt": {
"type": "string",
"format": "date-time",
"description": "When the snapshot behind these figures was taken."
},
"currency": {
"type": "string"
},
"plan": {
"type": "string"
},
"historyDays": {
"type": "integer",
"description": "The window the trend actually covers, which on a free plan is\nshorter than the one requested. Label charts from this, not from\nwhat you asked for.\n"
},
"windowNote": {
"type": "string",
"description": "Present only when the plan shortened the window."
},
"portfolio": {
"type": "object",
"properties": {
"mrrUsd": {
"$ref": "#/$defs/Money"
},
"costMonthlyUsd": {
"$ref": "#/$defs/Money"
},
"netMonthlyUsd": {
"$ref": "#/$defs/Money"
},
"activeSubs": {
"type": [
"integer",
"null"
]
},
"users": {
"type": [
"integer",
"null"
]
}
}
},
"trend": {
"type": "array",
"description": "Portfolio net over the window, one point per pull.",
"items": {
"$ref": "#/$defs/Money"
}
},
"earnedYear": {
"type": [
"integer",
"null"
]
},
"earnedThisYearUsd": {
"$ref": "#/$defs/Money"
},
"earnedTotalUsd": {
"$ref": "#/$defs/Money"
},
"earnedThisMonthSoFarUsd": {
"allOf": [
{
"$ref": "#/$defs/Money"
}
],
"description": "The month still running, deliberately kept out of the two totals\nabove. Null means nothing in scope reports before a month closes.\n"
},
"earnedThisMonthMissingRails": {
"type": "array",
"items": {
"type": "string"
},
"description": "Rails that report nothing until a month closes, so the\nmonth-to-date figure is known to be incomplete and says which\nparts are absent.\n"
},
"earnedSeries": {
"type": [
"object",
"null"
],
"additionalProperties": true,
"description": "Twelve slots per year, null where nothing was measured. Null and\nzero differ: an unreported month is unknown, not a month of no\nmoney.\n"
},
"projects": {
"type": "array",
"description": "Worst net margin first; unknown net sorts last.",
"items": {
"$ref": "#/$defs/ProjectRow"
}
}
},
"required": [
"pulledAt",
"portfolio",
"projects"
],
"$defs": {
"Money": {
"type": [
"number",
"null"
],
"description": "Canonical USD. **Null means not reported** — never zero. A rail that\ndoes not publish a figure leaves it null, and so does a cost nobody has\nentered; treating either as 0 turns an unknown into a claim.\n"
},
"ProjectRow": {
"type": "object",
"properties": {
"project": {
"type": "string",
"format": "uuid"
},
"name": {
"type": "string"
},
"mrrUsd": {
"$ref": "#/$defs/Money"
},
"costMonthlyUsd": {
"$ref": "#/$defs/Money"
},
"netMonthlyUsd": {
"$ref": "#/$defs/Money"
},
"activeSubs": {
"type": [
"integer",
"null"
]
},
"users": {
"type": [
"integer",
"null"
]
},
"churnedSubs": {
"type": [
"integer",
"null"
]
},
"oneOffRevenueUsd": {
"allOf": [
{
"$ref": "#/$defs/Money"
}
],
"description": "Kept out of net on purpose — one-off money is not a run rate."
},
"channels": {
"type": "array",
"items": {
"type": "object",
"properties": {
"channel": {
"type": "string"
},
"rail": {
"type": "string"
},
"mrrUsd": {
"$ref": "#/$defs/Money"
}
},
"additionalProperties": true
}
}
}
}
}
}
Work with this as data
Every JSON Schema here is available over the APIs.io API and to AI agents over MCP.
MCP server
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
Tools for schemas
4 MCP tools reach this
find_json_schemasBrowse and filter every JSON Schema in the catalog.apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.resolveTurn a domain, URL or GitHub org into the provider it belongs to.find_cohortsEvery scored population of providers in the catalog.
Call it yourself
curl for this page
This JSON Schema
curl "https://apis.io/api/v1/json-schemas/devmargin-app-portfolio"
All schemas
curl "https://apis.io/api/v1/json-schemas?limit=25"
Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.
Get an API key
Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.
A second provider on the same verified email joins the account you already have.