Skip to content

Webhooks

FSCO can push events to your backend instead of making you poll our API. You can subscribe to specific events and we’ll POST a JSON payload to your server seconds after it happens.

  1. Go to Dashboard → Developers → Webhooks
  2. Click New Webhook
  3. Enter your destination URL
  4. Pick events you want to subscribe to
  5. Copy your Signing Secret

ℹ️ Webhooks are orginsation-scoped. We recommend using our staging environment to test your webhook before using them in production. Contact us if you need to use a different environment.

Every webhook sent by FSCO follows a consistent structure, regardless of the originating service:

{
"id": "85a94d40-370a-49a8-b328-383477a4a710", // Unique identifier for the event
"type": "listing.created", // The type of event that occurred
"created": "2025-05-05T05:33:21.456Z", // Timestamp of when the event occurred
"data": {
"object": {
//Even payload here
}
}
}

We send this as the raw request body with Content-Type: application/json.

Every request has a X-Signature header:

X-Signature: hex-encoded HMAC-SHA256 // The signature of the event

You can verify the signature using the Signing Secret you copied when you created the webhook.

Below is a sample implementation in TypeScript / Express.js.

Verify the signature
import * as crypto from 'crypto';
/**
* Verifies the FSCO webhook signature.
* @param rawBody Raw JSON string (not parsed!)
* @param headerSignature Value from "X-Signature" header
* @param secret Your webhook's signing secret
*/
export function verifyFscoSignature(
rawBody: string,
headerSignature: string,
secret: string,
): boolean {
const expected = crypto
.createHmac('sha256', secret)
.update(rawBody)
.digest('hex');
try {
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(headerSignature),
);
} catch {
return false; // Always return false on mismatch or malformed signature
}
}
Usage
import { verifyFscoSignature } from './verifyFscoSignature';
app.post('/webhook', (req, res) => {
const rawBody = (req as any).rawBody;
const signature = req.get('X-Signature') || '';
const secret = process.env.FSCO_WEBHOOK_SECRET!;
const isValid = verifyFscoSignature(rawBody, signature, secret);
if (!isValid) {
return res.status(400).send('Invalid signature');
}
const event = req.body;
// Process event safely
console.log('✅ Valid event received: ${event.type}');
res.status(200).send('OK');
});

If your endpoint is temporarily unreachable or responds with a non-2xx HTTP code, FSCO will automatically retry delivery with exponential backoff.

FSCO retries failed webhook deliveries up to 5 times using exponential backoff starting at 1 second. Each attempt uses an HTTP POST request with Content-Type: application/json, and every payload is signed using HMAC SHA256 via the X-Signature header for verification. Requests time out after 10 seconds if no response is received.

We mark each attempt in the dashboard and expose detailed logs including response code, message, and retry count.

  • No response (timeout or DNS failure)
  • Response is not a 2xx status (e.g. 400, 500)
  • Response takes longer than 10 seconds

Below is a list of all supported webhook events you can subscribe to. Each event includes a unique name and a brief description of what it indicates.

Event NameDescription
wallet.createdWallet created
webhook.createdWebhook created
webhook.updatedWebhook updated
webhook.secret.rolledWebhook secret rolled
webhook.testedWebhook tested
hcs.topic.createdHCS topic created
hcs.message.addedHCS message added to topic
ai.typeSelectedAI Document Type Selected
ai.processedAI Prompt Answered
ai.promptTestedAI Document Prompt Test Processed
listing.createdListing created
listing.state.changedListing state changed
listing.purchase.initiatedListing purchase initiated
listing.purchase.progressedListing purchase progressed
listing.purchase.completedListing purchase completed
listing.purchase.failedListing purchase failed
listing.boughtListing bought
listing.soldListing sold
marketplace.createdMarketplace created
asset.mintedAsset minted
asset.burnedAsset retired
asset.transferredAsset transferred
ocr.startedOCR started processing
ocr.completedOCR done processing

💡 Need a specific event not listed here? Contact support. More are being added all the time!

  • Return a 200 status code (quickly) to acknowledge receipt of the webhook.
  • Store the event ID in your database for reference to de-duplicate events.
  • Use separate secrets per environment and utilise the staging environment for development before using these in production.
  • Do not IP allowlist as this may prevent FSCO from reaching your endpoint. Signature verification is the only way to ensure the request is from FSCO.

Need help? Contact us at support@fsco.io