All Collections
Hosting
Webhook Integrations
Webhook Integrations

Send the contents of your project to a specified endpoint. Add the content to your CMS or distribute it to a network

Diego Muralles avatar
Written by Diego Muralles
Updated over a week ago

Webhooks can be used to automatically publish the website when you have finished building your Vev project. We can trigger a webhook, which is essentially an HTTP POST request containing the relevant data needed to publish your Vev project. This webhook is sent to a webhook receiver, which could be another application or service that is responsible for handling the publishing process. The webhook receiver would then process the webhook data, which could include the HTML, CSS, and JavaScript files needed to publish the website. The receiver would then use this data to publish the website to your desired location, such as a web server or a content delivery network (CDN).

Once the webhook is set up, the publishing process can be automated, reducing the time and effort required to publish the website manually.

Our webhook integration is straightforward and requires the user's service to respond with a 2xx code; any other response codes will be considered an error. The requests have a 20-second timeout.

βž• Adding a Webhook trigger to your account

  • In the dashboard, click the User tab on the bottom left corner

  • Select Hosting

  • Click on Add domain

  • Enter your domain or sub-domain (e.g www.mywebsite.com)

  • Select Advanced hosting option

  • Choose Webhook trigger from the list

  • Within Access options, toggle if you want to share your domain across your team. It'll be off by default making it only available for you

  • Click on Add domain

βš™οΈ Setting up a Webhook trigger

You'll need to supply a number of parameters to properly connect your Webhook trigger, some of them are optional depending on how your server is set up.

Have a look at the chart below to understand how each parameter works.

Parameter

Required

Description

Webhook URL

Yes

The address where Vev will send the contents when you publish from Vev. If you do not have a server/endpoint available, you can use a tunneling service such as Ngrok to send contents to your local computer.

Page content to send in addition to body

No

Send full page: Check off if you want Vev to generate the full page (<html /> and all). Without this setting on, only the HTML to render the content will be sent.

Send plugin settings: Add the generated data from the Hosting Plugins of your project and attach them as a JSON attribute.

Ping

No

Check off to grant Vev permission to send pings

Unpublish

No

Check off to grant Vev permission to unpublish the content

Adding a Web Path

You can add a Path to your domain at the core level, which means it will be used as a base path in all projects to which the domain is added. Follow the steps below to learn how to do it.

  • In the dashboard, click the User tab on the bottom left corner

  • Select Hosting

  • Select your domain

  • Enter your path in the Web path field

Payload settings (closed beta)

If you encounter publishing issues regarding payload too large, then Content as links might be the right solution for you. Selecting the Content as links option will send a list of HTML files, instead of having the code included in the payload's pages field. This requires the files to be downloaded from the receiving server which requires some more code, but it also allows for much larger projects and smaller payload sizes. URLs to the files required are placed in the field htmlFiles in the form of an array of strings, and items in pages will no longer have the page field.

Please contact our support team, if you want to use this feature.

Signature

The token is set by you and can be anything; it is used to verify that the content is sent from Vev. To see or generate a Secret for your webhook, go to the Hosting overview and click on Generate token. This string of characters is used in the Webhook server code.

When publishing to a Webhook all requests from Vev is signed with a header X-Vev-Signature for clients to verify that Vev is the actual sender. In order to verify the signature from the request, you need the secret set by you in Vev and a crypto library to create HMAC digests.

X-Vev-Signature value consists of an algorithm to generate a hash and the signature itself, e.g 'sha512=super-long-hashed-value'. For now, we only support sha512 as an algorithm to create a signature. If you use the payload and secret with sha512, you get the same value as the signature.

Endpoint security

It is used to communicate with users' endpoints in the correct way. We support non-secured endpoints, basic, and token-based. OpenID Connect (OIDC) is not supported yet.

Tip: Go to our roadmap and submit your request if you'd like OpenID endpoints to be supported.

Adding a Favicon

Follow the steps below to learn how to add a Favicon to your domain.

  • In the dashboard, click the User tab on the top right corner

  • Select Hosting

  • Select your domain

  • Scroll down to the Favicon section

  • Drag and drop your file or click to upload it from your computer

πŸ“š Publishing to a Webhook trigger

Once your Webhook trigger has been properly set you'll need to add it to your project so that you can publish to it. Read the steps below to learn how to do it.

  • Open the project you want to publish

  • Click the Publish button on the top right corner

  • Select Add publish destination from the publish dialog

  • Choose your domain from the dropdown list

  • Add a path to your domain or leave it blank if you want to publish to its root (the path will only be added at a project level)

  • Hit Add publish destination

  • Open the publish dialog

  • Hit Publish project

Events

All requests are sent as type events, every event contains meta information for the event, and every event has a payload. We currently support two types of events: Ping and Publish. Ping is used for testing the webhook integration with your backend. Publish event contains all necessary HTML, CSS, and JavaScript to display the project.

WebhookRequest

export interface WebhookRequest {
id: string;
hosting: string;
event: WebhookEvent;
payload: Json;
}


PublishWebhookPayload

export interface PublishWebhookPayload {
projectId: string;
version: number;
dir: string;
pages: WebhookPage[];
workspace?: IWorkspace;
team?: FSTeam;
css: ExternalFile[];
js: ExternalFile[];
other: ExternalFile[];
pluginsData?: any;
}

PingPayload

interface PingPayload {
message: string;
html: string;
css: ExternalFile[];
js: ExternalFile[];
}


PublishPayload

interface PublishPayload {
projectId: string;
version: number;
dir: string;
pages: WebhookPage[];
workspace?: IWorkspace;
team?: FSTeam;
css: ExternalFile[];
js: ExternalFile[];
other: ExternalFile[];
pluginsData?: any;
}

interface WebhookPage {
html: string;
key: string;
title: string;
path: string;
cover?: string;
image?: { thumb: string; location: string };
index?: boolean;
settings?: any;
}

interface ExternalFile {
url: string;
contentType?: string;
cacheControl?: string;
}

πŸš€ Examples

Vev JSON request

Download an example of the JSON which is sent from Vev here.

Implementation Examples

These examples are for NodeJS and PHP, but you can use any language you like (.NET, Ruby) as long as you can run a web server that can receive a POST request and parse it as JSON.

NodeJS

  • Create a folder called vev-webhook-server

  • Create the file index.js as per below

  • Run npm install express body-parser crypto

  • Run node index.js

Note: NodeJS (server-side JavaScript, requires NodeJS & Node Package Manager to run).

index.js (server code):

/**
* Vev Examples - Webhook Server
*
* A NodeJS + Express example server for receiving
* PUBLISH events from Vev securely.
*
* [Read more here](https://help.vev.design/hosting/custom/webhook)
*/
const express = require("express");
const fs = require("fs");
const crypto = require("crypto");
const bodyParser = require("body-parser");
const path = require("path");

// This should not be stored in plain text

const VEV_SECRET = "...";
const VEV_IP = "34.72.55.20";

const app = express();
// Add this to get IP information (no required, just an additional layer of security)
app.set("trust proxy", true);

// Since the large full websites can be sent over the web
const LargeJSONBodyParser = bodyParser.json({
limit: "150mb"
});
app.use(express.static(path.join(__dirname, "..", "public")));

// Creating a post route to handle the the webhook call
// Adding json body parser midleware
// Also Adding vev signature validator (you find the implementation at the bottom)
app.post(
"/webhook-receiver",
LargeJSONBodyParser,
VevSignatureMiddleware,
async (req, res) => {
const { payload, event } = req.body;
console.log("event: ", event);
console.log("payload: ", payload);
if (event === "PUBLISH") {
await Promise.all(payload.pages.map(StoreVevPage));
} else if (event === "PING") {
console.log("Webhook test ping recieved from: " + req.ip);
}

res.send({ message: "I received your webhook!!" });
}
);

async function StoreVevPage(page) {
// Putting the files in the public dir
// if page is index page then set the path to be public/index.html
let pagePath = path.join("./public", page.index ? "index.html" : page.path);
// Page path can have file extntion
if (!path.extname(pagePath)) pagePath = path.join(pagePath, "index.html");

// Creating the dir to put the file in
// Remeber that in vev the page path can be nested (example dir1/dir2/index.html)
// So important to create dir recursive
const dir = path.dirname(pagePath);
try {
fs.promises.access(dir);
} catch (e) {
await fs.promises.mkdir(dir, { recursive: true });
}

//Writing the file to the page path
await fs.promises.writeFile(pagePath, page.html);
}

function VevSignatureMiddleware(req, res, next) {
const signatureHeader = req.get("X-Vev-Signature");
if (!signatureHeader) return next("Missing signature");

// For extra secuirty you can validate that the IP is the vev IP address
if (req.ips.indexOf(VEV_IP) === -1)
return next("Invlid IP request (not from vev)");

const [algorithm, signature] = signatureHeader.split("=");
if (!algorithm || !signature) return next("Invalid signature");

// Validating signature of request
// Done by comparing the signature with HMAC (hash-based message authentication code)) using the secret key for hasing
const hmac = crypto.createHmac(algorithm, VEV_SECRET);
const generatedSignature = hmac
.update(JSON.stringify(req.body))
.digest("hex");

// Comparing the request signature with the generated
// This will validate that the sender knows the secret
// and that the content was not tampered with and that the
if (generatedSignature !== signature) {
console.error("Webhook trigered with invalid signature");
return next("Invliad signature");
}

next();
}

app.listen(8001, () => console.log(`Example app listening on port 8001!`));

Note: You will still need to set the Webhook URL in your webhook settings to a URL that points to where you are running your webhook server.

PHP

<?php

/**
* Vev Examples - Webhook endpoint
*
* PHP example script for receiving PUBLISH events from Vev securely.
*
* [Read more here](https://help.vev.design/hosting/custom/webhook)
*/

const VEV_SECRET = '85806154-43ae-4427-8f27-479af8239b2e';

if (!isset($_SERVER['X-Vev-Signature'])) return 'Missing signature';

$signatureHeader = $_SERVER['X-Vev-Signature'];

if (!$signatureHeader) return 'Missing signature';

list($algorithm, $signature) = explode('=', $signatureHeader);

if (!$algorithm || !$signature) return 'Invalid signature';

if (!in_array($algorithm, hash_hmac_algos())) return 'Invalid algorithm';

$requestBody = json_decode(file_get_contents('php://input'));

// Validating signature of request
// Done by comparing the signature with HMAC (hash-based message authentication code)) using the secret key for hasing
$generatedSignature = hash_hmac($algorithm, json_encode($requestBody), VEV_SECRET);

// Comparing the request signature with the generated
// This will validate that the sender knows the secret and that the content was not tampered with
if ($generatedSignature !== $signature) return 'Invalid signature';

$ip = $_SERVER['REMOTE_ADDR'];

if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
if (!empty($_SERVER['HTTP_CLIENT_IP'])) $ip = $_SERVER['HTTP_CLIENT_IP'];

function storeVevPage ($page) {

// Putting the files in the public dir
// if page is index page then set the path to be public/index.html
$pagePath = './public/' . ($page['index'] ? 'index.html' : $page['path']);

if (!str_contains($pagePath, '.')) $pagePath .= '/index.html';

$directory = substr($pagePath, 0, strrpos($pagePath, '/') - 1);

if (!file_exists($directory)) mkdir($directory, 0777, true);

// Writing the file to the page path
file_put_contents($pagePath, $page['html']);

}

$payload = $requestBody['payload'];
$event = $requestBody['event'];

echo $payload;
echo $event;

switch ($event) {

case 'PUBLISH':

foreach ($payload['pages'] as $page) {

storeVevPage($page);

}

break;

case 'PING':

echo "Webhook test ping received from {$ip}";

break;

}

echo 'I received your webhook';

πŸ”™ Unpublishing a project

To unpublish your project from your Webhook:

  • In the dashboard, click the User tab on the bottom left corner

  • Click "Hosting"

  • Select your domain

  • Click the "Projects" tab on the left bar

  • If you have published projects, click the three dots next to the project you want to unpublish and click "Unpublish".

The project will no longer appear on the list.

Did this answer your question?