HTTP Webhooks

If you have enabled HTTP Webhooks within the dashboard settings, Zipline will send a POST request to the URL with the file/url information.

Events

upload

This event is triggered when a file is uploaded to Zipline.

HeaderValue
x-zipline-webhooktrue
x-zipline-webhook-typeupload

Example Payload (application/json):

{
  "type": "upload",
  "data": {
    "user": {
      "id": "cm0ahwkkt00025216yi47btrb",
      "username": "administrator",
      "createdAt": "2024-08-26T04:25:45.005Z",
      "updatedAt": "2024-09-17T23:50:24.492Z",
      "role": "SUPERADMIN",
      "view": {},
      "quota": null,
      "sessions": [
        "hKb3nyHqCKE6RsHSX4w2KO3zDvjPrsct",
        "gOARAvpu9hQ7PW6XK6WXoIZ549CKweIf",
        "XAQf80SaJ8hORk5sgtzwGjV5E8qJ8zjY",
        "YEk0lvuTl3RB5dYjFNktf9cqnVJ8OIkv",
        "eSnaw6WVJ5mojRKztpELjvtMpW8nzTZt",
        "SzH6j84CWBIMhbWZyqFANZ10t6iKUUFd",
        "pvlJI8w8miXKDfFvQGrsckv4W4F6sP1N"
      ]
    },
    "file": {
      "createdAt": "2024-09-19T19:14:37.938Z",
      "updatedAt": "2024-09-19T19:14:37.938Z",
      "deletesAt": null,
      "favorite": false,
      "id": "cm19o84j60008rjuy4ufwlw7d",
      "originalName": null,
      "name": "uGILmB.png",
      "size": 124104,
      "type": "image/png",
      "views": 0,
      "maxViews": null,
      "folderId": null,
      "thumbnail": null,
      "tags": []
    },
    "link": {
      "raw": "http://localhost:3000/raw/uGILmB.png",
      "returned": "http://localhost:3000/u/uGILmB.png"
    }
  }
}

shorten

This event is triggered when a URL is shortened.

HeaderValue
x-zipline-webhooktrue
x-zipline-webhook-typeshorten

Example Payload (application/json):

{
  "type": "shorten",
  "data": {
    "user": {
      "id": "cm0ahwkkt00025216yi47btrb",
      "username": "administrator",
      "createdAt": "2024-08-26T04:25:45.005Z",
      "updatedAt": "2024-09-17T23:50:24.492Z",
      "role": "SUPERADMIN",
      "view": {},
      "quota": null,
      "sessions": [
        "hKb3nyHqCKE6RsHSX4w2KO3zDvjPrsct",
        "gOARAvpu9hQ7PW6XK6WXoIZ549CKweIf",
        "XAQf80SaJ8hORk5sgtzwGjV5E8qJ8zjY",
        "YEk0lvuTl3RB5dYjFNktf9cqnVJ8OIkv",
        "eSnaw6WVJ5mojRKztpELjvtMpW8nzTZt",
        "SzH6j84CWBIMhbWZyqFANZ10t6iKUUFd",
        "pvlJI8w8miXKDfFvQGrsckv4W4F6sP1N"
      ]
    },
    "url": {
      "id": "cm19o9at4000arjuyg2n8t7rv",
      "createdAt": "2024-09-19T19:15:32.728Z",
      "updatedAt": "2024-09-19T19:15:32.728Z",
      "code": "AZCYqt",
      "vanity": "google",
      "destination": "https://google.com",
      "views": 0,
      "maxViews": null,
      "userId": "cm0ahwkkt00025216yi47btrb"
    },
    "link": {
      "returned": "http://localhost:3333/go/google"
    }
  }
}

Example Node.js Server

The following code is in TypeScript.

webhook.ts
import { IncomingHttpHeaders, createServer } from 'http';

function receive(
  data: Uint8Array,
  {
    'x-zipline-webhook': webhook, // will always just be "true"
    'x-zipline-webhook-type': type,
  }: IncomingHttpHeaders,
) {
  const str = new TextDecoder().decode(data);
  const parsed = JSON.parse(str);

  // handle data in parsed...
  // if (type === 'upload') handleUpload(parsed);
  // if (type === 'shorten') handleShorten(parsed);

  console.log(`recv(${type}) data: `, parsed);
}

const server = createServer((req, res) => {
  const data = new Uint8Array(Number(req.headers['content-length']));
  let offset = 0;

  req.on('data', (chunk) => {
    data.set(chunk, offset);
    offset += chunk.length;
  });

  req.on('end', () => {
    receive(data, req.headers);
    res.statusCode = 200;
    res.end();
  });

  req.on('error', (err) => {
    console.error(err);
    res.statusCode = 500;
    res.end();
  });
});

server.listen(3001, () => {
  console.log('Server is running on', server.address());
});

Example Python Server

This example uses http.server, but is not recommended to be used in production.

webhook.py
from http.server import HTTPServer, BaseHTTPRequestHandler
import json

class WebhookHandler(BaseHTTPRequestHandler):
  def do_POST(self):
    content_length = int(self.headers.get('Content-Length', 0))
    data = self.rfile.read(content_length)

    webhook = self.headers.get('x-zipline-webhook')  # Should always be "true"
    type = self.headers.get('x-zipline-webhook-type')

    try:
      parsed = json.loads(data.decode('utf-8'))
      print(f"recv({type}) data:", parsed)
      # handle data in parsed...
      # if type == 'upload': handle_upload(parsed)
      # if type == 'shorten': handle_shorten(parsed)
    except json.JSONDecodeError:
      self.send_response(400)
      self.end_headers()
      self.wfile.write(b'Invalid JSON')
      return

    self.send_response(200)
    self.end_headers()


def run(server_class=HTTPServer, handler_class=WebhookHandler, port=3002):
  server_address = ('', port)
  httpd = server_class(server_address, handler_class)
  print(f'Server is running on port {port}')
  httpd.serve_forever()


if __name__ == '__main__':
  run()

Exmaple Go Server

webhook.go
package main

import (
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
)

func receive(data []byte, headers http.Header) {
	// var webhook = headers.Get("x-zipline-webhook") // will always just be "true"
	var type_ = headers.Get("x-zipline-webhook-type")
	var parsed map[string]interface{}
	if err := json.Unmarshal(data, &parsed); err != nil {
		log.Println("Invalid JSON:", err)
		return
	}

	// handle data in parsed...
	// if type_ == "upload" { handleUpload(parsed) }
	// if type_ == "shorten" { handleShorten(parsed) }

	fmt.Printf("recv(%s): %+v\n", type_, parsed)
}

func main() {
	http.HandleFunc("/", func (w http.ResponseWriter, r *http.Request) {
		body, err := io.ReadAll(r.Body)
		if err != nil {
			http.Error(w, "Failed to read request body", http.StatusInternalServerError)
			return
		}
		defer r.Body.Close()

		receive(body, r.Header)
		w.WriteHeader(http.StatusOK)
	})

	port := 3002
	fmt.Printf("Server is running on :%d\n", port)

	if err := http.ListenAndServe(fmt.Sprintf(":%d", port), nil); err != nil {
		log.Fatal("Server failed:", err)
	}
}


Last updated: Jan 31, 2026
Edit this page on GitHub