Security

How we protect your property data.

YieldOptix is built for independent operators handling small portfolios. This page explains, in plain language, the security commitments that apply to your workspace: encryption, access control, and the audit trail we keep on every capture and scheduled job.

Encryption

At rest. Workspace data — your property inventory, rate inputs, integration credentials, and the captures from the free benchmark flow — is stored in a managed Postgres database with AES-256 encryption applied to storage at rest. The encryption keys are managed by our infrastructure provider; we do not export plaintext snapshots and we do not log row content to any other system.

In transit. Every connection the YieldOptix application makes to that database is terminated over TLS. There is no plaintext hop between the app and the database, no replica shipped over an unencrypted channel, and no analyst or migration job that reads rows over a non-TLS path.

Access control

Per-property row-level scoping. Every authenticated read or write against your workspace is gated by requireAuth() and scoped with a where: { userId: user.id } filter. That means a signed-in operator can only see rows their own userId owns — there is no shared workspace view, no implicit cross-tenant query, and no reporting endpoint that bypasses the row-level check. The pattern is wired by the better-auth module at the framework layer; we do not ship an ad-hoc admin override.

Sub-processors with least privilege. Beyond our own application, the following third parties handle data on our behalf. Each is limited to a single, named purpose — and the same list is mirrored on the data residency page so the two pages reconcile.

Polsia
Hosting and platform infrastructure
Plausible analytics
Privacy-friendly product analytics
Email proxy
Transactional and outbound email delivery
Instantly
Warmup outreach for our deliverability

Audit-log commitments

Every capture is timestamped and attributed. When a benchmark request arrives through the free benchmark form, the resulting row is created with a server-assigned createdAt timestamp and carries the campaign attribution fields — utmSource, utmMedium, utmCampaign, and referrerHost — captured at the moment of submission. The same pattern applies to every YieldOptix capture inside the platform.

Every cron run is observable. Scheduled background work — the post-capture nurture processor is one example — runs against a held-over row and stamps it with contactedAt, nurturedAt, and bookedAt markers as each step in the lifecycle runs. The internal /admin/free-benchmark-leads view surfaces those markers so our team can answer, for any individual capture, when it was created, when it was contacted, and when it converted.

This page reflects our current commitments. We will update it before any change to the encryption posture, the row-level-scoping approach, or the sub-processor list takes effect.