Abound has comprehensive webhook support ensuring your system can stay in sync with activity across our entire 1099 automation platform.

Webhooks fire by sending a POST request to the URL you register after a subscribed event occurs. For added rigidity, webhooks will fire up to 3 times if your webhook URL returns a 4xx or 5xx server code.

Webhook events fire regardless of where the event originates. For example, this means a TIN_VERIFICATION_CREATED webhook could fire as a result of any of the following actions:

  • CSV data upload from within the Abound Dashboard
  • End-user submitting information in a Drop-In Component
  • A tin verification request directly to the Abound API

Registering a webhook

To register a webhook url and subscribe to specific events go to the Webhook page in the Abound Dashboard.

You will be able to give your webhook a nickname and control if its enabled or disabled.

Register as many webhook URLs as you need.


Webhook payloads

The body of each webhook POST call will have the following format:

{
  "id": "webhookLogId_sample4RMH0Ly5DQ",
  "webhookId": "webhookId_samplexGCArf0Tcv",
  "timestamp": "2023-01-01T00:00:00.000Z",
  "event": "W_9_CREATED",
  "resourceId": "documentId_sampleVppNzzIbQT",
  "resourceUrl":"https://sandbox-api.withabound.com/v4/documents/w-9/documentId_sampleVppNzzIbQT"
}

Validating webhooks

Included in every webhook POST call is the Abound-Signature header which contains a SHA-256 HMAC hash that can be used to validate the data has originated from Abound.

Below are examples on to use your webhook's validationKey to sign and validate the payload of the webhook. You can find your webhook's unique validationKey in the Abound Dashboard on the Webhook page.

const {
  createHmac
} = await import('crypto');

// Header containing webhook signature
const sigHeader = event.headers['Abound-Signature'];

// Raw body of received request
const rawBody = event.body;

const hmac = createHmac('sha256', 'YOUR_WEBHOOKS_VALIDATION_KEY');
hmac.update(event.body);
const sigGenerated = hmac.digest('hex');

// Returns true if match
return sigGenerated === sigHeader
import hmac
import hashlib

## Header containing webhook signature
sig_header = request.headers.get("Abound-Signature")
##  Raw body of received request
raw_body = request.get_data(parse_form_data=True)

digest = hmac.new(
  key="YOUR_APP_SECRET".encode("utf-8"),
  msg=raw_body.encode(),
  digestmod=hashlib.sha256,
).hexdigest()

## Returns true if match
return digest == sig_header
package main

import (
    "crypto/hmac"
    "crypto/sha256"
    "encoding/hex"
    "fmt"
)

func main() {
	// Header containing webhook signature
  sig_header:= r.Header.Get("Abound-Signature")
  
	// Raw body of received request
  raw_body := r.Body
  
	hmacVal := hmac.New(sha256.New,[]byte("YOUR_API_KEY"))
	hmacVal.Write([]byte(raw_body))
	sigGenerated := hex.EncodeToString(hmacVal.Sum(nil))

  // Returns true if match
  fmt.Println( hmac.Equal([]byte(sigGenerated), []byte(sig_header)))

}
require 'openssl'

## Header containing webhook signature
sig_header = request.headers.get("Abound-Signature")
##  Raw body of received request
raw_body = request.body

hmac = OpenSSL::HMAC.hexdigest("SHA256", 'YOUR_API_KEY', raw_body)

## Returns true if match
return hmac == sig_header

List of webhook events

Webhook events are API-resource specific. Here is a complete list of the webhook events we offer: