Skip to main content

Overview

Webhooks allow you to receive real-time notifications when your zip creation jobs complete. Instead of polling the status endpoint, ZipKit will automatically send an HTTP POST request to your specified URL when a zip finishes processing.

Why Use Webhooks?

  • Real-time notifications - Get instant updates when zips complete
  • Reduce API calls - No need to poll the status endpoint repeatedly
  • Better user experience - Respond immediately to completed zips
  • Reliable delivery - Webhooks are sent as soon as the job completes

Configuring Webhooks

Webhooks are configured through the ZipKit dashboard for your project.

Step-by-Step Setup

1

Navigate to Webhooks

  1. Log in to your ZipKit dashboard
  2. Select your project
  3. Go to the “Webhooks” section
  4. Click “Create Webhook” or “New Webhook”
2

Configure the webhook

URL (Required) Enter the full HTTPS URL where you want to receive webhook notifications. Example: https://api.myapp.com/webhooks/zipkitDescription (Optional) Add a description to help identify this webhook’s purpose. Example: “Production webhook for zip completion events”
3

Save and test

  1. Click “Save” or “Create”
  2. Your webhook will now receive notifications for all zip jobs in this project
HTTPS Required: For security, webhook URLs must use HTTPS (not HTTP). This ensures webhook payloads are encrypted in transit.

Webhook Payload

When a zip completes (successfully or with failure), ZipKit sends a POST request to your webhook URL with a Stripe-style event payload:

Event Structure

{
  "id": "evt_a1b2c3d4e5f6g7h8i9j0k1l2",
  "object": "event",
  "type": "zip.completed",
  "created": 1701234567,
  "data": {
    "object": {
      "id": "zip_abc123",
      "object": "zip",
      "status": "succeeded",
      "key": "reports/monthly-2025-11.zip",
      "bucket": {
        "service": "s3",
        "name": "my-destination-bucket"
      },
      "metadata": {
        "user_id": "user_123",
        "order_id": "order_456"
      },
      "checksum": "d8e8fca2dc0f896fd7cb4cb0031ba249",
      "size_bytes": 12345,
      "content_type": "application/zip"
    }
  }
}

Failed Zip

When a zip fails, the payload includes an error object:
{
  "id": "evt_def456ghi789jkl012mno345",
  "object": "event",
  "type": "zip.completed",
  "created": 1701234567,
  "data": {
    "object": {
      "id": "zip_def456",
      "object": "zip",
      "status": "failed",
      "key": "reports/monthly-2025-11.zip",
      "bucket": {
        "service": "s3",
        "name": "my-destination-bucket"
      },
      "metadata": {
        "user_id": "user_123",
        "order_id": "order_456"
      }
    },
    "error": {
      "type": "bucket_error",
      "code": "upload_failed",
      "message": "Failed to upload zip to bucket"
    }
  }
}

Event Fields

id
string
Unique event identifier with evt_ prefix.
object
string
Always "event".
type
string
The event type. Currently always "zip.completed".
created
integer
Unix timestamp when the event was created.
data.object
object
The zip object that triggered the event.
data.error
object
Error details when the zip fails. Only present on failed zips. Contains type, code, and message fields.

Zip Object Fields

data.object.id
string
Unique zip identifier with zip_ prefix.
data.object.object
string
Always "zip".
data.object.status
string
The final status of the zip job.Possible values:
  • "succeeded" - zip was created and uploaded successfully
  • "failed" - zip creation or upload failed
data.object.key
string
The storage key (filename/path) of the zip archive in the bucket.
data.object.bucket
object
Information about the destination bucket.
data.object.bucket.service
string
The cloud storage service ("s3" or "r2").
data.object.bucket.name
string
The name of the bucket where the zip was stored (or attempted to be stored).
data.object.metadata
object
The custom metadata object that was provided when the zip was created. Contains any custom data you attached to track user IDs, order IDs, or other contextual information. Returns an empty object {} if no metadata was provided.
data.object.checksum
string
The ETag/checksum of the uploaded zip file. Only present for successful uploads.
data.object.size_bytes
integer
The size of the zip file in bytes. Only present for successful uploads.
data.object.content_type
string
The MIME type of the zip file. Typically "application/zip". Only present for successful uploads.

Implementing a Webhook Endpoint

Your webhook endpoint should:
  1. Accept POST requests with JSON payloads
  2. Respond quickly (within 5-10 seconds)
  3. Return a 2xx status code to acknowledge receipt
  4. Verify the webhook source (optional but recommended)

Best Practices

Your endpoint should respond within 5-10 seconds. If you need to perform long-running tasks, process them asynchronously in a background job.
@app.route('/webhooks/zipkit', methods=['POST'])
def zipkit_webhook():
    payload = request.json

    # Queue for background processing
    celery.send_task('process_zip', args=[payload])

    # Respond immediately
    return jsonify({'received': True}), 200
Since webhooks don’t currently include authentication headers, verify requests by:
  • Restricting webhook endpoint access to ZipKit’s IP addresses
  • Using HTTPS to ensure requests aren’t intercepted
  • Validating the webhook payload structure and data types
  • Implementing request signing (future feature)
Make your webhook endpoint idempotent. ZipKit may retry sending webhooks if your endpoint fails to respond. Use the event id or data.object.id to deduplicate events.
# Check if we've already processed this event
event_id = payload['id']
if already_processed(event_id):
    return jsonify({'received': True}), 200

# Process the webhook
process_webhook(payload)
mark_as_processed(event_id)
Log all webhook receipts for debugging and auditing purposes.
import logging

zip_data = payload['data']['object']
logger.info(f"Received {payload['type']} for zip {zip_data['id']}: {zip_data['status']}")
  • Return 200 or 204 for successful receipt
  • Return 401 for authentication failures
  • Return 500 only for actual server errors
ZipKit considers 2xx responses as successful delivery.
Ensure your webhook endpoint uses HTTPS with a valid SSL certificate. Self-signed certificates may cause delivery failures.

Testing Webhooks

Local Development

For testing webhooks locally, use tools like: Example with ngrok:
# Start your local server
python app.py  # Running on port 5000

# In another terminal, create a tunnel
ngrok http 5000

# Use the ngrok HTTPS URL in ZipKit
# https://abc123.ngrok.io/webhooks/zipkit

Production Testing

Create a test webhook that logs all received payloads to verify everything works correctly before going live.

Managing Webhooks

Viewing Webhooks

All configured webhooks are listed in your project’s “Webhooks” section, showing:
  • Webhook URL
  • Description
  • Creation date
Security: The Authorization header is never displayed after creation.

Editing Webhooks

To update a webhook:
  1. Go to “Webhooks” section
  2. Click “Edit” next to the webhook
  3. Update the URL, description, or authorization header
  4. Save changes

Deleting Webhooks

To remove a webhook:
  1. Go to “Webhooks” section
  2. Click “Delete” next to the webhook
  3. Confirm deletion
Once deleted, you’ll stop receiving notifications for zip completions. Any in-flight webhooks may still be delivered.

Troubleshooting

Not receiving webhooks

Possible causes:
  • Webhook URL is incorrect or unreachable
  • Your server is blocking requests from ZipKit
  • SSL certificate issues (expired or self-signed)
  • Firewall blocking incoming requests
Solutions:
  • Verify the webhook URL is correct and accessible
  • Check server logs for incoming requests
  • Ensure HTTPS is properly configured
  • Test with webhook.site first to verify ZipKit is sending requests

Receiving duplicate webhooks

This can happen if:
  • Your endpoint took too long to respond
  • Your endpoint returned an error status code
  • Network issues caused ZipKit to retry
Solution: Make your webhook handler idempotent using the event id to deduplicate.

Securing webhook endpoints

Best practices:
  • Use HTTPS with valid SSL certificates
  • Restrict access to your webhook endpoint by IP address
  • Validate the structure and content of webhook payloads
  • Log all webhook receipts for monitoring

Security Considerations

Webhook Security: Anyone who knows your webhook URL could potentially send fake webhook requests. Secure your webhook endpoint appropriately.
Best practices:
  • ✅ Use HTTPS to encrypt webhook payloads in transit
  • ✅ Restrict access to your webhook endpoint by IP address
  • ✅ Validate the webhook payload structure and data types
  • ✅ Use unique, hard-to-guess webhook URLs
  • ✅ Log all webhook receipts for monitoring
  • ✅ Implement idempotency to handle duplicate deliveries

Multiple Webhooks

You can configure multiple webhook URLs in a single project for:
  • Different endpoints for different environments
  • Redundancy (send to multiple systems)
  • Different services that need to be notified
All configured webhooks will receive notifications for every zip completion in the project.