Summary
When Ironclad is integrated with Snowflake, Snowflake becomes your reporting and auditing layer. Admin changes, workflow activities, comments, approvers, and other actions taken in Ironclad flow into Snowflake tables on a near real-time basis. Use this guide to verify the integration end to end. You will:
- Confirm data is flowing from Ironclad to Snowflake
- Generate test activity in Ironclad
- Query Snowflake to validate the activity appears in the audit log
- Troubleshoot common query and access issues
By the end, you will have a repeatable playbook you can use anytime you need to validate the integration.
Who is this for?
- Ironclad Admins responsible for auditing and reporting
- Data and Analytics teams building dashboards on top of Snowflake
- Compliance and Legal Ops teams validating that audit trails are complete
Prerequisites
Make sure you have the following:
| Requirement | Details |
|---|---|
| Ironclad Admin access | Needed to make admin changes and trigger workflow activity |
| Snowflake access | At minimum, SELECT access on the Ironclad export schema, for example: <YOUR_DATABASE>.<YOUR_SCHEMA>
|
| Data Export enabled | Confirm Ironclad's Snowflake Data Export integration is configured and active |
| Audit log table name | Example used in this guide: <YOUR_AUDIT_LOG_TABLE>
|
| Active warehouse | Example: COMPUTE_WH
|
Sync Expectation: Ironclad to Snowflake sync is typically near real-time, but allow 2 to 10 minutes after taking an action before expecting it to appear.
Schema Reference
The Ironclad audit log table has the following structure. Column names are lowercase and should be wrapped in double quotes in Snowflake queries.
| Column | Type | Description |
|---|---|---|
"actor_name" |
string | Display name of the user who performed the event |
"actor_email" |
string | Email of the user |
"actor_user_id" |
string | Internal Ironclad user ID |
"actor_company_id" |
string | Workspace or company ID |
"event_time" |
number | Unix timestamp in microseconds |
"event_name" |
string | Event type, for example: WORKFLOW_VIEWED or WORKFLOW_COMMENT_CREATED
|
"event_data" |
VARIANT | Full event payload, including fields such as workflowId and workflowName
|
Common gotchas
- There is no top-level
workflow_idcolumn. Extract it from"event_data"using"event_data":workflowId::string. -
"event_time"is stored as microseconds since epoch, not as a Snowflake timestamp. Convert it withTO_TIMESTAMP_NTZ("event_time" / 1000000).
Test the Integration
Part 1: Confirm the integration is live
Step 1: Query the audit log directly
Your role may not have privileges for SHOW TABLES, but direct SELECT queries can still work.
SQL SELECT * FROM <YOUR_DATABASE>.<YOUR_SCHEMA>.<YOUR_AUDIT_LOG_TABLE> LIMIT 10;
If rows return, the integration is live and you have the access you need.
Step 2: Inspect the columns
Use this query to confirm the available column names and casing:
SQL SELECT * FROM <YOUR_DATABASE>.<YOUR_SCHEMA>.<YOUR_AUDIT_LOG_TABLE> LIMIT 1;
Check the result grid and confirm the exact lowercase column names.
Step 3: Capture a baseline timestamp
Convert the latest event time into a readable timestamp:
SQL
SELECT TO_TIMESTAMP_NTZ(MAX("event_time") / 1000000) AS last_event_synced
FROM <YOUR_DATABASE>.<YOUR_SCHEMA>.<YOUR_AUDIT_LOG_TABLE>;Record this value. Any test activity you generate next should appear after this timestamp.
Part 2: Generate test activity in Ironclad
Trigger the following categories of activity to confirm each event flows into Snowflake.
Test A: Admin change
In Ironclad, go to Company Settings → Users & Permissions or another admin area.
Make a small, reversible change, such as:
- Add or remove a user from a group
- Update a workflow configuration setting
- Change a tag or property
Note the time of the change.
Test B: Workflow comment
Open any in-progress workflow.
Add a comment such as:
Snowflake sync test - [your initials] - [timestamp]
Submit the comment.
Test C: Add an approver
In the same workflow, or another active workflow, add yourself or a teammate as an Approver. Note the workflow ID from the URL.
Test D: Take a workflow action
Take a workflow action such as:
- Approve
- Sign
- Reject
- Cancel
Note the time of the action.
Part 3: Validate activity in Snowflake
Wait about 2 to 5 minutes, then run the following queries.
Query 1: View the most recent events
SQL
SELECT
TO_TIMESTAMP_NTZ("event_time" / 1000000) AS event_ts,
"event_name",
"actor_email",
"event_data":workflowId::string AS workflow_id,
"event_data"
FROM <YOUR_DATABASE>.<YOUR_SCHEMA>.<YOUR_AUDIT_LOG_TABLE>
ORDER BY "event_time" DESC
LIMIT 25;You should see your recent admin change, comment, approver addition, and workflow actions near the top.
Query 2: Filter to events from the last hour
SQL
SELECT
TO_TIMESTAMP_NTZ("event_time" / 1000000) AS event_ts,
"event_name",
"actor_email",
"event_data":workflowId::string AS workflow_id,
"event_data"
FROM <YOUR_DATABASE>.<YOUR_SCHEMA>.<YOUR_AUDIT_LOG_TABLE>
WHERE "event_time" / 1000000 >= DATE_PART(EPOCH_SECOND, DATEADD(HOUR, -1, CURRENT_TIMESTAMP()))
ORDER BY "event_time" DESC;
Query 3: Filter to events after a specific date and time
SQL
SELECT
TO_TIMESTAMP_NTZ("event_time" / 1000000) AS event_ts,
"event_name",
"actor_email"
"event_data"
FROM <YOUR_DATABASE>.<YOUR_SCHEMA>.<YOUR_AUDIT_LOG_TABLE>
WHERE TO_TIMESTAMP_NTZ("event_time" / 1000000) >= '2025-05-05 21:30:00' ORDER BY "event_time" DESC;
Query 4: Filter to your own activity
SQL
SELECT
TO_TIMESTAMP_NTZ("event_time" / 1000000) AS event_ts, "event_name",
"event_data":workflowId::string AS workflow_id,
"event_data"
FROM <YOUR_DATABASE>.<YOUR_SCHEMA>.<YOUR_AUDIT_LOG_TABLE>
WHERE "actor_email" = 'your.email@ironcladhq.com'
ORDER BY "event_time" DESC
LIMIT 50;
Query 5: Discover all event types in your tenant
Run this once to find the exact event_name values available in your environment.
SQL SELECT DISTINCT "event_name" FROM <YOUR_DATABASE>.<YOUR_SCHEMA>.<YOUR_AUDIT_LOG_TABLE> ORDER BY "event_name";
Query 6: Filter to specific event types
After identifying the exact values in your tenant, filter for the ones you care about.
SQL
SELECT
TO_TIMESTAMP_NTZ("event_time" / 1000000) AS event_ts, "event_name",
"actor_email",
"event_data":workflowId::string AS workflow_id,
"event_data"
FROM <YOUR_DATABASE>.<YOUR_SCHEMA>.<YOUR_AUDIT_LOG_TABLE> WHERE "event_name" IN (
'WORKFLOW_LAUNCHED',
'WORKFLOW_VIEWED',
'WORKFLOW_COMMENT_CREATED',
'WORKFLOW_APPROVER_ADDED',
'WORKFLOW_APPROVED',
'WORKFLOW_REJECTED',
'WORKFLOW_SIGNED',
'ADMIN_USER_UPDATED',
'ADMIN_GROUP_UPDATED'
)
ORDER BY "event_time" DESC
LIMIT 100;
Query 7: Filter by workflow ID
SQL
SELECT
TO_TIMESTAMP_NTZ("event_time" / 1000000) AS event_ts
"event_name",
"actor_email",
"event_data"
FROM <YOUR_DATABASE>.<YOUR_SCHEMA>.<YOUR_AUDIT_LOG_TABLE>
WHERE "event_data":workflowId::string = '<your-test-workflow-id>' ORDER BY "event_time" DESC;
Query 8: Inspect the raw JSON payload
Different event types carry different JSON structures. Use this query to inspect the payload.
SQL SELECT "event_name" "event_data" FROM <YOUR_DATABASE>.<YOUR_SCHEMA>.<YOUR_AUDIT_LOG_TABLE> ORDER BY "event_time" DESC LIMIT 10;
Use the keys you find in "event_data" such as workflowId, workflowName, commentId, or stepId in later queries.
Part 4: Confirm the test passed
Use this checklist to validate the integration end to end:
-
SELECT *on the audit log table returns rows -
MAX("event_time")shows a recent timestamp - Your admin change appears in the audit log with the expected
actor_emailandtime - Your workflow comment appears, likely as
WORKFLOW_COMMENT_CREATED - Your approver addition appears, likely as
WORKFLOW_APPROVER_ADDED - Your workflow action appears, for example
WORKFLOW_APPROVEDorWORKFLOW_SIGNED -
"event_data":workflowId::stringmatches the workflow ID from the Ironclad URL
If every item is confirmed, the integration is working as expected.
Troubleshooting
| Issue | Likely cause | Fix |
|---|---|---|
SHOW TABLES returns nothing or errors |
Role lacks metadata privileges | Skip SHOW TABLES and query the known table directly |
invalid identifier 'TIMESTAMP' |
That column does not exist | Use "event_time" |
invalid identifier 'EVENT_TYPE' |
The column is actually named "event_name" |
Use "event_name" |
MAX("event_time")returns a very large number |
The value is stored as Unix microseconds |
Wrap it with TO_TIMESTAMP_NTZ("even t_time" / 1000000) |
WHERE "event_time" >= '2025-05-05' returns nothing |
You are comparing a numeric microsecond field to a string | Convert first with TO_TIMESTAMP_NTZ("even t_time" / 1000000)
|
You cannot find a workflow_id column |
It lives inside "event_data" |
Extract it with "event_data":workflowI d::string
|
| No new rows appear after taking action | Sync delay | Wait 5 to 10 minutes and query again |
| Some event types are missing | Event export may not be enabled | Check Ironclad Snowflake export configuration |
| Permission denied or object does not exist | Missing USAGE on database or schema |
Ask a Snowflake admin to grant USAGE and SELECT
|
| Only old data appears | Sync may be paused or credentials may have expired | Check integration status in Ironclad and Snowflake |
Potential error causes
Quoted lowercase column names
Ironclad data export creates quoted, lowercase identifiers. In Snowflake, quoted identifiers preserve case, so unquoted references such as EVENT_TIME or TIMESTAMP will not match the exported column names.
Microsecond timestamps
Many event-streaming systems store timestamps in microseconds for higher precision. In Snowflake, divide by 1000000 before converting with TO_TIMESTAMP_NTZ.
JSON-nested fields
Fields such as workflowId are often nested inside the "event_data" VARIANT column rather than exposed as top-level columns. Extract them with Snowflake's JSON path syntax.
Useful Queries
Latest sync timestamp
SQL
SELECT TO_TIMESTAMP_NTZ(MAX("event_time") / 1000000) AS last_event_synced
FROM <YOUR_DATABASE>.<YOUR_SCHEMA>.<YOUR_AUDIT_LOG_TABLE>;
Count events by type in the last 24 hours
SQL SELECT "event_name", COUNT(*) AS event_count FROM <YOUR_DATABASE>.<YOUR_SCHEMA>.<YOUR_AUDIT_LOG_TABLE> WHERE "event_time" / 1000000 >= DATE_PART(EPOCH_SECOND, DATEADD(HOUR, -24, CURRENT_TIMESTAMP())) GROUP BY "event_name" ORDER BY event_count DESC;
Count events by user in the last 7 days
SQL SELECT "actor_email", COUNT(*) AS event_count FROM <YOUR_DATABASE>.<YOUR_SCHEMA>.<YOUR_AUDIT_LOG_TABLE> WHERE "event_time" / 1000000 >= DATE_PART(EPOCH_SECOND, DATEADD(DAY, -7, CURRENT_TIMESTAMP())) GROUP BY "actor_email" ORDER BY event_count DESC;
Pretty event timeline
SQL
SELECT
TO_TIMESTAMP_NTZ("event_time" / 1000000) AS event_ts, "event_name",
"actor_name",
"actor_email",
"event_data":workflowId::string AS workflow_id,
"event_data":workflowName::string AS workflow_name
FROM <YOUR_DATABASE>.<YOUR_SCHEMA>.<YOUR_AUDIT_LOG_TABLE> ORDER BY "event_time" DESC
LIMIT 50;
Resources
Explore articles, courses, and support options to get the most out of Ironclad.
Snowflake
Academy
- No relevant resources at this time.