Skip to content

Maverick Integration

Maverick Integration

The Maverick integration enables seamless bi-directional synchronization between Pulse and Maverick, a merchant services platform. This integration automatically syncs tickets, categories, and maintains data consistency across both systems.

Overview

What is Maverick?

Maverick is a merchant services platform that manages:

  • Merchant boarding applications
  • Support tickets
  • Document management
  • Merchant account data

Integration Capabilities

The Pulse-Maverick integration provides:

  1. Bi-directional Ticket Sync - Pull tickets from Maverick, push changes back
  2. Status Synchronization - Keep ticket statuses in sync across platforms
  3. Comment Synchronization - Sync responses and internal notes
  4. Category Mapping - Automatically map Maverick categories to Pulse types
  5. Conflict Prevention - Intelligent handling of concurrent modifications
  6. Document Transfer - Sync documents between systems

Configuration

Setting Up the Integration

const response = await fetch("/api/integrations/maverick/config", {
method: "PUT",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${token}`,
},
body: JSON.stringify({
enabled: true,
apiUrl: "https://api.maverick.com",
apiKey: "your-maverick-api-key",
autoSync: true,
syncIntervalMinutes: 15,
syncDirection: "bidirectional", // 'inbound', 'outbound', or 'bidirectional'
defaultAssigneeId: 123, // User to assign imported tickets to
defaultTeamId: 5, // Team to assign imported tickets to
}),
});

Configuration Options

Connection Settings

  • enabled (boolean) - Whether integration is active
  • apiUrl (string) - Maverick API base URL
  • apiKey (string) - Maverick API authentication token

Sync Settings

  • autoSync (boolean) - Enable automatic background synchronization
  • syncIntervalMinutes (number) - How often to sync (default: 15 minutes)
  • syncDirection (string) - Sync direction:
    • inbound - Only pull from Maverick to Pulse
    • outbound - Only push from Pulse to Maverick
    • bidirectional - Sync both directions (default)

Assignment Defaults

  • defaultAssigneeId (number) - User to assign imported tickets to
  • defaultTeamId (number) - Team to assign imported tickets to

Testing the Connection

Before enabling the integration, test the connection:

const response = await fetch('/api/integrations/maverick/config/test', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
body: JSON.stringify({
apiUrl: 'https://api.maverick.com',
apiKey: 'your-maverick-api-key'
})
});
// Returns:
{
"success": true,
"message": "Connection successful",
"version": "1.2.3"
}

Ticket Synchronization

Inbound Sync (Maverick → Pulse)

Pull tickets from Maverick into Pulse:

const response = await fetch('/api/tickets/maverick', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
body: JSON.stringify({
syncAll: false, // If true, sync all tickets; if false, sync only recent
since: '2025-11-01T00:00:00Z', // Optional: only sync tickets modified after this time
limit: 100 // Optional: limit number of tickets to sync
})
});
// Returns:
{
"success": true,
"created": 15,
"updated": 23,
"skipped": 7, // Locally modified tickets
"errors": 2,
"conflicts": 3,
"totalProcessed": 47
}

How Inbound Sync Works

  1. Fetch Tickets - Retrieves tickets from Maverick API
  2. Map Data - Converts Maverick format to Pulse format
  3. Check Conflicts - Identifies locally modified tickets
  4. Upsert - Creates new tickets or updates existing ones
  5. Skip Local Changes - Preserves local modifications to prevent overwriting
  6. Update Sync Timestamp - Records last sync time

Outbound Sync (Pulse → Maverick)

Push changes from Pulse to Maverick automatically when:

  • Ticket status changes
  • Comments are added
  • Priority is modified

Status Synchronization

// Automatically called when ticket is closed in Pulse
await syncTicketStatusToMaverick(ticketId, "closed");
// Automatically called when ticket is reopened in Pulse
await syncTicketStatusToMaverick(ticketId, "open");

Comment Synchronization

// Automatically called when comment is added in Pulse
await syncCommentToMaverick(ticketId, commentId, {
isInternal: false, // False = response, True = internal note
body: "Your ticket has been resolved...",
});

Data Mapping

Status Mapping

Maverick StatusPulse Status
newopen
openin_progress
pendingwaiting_customer
waitingwaiting_customer
resolvedresolved
closedclosed

Priority Mapping

Maverick PriorityPulse Priority
criticalurgent
highhigh
normalmedium
lowlow

Category Mapping

Maverick categories are automatically mapped to Pulse ticket types:

// Maverick categories are fetched and mapped
const response = await fetch('/api/tickets/maverick/categories', {
headers: {
'Authorization': `Bearer ${token}`
}
});
// Returns:
{
"categories": [
{
"id": 1,
"name": "Technical Support",
"maverickCategoryId": "tech-support",
"pulseTicketTypeId": 5
},
{
"id": 2,
"name": "Billing Question",
"maverickCategoryId": "billing",
"pulseTicketTypeId": 3
}
]
}

Categories are auto-created in Pulse if they don’t exist.

Synced Ticket Properties

Tickets imported from Maverick include additional metadata:

External Source Tracking

{
"externalSource": "maverick",
"externalTicketId": "MV-12345", // Original Maverick ticket ID
"externalUrl": "https://maverick.com/tickets/12345", // Link back to Maverick
"lastSyncedFromSource": "2025-11-01T14:30:00Z", // Last inbound sync
"lastSyncedToSource": "2025-11-01T14:35:00Z", // Last outbound sync
"syncStatus": "synced", // or "conflict", "error"
"locallyModified": false // True if modified in Pulse after sync
}

Custom Fields

Maverick-specific data is stored in custom fields:

{
"customFields": {
"maverickTicketId": "12345", // Maverick internal ID
"maverickDbaId": "DBA-789", // Merchant DBA identifier
"maverickCategoryId": "tech-support", // Original category
"notifyMerchant": true, // Whether to notify merchant
"attentionMerchant": false // Requires merchant attention flag
}
}

Conflict Resolution

What Causes Conflicts?

Conflicts occur when a ticket is modified in both systems between syncs:

  1. Ticket updated in Maverick
  2. Same ticket updated in Pulse
  3. Sync attempts to pull Maverick changes
  4. Conflict detected

Conflict Prevention

The integration uses several strategies to prevent conflicts:

Local Modification Flag

When a ticket is modified in Pulse, locallyModified is set to true. During inbound sync, these tickets are skipped to preserve local changes.

// Ticket modified in Pulse
{
"locallyModified": true,
"lastSyncedFromSource": "2025-11-01T14:00:00Z"
}
// During sync, this ticket is skipped
{
"skipped": 1,
"reason": "Locally modified, preventing overwrite"
}

Sync Timestamps

Separate timestamps track inbound vs. outbound syncs:

{
"lastSyncedFromSource": "2025-11-01T14:00:00Z", // Last pulled from Maverick
"lastSyncedToSource": "2025-11-01T14:30:00Z" // Last pushed to Maverick
}

Sync Status

{
"syncStatus": "synced" // or "conflict", "error", "pending"
}

Manual Conflict Resolution

If a conflict occurs, you can manually resolve it:

// Force sync from Maverick (overwrite local changes)
const response = await fetch("/api/tickets/1234/sync/force-inbound", {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
},
});
// Force sync to Maverick (overwrite Maverick changes)
const response = await fetch("/api/tickets/1234/sync/force-outbound", {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
},
});
// Mark conflict as resolved without syncing
const response = await fetch("/api/tickets/1234/sync/mark-resolved", {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
},
});

Viewing Maverick Tickets

List Maverick Tickets in Pulse

const response = await fetch("/api/tickets/maverick", {
headers: {
Authorization: `Bearer ${token}`,
},
});
// Returns Pulse tickets that originated from Maverick

Get Maverick Ticket Details

// Get full details from Maverick API
const response = await fetch("/api/tickets/maverick/MV-12345", {
headers: {
Authorization: `Bearer ${token}`,
},
});
// Returns detailed Maverick ticket data

View Ticket Responses from Maverick

// Get all responses/comments from Maverick
const response = await fetch('/api/tickets/maverick/MV-12345/responses', {
headers: {
'Authorization': `Bearer ${token}`
}
});
// Returns:
{
"responses": [
{
"id": "resp-123",
"body": "We're investigating your issue...",
"isInternal": false,
"createdBy": "agent@company.com",
"createdAt": "2025-11-01T14:15:00Z"
}
]
}

Automatic Synchronization

Background Sync Job

When autoSync: true, the integration runs a background job at the configured interval:

Every 15 minutes:
1. Fetch recent Maverick tickets (modified since last sync)
2. Map and validate data
3. Create/update tickets in Pulse
4. Log sync results
5. Update lastSyncedFromSource timestamp

Sync Job Logs

View sync history:

const response = await fetch('/api/integrations/maverick/sync-history', {
headers: {
'Authorization': `Bearer ${token}`
}
});
// Returns:
{
"history": [
{
"startedAt": "2025-11-01T14:00:00Z",
"completedAt": "2025-11-01T14:02:35Z",
"created": 5,
"updated": 12,
"skipped": 3,
"errors": 0,
"conflicts": 1
}
]
}

Manual Sync

Trigger a manual sync at any time:

const response = await fetch("/api/tickets/maverick/sync", {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
},
});

Document Transfer

Syncing Documents from Maverick

const response = await fetch('/api/tickets/maverick/1234/documents/sync', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`
}
});
// Returns:
{
"success": true,
"documentsSynced": 3,
"documents": [
{
"id": "doc-123",
"filename": "invoice.pdf",
"url": "/api/files/tickets/1234/invoice.pdf"
}
]
}

Uploading Documents to Maverick

const response = await fetch("/api/tickets/1234/documents/push-to-maverick", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${token}`,
},
body: JSON.stringify({
documentId: 456,
}),
});

Merchant Boarding Integration

The integration also supports syncing merchant boarding applications:

Sync Boarding Application

const response = await fetch("/api/applications/sync-from-maverick", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${token}`,
},
body: JSON.stringify({
maverickApplicationId: "app-12345",
}),
});

Webhook Integration

Configure Maverick webhooks to receive real-time updates:

Webhook Endpoint

POST /api/webhooks/maverick/tickets

Webhook Payload

{
"event": "ticket.updated",
"ticketId": "MV-12345",
"timestamp": "2025-11-01T14:30:00Z",
"changes": {
"status": "resolved",
"assignedTo": "agent@maverick.com"
}
}

Setting Up Webhooks in Maverick

  1. Log into Maverick admin panel
  2. Navigate to Settings → Webhooks
  3. Add new webhook:
    • URL: https://your-pulse-domain.com/api/webhooks/maverick/tickets
    • Events: ticket.created, ticket.updated, ticket.comment_added
    • Secret: Generate a webhook secret
  4. Save the webhook configuration

Configure Webhook Secret in Pulse

const response = await fetch("/api/integrations/maverick/config", {
method: "PUT",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${token}`,
},
body: JSON.stringify({
webhookSecret: "your-webhook-secret",
}),
});

Monitoring and Troubleshooting

Sync Statistics

View overall sync health:

const response = await fetch('/api/integrations/maverick/stats', {
headers: {
'Authorization': `Bearer ${token}`
}
});
// Returns:
{
"totalTickets": 1250,
"lastSyncAt": "2025-11-01T14:00:00Z",
"syncStatus": "healthy",
"conflictCount": 3,
"errorCount": 0,
"averageSyncDuration": 125 // seconds
}

Viewing Conflicts

const response = await fetch("/api/tickets?syncStatus=conflict", {
headers: {
Authorization: `Bearer ${token}`,
},
});

Viewing Sync Errors

const response = await fetch('/api/integrations/maverick/errors', {
headers: {
'Authorization': `Bearer ${token}`
}
});
// Returns:
{
"errors": [
{
"ticketId": "MV-12345",
"error": "Invalid status value",
"timestamp": "2025-11-01T14:30:00Z",
"retryCount": 2
}
]
}

Retry Failed Syncs

const response = await fetch("/api/integrations/maverick/retry-errors", {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
},
});

Best Practices

1. Start with Inbound Only

Initially configure syncDirection: 'inbound' to safely test importing Maverick tickets before enabling bi-directional sync.

2. Set Appropriate Sync Interval

  • High-volume systems: 30-60 minutes
  • Medium-volume: 15-30 minutes
  • Low-volume: 5-15 minutes

Shorter intervals increase API load but provide faster synchronization.

3. Monitor Conflicts Regularly

Check for conflicts daily and resolve them promptly to maintain data consistency.

4. Use Webhooks for Real-Time Updates

Configure Maverick webhooks for immediate notification of changes, reducing need for frequent polling.

5. Document Category Mappings

Maintain clear documentation of how Maverick categories map to Pulse ticket types.

6. Test Before Production

Use a staging environment to test the integration thoroughly before deploying to production.

7. Audit Sync Logs

Regularly review sync logs to identify patterns in errors or conflicts.

8. Handle Rate Limits

Maverick API has rate limits (10ms delay between requests). The client automatically handles this, but be aware when syncing large volumes.

Security Considerations

API Key Management

  • Store Maverick API keys securely (encrypted at rest)
  • Rotate API keys regularly (every 90 days recommended)
  • Use separate API keys for staging and production

Data Access

  • Integration requires Permission.readSupport and Permission.writeSupport
  • Limit integration user permissions to only what’s necessary
  • Audit integration access regularly

Webhook Security

  • Always configure webhook secret
  • Verify webhook signatures on incoming requests
  • Use HTTPS endpoints only

Permissions

Maverick integration requires:

  • Permission.readSupport - View tickets
  • Permission.writeSupport - Create/update tickets
  • Permission.manageIntegrations - Configure integration settings

API Endpoints

Configuration

  • GET /api/integrations/maverick/config - Get configuration
  • PUT /api/integrations/maverick/config - Update configuration
  • POST /api/integrations/maverick/config/test - Test connection

Tickets

  • GET /api/tickets/maverick - List Maverick tickets in Pulse
  • POST /api/tickets/maverick - Sync tickets from Maverick
  • GET /api/tickets/maverick/:ticketId - Get Maverick ticket details
  • GET /api/tickets/maverick/:ticketId/responses - Get ticket responses

Synchronization

  • POST /api/tickets/maverick/sync - Trigger manual sync
  • POST /api/tickets/:id/sync/force-inbound - Force inbound sync
  • POST /api/tickets/:id/sync/force-outbound - Force outbound sync
  • POST /api/tickets/:id/sync/mark-resolved - Resolve conflict

Categories

  • GET /api/tickets/maverick/categories - Get category mappings

Monitoring

  • GET /api/integrations/maverick/stats - Get sync statistics
  • GET /api/integrations/maverick/sync-history - View sync history
  • GET /api/integrations/maverick/errors - View sync errors
  • POST /api/integrations/maverick/retry-errors - Retry failed syncs

Webhooks

  • POST /api/webhooks/maverick/tickets - Webhook endpoint for Maverick

Database Schema

Integration Configuration

Stored in integration_settings table:

{
"provider": "maverick",
"config": {
"enabled": true,
"apiUrl": "https://api.maverick.com",
"apiKey": "encrypted-key",
"autoSync": true,
"syncIntervalMinutes": 15,
"syncDirection": "bidirectional",
"webhookSecret": "encrypted-secret"
}
}

Ticket Fields

Maverick-related fields on tickets table:

  • externalSource - “maverick”
  • externalTicketId - Maverick ticket ID
  • externalUrl - Link to Maverick ticket
  • lastSyncedFromSource - Last inbound sync timestamp
  • lastSyncedToSource - Last outbound sync timestamp
  • syncStatus - Current sync status
  • locallyModified - Local modification flag
  • customFields - JSON with Maverick metadata

Limitations

Rate Limiting

  • Maverick API: 10ms delay between requests enforced
  • Bulk operations may take time with large datasets

Data Mapping

  • Some Maverick fields may not have direct Pulse equivalents
  • Custom fields handle unmapped data
  • Complex status workflows may require manual mapping

Real-Time Sync

  • Background sync has configured interval (not instant)
  • Webhooks provide near-real-time updates
  • Some delay expected between systems

Troubleshooting

Tickets not syncing

  1. Check integration enabled - Verify enabled: true
  2. Test connection - Use test endpoint to verify API key
  3. Review sync logs - Check for errors in sync history
  4. Verify permissions - Ensure Maverick API key has proper permissions

Duplicate tickets

  1. Check external ID tracking - Ensure externalTicketId is set correctly
  2. Review upsert logic - Verify tickets are being updated, not created
  3. Audit sync logs - Look for multiple creates for same ticket

Status not syncing correctly

  1. Review status mapping - Verify status values map correctly
  2. Check bidirectional setting - Ensure outbound sync is enabled
  3. Test manually - Try manual status update to test sync

Conflicts persisting

  1. Determine source of truth - Decide which system should win
  2. Force sync - Use force-inbound or force-outbound endpoints
  3. Clear local modified flag - Reset conflict state if needed