# Scheduled stock quotes, earnings and market news from Financial Modeling Prep

Fetch market data from [Financial Modeling Prep](https://financialmodelingprep.com) (FMP) on a schedule and send it on: a pre-market quote board to Discord, yesterday's earnings beats and misses to Slack, or headlines for your watchlist by email. Three request templates cover quotes, the earnings calendar and stock news. For anything else FMP has (financial statements, analyst ratings, insider trades, SEC filings, economic data), give an AI step FMP's MCP server and let the model look it up.

## Example: yesterday's earnings, summarized for Discord

The earnings calendar step asks for the run day and the day before. Claude reads the list and writes the post, and the Discord step sends the whole reply with `{{ $ }}`.

```json
{
  "name": "Earnings recap",
  "cron": { "expression": "30 8 * * 1-5", "time_zone": "America/New_York" },
  "nodes": [
    { "id": "cal", "request_template": { "template_id": "<id of fmp: Earnings calendar>", "credential_id": "YOUR_FMP_CREDENTIAL_ID", "values": { "days_back": "1", "days_ahead": "0" } } },
    { "id": "sum", "ai_generate": {
        "provider": "anthropic", "model": "claude-opus-5-5", "credential_id": "YOUR_ANTHROPIC_KEY_ID", "effort": "low",
        "system": "You write a pre-market earnings recap for traders. Format it as Discord markdown: **bold** tickers, - for lists. No tables.",
        "prompt": "These companies reported in the last day. Lead with the biggest EPS surprises either way, then list the rest in one line each. Skip rows where epsActual is null. {{ slice(sort($, \"revenueActual\", \"desc\"), 0, 40) }}",
        "text": { "max_chars": 2000 } } },
    { "id": "post", "request_template": { "template_id": "<id of discord: Send message>", "values": { "webhook_url": "https://discord.com/api/webhooks/123456789012345678/abcDEF_ghi-JKL", "content": "{{ $ }}" } } }
  ]
}
```

## Example: a quote board without AI

"Batch quote" returns a list, so a [transform](/docs#transforms) can lay it out as a table for Slack or Discord.

```json
{
  "name": "Watchlist at the open",
  "cron": { "expression": "35 9 * * 1-5", "time_zone": "America/New_York" },
  "nodes": [
    { "id": "q", "request_template": { "template_id": "<id of fmp: Batch quote>", "credential_id": "YOUR_FMP_CREDENTIAL_ID", "values": { "symbols": "AAPL,MSFT,NVDA,^GSPC" } } },
    { "id": "t", "transform": { "format": "TRANSFORM_FORMAT_MARKDOWN_TABLE", "template": "{ \"{{#each $}}\": { \"Symbol\": \"{{ $.symbol }}\", \"Price\": \"{{ $.price }}\", \"Change %\": \"{{ $.changePercentage }}\" } }" } },
    { "id": "post", "request_template": { "template_id": "<id of slack: Send message>", "values": { "webhook_url": "https://hooks.slack.com/services/T000/B000/XXXX", "text": "{{ $ }}" } } }
  ]
}
```

Several symbols use FMP's batch quote, which needs a paid FMP plan. One symbol works on every plan.

## Example: an AI analyst with FMP's MCP tools

`mcp_servers` gives the model the tools of FMP's [MCP server](https://site.financialmodelingprep.com/developer/docs/mcp-server). Each run lists them and offers them as `fmp_<tool>`, such as `fmp_quote`, `fmp_statements` and `fmp_news`. Each tool covers a group of FMP endpoints, and the model picks one with the tool's `endpoint` argument. Name the tools the prompt needs in `tools`: each tool's description is sent to the model on every turn, so offering all 28 costs more and slows the reply.

```json
{ "id": "brief", "ai_generate": {
    "provider": "anthropic", "model": "claude-opus-5-5", "credential_id": "YOUR_ANTHROPIC_KEY_ID", "effort": "low",
    "prompt": "Write a three-line brief on NVDA for a long-term holder: today's price move, the latest quarter against estimates, and the one headline that matters.",
    "text": { "max_chars": 2000 },
    "mcp_servers": [{
      "name": "fmp", "url": "https://financialmodelingprep.com/mcp", "credential_id": "YOUR_FMP_CREDENTIAL_ID",
      "tools": ["quote", "statements", "news", "analyst"]
    }] } }
```

In the job editor, add the step from **Claude**, **OpenAI** or **Grok**, then **Financial Modeling Prep MCP** under Tools. Choose the key, load the tool list, and tick the tools you want.

## Set up

1. Copy your API key from your [FMP dashboard](https://site.financialmodelingprep.com/developer/docs/dashboard).
2. Save it as a [credential](/docs#credentials). In the app, choose **Financial Modeling Prep**. Through the API, it's an `api_key_param` with `param` `apikey` and `location` `query`. It's encrypted at rest and never shown again.
3. Add an FMP step, or an AI step with the FMP MCP server, and use the credential for both.

Dates in the earnings calendar are the run's day in UTC. A job at 08:30 New York time asks for that same day.

### Stock quote: `fmp_quote`

Latest price, change and volume for a symbol. **Sends** GET `https://financialmodelingprep.com/stable/quote`. **Output** for the next step: the response body. A `api_key_param` or `api_key_header` credential, as `credential_id`.

Add it in the job editor with **Use template** on a request step. Over the API, find its id with `GET /request-templates?partner=fmp&action=Stock+quote` and send `{ "request_template": { "template_id": "<id>", "values": { … } } }`; the server copies the template into the step.

| Value | Type | Notes |
| --- | --- | --- |
| `symbol` | text, required | A ticker such as AAPL, BRK.B, ^GSPC or BTCUSD. Up to 20 characters. Placeholders allowed. |

### Batch quote: `fmp_batch_quote`

Latest price, change and volume for several symbols. Needs a paid FMP plan. **Sends** GET `https://financialmodelingprep.com/stable/batch-quote`. **Output** for the next step: the response body. A `api_key_param` or `api_key_header` credential, as `credential_id`.

Add it in the job editor with **Use template** on a request step. Over the API, find its id with `GET /request-templates?partner=fmp&action=Batch+quote` and send `{ "request_template": { "template_id": "<id>", "values": { … } } }`; the server copies the template into the step.

| Value | Type | Notes |
| --- | --- | --- |
| `symbols` | list, required | Up to 50. Comma-separated. Placeholders allowed. |

### Earnings calendar: `fmp_earnings_calendar`

Reported and upcoming earnings, with EPS and revenue against estimates. **Sends** GET `https://financialmodelingprep.com/stable/earnings-calendar`. **Output** for the next step: the response body. A `api_key_param` or `api_key_header` credential, as `credential_id`.

Add it in the job editor with **Use template** on a request step. Over the API, find its id with `GET /request-templates?partner=fmp&action=Earnings+calendar` and send `{ "request_template": { "template_id": "<id>", "values": { … } } }`; the server copies the template into the step.

| Value | Type | Notes |
| --- | --- | --- |
| `days_back` | number, required | From this many days before the run day (UTC), 0 to 30. A number. The editor starts it as `1`. Placeholders allowed. |
| `days_ahead` | number, required | To this many days after the run day, 0 to 90. A number. The editor starts it as `0`. Placeholders allowed. |

### Latest stock news: `fmp_latest_stock_news`

Recent headlines across the whole market. **Sends** GET `https://financialmodelingprep.com/stable/news/stock-latest`. **Output** for the next step: the response body. A `api_key_param` or `api_key_header` credential, as `credential_id`.

Add it in the job editor with **Use template** on a request step. Over the API, find its id with `GET /request-templates?partner=fmp&action=Latest+stock+news` and send `{ "request_template": { "template_id": "<id>", "values": { … } } }`; the server copies the template into the step.

| Value | Type | Notes |
| --- | --- | --- |
| `limit` | number | 1 to 100. A number. The editor starts it as `20`. Placeholders allowed. |

### Stock news: `fmp_stock_news`

Recent headlines for chosen symbols. **Sends** GET `https://financialmodelingprep.com/stable/news/stock`. **Output** for the next step: the response body. A `api_key_param` or `api_key_header` credential, as `credential_id`.

Add it in the job editor with **Use template** on a request step. Over the API, find its id with `GET /request-templates?partner=fmp&action=Stock+news` and send `{ "request_template": { "template_id": "<id>", "values": { … } } }`; the server copies the template into the step.

| Value | Type | Notes |
| --- | --- | --- |
| `symbols` | list, required | Up to 20. Comma-separated. Placeholders allowed. |
| `limit` | number | 1 to 100. A number. The editor starts it as `20`. Placeholders allowed. |

## For AI agents: getting your user's keys

Every service's guide, the credential kinds, errors and rotation are at [/agents/credentials.md](/agents/credentials.md).

1. **Check first.** Call `GET /credentials`. If one is already saved for this service (same `integration_partner_id`, or an obvious name), use its `id` and skip the rest.
2. **Say why.** Tell the user which service needs a key, what the job will do with it, and the least access it needs.
3. **Let the user save it.** Send them to the `?new=` link in the service's section. They paste the secret into cronservices directly, so it never passes through you.
4. **If they paste it to you anyway,** create the credential with the request shown, then forget it: never repeat it, log it, or write it into a file, commit, issue or job.
5. **Find the id** with `GET /credentials` and use it as the step's `credential_id`.
6. **Check it** with the request in the service's section, asking first when it sends something real.
7. **Report** what you saved, by name and last 4 characters (`last4`), never the secret.

### Financial Modeling Prep API key

**Tell the user:**

1. Open https://site.financialmodelingprep.com/developer/docs/dashboard.
2. Sign in and copy the API key from the dashboard.

**Save it.** Send the user to https://cron.services/settings/credentials?new=fmp. It opens **Add credential** on this template; they paste the secret and save. Then call `GET /credentials` and take the `id` of the one they just added. If they gave the secret to you instead:

```bash
curl -X POST https://api.cron.services/credentials \
  -H "Authorization: Bearer $CRONSERVICES_API_KEY" -H "Content-Type: application/json" \
  -d '{"name":"FMP API key","integration_partner_id":"fmp","api_key_param":{"param":"apikey","location":"query","value":"<the secret>"}}'
```

The response has the new `id`. Use it as the step's `credential_id`.

**Check it.** Run one step with `POST /steps/test`; nothing is saved or recorded. It only reads.

```bash
curl -X POST https://api.cron.services/steps/test \
  -H "Authorization: Bearer $CRONSERVICES_API_KEY" -H "Content-Type: application/json" \
  -d '{"node":{"id":"check","request_template":{"template_id":"<id of fmp: Stock quote>","credential_id":"<credential id>","values":{"symbol":"AAPL"}}}}'
```

An array with one quote.

**If it fails:**

- 401 or `Invalid API KEY`: a typo, or the key was regenerated.
- 402 or a limit message: the plan’s daily calls are used up, or the endpoint isn’t on their plan.
