Why teams build this
Security and GRC leaders are increasingly asked to show that the trust center is doing commercial work. The question from leadership is usually some version of “which accounts are reviewing us, and what are they reading?” Answering it in a spreadsheet gets stale within a week. Answering it in Hex lets you join trust center activity to the CRM and pipeline data you already have there, so document engagement sits next to deal stage and account owner.What one row looks like
The dataset this guide produces has one row per interaction:
No cell is ever null. Rows carry
unattributed and an empty email when a visit has not been tied to a company or a person, and two boolean columns let you filter to the level of attribution you want. See how much of the activity is identified.
event_type currently returns one of DOCUMENT_VIEWED, DOCUMENT_DOWNLOADED, or LINK_DOCUMENT_OPENED. Treat it as a passthrough column so new activity types flow into your dashboard without a code change.
Before you start
Bind the key to a service account. A scheduled Hex refresh then keeps working when the person who created the key changes roles or leaves the company. See service accounts.
Step 1: Create an API key
1
Create the service account first
Go to Settings → Service accounts and create one named something like
Hex reporting. Set its role to Admin, because the per-document endpoint this guide uses is admin only and the role selector starts on User.Do this before opening API settings. The Owner dropdown on the key dialog lists the service accounts that already exist, so it offers only Yourself until one is there to pick. Full walkthrough: service accounts.2
Open API settings
Go to Settings → API. This page is visible to admins.
3
Create the key
Click Create API key. Give it a Name such as
Hex trust center reporting, set Owner to your service account, and pick an Expiration.4
Copy it once
The key is shown a single time and starts with
wolfia-api-. Copy it before closing the dialog.Step 2: Store the key as a Hex secret
Open the Variables sidebar in your Hex project. In the Secrets section, click +Add, choose Create project secret, and name itWOLFIA_API_KEY.
Hex stores secrets in an encrypted vault and renders them as [SECRET VALUE] if anything tries to display them, so the key stays out of your notebook source and out of any published app. A secret is referenced in a Python cell by its bare name, which is why the sample below uses WOLFIA_API_KEY directly with no lookup around it.
Step 3: Build the interactions dataframe
This cell walks every document in your trust center, pulls the interaction history for each one, and returns a tidy dataframe. It requests one calendar month at a time. A single request returns at most 100 activity events, so a busy document in a wide date window would silently lose its older events. Monthly windows keep each request comfortably under that ceiling.How much of the activity is identified
A trust center is a public page. Someone can read your SOC 2 before they ever tell you who they are, so every interaction falls into one of three levels of identification. The sample code labels all three so your dashboard has no blank cells, and it sets two boolean columns so you can filter deliberately.
Two things follow from how this works, and both are useful:
- An email never appears without a domain. Individual identification comes from an access request, and an access request always belongs to an account. So
account_domainis always at least as complete asuser_email, and it is the right column to group by for account level reporting. - Unidentified visits are real engagement. Dropping them understates how much your trust center is being read, which is usually the opposite of the point. Keep them in the totals and filter only when you specifically need account level attribution:
Choosing your join keys
Usedocument_title as the document key. Documents are grouped by title, so re-uploading a refreshed SOC 2 keeps its history in one place. The document_id you pass to the API points at the current representative version of a title and can change after a re-upload, which makes it a poor primary key for a saved dashboard.
One caveat: grouping is by exact title, so SOC 2 Type 2 Report and Acme SOC 2 Type II Report count as two documents. If you have renamed a document over time, map the variants to one canonical name in your dashboard.
Use account_domain as the customer key. It is the stable identifier for a visiting company and joins cleanly to the website or domain field on your CRM accounts.
Keeping the dataset fresh
Re-pull a trailing window on every run
Re-pull a trailing window on every run
A visitor can browse before they finish verifying their identity. When they do verify, their earlier activity is attributed to them and to their account, so a row that was anonymous an hour ago can gain an
account_domain and a user_email.Set each scheduled run to re-pull the last 30 days and let event_id de-duplicate. Rows that gained attribution get corrected, and nothing is double counted.De-duplicate on event_id
De-duplicate on event_id
event_id is unique and stable per interaction. It is the right key for an upsert into a warehouse table and for drop_duplicates in a notebook.Backfill once, then run incrementally
Backfill once, then run incrementally
Run the full historical range once and write it to a table. After that, schedule a run over a trailing window only. A full backfill across many months and many documents makes a lot of requests, so keep it to a one-off.
Removed documents stay reportable
Removed documents stay reportable
Documents you have taken down still appear in the document list, flagged with
is_deleted. Their historical interactions remain available so a trend line does not develop a hole when you retire a report.Limits to design around
Troubleshooting
403 Forbidden
403 Forbidden
The per-document endpoint requires the Admin role. If the key is bound to a service account, raise that service account to Admin or issue the key under an admin owner.
429 Too Many Requests
429 Too Many Requests
You have exceeded the hourly or burst rate limit. Increase
REQUEST_PAUSE_SECONDS, and split a large backfill across several runs.The dataframe is empty
The dataframe is empty
Check the date window first.
start_date and end_date are microseconds, and passing seconds or milliseconds produces a window that matches nothing. Then confirm your trust center was live during the period you asked for.Many rows have an empty user_email
Many rows have an empty user_email
This is expected on a public trust center rather than a fault in the extract. A visitor can read a public document without identifying themselves, and a row gains an email only once someone verifies their identity, so re-pulling a trailing window fills in more of them over time.Group by
account_domain for account level reporting, or filter on has_known_person when you specifically need named individuals. The three levels of identification are explained in how much of the activity is identified.Rows show account_domain as unattributed
Rows show account_domain as unattributed
Same cause, one level up. The visit was not tied to any company, usually because the reader arrived on a public page and never requested access. The sample code labels these
unattributed so nothing is silently dropped from your totals. Filter on has_known_account to exclude them from account level views.Adapting this to other tools
Nothing here is specific to Hex beyond where the credential lives. The same requests work from any scheduler or notebook that can hold a secret and make HTTPS calls, including Databricks, Snowflake external functions, Airflow, and dbt Python models. Replace the bareWOLFIA_API_KEY reference with your platform’s own secret lookup, which on most of them is os.environ["WOLFIA_API_KEY"], and keep the rest of the code as it is.
Next steps
Trust analytics API
The full endpoint reference, including revenue attribution, active accounts, and access requests.
API overview
Authentication, rate limits, status codes, and every endpoint area.
Service accounts
Bind API keys to a non-human identity so scheduled jobs survive team changes.
Trust Center
Set up documents, branding, and access controls on the trust center itself.

