Skip to main content
Cove sends HTTP POST requests to your configured webhook_url when bureau submission statuses change.

Event types

EventWhen FiredKey Data Fields
submission.pendingMetro 2 file generated, queued for deliverytradeline_id, bureau, submission_date
submission.submittedFile uploaded to bureau via SFTPtradeline_id, bureau, submission_date
submission.acceptedBureau confirmed acceptancetradeline_id, bureau, response_code, response_message
submission.rejectedBureau rejected the recordtradeline_id, bureau, response_code, response_message
tradeline.updatedTradeline status changedtradeline_id, changes

Payload format

{
  "id": "550e8400-e29b-41d4-a716-446655440099",
  "event": "submission.accepted",
  "created_at": "2026-02-06T14:30:00Z",
  "data": {
    "tradeline_id": "660e8400-e29b-41d4-a716-446655440001",
    "bureau": "equifax",
    "submission_date": "2026-02-05",
    "status": "accepted",
    "response_code": "00",
    "response_message": "Record accepted successfully"
  }
}

Headers

Every webhook POST includes these headers:
HeaderValue
Content-Typeapplication/json
X-Cove-Signaturesha256=<HMAC-SHA256 hex digest>
X-Cove-EventEvent type (e.g., submission.accepted)
X-Cove-DeliveryUnique delivery UUID

Signature verification

The X-Cove-Signature header contains an HMAC-SHA256 digest of the raw request body, signed with your webhook_secret.
const crypto = require('crypto');

function verifyWebhook(body, signature, secret) {
  const expected = 'sha256=' + crypto
    .createHmac('sha256', secret)
    .update(body, 'utf8')
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  );
}

// In your webhook handler:
const rawBody = req.body; // raw string, not parsed JSON
const signature = req.headers['x-cove-signature'];
if (!verifyWebhook(rawBody, signature, process.env.WEBHOOK_SECRET)) {
  return res.status(401).send('Invalid signature');
}

Retry behavior

AttemptDelayNotes
1ImmediateFirst delivery attempt
21 minuteAfter first failure
310 minutesAfter second failure
41 hourFinal attempt
  • Each attempt has a 10-second timeout.
  • After all retries are exhausted, the event is marked as failed.
Fallback: Poll GET /submissions to check status if webhooks are missed.

Best practices

  • Return 2xx quickly — process webhook data asynchronously. The 10-second timeout is strict.
  • Handle duplicates — webhooks may be delivered more than once. Use the id field for idempotency.
  • Use GET /submissions for reconciliation — don’t rely solely on webhooks for critical business logic.