LogoFreestyle

Git Triggers & Webhooks

Automate workflows with Git repository event triggers.

Git Triggers & Webhooks

Git triggers allow you to automate actions when events occur in your repositories, such as pushes to specific branches.

Creating a Trigger

Create a webhook trigger for pushes:

sandboxes
  .createGitTrigger({
    repoId: "repo-id",
    trigger: {
      event: "push",
      branch: ["main"], // Optional: filter by branch
      fileGlob: ["*.js"], // Optional: filter by file patterns
    },
    action: {
      type: "webhook",
      url: "https://your-webhook-url.com",
    },
  })
  .then((result) => {
    console.log(`Trigger created: ${result.triggerId}`);
  });

Webhook Payload

The webhook receives the following payload:

interface GitTriggerPayload {
  repoId: string;
  branch: string; // The branch that was updated
  commit: string; // The SHA of the commit
}

Webhook Signing

Webhooks include a signature in the x-freestyle-signature header for verifying request authenticity. The signature is a JWT (EdDSA) containing a body_sha256 field with the SHA256 hash of the webhook payload.

The public key for verification is available at https://git.freestyle.sh/.well-known/jwks.json.

To verify a webhook:

import crypto from 'crypto';
import { createRemoteJWKSet, jwtVerify } from 'jose';

const JWKS = createRemoteJWKSet(new URL('https://git.freestyle.sh/.well-known/jwks.json'));

async function verifyWebhook(request) {
  const signature = request.headers['x-freestyle-signature'];
  const bodyText = await request.text(); // Get raw body text

  // Verify JWT signature
  const { payload } = await jwtVerify(signature, JWKS, {
    algorithms: ['EdDSA'],
  });

  // Verify payload hash
  const payloadHash = crypto
    .createHash('sha256')
    .update(bodyText)
    .digest('hex');

  if (payload.body_sha256 !== payloadHash) {
    throw new Error('Payload verification failed');
  }

  // Parse body after verification
  const body = JSON.parse(bodyText);
  return { payload, body };
}

Listing Triggers

sandboxes
  .listGitTriggers({
    repoId: "repo-id",
  })
  .then((triggers) => {
    console.log(triggers);
  });

Deleting Triggers

sandboxes
  .deleteGitTrigger({
    repoId: "repo-id",
    triggerId: "trigger-id",
  })
  .then(() => {
    console.log("Trigger deleted");
  });

Local Development

For local development, use a tool like Tailscale to create a secure tunnel to your localhost.

Install Tailscale following the quickstart guide, then expose your local server:

# Replace 3000 with your server's port
tailscale funnel 3000

The output provides a public URL:

Available on the internet:

https://<device name>.<tailnet id/name>.ts.net/
|-- proxy http://127.0.0.1:3000

Press Ctrl+C to exit.

Use this URL as the webhook URL in your trigger configuration.

Freestyle AI

Documentation assistant

Experimental: AI responses may not always be accurate—please verify important details with the official documentation.

How can I help?

Ask me about Freestyle while you browse the docs.