How to Generate a PDF Report from Snowflake Query Results

Run a Snowflake SQL query on a schedule, turn the result into a formatted PDF report with a title, summary and table, and email it or save it to your File Store, with no BI licence for the people who receive it.

What This Integration Does

Plenty of people need a Snowflake number every week but will never open a worksheet or a dashboard: store managers, suppliers, the board. A PDF in their inbox is what they read. This Spojit workflow runs your SQL through the Snowflake SQL API, passes the rows to the PDF Tools connector's create-pdf tool, which lays them out as a paginated table under a heading and a short summary, and sends the file by email or saves it to your File Store. An optional AI step writes the summary paragraph from the numbers.

Every run executes the query fresh, so the report always reflects current data, and nothing in Snowflake is changed. The query runs under a role you choose, so the report can only ever contain what that role is allowed to see.

Prerequisites

  • A Snowflake user for the integration (ideally TYPE = SERVICE) with a role that can use the warehouse and read the tables in the query.
  • A programmatic access token (PAT) for that user, created in Snowsight from the user's profile under Programmatic access tokens, restricted to the reporting role. Snowflake shows the token once; copy it.
  • A network policy that allows the token to be used. By default Snowflake requires the user to be covered by a network policy before a PAT can authenticate; your Snowflake admin can add one, or relax the requirement with an authentication policy.
  • An HTTP Requests connection in Spojit with Base URL https://YOUR_ACCOUNT.snowflakecomputing.com (your account identifier, such as myorg-myaccount) and Auth Method Bearer token set to the PAT.

Step 1: Schedule Trigger

Add a Trigger node with type Schedule, for example 0 7 * * 1 for 7 AM every Monday in the recipients' timezone.

Step 2: Run the Query

Add a Connector node on your Snowflake HTTP connection with http-post:

  • url: /api/v2/statements
  • headers: { "Content-Type": "application/json", "Accept": "application/json", "X-Snowflake-Authorization-Token-Type": "PROGRAMMATIC_ACCESS_TOKEN" }
  • body:
    {
      "statement": "SELECT region, COUNT(*) AS orders, ROUND(SUM(total), 2) AS revenue FROM sales.public.orders WHERE order_date >= DATEADD(day, -7, CURRENT_DATE) GROUP BY region ORDER BY revenue DESC",
      "timeout": 60,
      "warehouse": "REPORTING_WH",
      "role": "REPORTING",
      "database": "SALES",
      "schema": "PUBLIC"
    }

Name the output result. Snowflake returns the column definitions in result.data.resultSetMetaData.rowType (one entry per column, with its name) and the rows in result.data.data as arrays of strings.

Step 3: Get the Column Names

Add a Connector node on Array Tools with pluck, plucking name from {{ result.data.resultSetMetaData.rowType }}. Name it columns; the names are in {{ columns.items }}. These become the table headers in the PDF.

Step 4: Write a Summary (Optional)

Add a Connector node in Agent Mode on the Text Tools connector (its tools only reshape text, so the step only writes the summary) with a prompt such as: "Here are last week's orders and revenue by region: {{ result.data.data }} with columns {{ columns.items }}. Write two sentences for a store manager: the total, the best region, and anything unusual. No headings." Name the output summary.

Step 5: Create the PDF

Add a Connector node on PDF Tools with create-pdf:

  • title: Weekly sales by region (and add a Date & Time format step named week_ending before this one for the date in the content)
  • content:
    **Week ending:** {{ week_ending.result }}
    **Prepared:** automatically from Snowflake
    
    {{ summary }}
    
    ## Orders and revenue by region
  • rows: {{ result.data.data }}
  • columns: {{ columns.items }}
  • footer: Acme Pty Ltd - internal
  • orientation: landscape if the query returns many columns.

The table prints after the content, with its header repeated on every page. Name the output report; the file is {{ report.pdf }}, Base64-encoded.

Step 6: Deliver the Report

Email it with a Resend or SMTP Email step using send-email, adding an attachment with filename weekly-sales.pdf and content {{ report.pdf }}. Or save it with a File Store node (Save a file, content {{ report.pdf }}, content type application/pdf) to keep an archive of every week's report.

Tips

  • Several sections: run more than one query and put the extra results in the blocks input as additional table blocks with their own headings.
  • Numbers as text: Snowflake returns every value as a string. Format numbers in SQL (TO_CHAR(revenue, '999,999,990.00')) so the PDF shows them the way readers expect.
  • Long results: results over a certain size come back in partitions. Fetch the rest with GET /api/v2/statements/{statementHandle}?partition=1 and so on, or aggregate in SQL so the report stays readable.
  • Snowflake MCP alternative: if your account has Snowflake's managed MCP server set up, the Snowflake (Official MCP) connector lets an Agent Mode step answer questions in plain English. For fixed weekly reports, the SQL API keeps the query exact.

Common Pitfalls

  • Asynchronous responses: if a query does not finish within the time Snowflake waits for a synchronous reply (about 45 seconds), Snowflake returns 202 with a statementHandle instead of rows and keeps running it; timeout is when Snowflake cancels the statement altogether. Poll GET /api/v2/statements/{statementHandle} in a Loop until it returns 200, or make the query faster.
  • Case-sensitive context: warehouse, role, database and schema must match the names Snowflake shows in SHOW commands, usually upper case.
  • Token rejected: a PAT fails if the user is not covered by a network policy (when one is required), if the role restriction does not include the role in the request, or after the token expires. Check the user's login history in Snowsight.
  • Escaping SQL in JSON: double quotes inside the SQL must be escaped as \" in the body. Prefer single quotes for string literals.

Testing

Run the workflow manually with LIMIT 20 on the query and open the PDF in your File Store. Check the columns, number formatting and page breaks, then remove the limit and turn on the schedule.

Learn More

Ready to build this?

Start on the free plan: 500 AI credits a month, no card needed.

Start free

Did this answer your question? Thanks for the feedback There was a problem submitting your feedback. Please try again later.