This page covers integration-side setup for each CRM driver. The platform-level overview (driver interface, encryption, audit posture) lives at Product → CRM; this page is the per-driver how-to.Documentation Index
Fetch the complete documentation index at: https://docs.vorel.ai/llms.txt
Use this file to discover all available pages before exploring further.
Driver compatibility matrix
| Driver | Auth | Refreshable | Read | Write | Delete |
|---|---|---|---|---|---|
| HubSpot | OAuth 2.0 | ✓ (auto-refresh + re-encrypt) | ✓ | ✓ | Soft (archive) |
| Salesforce | OAuth 2.0 | ✓ | ✓ | ✓ | Soft (archive) |
| Zoho | OAuth 2.0 (per-DC) | ✓ | ✓ | ✓ | Soft (archive) |
| Athenahealth | OAuth 2.0 (client_credentials) | ✓ (lazy cache) | ✓ | ✓ | Soft |
| Mindbody | Form (site id + API key) | n/a (long-lived) | ✓ | ✓ | Manual at provider |
| Tekmetric | Form (shop id + API key) | n/a | ✓ | ✓ | Manual at provider |
| Odoo | Form (URL + DB + user + key) | n/a | ✓ | ✓ | Hard (unlink) |
| Custom webhook | HMAC | n/a | Optional | ✓ | Optional |
| OpenTable | partnership-only | — | — | — | — |
custom_webhook driver against a partner-built adapter.
OAuth providers (HubSpot / Salesforce / Zoho / Athenahealth)
OAuth providers connect via a guided flow during the kickoff call:Operator initiates the OAuth flow
From
/admin/tenants/[id]/crm, your Vorel operator clicks Connect HubSpot (or
Salesforce / Zoho / Athenahealth). The provider’s OAuth page opens.You sign in on the provider side
Authenticate on HubSpot.com / Salesforce.com / etc. with an account that has the required
scopes (read + write on the relevant objects — leads, contacts, deals, appointments,
depending on the provider).
Provider redirects with a code
Provider sends back to Vorel’s callback handler with an authorization code. Vorel exchanges
it for an access token + refresh token + per-instance metadata.
Tokens land encrypted
Vorel envelope-encrypts the credential payload (access token + refresh token + instance URL
- scopes) with AES-256-GCM and writes the row into
tenant_credentialswith status'active'.
Refresh handling
Each OAuth driver knows how to handle401 Unauthorized from the provider:
- Detect 401 during a tool call.
- Refresh via the refresh token.
- Retry the original call with the new access token (single retry).
- Re-encrypt + persist the refreshed credential payload back into
tenant_credentials(rotated_at updated, audit-log entry written). - Bubble up if the refresh itself fails (audit-log +
auth_errorto the agent).
Common OAuth failures
Refresh token expired (long-stale tenant)
Refresh token expired (long-stale tenant)
HubSpot refresh tokens expire after 6 months of inactivity. If a tenant’s CRM is dormant
for that long and a tool call eventually fires, refresh fails with
auth_error / refresh_failed. Operator re-runs the OAuth flow; new tokens land.OAuth-grant user revoked at provider
OAuth-grant user revoked at provider
The user who connected may have been deactivated. Symptom is the same as above. Solution:
operator re-runs OAuth with an active user.
Scope mismatch
Scope mismatch
If the OAuth grant didn’t include all the scopes Vorel needs (e.g. tenant accidentally
chose a read-only OAuth profile), the agent’s first write call fails with
auth_error / insufficient_scope. Operator re-runs OAuth with the right scope set.Per-DC routing (Zoho)
Per-DC routing (Zoho)
Zoho has US / EU / IN / CN data centres. The OAuth flow captures which DC the customer is
on; the driver pins all calls to that DC’s endpoints. If the customer migrates DCs (rare),
re-run OAuth.
Form-based providers (Mindbody / Tekmetric / Odoo)
Providers without standard OAuth use form-based credential entry:Collect credentials from the customer
Each provider’s credential set differs:
- Mindbody: Site ID + API key (issued in the Mindbody developer portal).
- Tekmetric: Shop ID + API key (issued from Tekmetric admin).
- Odoo: Instance URL + database + username + API key (or password). The user must have
access to
res.partner+crm.leadmodels.
Operator enters them in the admin form
/admin/tenants/[id]/crm → driver-specific form. Credentials encrypt at rest the same way
OAuth tokens do (AES-256-GCM, env-var master key).Test connection live
Vorel calls the provider’s lightest endpoint to verify. If it fails, the operator
troubleshoots with the customer on the call.
Custom webhook driver
For CRMs without a Vorel-shipped driver, thecustom_webhook driver is the universal adapter:
- Vorel POSTs lead / appointment / customer payloads to your team’s HTTPS endpoint.
- Vorel signs each request with a per-tenant HMAC.
- Your team translates the canonical Vorel shape to the underlying CRM’s native format.
- CRMs without a Vorel-native driver (Pipedrive, Insightly, Microsoft Dynamics, etc.)
- Internal warehouses (push leads into your own database / data lake)
- Multi-fan-out scenarios (write to two CRMs simultaneously — Vorel writes once, your webhook handler fans out)
Build the webhook receiver
Standard HTTPS endpoint accepting POST + JSON. Verify HMAC against the per-tenant secret
Vorel surfaces during connection.
Map the canonical shape to your CRM
Vorel calls the receiver with a uniform shape (
{object, fields, idempotency_key}). Your
handler translates fields into the target CRM’s native call.Per-tenant field mapping
Every driver supports per-tenant field mapping viatenant_crm_field_mappings. Your CRM’s “Mobile
Phone” custom field is not Vorel’s customer.phone; the mapping table translates Vorel slot
names (e.g. lead.budget_max) to your CRM’s field paths (e.g. Salesforce lead.UF_Budget_Max__c,
HubSpot deal.budget_aed).
Configured during the kickoff call. Default mappings ship per-vertical for common slots; tenants
override per-field as needed.
The mapping is write-direction today — Vorel writes named fields into your CRM. Reading
arbitrary CRM custom fields back into Vorel slots is a Phase A2 follow-up.
Right-to-erasure
When a customer requests deletion under PDPL Art. 17 / GDPR Art. 17:- Vorel-side scrub runs via
/api/tenant/forget(operator-gated, dry-run-by-default). - CRM-side scrub calls the driver’s
deleteRecordfor the customer’s CRM-side record. - Drivers without a delete API (Mindbody, Tekmetric) throw
delete_unsupported. The operator gets a flag indicating manual rotation at the provider’s dashboard is required. - Audit log records the divergence so you can demonstrate compliance even when the CRM side requires manual action.
Connection rotation
Rotating credentials per your security policy:- OAuth providers — re-run the OAuth flow. Old refresh token continues to work until the new connection is verified, then operator marks the old row revoked.
- Form-based providers — customer issues a new API key at the provider, sends it to your
operator, operator updates the form. Old credential row is set to
status='revoked'. - Custom webhook — operator regenerates the HMAC secret in the admin form. Customer’s receiver updates to the new secret in the same maintenance window.
audit_log with the actor, the previous credential id,
and the new credential id.
What’s NOT supported today
- Multiple drivers per tenant. One CRM per tenant. Use
custom_webhookfor multi-fan-out. - Reading CRM custom fields back into Vorel slots. Write-direction only today.
- CRM-side webhook → Vorel. Listening for “CRM record updated” events is roadmap.
- Self-service CRM connect by tenant team. Operator-driven only — protects against misconfiguration during a regulated-vertical onboarding.
Related docs
- Product → CRM — driver interface, credential encryption, audit posture
- Quickstart — Step 5 of the kickoff flow
- Verticals — vertical-specific CRM expectations (clinic uses Athenahealth, salon uses Mindbody, auto-service uses Tekmetric)
- Security overview — encryption + audit posture