curl command and the equivalent Python snippet using the
requests library.
What you’ll build
- Authenticate and smoke-test the connection.
- Browse the public catalog and your own strategies.
- Look up companies by ticker.
- Create a strategy from an objective, submit it, and poll until it’s ready.
- Fetch the strategy’s companies and a constructed portfolio with weights.
- Backtest those holdings against a benchmark (e.g.
SPY).
Prerequisites
| Requirement | Value |
|---|---|
| REST base URL | https://api.noonum.ai/v2 |
| Auth header | Authorization: Bearer <token> |
<token> | Your Noonum API key |
| Tools | curl for the shell examples; Python 3.9+ with requests for the code |
<token> is your Noonum API key. See
Authentication for how to obtain and send it.
Install the Python dependency if you plan to follow the code snippets:
Authenticate and smoke-test
Confirm the service is reachable and your token works.Hit the unauthenticated health check to verify connectivity:A The equivalent set-up in Python. Every later snippet reuses this
200 OK with {"status":"OK","message":"Service is running"} means the API is up.Now make your first authenticated call. Listing your strategies validates the token: it
returns 200 (even if the list is empty) when the token is good, and 401 Unauthorized
when it isn’t. Replace YOUR_API_KEY with your key:BASE_URL and headers:Browse the public catalog
Noonum publishes a catalog of public strategies. Inspect them to see the data shape before
you build your own. Pass Each item is a
scope=public to list the catalog (public, non-archived,
completed strategies):Strategy object with an id, name, objective, and status. Read the
companies inside any public strategy with GET /strategies/{strategyId}/companies, the
same endpoint you’ll use for your own strategies in Step 5. Public strategies also expose
read-only per-company evidence and historical runs through those same
/strategies/{strategyId}/... endpoints, covered in
Working with public strategies below.Look up companies by ticker
Most Noonum endpoints identify companies by a UUID, not a ticker. Resolve a ticker, name,
ISIN, or FIGI fragment to a company id with the helper search endpoint:Results are ranked with exact matches first, then prefix matches, capped at the top 10.
Each result lists its active
securities (primary listing first). Any endpoint that takes
a company id, including the backtest later in this tutorial, can use an id resolved here.Create and build a strategy
This is the create → submit → poll loop from
Build a strategy, in code: create the strategy (synchronous),
submit to start the async theme analysis, then poll until it’s done.A A The
4a. Create
POST /strategies requires a name and an objective; exclusions is optional.201 Created returns the new Strategy object. Save its id. A fresh strategy has
active_version_id: null and status: 0 until you submit it.4b. Submit for processing
Submitting kicks off the async build. With noas_of_date, this is a LIVE run against
the current draft:423 Locked here means a run for this version and date is already in flight. Wait for it
to finish before resubmitting.4c. Poll until complete
PollGET /strategies/{strategyId} and watch status, the percent-complete field; 100
means the build has finished.status codes are 0 not started, 1–95 in progress, 100 done, -1 error, and
-2 permanently failed.Fetch holdings
With the strategy built, retrieve its companies. Pass By default this reads the active version’s latest completed run. Each entry is a The response carries a
includeReasoning=true to also get
the human-readable explanation for each inclusion.Company
with id, symbol, name, sector, marketCap, linguisticBeta, marketBuzz, and a
convictionScore in (0, 1). The convictionScore is the default ranking metric, an
overall thematic-strength score independent of company size. See
Signals and scores for what each field means.Turn the list into a weighted portfolio
The raw company list is unweighted. To get an investable portfolio with per-holding weights, use the construction endpoint.POST /strategies/{strategyId}/optimize tilts the
weights by a signal score (default convictionScore):metadata block (number of holdings, weighted signal score, and
expected return/volatility/Sharpe stats) plus a portfolio array where every company also
has a weight. A 404 Not Found here means there is no completed run yet for the resolved
version and date. Keep polling Step 4c until status == 100, then retry.Backtest the holdings
Validate the portfolio against history. The same call with The response includes:
POST /backtest takes a list of holdings (each
a companyId + weight), resolves each to a tradeable security, and computes a
buy-and-hold NAV with risk statistics versus a benchmark.Build the request from the constructed portfolio you fetched:curl (using two holdings for brevity):metadata: totalreturns,annualizedReturn(CAGR),variance,sharpeRatio,maxDrawdown, plusstockCount,weekCount, and anywarnings.timeSeries:[timestamp, navValue]pairs rebased to 10,000.benchmarkMetadataandbenchmarkTimeSeries: the same stats for the benchmark, aligned to the portfolio’s dates so you can chart them together.
years accepts 1–20 (default 5) and benchmark accepts any symbol such as SPY or
QQQ (default SPY). A 400 Bad Request means there was insufficient price data or no
companies could be resolved.Handling errors
Every endpoint shares the same auth and error conventions:| Status | Meaning | What to do |
|---|---|---|
401 Unauthorized | Missing/invalid token, or an inactive account | Recheck the Authorization header; revisit Authentication |
400 Bad Request | Malformed body or invalid identifier (e.g. a non-UUID company id), or a future as_of_date | Read the error field in the JSON body and fix the input |
404 Not Found | The strategy, company, or run doesn’t exist or isn’t visible to you, or there is no completed run for the selected version/date | Verify the id, or poll until a run completes |
423 Locked | A run for this version and date is already in flight | Wait, then resubmit |
429 Too Many Requests | The historical submission rate limit was exceeded | Back off; the body reports available/requested credits |
Working with public strategies
The public catalog (GET /strategies?scope=public) exposes the same read-only surface as
your own strategies. Beyond listing them and fetching their companies (Step 2), you can
inspect the evidence behind each holding and pull historical runs. Every endpoint below
takes a public strategy id: the catalog_id you captured in Step 2, not the strategy_id
of the strategy you built.
Get evidence for a specific company
This endpoint explains why a company is in the strategy: a human-readablereasoning plus
supporting summaries (evidence excerpts). It takes the catalog_id and a company id from
that strategy’s holdings:
provider (the source), pubDate (a Unix timestamp), and text
(the evidence content).
Get evidence for every company at once
Fetch reasoning and evidence for all included companies in the strategy in a single call:List the dates with historical data
Strategy runs are dated. Check which as-of dates have a completed run before requesting one:{"available_dates": ["2024-01-31", "2024-02-29", ...]} in ascending
order. Only dates with a completed run appear.
Download the holdings for a historical date
Read the company list as it stood on a specific date with the samecompanies endpoint,
passing asOfDate:
asOfDate with no completed run returns
404 Not Found; pick another date from available_dates.
On your own strategies, you generate historical results by submitting a run with a past
as_of_date. See Part 2 of the iteration walkthrough for the
submit-poll-read loop.Next steps
You now have the full loop: authenticate → build → fetch holdings → optimize → backtest. From here:- Refine results with exclusions in the Iterate a strategy guide.
- Browse every endpoint, with request/response schemas and an interactive try-it console, in the API Reference.
- Drive Noonum from an AI agent with the same token via the MCP overview.