BMarker report API

Send a transaction log, run BMarker's portfolio analysis, and receive a branded report. API access is included with BMarker Pro.

POSThttps://bmarker.com/api/v1/reports

Get started

  1. 1
    Activate BMarker Pro.

    The report endpoint is available to workspaces with an active Pro plan.

  2. 2
    Create an API key.

    Open Settings → Report API keys, name the key, and copy its secret.

  3. 3
    Send the key with each request.

    Store it with your application secrets and use the Bearer header below.

Authorization headerAuthorization: Bearer bmk_live_your_key

Request and HTML example

This request produced the report shown beside it. The checked-in HTML was generated from the same shared report component as the API's HTML and PDF output.

report.json
{
  "analysis": {
    "analysisWindow": null,
    "balanceNormalization": "enabled",
    "regressionWindow": null,
    "rollingWindow": 126
  },
  "branding": {
    "accentColor": "#0c6748",
    "logoDataUrl": null,
    "name": "Example Capital",
    "showBmarker": false,
    "websiteUrl": "https://example.com"
  },
  "format": "html",
  "portfolio": {
    "benchmarkSymbol": "SPY",
    "currency": "USD",
    "name": "Long-term portfolio"
  },
  "presentation": {
    "balancePrivacy": true,
    "shareTransactionNotes": false,
    "showHoldings": false,
    "showTrades": false
  },
  "title": "Portfolio performance report",
  "transactions": [
    {
      "date": "2026-01-05",
      "fees": "1",
      "notes": "Opened the position",
      "price": "185",
      "quantity": "10",
      "symbol": "AAPL",
      "type": "BUY"
    },
    {
      "date": "2026-03-02",
      "fees": "0.5",
      "notes": "Trimmed the position",
      "price": "201.4",
      "quantity": "2",
      "symbol": "AAPL",
      "type": "SELL"
    }
  ]
}
cURL
curl --request POST https://bmarker.com/api/v1/reports \
  --header "Authorization: Bearer $BMARKER_API_KEY" \
  --header "Content-Type: application/json" \
  --data @report.json \
  --output portfolio-report.html

Change format and the output filename to create PDF, XML, or JSON.

Request fields

Send UTF-8 JSON with Content-Type: application/json. Prices, quantities, and fees accept JSON numbers or decimal strings.

Top-level fields

FieldRequiredDescription
formatYeshtml, pdf, xml, or json.
portfolioYesThe portfolio name, currency, and benchmark ticker.
transactionsYesBetween 1 and 2,000 BUY or SELL records.
analysisNoAnalysis, regression, rolling, and balance-normalization settings.
presentationNoBalance privacy, holdings, trades, and transaction-note settings.
titleNoUp to 140 characters. Defaults to “Portfolio performance report.”
brandingNoA display name, accent color, and website link.

Portfolio and analysis

FieldAccepted values
portfolio.name1–100 characters.
portfolio.currencyA three-letter code. Defaults to USD.
portfolio.benchmarkSymbolA ticker up to 20 characters. Defaults to SPY.
analysis.analysisWindownull, 21, 63, 126, or 252. Null uses all available history.
analysis.regressionWindownull, 21, 63, 126, or 252. Null uses the full analysis span.
analysis.rollingWindow21, 63, 126, or 252. Defaults to 126.
analysis.balanceNormalizationenabled or disabled. Defaults to enabled.

Presentation

These fields are passed to the shared report component used by public share pages. The defaults match a new share page.

FieldDefaultUse
presentation.balancePrivacytrueShows return, benchmark, excess-return, and drawdown cards. Set to false to show current value, net invested, gain/loss, and portfolio return.
presentation.showHoldingsfalseAdds current holdings and holdings-over-time sections.
presentation.showTradesfalseAdds the trade-activity section.
presentation.shareTransactionNotesfalseIncludes transaction notes when trade activity is shown.

Branding

Branding appears in the HTML and PDF header and is included in the XML and JSON report envelope. When branding is omitted, the report uses “Portfolio report” and BMarker green.

FieldDefaultUse
branding.namePortfolio reportA 1–100 character brand name shown in the report header.
branding.websiteUrlnullAn HTTP or HTTPS link for the brand name and logo. Credentials in the URL are rejected.
branding.accentColor#0c6748A six-digit hex color used for report accents and positive values.
branding.logoDataUrlnullA base64 PNG, JPEG, or WebP data URL up to 350,000 characters. The header uses the first letter of the brand name when this is null.
branding.showBmarkerfalseSet to true to add the “Powered by BMarker” footer.

A logo value begins with a media prefix such asdata:image/png;base64,, followed by the image's base64 data. PNG, JPEG, and WebP signatures are checked before the report is generated.

Transaction fields

FieldRequiredDescription
dateYesA real calendar date in YYYY-MM-DD form.
typeYesBUY or SELL.
symbolYesA ticker up to 20 characters.
quantityYesA decimal value greater than zero.
priceYesThe execution price, greater than zero.
feesNoA decimal value of zero or greater. Defaults to zero.
notesNoUp to 500 characters, or null.

Report data

BMarker loads completed daily closes, applies stock splits, repairs missing close ranges, and runs the same transaction-aware performance engine used by the app. QuantStats supplies the deeper risk and benchmark-relative analytics.

FieldContents
performanceSummary, timeframe returns, holdings, daily series, cumulative growth, excess return, alpha, balance, and holdings history.
analyticsSharpe, Sortino, CAGR, volatility, drawdowns, capture, correlation, calendar returns, distributions, and rolling series.
intradayThe latest Pro price snapshot and current portfolio valuation, including quote freshness and any fallback symbols.
methodologyThe calculation rules and engine version used for the report.
effectiveWindowsThe analysis and regression windows supported by the available observations.
excludedSymbolsSymbols that could not be analyzed, with reasons and affected transaction row IDs.
transactionsThe normalized transaction rows used by the analysis.

Historical returns and risk metrics have a completed-close timestamp inperformance.summary.asOf. Current valuation comes fromintraday.valuation, with quote details in intraday.snapshot. HTML and PDF show that value whenpresentation.balancePrivacy is false.

Formats

A successful response has status 200 and a filename in theContent-Disposition header, such aslong-term-portfolio-performance.pdf.

FormatContent-TypeContents
htmltext/htmlA self-contained share-page report with embedded styles.
pdfapplication/pdfA print rendering of the same HTML report.
xmlapplication/xmlThe complete report envelope as XML.
jsonapplication/jsonThe complete report envelope as JSON.

Errors

Error responses use JSON. Every response has an X-Request-ID header; error bodies repeat it as requestId for support requests.

Error response
{
  "error": {
    "code": "invalid_request",
    "message": "transactions.0.date: Use a real calendar date."
  },
  "requestId": "87a20465-1b42-4d85-9305-55467b783064"
}
StatusMeaning
400The JSON or one of its fields is invalid.
401The API key is missing, malformed, deleted, or unknown.
403The key lacks report permission or the workspace needs an active Pro plan.
413The request body exceeds 2 MiB.
415The Content-Type header must be application/json.
422The transactions could not produce an analyzable portfolio report. The body includes the performance issues.
429The market-data provider is rate limited.
503Market data, analytics, or the report renderer is temporarily unavailable.
504Analytics or PDF rendering timed out.

API keys

The full key appears once when it is created. Give each integration its own key so its access can be managed independently.

Roll creates a replacement while the current key stays active. Update the integration, confirm a successful request, and delete the previous key. Deletion takes effect immediately.

Manage API keys →

Limits

  • 1–2,000 transactions per report.
  • Up to 50 unique transaction symbols.
  • 2 MiB maximum request body.
  • Up to 12 decimal places in decimal-string inputs.
  • Submitted transactions remain in process memory while the report is generated.
  • Completed daily market prices use BMarker's shared market-data cache.

Questions? Email support@bytescale.io.