Integrator Best-Practice Guide
Overview 🔗
This guide is for ticket-system vendors building a deep helpdesk integration with pcvisit (e.g. DocBee, or any partner using the Integrators enum). It focuses on recommendations, responsibilities, and pitfalls — not on repeating API call details.
Use this guide together with:
| Document | Purpose |
|---|---|
| Integration Manual | End-to-end walkthrough with GraphQL examples, URL formats, and webhook payloads |
| API Reference | Complete schema: operations, types, fields, and enums |
Audience: Product owners and engineers at ticket-system / PSA vendors who orchestrate onboarding, sessions, webhooks, and device matching on behalf of MSP customers.
Not in scope here: pcvisit backend internals, BPL bounded-context design, or pcvisit webapp UX implementation.
Mental Model 🔗
Closed loop 🔗
pcvisit acts as the process engine for remote support: sessions run in pcvisit, results are recorded in pcvisit work history, and session completion is pushed to your webhook. Your system closes the loop by attaching duration, participants, and comments to the correct ticket and device.
flowchart LR
subgraph integrator [Your ticket system]
Onboard[Onboard MSP]
Ticket[Ticket and device DB]
WebhookEP[Webhook endpoint]
end
subgraph pcvisit [pcvisit]
API[GraphQL API]
Session[Remote session]
WH[Webhook delivery]
end
Onboard -->|activate token register webhook| API
API -->|asset sync thirdPartyIds| Ticket
Ticket -->|SSO URL ticket_ref| Session
Session -->|SessionCompleted| WH
WH --> WebhookEP
WebhookEP --> Ticket
Responsibility split 🔗
| Area | Your responsibility | pcvisit responsibility |
|---|---|---|
| Onboarding UX | Pre-check account, provision or link company, store token securely | Create account/company, issue integrator token, send lifecycle e-mails |
| Team membership | Explicitly add technicians before SSO (no auto-join) | Enforce team limits, notify owner on add/remove |
| Session start | Request JWT, build session URL with ticket_ref (and optional JWE) |
Authenticate technician, create session, persist externalContext |
| Session results | Verify HMAC, parse payload, idempotent processing, user-friendly 4xx on business errors | Deliver webhooks with retries; never require polling |
| Device matching | Map thirdPartyIds / computerId to your records |
Collect and expose IDs on assets and in webhooks |
| Errors in your UI | Display comment_for_user verbatim; branch on error |
Provide stable ErrorIDs and localized user text |
| Integration teardown | Call CaDeleteIntegration or detect invalid token and prompt re-link |
Invalidate token, cascade-delete webhooks |
Recommended Integration Sequence 🔗
Follow these phases in order for a minimal viable integration. Step-by-step API examples live in the Integration Manual — Integrator Integration.
| Phase | Goal | Manual section |
|---|---|---|
| 1. Setup | Provision or link company, activate integration, register webhook, initial asset sync | Step 1, Step 2, Step 7 |
| 2. Session start | Onboard technician, issue SSO JWT, open session URL from ticket | Step 3, Step 4, Step 6 |
| 3. Ticket assignment | Receive SessionCompleted, match ticket/device, book time |
Step 8 |
| 4. Teardown | Detach integration when MSP disconnects | Step 9 |
Pilot recommendation: Implement Phase 1 + outbound session with ticket_ref + SessionCompleted webhook before optional features (JWE credentials, live asset subscription, inbound-only sessions).
Best Practices by Topic 🔗
Onboarding and provisioning 🔗
- Always pre-check with
SiFindUserByMailbefore creating a company — avoids duplicate accounts and drives the correct branch (new vs. existing customer). See Manual — Pre-Check. - Prefer API-only onboarding — there is no web handshake,
return_url, or redirect flow. Your UI owns the entire journey. - Treat
CaCreateIntegrationas idempotent in intent — one active integration per integrator + company; store the returnedCreatedIntegration.tokenin your secrets store (never in client-side code or logs). - Register the webhook immediately after activation (
CaRegisterIntegrationWebhook). Without it, session results have nowhere to go. - For existing accounts, resolve eligible companies via
FindCompanyTeam+CaRetrievePublicCompanyData; only owner/admin roles may bind the integration. - Optional
tenantUrlonCreateIntegrationInput: use when MSPs configure integration from the pcvisit webapp (inbound path); not required for outbound-only onboarding.
Token and JWT handling 🔗
- Two token layers: partner-wide credentials for provisioning vs. per-company integrator token (
CreatedIntegration.token) for day-to-day operations. Scope API calls accordingly. - SSO JWTs are short-lived — request via
SiRetrieveSignedJwtimmediately before opening the session URL; do not cache them for reuse across tickets. - Detect revoked integrations: if the integrator token fails authentication (e.g. on
SiRetrieveSignedJwtor asset sync), treat it as integration detached — pcvisit does not push an active callback when the admin removes the integration in the pcvisit UI. Prompt the MSP to re-link. See Manual — Step 9.
Team membership (no auto-join) 🔗
- Never assume a technician is already in the pcvisit team. Call
InviteToCompanyTeamOnBehalfOfIntegratoronce before their first session. - Handle
TeamUserLimitReachedby surfacingFailure.comment_for_userto the technician and routing upgrade actions to the company owner. - Removal via
SiRemoveFromCompanyTeamtriggers owner notification — set expectations in your admin UI.
SSO and impersonation 🔗
- Pass
targetUserEmailto issue a JWT for that technician (impersonation). Without it, the JWT is for the integrator identity only. - If SSO fails with
SiSignedJwtTargetNotTeammember, add the technician first — do not retry SSO in a loop. - Request
requestEncryptionKey: trueonly when you will pass JWE credentials in the same flow — RSA key generation is expensive and unnecessary otherwise.
JWE credential handover 🔗
- Use JWE only for known devices (
/computer/{id}URLs). Ad-hoc sessions have no fixed target at URL build time. - Never put credentials in clear text in URLs or GraphQL. Encrypt with the JWK from
SiRetrieveSignedJwt(RSA-OAEP+A256GCM). Details: Manual — Step 5. - Do not call
SiDecryptAuthTokenfrom your backend in production flows — the pcvisit webapp consumesauth_tokenonce. Your job is to build the JWE, not to decrypt it.
Webhooks 🔗
- Mandatory: Verify
X-Pcvisit-Signature=HMAC-SHA256(signingSecret, raw_body)on every request. Reject unsigned or invalid payloads. - Idempotency: De-duplicate on
data.taskId, notdeliveryId— retries get a newdeliveryIdbut the same task. - Response semantics:
- HTTP 2xx — accepted; pcvisit stops retrying for that attempt.
- HTTP 4xx — no retry; return a clear JSON
{ "message": "..." }for display in pcvisit admin UI. - HTTP 5xx / timeout — pcvisit retries with backoff; your handler must stay idempotent.
- Do not poll session history to replace webhooks — pcvisit owns delivery and recovery.
- Pilot scope: Subscribe to
SessionCompletedonly;SessionStartedandSessionParticipantChangedare reserved for later phases.
Full payload and headers: Manual — Step 8.
Device matching 🔗
- Initial sync:
FindCurrentAssetswithbaseDNdepthsubfrom root (seeBaseDN). - Ongoing sync: Prefer
AmFindAssetssubscription for online/offline and ID updates; fall back to periodic full query if WebSocket infrastructure is unavailable. - Matching priority: Compare
ThirdPartyIdsfields your product already stores (e.g.ninjaOneDeviceId,teamViewerId,dattoAgentId); usesiteIdfor same-network clustering; usecustomIdsfor vendor-specific fallbacks. - Availability: Not every ID is present on every device immediately — agent collectors roll out over time. Design matching to tolerate partial
thirdPartyIdsand enrich on later syncs/webhooks. - Tree, not flat list: Assets include
FolderandComputernodes — use GraphQL inline fragments; folder semantics are MSP-defined (customer, site, department).
External session context 🔗
- Pass
ExternalSessionContextwhen creating sessions via API, orticket_refon the session-start URL for browser flows. - Conventions: Set
integratorIdconsistently; useticketIdfor your ticket key; optionalexternalDeviceReffor your device primary key;metadatafor non-standard tags (keep keys stable). - Inbound sessions (started in pcvisit without ticket): rely on webhook
thirdPartyIds+computerIdfor post-hoc ticket/device assignment.
Error handling 🔗
- Always handle the
Failureunion branch on mutations and queries. - Show
comment_for_userin your UI — do not parse or rewrite it; do not expose rawerrorcodes to end users. - Branch logic on
error(ErrorIDs) for retries, re-link flows, and owner vs. technician routing. - Integrator-relevant codes (see Manual — Error Handling):
SiSignedJwtTargetNotTeammember,SiSignedJwtLimitExceeded,TeamUserLimitReached, plusCanceledSubscription/FeatureNotLicensedwhere applicable.
Resilience and data loss 🔗
- Session data remains in pcvisit work history even if webhook delivery fails — pcvisit retries and runs internal recovery (~24h). Recommend MSPs keep work-history licensing as a safety net.
- Your webhook endpoint must be highly available — use idempotent handlers and monitor 4xx rates (they are not retried).
- Asset sync gaps: If sync fails due to invalid token, pause sync and surface re-link — do not silently drop device mappings.
User communication (pass-through) 🔗
pcvisit sends lifecycle e-mails and provides webapp touchpoints (onboarding, trial limits, integration removed). Your responsibilities:
- Display
comment_for_userfrom API failures directly in ticket/session UI. - On integrator-token auth failure, guide admin to re-link integration.
- Link to pcvisit-hosted informational pages where provided — do not duplicate long-form pcvisit legal/product copy in your product.
Rollout Recommendations 🔗
- Sandbox first — use a dedicated stage GraphQL endpoint and test full loop: provision → webhook → SSO URL → complete session → receive webhook.
- MVP feature set:
SiFindUserByMail,FirstTimeCustomerPlaceOrderOnBehalfOfIntegratoror link path,CaCreateIntegration,CaRegisterIntegrationWebhook,InviteToCompanyTeamOnBehalfOfIntegrator,SiRetrieveSignedJwt, session URL withticket_ref,FindCurrentAssets,SessionCompletedhandler. - Phase 2 enhancements: JWE credentials,
AmFindAssetslive sync, inbound session matching,CaDeleteIntegrationadmin action. - Security review checklist: Token storage, webhook HMAC, TLS-only callback URL, no credential logging, JWE only on known devices.
Quick Reference Map 🔗
| Task | Integration Manual | API Reference |
|---|---|---|
| Check if user exists | Pre-Check | SiFindUserByMail |
| Provision new company | Zero-Touch Provisioning | FirstTimeCustomerPlaceOrderOnBehalfOfIntegrator |
| Activate integration | Step 1 — CaCreateIntegration | CaCreateIntegration |
| Register webhook | Step 2 | CaRegisterIntegrationWebhook |
| Add technician | Step 3 | InviteToCompanyTeamOnBehalfOfIntegrator |
| SSO JWT | Step 4 | SiRetrieveSignedJwt |
| JWE credentials | Step 5 | SiDecryptAuthToken (pcvisit webapp) |
| Session URL | Opening a Session via Link | ExternalSessionContext |
| Asset sync | Step 7 | FindCurrentAssets, AmFindAssets |
| Webhook handling | Step 8 | WebhookType, WebhookEventType |
| Teardown | Step 9 | CaDeleteIntegration |
| Authentication | Authentication | — |
| Error codes | Error Handling | ErrorIDs, Failure |
DocBee as Reference Implementation 🔗
Throughout the Integration Manual, DocBee is used as the concrete integratorId example. The same patterns apply to any vendor entry in Integrators once enabled for your partner credentials.
When comparing against internal specs, treat the published Manual and API Reference as the contract for implementation; they are aligned with the current GraphQL schema in public_api.schema.json.