Skip to main content
The most critical pattern for reliable webhook handling is separating acknowledgment from processing.

Decouple Receipt from Processing

Return 200 immediately, process asynchronously. This is the foundation of a reliable webhook integration.
1

Receive the webhook

Your endpoint receives the POST request from Smartcar
2

Persist immediately

Write the raw payload to a queue, database, or object storage
3

Return 200

Acknowledge receipt with a 200 status code (within 15 seconds)
4

Process asynchronously

A background worker processes the persisted payload

Why This Matters

  • Prevents timeouts from slow business logic
  • Allows retry of processing without requesting redelivery
  • Enables processing updates without losing historical events
  • Survives outages in downstream systems

Implementation Examples

const express = require('express');
const AWS = require('aws-sdk');

const app = express();
const sqs = new AWS.SQS();

app.post('/webhooks/smartcar', async (req, res) => {
  try {
    // 1. Get the raw payload
    const payload = req.body;
    
    // 2. Queue for processing
    await sqs.sendMessage({
      QueueUrl: process.env.WEBHOOK_QUEUE_URL,
      MessageBody: JSON.stringify(payload)
    }).promise();
    
    // 3. Return immediately
    res.status(200).json({ status: 'received' });
  } catch (error) {
    console.error('Failed to queue webhook:', error);
    res.status(500).json({ error: 'Internal error' });
  }
});

// Separate worker processes the queue
async function processWebhook(payload) {
  const { eventType } = payload;
  
  if (eventType === 'VEHICLE_STATE') {
    await updateVehicleState(payload);
  } else if (eventType === 'VEHICLE_ERROR') {
    await handleVehicleError(payload);
  }
}
Don’t do this: If you perform heavy processing before returning a response, your endpoint may timeout and Smartcar will retry, creating duplicate processing work.
Bad Example
@app.post("/webhooks/smartcar")
def webhook_handler():
    payload = request.get_json()
    
    # DON'T DO THIS: These operations might take too long
    update_database(payload)
    call_external_api(payload)
    send_notifications(payload)
    
    # Might timeout before reaching this line
    return {"status": "received"}, 200

Production-Ready Pattern

For a complete serverless implementation, see the Webhook Receiver Recipe, which provides:
  • API Gateway for HTTPS endpoint
  • Lambda function for webhook receipt
  • SQS queue for async processing
  • Dead letter queue for failed messages
  • CloudWatch monitoring and alerts

Next Steps