← Back to Smokeball Integration

Smokeball Developer Documentation

Technical reference for the CaseHug–Smokeball integration. OAuth flow, API endpoints, data models, and webhooks.

Architecture

The Smokeball integration consists of three library files and six API routes:

lib/integrations/
├── smokeball.ts          # API client, OAuth, types
├── smokeball-sync.ts     # Sync engine (matters, contacts, documents)
└── smokeball-mappings.ts # Case type → matter type mapper

app/api/v1/integrations/smokeball/
├── connect/route.ts      # Initiate OAuth
├── callback/route.ts     # OAuth callback
├── disconnect/route.ts   # Revoke + cleanup
├── sync/route.ts         # Manual sync + history
├── webhooks/route.ts     # Webhook receiver
└── status/route.ts       # Connection status + settings

OAuth 2.0 Flow

Grant Type: Authorization Code (user context) + Client Credentials (server-to-server)

Auth URL: https://auth.smokeball.com/oauth2/authorize

Token URL: https://auth.smokeball.com/oauth2/token

Scopes: openid, profile, matters, contacts, files, tasks, events, invoices, staff

1. User clicks "Connect to Smokeball"
2. CaseHug generates CSRF state, stores in oauth_states table
3. Redirect to Smokeball authorize URL with state + scopes
4. User signs in to Smokeball, clicks Allow
5. Smokeball redirects to /api/v1/integrations/smokeball/callback
6. CaseHug validates state, exchanges code for tokens
7. Tokens stored in firm_integrations (upsert on firm_id + platform)
8. Redirect to dashboard with success message

Environment Variables

VariableDescriptionRequired
SMOKEBALL_CLIENT_IDOAuth client ID from Smokeball Developer Console
SMOKEBALL_CLIENT_SECRETOAuth client secret from Smokeball Developer Console
SMOKEBALL_REDIRECT_URIOAuth callback URL (defaults to {SITE_URL}/api/v1/integrations/smokeball/callback)Optional

⚠️ API access must be requestedfrom the Smokeball partnership team. CaseHug does not have default credentials — each firm's Smokeball connection requires API access to be enabled on Smokeball's side.

API Endpoints

GET/api/v1/integrations/smokeball/connect

Initiates OAuth 2.0 Authorization Code flow. Generates CSRF state token, stores in DB, redirects to Smokeball authorize URL.

Auth: firm_admin role requiredResponse: 302 Redirect to Smokeball OAuth
GET/api/v1/integrations/smokeball/callback

Handles OAuth callback from Smokeball. Validates CSRF state, exchanges code for tokens, stores tokens in firm_integrations table.

Auth: None (callback from Smokeball)Response: 302 Redirect to dashboard/settings/integrations
POST/api/v1/integrations/smokeball/disconnect

Disconnects Smokeball, deletes registered webhooks (best effort), removes tokens from DB.

Auth: firm_admin role requiredResponse: { success: true, platform: "smokeball" }
GET/api/v1/integrations/smokeball/status

Returns connection status, Smokeball user/firm info, sync settings, and last sync event.

Auth: Authenticated userResponse: { connected, configured, smokeball_user, smokeball_firm, settings, last_sync }
PATCH/api/v1/integrations/smokeball/status

Update integration settings (auto_sync_on_approval, auto_sync_on_matter_created, case_type_mappings).

Auth: Authenticated userResponse: { success: true, settings }
POST/api/v1/integrations/smokeball/sync

Sync a matter to Smokeball. Body: { matter_id, action?: "sync_matter" | "pull_matters" }

Auth: Authenticated userResponse: { success, smokeball_matter_id, smokeball_contact_id, documents_uploaded, documents_failed }
GET/api/v1/integrations/smokeball/sync

Get sync history. Query: ?matter_id=xxx&limit=20

Auth: Authenticated userResponse: { logs: [...], total }
POST/api/v1/integrations/smokeball/webhooks

Receives webhook events from Smokeball. Handles challenge verification, HMAC signature validation, and event processing.

Auth: HMAC-SHA256 signatureResponse: { received: true }

Webhook Events

EventDescriptionCaseHug Action
matter.createNew matter created in SmokeballLogged for future import
matter.updateMatter updated (status, name, etc.)Updates linked CaseHug matter status
contact.createNew contact createdLogged for audit trail
contact.updateContact updatedLogged for future sync
file.createFile uploaded to matterLogged
file.updateFile updated/renamedLogged
invoice.createInvoice createdLogged

Database Schema

Migration 023 adds Smokeball-specific columns and tables:

firm_integrations

firm_id, platform='smokeball', access_token, refresh_token, token_expires_at, is_active, settings (JSONB), webhook_secret

One row per firm per platform. Upserted on connect.

matters

smokeball_matter_id (TEXT), smokeball_synced_at (TIMESTAMPTZ)

Added by migration 023. Indexed where not null.

uploads

smokeball_file_id (TEXT), smokeball_synced_at (TIMESTAMPTZ)

Added by migration 023. Indexed where not null.

smokeball_webhook_events

id, firm_id, event_type, resource_type, resource_id, payload (JSONB), processed, processed_at, error_message, created_at

Created by migration 023. RLS enabled.

integration_sync_logs

firm_id, integration_id, matter_id, upload_id, action, status, external_id, details (JSONB), error_message

Shared with all integrations. Used for sync history.

Rate Limiting & Error Handling

Rate limit: CaseHug throttles requests to ~8/sec with a 120ms minimum delay between requests.

429 handling: Automatic retry with exponential backoff. Respects Retry-After header. Max 2 retries.

Token refresh: Tokens are auto-refreshed 5 minutes before expiry. Refresh failures fall back to existing token.

Sync idempotency: All sync operations check for existing IDs before creating. Safe to re-run.

Error logging: All errors logged to integration_sync_logs with timestamps and details.

Need help integrating?

Contact our engineering team for integration support or API questions.

Contact Engineering →