CRM Integrations (Jobber & Housecall Pro)
Deskly ships an OAuth connect scaffold for two field-service CRMs — Jobber and Housecall Pro — as groundwork for eventually letting a bot write appointments directly onto a business's real calendar. Read this page before wiring these into a customer-facing flow: part of this is real, part of it deliberately throws an error.
What's real
- OAuth endpoints — verified against each provider's public developer docs:
- Jobber: authorization-code grant with PKCE,
https://api.getjobber.com/api/oauth/{authorize,token} - Housecall Pro:
https://api.housecallpro.com/oauth/{authorize,token}
- Jobber: authorization-code grant with PKCE,
- The connect/callback flow —
GET /api/crm/[provider]/connectandGET /api/crm/[provider]/callbackimplement a complete, working OAuth round trip: CSRF-safestate, PKCE for Jobber, short-livedhttpOnlycookies, and a token exchange that storesaccess_token/refresh_token/expires_atin thecrm_connectionstable. - The
crm_connectionstable — one row per(bot_id, provider), with no client-facingselectpolicy on the token columns (only adeletepolicy for disconnecting), so tokens never round-trip to the browser.
If you connect a real Jobber or Housecall Pro developer account, the connect flow will genuinely authenticate and store working tokens.
What's stubbed
Appointment creation is not implemented. createAppointment() on both createJobberClient() and createHousecallProClient() throws immediately:
async createAppointment(_input: CreateAppointmentInput) {
throw new Error(
"Jobber createAppointment is not implemented — verify the scheduling " +
"mutation against a real sandbox account first"
);
}
This is deliberate, not an oversight. Jobber's appointment/visit creation is GraphQL-based and Housecall Pro's is REST-based, and neither mutation/endpoint shape was verified against a real sandbox account when this scaffold was written — guessing at the shape would be worse than an explicit, loud failure. The CreateAppointmentInput type itself is documented as "a guess at what any field-service CRM needs," not a confirmed contract.
Before you rely on this in production
- Register a real developer app with Jobber and/or Housecall Pro and get sandbox credentials
- Open GraphiQL (Jobber) or the REST docs (Housecall Pro) against that sandbox and find the actual mutation/endpoint for creating a scheduled visit or job
- Confirm the
X-JOBBER-GRAPHQL-VERSIONheader value against Jobber's current dated API version — the scaffold has a placeholder that is explicitly flagged as unconfirmed - Replace the
throwincreateAppointment()with a real call using the confirmed shape - Update
CreateAppointmentInputif the real API needs different fields
Related
- API Reference for the connect/callback request shapes
- Configuration for the
JOBBER_*/HOUSECALL_PRO_*env vars