Agent skill

Green Dot Webhooks Skill

Receive and authenticate Green Dot Embedded Finance (BaaS) webhooks. Use when setting up a Green Dot partner webhook endpoint, validating the OAuth client_credentials Bearer token (scope post:webhook), handling the optional undocumented x-gd-signature header, echoing the x-GD-RequestId header, returning the responseDetails acknowledgement, or handling eventType events like transaction, accountUpdated, achTransfer, cardUpdate, billPayTransfer, directDepositSwitch, and provisioning.

Install this skill

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


Green Dot Embedded Finance (Banking-as-a-Service) does not use the Standard Webhooks spec or a single HMAC signature. It uses push authentication: Green Dot authenticates itself to your partner-hosted endpoint. The primary model is an OAuth 2.0 client_credentials Bearer token (scope post:webhook) sent on every delivery, with a Certificate (mTLS) variant as an alternative.

When to Use This Skill

  • How do I receive Green Dot Embedded Finance / BaaS webhooks?
  • How do I authenticate the Green Dot OAuth Bearer token on my endpoint?
  • What is the x-gd-signature header and can I verify it?
  • How do I echo the x-GD-RequestId header and return responseDetails?
  • How do I handle transaction, accountUpdated, or achTransfer events?
  • Why does Green Dot keep retrying my webhook endpoint?

Verification (core)

Authenticate the delivery by validating the OAuth client_credentials Bearer token and requiring the post:webhook scope. This is the real gate. Always parse JSON after authentication passes.

const jwt = require('jsonwebtoken');

// Authenticate: validate the OAuth client_credentials Bearer token + scope.
// In production validate against your authorization server (JWKS / RS256 or
// token introspection). HS256 with a shared program secret is shown here.
function verifyToken(authHeader) {
  const token = String(authHeader || '').replace(/^Bearer\s+/i, '').trim();
  const claims = jwt.verify(token, process.env.GREENDOT_WEBHOOK_TOKEN_SECRET);
  const scopes = String(claims.scope || claims.scp || '').split(/[\s,]+/);
  if (!scopes.includes('post:webhook')) throw new Error('missing post:webhook scope');
  return claims;
}

If you use the Certificate (mTLS) variant instead of OAuth, the token check is replaced by client-certificate validation at your TLS terminator / reverse proxy — there is no application-level token to check.

About x-gd-signature: a delivery may carry an x-gd-signature header, but Green Dot's public docs do not document its algorithm, encoding, or the canonical payload it covers. This skill therefore does not implement a signature check — a guessed HMAC would give false confidence in an unverified payload. If you need payload-level verification, obtain the exact specification (and signing key) from your Green Dot representative before implementing any check. Authenticity comes from the OAuth Bearer token (and/or mTLS). See TODO.md.

Green Dot also sends an API-Key header (your program's own static key, echoed back) on every delivery — it is not a signature, so don't treat it as proof of authenticity beyond weak defense-in-depth on top of the Bearer token.

Then echo the x-GD-RequestId header back and respond 200/201 with a responseDetails body, otherwise Green Dot treats the delivery as failed:

{ "responseDetails": [{ "code": 0, "subCode": 0, "description": "<x-GD-RequestId>" }] }

For complete handlers with token verification, event dispatch, the responseDetails acknowledgement, and tests, see:

Common Event Types

The event name is the eventType field in the JSON body:

eventTypeTriggered when
transactionA card or account transaction posts
accountUpdatedAccount details or status change
achTransferAn ACH transfer changes state
cardUpdateA card is issued, activated, or its status changes
billPayTransferA bill pay transfer changes state
directDepositSwitchA direct-deposit switch progresses
provisioningAccount / card provisioning progresses

Green Dot also emits statement-ready, interest-paid, NSF/failed-transfer, NOC, eWallet, paper-check, P2P, ATM PIN, and adjustment events. The exact set is program-specific — confirm the enabled eventType values with your Green Dot representative.

Environment Variables

# Secret used to validate the OAuth client_credentials Bearer token (HS256).
# Shared with whoever issues Green Dot's token for your program.
GREENDOT_WEBHOOK_TOKEN_SECRET=your_token_signing_secret

# Required OAuth scope on the token (default: post:webhook).
GREENDOT_WEBHOOK_SCOPE=post:webhook

The x-gd-signature header is not verified by this skill (its algorithm is undocumented — see TODO.md), so there is no signing-key environment variable.

Setup Notes

  • Endpoints are registered by your Green Dot representative — there is no self-serve dashboard. You provide the callback URL, the OAuth details, and the event types to enable.
  • Retries must be explicitly enabled per-partner. When on, Green Dot retries on 5xx, timeouts, DNS/connection/SSL failures (and 401/403 once the root cause is fixed), hourly for up to 24 hours.
  • There is no official SDK — all verification is manual.

Local Development

# Start tunnel (no account needed)
npx hookdeck-cli listen 3000 greendot --path /webhooks/greendot

Reference Materials


Repository

hookdeck/webhook-skills

v0.1.0 · MIT · Updated Aug 5, 2026

View on GitHub →