To find a company's earnings and dividend dates, search for its instrument id and request its earnings and dividends lists. Narwhal returns each report date with its EPS estimate and actual figure, and each ex-dividend date with its amount and currency.
Find the instrument id
The earnings and dividend endpoints take an instrument id, so look it up first. GET /v1/equities/search takes a query q and optional country and type filters. Each result has an id made of the exchange code and the symbol, a symbol, a name, a currency and, for listed companies, a company_id that links to the filings endpoints.
curl -s -H "Authorization: Bearer $NARWHAL_API_KEY" \
"https://api.narwhalapi.com/v1/equities/search?q=microsoft&country=USA"{
"results": [
{"id": "XNAS:MSFT", "symbol": "MSFT", "name": "Microsoft Corporation Common Stock", "type": "common_stock", "mic": "XNAS", "country": "USA", "currency": "USD", "company_id": "usa:0000789019"}
],
"next_cursor": null
}The id is XNAS:MSFT: XNAS is the exchange code of the listing and MSFT the symbol. A search for apple without a country filter returns several listings under that name, including XNAS:AAPL, a Brazilian receipt BVMF:AAPL34 and Argentine receipts, so pick the row whose mic and currency match the market you care about.
Get the earnings dates
GET /v1/equities/{id}/earnings lists a company's earnings reports, newest first. Each row has the date and the time of day, the analysts' estimate in eps_estimate, the reported figure in eps_actual, the gap in surprise and surprise_percent, and the filing_id of the matching SEC filing.
curl -s -H "Authorization: Bearer $NARWHAL_API_KEY" \
"https://api.narwhalapi.com/v1/equities/XNAS:MSFT/earnings"{
"id": "XNAS:MSFT",
"earnings": [
{"date": "2026-10-28", "time": "after_close", "eps_estimate": "4.72", "eps_actual": "4.89", "surprise": "0.17", "surprise_percent": "3.60", "filing_id": "usa:0000789019:0001193125-26-436133"},
{"date": "2026-07-29", "time": "after_close", "eps_estimate": "4.24", "eps_actual": "4.74", "surprise": "0.50", "surprise_percent": "11.79", "filing_id": "usa:0000789019:0001193125-26-323660"}
]
}On 2026-10-28, after the close, the company reported 4.89 against an estimate of 4.72, which is the 3.60 percent surprise in the row. The newest rows for three US companies all had an eps_actual and a past date, so the list holds reports that have happened. It did not contain a scheduled future date, so take the next report date from the company's own announcement. The response is long: for Apple it held 100 rows and a next_cursor, which you send back as cursor to read older rows.
Get the dividend dates
GET /v1/equities/{id}/dividends lists ex-dividend dates with the amount and the currency, newest first. The ex-dividend date is the first day a buyer no longer receives that dividend. This request uses the bare symbol instead of the exchange form.
curl -s -H "Authorization: Bearer $NARWHAL_API_KEY" \
"https://api.narwhalapi.com/v1/equities/MSFT/dividends"{
"id": "XNAS:MSFT",
"dividends": [
{"ex_date": "2026-11-19", "amount": "0.98", "currency": "USD"},
{"ex_date": "2026-08-20", "amount": "0.91", "currency": "USD"},
{"ex_date": "2026-05-21", "amount": "0.91", "currency": "USD"}
]
}The first row is dated 2026-11-19, after the date of this request, so a dividend that is already announced can appear before it is paid. The id in the response is still XNAS:MSFT: the bare symbol resolved to the US listing, and AAPL resolved to XNAS:AAPL the same way even though another exchange also lists that symbol. Use the full form, such as XNAS:MSFT, when the exchange matters.
Pick out the next dates in code
The script reads both lists for one id, prints the latest report and takes the soonest ex-dividend date that is today or later. Because both lists come newest first, the last row of the future subset is the soonest one.
import json, os, urllib.request
from datetime import date
from decimal import Decimal
API = "https://api.narwhalapi.com"
def get(path):
req = urllib.request.Request(API + path, headers={"Authorization": f"Bearer {os.environ['NARWHAL_API_KEY']}"})
return json.load(urllib.request.urlopen(req))
earnings = get("/v1/equities/XNAS:MSFT/earnings")["earnings"]
dividends = get("/v1/equities/XNAS:MSFT/dividends")["dividends"]
last = earnings[0]
print("last report:", last["date"], last["time"], "EPS", last["eps_actual"], "vs", last["eps_estimate"])
today = date.today().isoformat()
upcoming = [d for d in dividends if d["ex_date"] >= today]
past = [d for d in dividends if d["ex_date"] < today]
if upcoming:
nxt = upcoming[-1]
print("next ex-dividend date:", nxt["ex_date"], nxt["amount"], nxt["currency"])
print("last four past dividends, summed:", sum(Decimal(d["amount"]) for d in past[:4]))last report: 2026-10-28 after_close EPS 4.89 vs 4.72
next ex-dividend date: 2026-11-19 0.98 USD
last four past dividends, summed: 3.64The four most recent past dividends are 0.91 each, and their sum of 3.64 comes from the same response. The next one, 0.98, is higher. Amounts are decimal strings, so the script adds them with Decimal.
How do I open the filing behind an earnings row?
Send the row's filing_id to GET /v1/filings/{filing_id}. The filing shows the form, the fiscal period and a link to the SEC page. The statements for that period sit in the financial statements API.
curl -s -H "Authorization: Bearer $NARWHAL_API_KEY" \
"https://api.narwhalapi.com/v1/filings/usa:0000789019:0001193125-26-436133"{
"id": "usa:0000789019:0001193125-26-436133",
"company_id": "usa:0000789019",
"form": "10-Q",
"type": "quarterly",
"fy": 2027,
"fp": "Q1",
"period_end": "2026-09-30",
"filed_at": "2026-10-28T20:07:39Z",
"url": "https://www.sec.gov/Archives/edgar/data/789019/000119312526436133/0001193125-26-436133-index.htm"
}This row is a 10-Q for fiscal quarter Q1 of fiscal year 2027, filed at 2026-10-28T20:07:39Z, which matches the earnings date.
Can I use a bare ticker or the exchange form?
Both work. AAPL and XNAS:AAPL returned identical earnings with the same id of XNAS:AAPL. The exchange form removes any doubt about which listing you mean, so use it when the same symbol trades on more than one exchange.
How are surprise and surprise_percent calculated?
surprise is eps_actual minus eps_estimate, and surprise_percent is that gap as a share of the estimate. For the 2026-10-28 report, 4.89 minus 4.72 is 0.17, and 0.17 divided by 4.72 is 3.60 percent. For the Apple report dated 2026-07-30, 2.02 minus 1.89 is 0.13, which is 6.88 percent.
A negative surprise means the company reported less than the estimate. Both fields are strings, like the other decimals in the response, so convert them with a decimal type before you compare them.
How do I watch a company for a new report or dividend?
Read the two lists on a schedule and compare the first row with the one you stored last time. A new date in the earnings list is a new report, and a new ex_date in the dividends list is a new dividend. The daily data pull guide shows a script that runs once a day, and the caching guide covers repeated reads.
Published .