Agent skill

Rocketlane Webhooks Skill

Receive and authenticate Rocketlane customer onboarding webhooks. Use when setting up a Rocketlane webhook endpoint, checking HTTP Basic authentication (username and password), debugging 401s, or handling events such as TASK_CREATED, TASK_UPDATED, PROJECT_CREATED and PHASE_UPDATED.

Install this skill

npx skills add hookdeck/webhook-skills --skill rocketlane-webhooks


Rocketlane (customer onboarding and project delivery) sends a POST with a JSON body to a webhook you define in Settings > Webhooks. A Send webhook action in an automation fires it. Payloads are not signed. The only authentication Rocketlane offers is HTTP Basic auth, which the docs call optional but recommended.

In Hookdeck: choose the Rocketlane source type. Choose Basic authentication and set a username and password on the Rocketlane webhook.

When to Use This Skill

  • How do I receive Rocketlane webhooks?
  • How do I verify a Rocketlane webhook? (Basic auth, there is no signature)
  • Why does my Rocketlane webhook endpoint return 401?
  • How do I handle TASK_CREATED, TASK_UPDATED or PROJECT_CREATED events?
  • Why does Rocketlane show my webhook delivery as failed?

Verification (core)

Rocketlane sends Authorization: Basic base64(username:password) using the credentials you entered on the webhook. Parse it strictly, split on the first colon, and compare the username and the password each in constant time. Evaluate both before deciding:

const crypto = require('crypto');

// Hash both sides: equal-length buffers, so timingSafeEqual never throws.
const safeEqual = (a, b) =>
  crypto.timingSafeEqual(
    crypto.createHash('sha256').update(a).digest(),
    crypto.createHash('sha256').update(b).digest());

function verifyRocketlane(authorization, user = process.env.ROCKETLANE_WEBHOOK_USERNAME,
                          pass = process.env.ROCKETLANE_WEBHOOK_PASSWORD) {
  if (!user || !pass) return false;                       // never accept when unconfigured
  const m = /^basic[ \t]+([A-Za-z0-9+/]+={0,2})$/i.exec((authorization || '').trim());
  if (!m || m[1].length % 4) return false;                // strict base64 only
  const bytes = Buffer.from(m[1], 'base64');
  if (bytes.toString('base64') !== m[1]) return false;    // non-canonical padding/bits
  let decoded;
  try {
    decoded = new TextDecoder('utf-8', { fatal: true }).decode(bytes);
  } catch {
    return false;                                         // not valid UTF-8
  }
  const i = decoded.indexOf(':');                         // first colon
  if (i < 0) return false;
  const userOk = safeEqual(decoded.slice(0, i), user);
  const passOk = safeEqual(decoded.slice(i + 1), pass);   // no short-circuit
  return userOk && passOk;
}

Return 401 when this fails, 400 for a body that isn't a JSON object, and 200 once handled. Express must read the body raw (express.raw({ type: '*/*' })) and parse it only after the check. In Python use base64.b64decode(token, validate=True) and hmac.compare_digest on bytes (a str with non-ASCII characters raises). Full Python and Next.js versions are in references/verification.md.

Know what this does and does not prove. A static shared credential authenticates the sender, not the body, and gives no replay protection (no signature, no timestamp). Use HTTPS only, and rotate the username and password if they leak. Dedupe on eventId.

Credentials must arrive on the first request. The docs don't say whether Rocketlane sends Basic credentials preemptively, and Hookdeck never answers with a 401 plus WWW-Authenticate challenge: it verifies the request as received.

For complete handlers with tests, see examples/express/, examples/nextjs/, examples/fastapi/.

Event Types

The body has eventType and resourceType. These eventType values come from Rocketlane's Event Payload page:

eventTypeFires when
TASK_CREATEDA task is created
TASK_UPDATEDA task changes (adds changeLog with changedFields, from, to)
TASK_DELETEDA task is deleted
PROJECT_CREATED, PROJECT_UPDATED, PROJECT_ARCHIVED, PROJECT_DELETEDProject lifecycle
PHASE_CREATED, PHASE_UPDATED, PHASE_DELETEDPhase lifecycle

The docs' payload-structure snippet prints "TASK_UPDATED." with a stray full stop; the real sample payloads have none, and the examples match the plain strings. Rocketlane lists only TASK as a supported resourceType and says only task triggers are supported for webhooks automations today, so expect task events first.

Delivery Rules

  • Only 200 or 204 count as delivered. Any other status, or no response in 10 seconds, is a failure.
  • Order is not guaranteed to be chronological. The docs say Rocketlane delivers each event exactly once.

Environment Variables

ROCKETLANE_WEBHOOK_USERNAME=rocketlane          # as entered on the Rocketlane webhook
ROCKETLANE_WEBHOOK_PASSWORD=replace-with-a-long-random-password

Local Development

npx hookdeck-cli listen 3000 rocketlane --path /webhooks/rocketlane

No account required. Paste the printed URL as the webhook URL in Rocketlane (HTTPS only).

Resources


Repository

hookdeck/webhook-skills

v0.1.0 · MIT · Updated Nov 6, 2026

View on GitHub →