> ## Documentation Index
> Fetch the complete documentation index at: https://fruitstand.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# How to Get Earnings Call Transcripts into Snowflake (3 Ways)

> Three ways to get earnings call transcripts into Snowflake: a Marketplace listing, Snowflake's free public data share, or loading an API yourself, with SQL.

*By [Fruit Stand Team](https://fruitstand.dev/about.md) · November 8, 2026 · Guides*

There are three ways to get earnings call transcripts into Snowflake:
subscribe to a **Snowflake Marketplace listing**, use Snowflake's **free
public data share**, or **load them from an API** and parse them into
speaker paragraphs yourself. A listing is fastest: the transcripts appear as
a database in minutes. The free share lags about three months, and loading
your own means maintaining a parser.

This post covers how to set up each one, with the SQL. Once the transcripts
are in, [How to Query Earnings Call Transcripts in Snowflake
SQL](https://fruitstand.dev/blog/query-earnings-call-transcripts-sql.md) covers reading calls,
splitting out the Q\&A and finding the analysts.

> [!NOTE]
>
> Fruit Stand publishes the Earnings Call Transcripts listing, one of the
> options below. Counts were checked in Snowflake on November 8, 2026.

## The short answer

| Method | Time to first query | What you get | Ongoing work | Cost |
| - | - | - | - | - |
| [Earnings Call Transcripts listing](https://app.snowflake.com/marketplace/listing/GZTYZ40XYU5) (Fruit Stand) | Minutes | 242,041 calls from 6,601 companies since October 2005, one row per paragraph | None; refreshed weekly | \$50/month after a 30-day trial |
| Snowflake Public Data (Free) | Minutes | Over 150,000 earnings calls since November 2009, plus investor days and other events, one JSON document per event | Deduplicating and flattening the JSON | Free, about three months behind |
| Your own API or file load | Days | Whatever your vendor licenses you | Parsing, re-deliveries, scheduling, monitoring | The vendor's price, plus compute |

## Option 1: Subscribe to a Marketplace listing

A Marketplace listing is shared into your account, not copied. The
provider's tables appear as a read-only database, each refresh shows up
without you doing anything, and you don't pay storage for it.

**1. Find the listing**

Open the [Earnings Call Transcripts listing](https://app.snowflake.com/marketplace/listing/GZTYZ40XYU5) on the Snowflake Marketplace.

**2. Get it**

Click **Get**, name the database it will mount as (for example `EARNINGS_CALLS`), and choose which roles can use it.

**3. Query it**

Select that database and its schema in a worksheet and query the views.

The listing has three views:

| View | One row per | Use it for |
| - | - | - |
| `earning_call_transcripts_flat_vw` | Speaker paragraph (15.6 million rows) | Filtering by speaker or text, splitting out the Q\&A |
| `earning_call_transcripts_vw` | Call, with the paragraphs as a JSON array | Copying whole calls, or feeding a call to an LLM |
| `earning_call_transcripts_cnt_vw` | Company, with its call count and date range | Checking coverage before you query |

To check coverage for the companies you care about:

```sql theme={null}
select symbol, total_transcripts, earliest_fiscal_year, latest_fiscal_year,
       latest_transcript_report_date
from earning_call_transcripts_cnt_vw
where symbol in ('AAPL', 'MSFT', 'NVDA', 'JPM')
order by symbol;
```

On November 8, 2026 that returned 85 calls for Apple since 2005, 84 for
Microsoft, 82 for NVIDIA and 78 for JPMorgan Chase since 2007, each through
its most recent call. Fiscal years follow each company's own calendar, so
Microsoft's and NVIDIA's latest calls are already in fiscal 2027.

**The trial covers Apple only.** During the 30-day trial the views return
Apple's 85 calls, so you can test your queries on real data. The other
6,600 companies appear once you subscribe.

### Keeping your own copy in sync

You don't need a copy to query the listing. If you want one, for example to
add embeddings or join to tables in another database, `src_updated_at` tells
you which calls are new or changed:

```sql theme={null}
select count(*) as calls, count(distinct symbol) as companies,
       min(report_date) as oldest_call, max(report_date) as newest_call
from earning_call_transcripts_vw
where src_updated_at >= dateadd(day, -7, current_timestamp());
```

In the seven days to November 8, 2026, that was 1,581 calls from 1,580
companies. The oldest was from August 13: transcripts get corrected after a
call, so sync on `src_updated_at`, not on the call date. A `MERGE` keyed on
the company and fiscal period keeps the copy current (this one targets a
table of your own, so adjust the names):

```sql theme={null}
merge into my_transcripts t
using (
    select *
    from earning_call_transcripts_vw
    where src_updated_at >= dateadd(day, -7, current_timestamp())
) s
    on t.symbol = s.symbol
   and t.fiscal_year = s.fiscal_year
   and t.fiscal_quarter = s.fiscal_quarter
when matched then update set
    report_date = s.report_date, transcripts = s.transcripts,
    src_updated_at = s.src_updated_at
when not matched then insert
    (symbol, fiscal_year, fiscal_quarter, report_date, transcripts, src_updated_at)
    values (s.symbol, s.fiscal_year, s.fiscal_quarter, s.report_date,
            s.transcripts, s.src_updated_at);
```

## Option 2: Use Snowflake's free public data share

Snowflake's own **Snowflake Public Data (Free)** listing includes event
transcripts in `company_event_transcript_attributes`. It's free, and it
covers more than earnings calls: conferences, annual meetings, investor
days and M\&A calls too.

Three things to handle:

* **It's about three months behind.** On November 8, 2026 its latest
  earnings call was from August 9.
* **Each call appears more than once.** There's a `RAW` and a
  `SPEAKERS_ANNOTATED` version, and sometimes several of each. Pick one
  type and the latest row per event.
* **The transcript is one JSON document.** Paragraphs and speakers are
  arrays inside it, so you flatten them before filtering on text.

Deduplicated, it has over 150,000 earnings calls for 7,732 tickers since
November 2009:

```sql theme={null}
select count(*) as calls, count(distinct primary_ticker) as companies,
       max(event_timestamp)::date as latest
from (
    select *
    from snowflake_public_data_free.public_data_free.company_event_transcript_attributes
    where event_type = 'Earnings Call'
      and transcript_type = 'SPEAKERS_ANNOTATED'
    qualify row_number() over (partition by primary_ticker, event_timestamp
                               order by updated_at desc) = 1
);
```

To flatten one call into paragraphs with speaker names and roles, see [the
free option in our querying
guide](https://fruitstand.dev/blog/query-earnings-call-transcripts-sql.md#the-free-option-in-snowflake).
Its speaker roles and firms are something our listing doesn't have.

## Option 3: Load transcripts from an API yourself

If your transcripts come from an API or as files, load the raw JSON first
and parse it in SQL. Keeping the raw payload means you can re-parse without
calling the API again.

**1. Land the raw JSON.** One row per call:

```sql theme={null}
create table if not exists raw_transcripts (
    payload    variant,
    loaded_at  timestamp_ltz default current_timestamp()
);
```

From a Python job, insert each API response as it arrives. From files in a
bucket, use `COPY INTO` with a JSON file format:

```sql theme={null}
copy into raw_transcripts (payload)
from @transcripts_stage
file_format = (type = json strip_outer_array = true);
```

**2. Parse it into paragraphs.** Most transcript APIs return the whole call
as one text field, with each paragraph on its own line starting with the
speaker's name: `Operator: Good afternoon...`. Financial Modeling Prep's
transcript endpoint, for example, returns its text in a `content` field
like that. Split the text on line breaks, take the speaker from the start
of each line, and carry it forward to lines that continue the same
speaker:

```sql theme={null}
create or replace table transcript_paragraphs as
with lines as (
    select r.payload:symbol::string as symbol,
           r.payload:year::int as fiscal_year,
           r.payload:period::string as fiscal_period,
           r.payload:date::date as report_date,
           l.index as line_number,
           regexp_substr(l.value, '^([A-Z][^:]{0,60}):\\s', 1, 1, 'e', 1) as speaker_label,
           trim(iff(speaker_label is null, l.value,
                    substr(l.value, length(speaker_label) + 2))) as content
    from raw_transcripts r,
         lateral split_to_table(r.payload:content::string, '\n') l
    where trim(l.value) <> ''
)
select symbol, fiscal_year, fiscal_period, report_date,
       row_number() over (partition by symbol, fiscal_year, fiscal_period
                          order by line_number) as paragraph_number,
       last_value(speaker_label ignore nulls) over (
           partition by symbol, fiscal_year, fiscal_period
           order by line_number
           rows between unbounded preceding and current row) as speaker,
       content
from lines;
```

The field names (`symbol`, `year`, `period`, `date`, `content`) depend on
your vendor, so rename them to match. We tested the parsing on a sample
call with a continuation paragraph and a colon inside the text, and it
returned one row per paragraph with the right speakers.

**3. Plan for what breaks.**

* **Speaker detection is a heuristic.** A paragraph that starts with
  something like `Revenue: up 12%` looks like a speaker label. Check each
  call's speaker list against a known list, or flag labels that appear only
  once.
* **Corrections arrive later.** Vendors re-deliver transcripts after
  the call. Keep the newest payload per call and rebuild that call's
  paragraphs, rather than appending.
* **Fiscal periods aren't calendar quarters.** Keep the call date next to
  the fiscal period, and compare companies by date.
* **Rate limits and plans.** Transcript endpoints are usually on higher
  tiers: FMP includes them on its \$139/month Ultimate plan. A full backfill
  is one request per company per quarter.
* **The license.** Check that your plan allows storing the text in a shared
  warehouse. [Where to Get Earnings Call Transcripts in
  Bulk](https://fruitstand.dev/blog/earnings-call-transcripts-bulk.md) compares the providers' terms.

## Check your load

Whichever option you use, run these on your paragraph table before trusting
it. Each call should have a sensible number of paragraphs and speakers:

```sql theme={null}
select symbol, fiscal_year, fiscal_period,
       count(*) as paragraphs,
       count(distinct speaker) as speakers
from transcript_paragraphs
group by 1, 2, 3
having count(distinct speaker) < 3 or count(*) < 10
order by symbol;
```

A real earnings call has at least a host or operator and one executive, and
usually several analysts. A call with one or two speakers, or a handful of
paragraphs, usually means the parser missed the speaker labels or the
transcript was cut short.

## Which should you choose?

* **You want every company's calls in SQL with nothing to build:** the
  Earnings Call Transcripts listing.
* **You need other company events, or speaker roles, and can wait three
  months:** Snowflake Public Data (Free).
* **You already license transcripts from a vendor with no Snowflake
  delivery:** load the raw JSON and parse it in SQL as above.

For the other financial data you can add the same way, see [What Financial
Datasets Are on the Snowflake
Marketplace?](https://fruitstand.dev/blog/financial-datasets-snowflake-marketplace.md)

## F.A.Q.

> [accordion] Are there free earnings call transcripts in Snowflake?
>
> Yes. Snowflake Public Data (Free) has over 150,000 earnings calls since 2009, about three months behind. Fruit Stand's listing has a 30-day free trial that covers Apple's calls.

> [accordion] Do I pay storage for a Marketplace listing?
>
> No. Shared data stays in the provider's account. You pay for the compute your queries use, plus the listing's price. Copies you make into your own tables are stored and billed like any other table.

> [accordion] How often are new calls added?
>
> Fruit Stand's listing refreshes weekly, with new calls and corrected transcripts. The free Snowflake share runs about three months behind.

> [accordion] Can I load transcripts from an API directly inside Snowflake?
>
> Yes, with an external access integration and a Python stored procedure, so no outside scheduler is needed. The parsing SQL above works the same way on what it loads.

> [accordion] Which companies are covered?
>
> Fruit Stand's listing has 6,601 companies with calls since October 2005. Query `earning_call_transcripts_cnt_vw` for each company's call count and date range.

To get every company's calls in Snowflake without building a pipeline,
start a free 30-day trial of the [Earnings Call Transcripts listing on the
Snowflake Marketplace](https://app.snowflake.com/marketplace/listing/GZTYZ40XYU5).
The schema is in the [dataset docs](https://fruitstand.dev/datasets/earnings-call-transcripts.md).
Questions? Reach out at [contact@fruitstand.dev](mailto:contact@fruitstand.dev).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.