Security & Data Flow
How Zoody handles your data, what permissions it needs, and how to evaluate it for your security review.
How data flows through Zoody
Zoody sits between your product and HubSpot. Your engineering team sends usage events to Zoody, and Zoody writes aggregated data into HubSpot properties. Here is the full path:
- 1
Your product sends events
A single POST request from your backend to api.zoody.io/v1/events. Events include an event name, a user email or company domain, and optional properties (e.g., feature name, duration). No SDK installation is required - a curl or fetch call works.
- 2
Zoody validates and stores
Events are validated server-side, deduplicated, and stored in a PostgreSQL database. Invalid events are rejected immediately with specific error messages. Events are never modified or enriched - Zoody stores exactly what you send.
- 3
Zoody matches and aggregates
Based on your mapping configuration, Zoody matches events to HubSpot contacts (by email) or companies (by domain) and computes aggregated values like counts, last-seen dates, or sums.
- 4
Zoody writes to HubSpot
Aggregated values are written to HubSpot contact or company properties via the HubSpot API using OAuth tokens you authorize during setup. Zoody only writes to properties you configure - it never modifies other HubSpot data.
What data Zoody receives
You control exactly what you send. A typical event contains:
| Field | Example | Purpose |
|---|---|---|
| eventName | "feature_used" | Identifies the action |
| "user@acme.com" | Match to HubSpot contact | |
| domain | "acme.com" | Match to HubSpot company |
| properties | { "feature": "reports" } | Optional metadata you define |
| timestamp | ISO 8601 datetime | When the event occurred |
Zoody does not require access to your application database, source code, or internal systems. It receives only the events you explicitly send.
Security details
Authentication
All API requests require a Bearer token (zo_live_...). Keys are created in your dashboard and can be revoked at any time. Each key is validated server-side against your workspace on every request.
Encryption
All data in transit is encrypted via TLS 1.2+. Data at rest is encrypted using AES-256. HubSpot OAuth refresh tokens are stored encrypted and never logged or exposed.
Infrastructure
Zoody runs on Railway (US region) with PostgreSQL and Redis. The infrastructure is isolated per service (API, worker, dashboard) with no shared runtime. Environment variables and secrets are managed through Railway's encrypted secret store.
Data retention
Events are retained for the duration of your subscription. You can delete individual events or all workspace data from the dashboard at any time. Account deletion removes all associated data.
HubSpot permissions
When you connect HubSpot, Zoody requests only the scopes it needs. Here is what each scope is used for:
| Scope | What Zoody does with it |
|---|---|
| crm.objects.contacts.read | Search contacts by email to match incoming events |
| crm.objects.contacts.write | Write aggregated usage data to contact properties |
| crm.objects.companies.read | Search companies by domain to match incoming events |
| crm.objects.companies.write | Write aggregated usage data to company properties |
| crm.objects.owners.read | Look up record owners for mapping context |
| crm.schemas.contacts.read | List available contact properties for mapping configuration |
| crm.schemas.contacts.write | Create custom contact properties for synced data |
| crm.schemas.companies.read | List available company properties for mapping configuration |
| crm.schemas.companies.write | Create custom company properties for synced data |
| crm.lists.read | Read HubSpot lists for audience targeting |
| crm.lists.write | Add contacts to lists based on usage data |
Zoody does not request access to deals, tickets, emails, conversations, or any other HubSpot objects. You can revoke access at any time from HubSpot Settings > Integrations > Connected Apps.
Integration footprint
For security teams evaluating what Zoody requires from your engineering side:
- One outbound HTTPS call from your backend to api.zoody.io. No inbound connections, webhooks, or open ports required.
- No SDK required. A simple POST request with an API key works from any language or environment. The optional TypeScript SDK adds convenience (batching, retries) but is not necessary.
- No database access. Zoody never connects to your database, application servers, or internal network.
- No client-side code. Zoody is a server-to-server integration. Nothing is added to your frontend or user-facing application.
- Fire-and-forget. The API call is non-blocking. If Zoody is unavailable, your product is unaffected - events are simply not recorded until service resumes.
Testing in pre-production
You can fully test Zoody without touching your production HubSpot or production application.
- 1
Create a HubSpot developer test account
Go to app.hubspot.com/signup-hubspot/developers and create a free test account. This gives you a sandbox HubSpot portal with no production data.
- 2
Sign up for Zoody (free plan)
Create a Zoody account at app.zoody.io and connect your test HubSpot portal. The free plan includes 1,000 events per month, enough for evaluation.
- 3
Send test events from staging
Point your staging or pre-prod environment at Zoody using a test API key. Or send events manually with curl to validate the integration before writing any code.
- 4
Configure mappings and verify
Set up a mapping in the Zoody dashboard (e.g., count of "feature_used" events to a HubSpot contact property). Send a few test events and confirm the values appear in your test HubSpot portal.
When you are ready to move to production, swap in your production HubSpot portal and a live API key. The integration code stays the same.
Questions for your security team?
If your team needs additional detail - SOC 2 status, a data processing agreement, or a technical walkthrough - reach out at zoody.io/contact or email security@zoody.io.