# Deploy *webhook listeners.*

Write your handler. Deploy it. Get a secure HTTPS URL.

We handle the URL, HTTPS, logs, and request history.

## Perfect for.

- **GitHub events.** Trigger builds, run tests, or deploy on every push.
- **Payment events.** Handle Stripe, PayPal, and payment webhooks instantly.
- **Third party integrations.** Connect with Slack, Twilio, SendGrid, whatever you use.
- **Event driven workflows.** React to any external event in real time.

## How it works.

1. **Write your handler.** Create an HTTP endpoint that processes webhook payloads.
2. **Deploy to Tokay.** `git push tokay`. We give you a secure HTTPS URL automatically.
3. **Configure the webhook.** Paste your Tokay URL into GitHub, Stripe, or your favorite service.
4. **Receive events.** Webhooks hit your endpoint. Every request shows up in the dashboard.

## Just write your handler.

Focus on the events. We handle HTTPS, uptime, and request history.

**Node.js webhook**

```javascript
const express = require('express');
const app = express();
const port = process.env.PORT || 3000;
const secret = process.env.WEBHOOK_SECRET;

app.use(express.json());

app.post('/webhook', (req, res) => {
  if (!secret || req.get('x-webhook-secret') !== secret) {
    return res.sendStatus(401);
  }

  console.log('event received', req.body.type);
  res.sendStatus(204);
});

app.listen(port);
```

**Python webhook**

```python
import os
from flask import Flask, request

app = Flask(__name__)

@app.post('/webhook')
def webhook():
    secret = os.getenv('WEBHOOK_SECRET')
    if not secret or request.headers.get('X-Webhook-Secret') != secret:
        return 'Unauthorized', 401

    event = (request.get_json(silent=True) or {}).get('type')
    print('event received', event)
    return '', 204

if __name__ == '__main__':
    port = int(os.getenv('PORT', '5000'))
    app.run(host='0.0.0.0', port=port)
```

**Go webhook**

```go
package main

import (
    "log"
    "net/http"
    "os"
)

func webhook(w http.ResponseWriter, r *http.Request) {
    secret := os.Getenv("WEBHOOK_SECRET")
    if secret == "" || r.Header.Get("X-Webhook-Secret") != secret {
        http.Error(w, "unauthorized", http.StatusUnauthorized)
        return
    }

    log.Println("event received")
    w.WriteHeader(http.StatusNoContent)
}

func main() {
    port := os.Getenv("PORT")
    if port == "" {
        port = "8080"
    }

    http.HandleFunc("/webhook", webhook)
    log.Fatal(http.ListenAndServe(":"+port, nil))
}
```

Deploy this and you get a URL like `https://your-app.tokay.app/webhook`. Paste it into the webhook config and you're live.

## Security tips.

- **Verify the sender.** Most providers include a signature or shared secret. Check it before processing payloads.
- **Store secrets safely.** Keep webhook secrets in the dashboard, not in your code. We inject them at runtime.

## What we handle for you.

- **Automatic HTTPS.** Every webhook URL is HTTPS by default. Certificates are automatic and always renewed.
- **Request history.** See every webhook request in the dashboard, including the detected source. Debug from one place.
- **Zero-config deploys.** No nginx, no load balancers, no reverse proxies. Push your code and get a URL.

- [Read the webhooks doc for request history, testing, and replay](/docs/webhooks)
- [Handle a real payment flow with the Stripe webhook guide](stripe-webhook-endpoint.md)
