Skip to main content

Webhook Overview

Legitmark sends real-time notifications about your service requests through webhooks. This enables immediate updates to your platform when authentication is complete or when issues arise. API Reference: See the webhook events and schemas in this section’s API documentation

Webhook Setup Process

Initial Configuration

  1. Provide webhook URL during partner onboarding
  2. Configure event subscriptions for the notifications you need
  3. Implement webhook handlers on your platform
  4. Verify webhook signatures for security (details provided during setup)

Security Requirements

  • HTTPS endpoint required for webhook delivery
  • Signature verification to authenticate webhook origin
  • Timeout handling for webhook processing (30 second max)
  • Retry logic for failed webhook deliveries

Key Webhook Events

State Change Notifications

Receive updates when authentication is complete or status changes. API Reference: state_change webhook When triggered:
  • Service request moves to “COMPLETE”
  • Authentication result: “APPROVED” or “REJECTED”
  • Status changes during processing
Payload Example:
{
  "event_type": "state_change",
  "timestamp": "2024-03-20T10:15:30Z",
  "sr_uuid": "service-request-uuid",
  "state": {
    "primary": "COMPLETE",
    "supplement": "APPROVED"
  },
  "reference_id": "your-internal-item-id"
}

Media Rejection Notifications

Get notified when images need to be re-uploaded with specific feedback. API Reference: media_rejected webhook When triggered:
  • Images fail quality control
  • Additional images are needed
  • Specific feedback provided for each rejected image
Payload Example:
{
  "event_type": "media_rejected",
  "timestamp": "2024-03-20T10:15:30Z",
  "sr_uuid": "service-request-uuid",
  "state": {
    "primary": "QC",
    "supplement": "REJECTED"
  },
  "sides": [
    {
      "side": "Front",
      "side_uuid": "side-uuid",
      "reason": "BLURRY",
      "reason_description": "The image is not clear enough to authenticate..."
    }
  ],
  "reference_id": "your-internal-item-id"
}

Service Request Invalidation

Receive notifications when a service request cannot be processed. API Reference: invalidate_sr webhook When triggered:
  • Item cannot be authenticated (unsupported brand, etc.)
  • Request is cancelled or expired
  • System-level issues
Payload Example:
{
  "event_type": "invalidate_sr", 
  "timestamp": "2024-03-20T14:30:45Z",
  "sr_uuid": "service-request-uuid",
  "state": {
    "primary": "CANCELLED",
    "supplement": null
  },
  "invalidation_reason": {
    "code": "NOT_SERVICEABLE",
    "description": "This item cannot be authenticated as it belongs to a brand not supported..."
  },
  "reference_id": "your-internal-item-id"
}

Implementation Guide

Webhook Endpoint Setup

// Express.js webhook handler example
app.post('/webhooks/legitmark', express.raw({type: 'application/json'}), (req, res) => {
  const signature = req.headers['x-webhook-signature'];
  const payload = req.body;

  // Verify webhook signature (implementation provided during setup)
  if (!verifyWebhookSignature(payload, signature)) {
    return res.status(401).send('Invalid signature');
  }

  const event = JSON.parse(payload);
  
  try {
    handleWebhookEvent(event);
    res.status(200).send('OK');
  } catch (error) {
    console.error('Webhook processing failed:', error);
    res.status(500).send('Processing failed');
  }
});

Event Handler Implementation

function handleWebhookEvent(event) {
  switch (event.event_type) {
    case 'state_change':
      handleStateChange(event);
      break;
    case 'media_rejected':
      handleMediaRejection(event);
      break;
    case 'invalidate_sr':
      handleServiceRequestInvalidation(event);
      break;
    default:
      console.warn('Unknown webhook event type:', event.event_type);
  }
}

function handleStateChange(event) {
  const { sr_uuid, state, reference_id } = event;
  
  // Update your database with authentication result
  updateItemStatus(reference_id, {
    sr_uuid,
    status: state.primary,
    result: state.supplement,
    updated_at: event.timestamp
  });

  // Notify user of completion
  if (state.primary === 'COMPLETE') {
    notifyUserOfResult(reference_id, state.supplement);
  }
}

function handleMediaRejection(event) {
  const { sr_uuid, sides, reference_id } = event;
  
  // Mark images for re-upload
  sides.forEach(side => {
    markImageForReupload(reference_id, side.side_uuid, {
      reason: side.reason,
      description: side.reason_description
    });
  });

  // Notify user of required image updates
  notifyUserOfImageIssues(reference_id, sides);
}

function handleServiceRequestInvalidation(event) {
  const { sr_uuid, invalidation_reason, reference_id } = event;
  
  // Update item status to cancelled
  updateItemStatus(reference_id, {
    status: 'CANCELLED',
    reason: invalidation_reason.description,
    updated_at: event.timestamp
  });

  // Notify user of cancellation
  notifyUserOfCancellation(reference_id, invalidation_reason);
}

Retry Logic

class WebhookProcessor {
  constructor() {
    this.maxRetries = 3;
    this.retryDelay = 1000; // 1 second
  }

  async processWebhook(event) {
    let attempt = 0;
    
    while (attempt < this.maxRetries) {
      try {
        await this.handleEvent(event);
        return; // Success, exit retry loop
      } catch (error) {
        attempt++;
        console.error(`Webhook processing attempt ${attempt} failed:`, error);
        
        if (attempt < this.maxRetries) {
          await this.sleep(this.retryDelay * attempt); // Exponential backoff
        }
      }
    }
    
    // All retries failed, log for manual intervention
    console.error('Webhook processing failed after all retries:', event);
    this.logFailedWebhook(event);
  }

  sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
  }
}

Testing Webhooks

Webhook Validation

Test webhook processing with sample payloads:
// Test webhook handler with sample data
const testEvent = {
  event_type: 'state_change',
  timestamp: new Date().toISOString(),
  sr_uuid: 'test-sr-uuid',
  state: {
    primary: 'COMPLETE',
    supplement: 'APPROVED'
  },
  reference_id: 'test-item-123'
};

handleWebhookEvent(testEvent);

Monitoring and Debugging

// Webhook monitoring and logging
app.post('/webhooks/legitmark', (req, res) => {
  const startTime = Date.now();
  const eventId = req.headers['x-webhook-id'] || 'unknown';
  
  console.log(`Webhook ${eventId} received at ${new Date().toISOString()}`);
  
  try {
    handleWebhookEvent(JSON.parse(req.body));
    
    const processingTime = Date.now() - startTime;
    console.log(`Webhook ${eventId} processed successfully in ${processingTime}ms`);
    
    res.status(200).send('OK');
  } catch (error) {
    const processingTime = Date.now() - startTime;
    console.error(`Webhook ${eventId} failed after ${processingTime}ms:`, error);
    
    res.status(500).send('Processing failed');
  }
});

Best Practices

Reliability

  • Implement idempotency to handle duplicate webhook deliveries
  • Use database transactions for atomic webhook processing
  • Handle partial failures gracefully
  • Log webhook events for debugging and monitoring

Performance

  • Process webhooks asynchronously to avoid timeouts
  • Batch related operations when possible
  • Use queues for high-volume webhook processing
  • Optimize database queries in webhook handlers

Security

  • Always verify signatures before processing webhooks
  • Use HTTPS endpoints for webhook URLs
  • Implement rate limiting on webhook endpoints
  • Validate webhook payload structure before processing

User Experience

  • Provide immediate feedback when webhooks are processed
  • Handle authentication results with appropriate user notifications
  • Offer re-upload options for rejected images
  • Display clear status updates throughout the process

Error Handling

Common Issues

  • Webhook endpoint timeouts: Ensure processing completes within 30 seconds
  • Invalid signatures: Verify signature calculation implementation
  • Duplicate events: Implement idempotency to handle retries
  • Network failures: Use retry logic with exponential backoff

Troubleshooting

// Webhook debugging helper
function debugWebhook(event, error = null) {
  console.log('Webhook Debug Info:', {
    timestamp: new Date().toISOString(),
    event_type: event.event_type,
    sr_uuid: event.sr_uuid,
    reference_id: event.reference_id,
    error: error ? error.message : null,
    stack: error ? error.stack : null
  });
}

Next Steps

Once webhook implementation is complete:
  1. Test end-to-end authentication flow with webhook notifications
  2. Monitor webhook processing performance and reliability
  3. Implement user notifications based on webhook events
  4. Set up monitoring and alerting for webhook failures