Webhooks
Webhooks
Receive real-time HTTP notifications when events occur on your listings. Configure webhooks from your Dashboard or the public API.
Overview
- Dashboard and API Management - Create, list, and delete webhooks by API; edit and test from the Dashboard
- Unlimited endpoints - Create as many webhook endpoints as your integration needs
- Per-listing binding - Select which webhooks fire for each listing
- HMAC-SHA256 Signatures - Verify payload authenticity
- Auto-disable - Deactivated after 5 consecutive failures
Management API
Public API keys can create, list, and delete webhooks. Dashboard-only actions such as testing, editing, toggling active state, and regenerating secrets are managed from the Dashboard. Webhook endpoints are unlimited for every Verified level.
Create Webhook
POST
/v1/webhooks| Field | Type | Required | Description |
|---|---|---|---|
name | string | No | Display name. Defaults to API Webhook. |
url | string | Yes | Endpoint that receives webhook POST requests. |
events | string[] | null | No | Subscribed event names. Omit or send empty to receive all supported events. |
Request
curl -X POST https://api.markidy.com/v1/webhooks \
-H "Authorization: Bearer mk_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"name": "Production Webhook",
"url": "https://example.com/webhooks/markidy",
"events": ["match_request.received", "message.new"]
}'Response (201)
{
"id": "wh_abc123",
"name": "Production Webhook",
"url": "https://example.com/webhooks/markidy",
"secret": "a1b2c3...",
"events": ["match_request.received", "message.new"],
"active": true,
"createdAt": "2026-03-18T12:00:00Z",
"updatedAt": "2026-03-18T12:00:00Z"
}List Webhooks
GET
/v1/webhooksResponse
{
"webhooks": [
{
"id": "wh_abc123",
"name": "Production Webhook",
"url": "https://example.com/webhooks/markidy",
"secret": "a1b2c3...",
"events": ["match_request.received"],
"active": true,
"failCount": 0,
"createdAt": "2026-03-18T12:00:00Z",
"updatedAt": "2026-03-18T12:00:00Z"
}
]
}Delete Webhook
DELETE
/v1/webhooks/{id}Response
{
"id": "wh_abc123",
"deleted": true
}Linking Webhooks to Listings
When creating or editing a listing, pass webhookIds to associate
specific webhooks:
POST /v1/listings
{
"categoryKey": "mentoring",
"roleKey": "mentor",
"meta": {
"headline": "Product mentor for early-stage founders",
"about-me": "<p>I help teams ship faster with better product decisions.</p>",
"format": "Remote",
"rate": "$50-$100 / hour"
},
"channels": ["markidy"],
"webhookIds": ["wh_abc123", "wh_def456"]
}If webhookIds is omitted or empty, no webhooks will
fire for that listing. Update bindings anytime via PATCH /v1/listings/{id}.
Events
| Event | Trigger | Who Receives |
|---|---|---|
match_request.received | New match request for a listing | Listing owner |
match_request.accepted | Owner accepts the request | Listing owner |
match_request.rejected | Owner rejects the request | Listing owner |
message.new | New message sent in conversation | Recipient |
match_request.* events fire to the webhooks bound
to the listing via webhookIds. message.new events fire to all active webhooks for
the user.Payload Format
Webhook Payload
{
"event": "match_request.received",
"timestamp": "2026-03-18T12:00:00Z",
"test": false,
"data": {
"requestId": "mr_...",
"status": "PENDING",
"listingId": "clx...",
"listingTitle": "AI Agent Developer...",
"requesterId": "usr_...",
"profile": {
"displayName": "Alice",
"verifiedLevel": 1,
"country": "us",
"socialLinks": {
"github": "https://github.com/alice",
"x": "https://x.com/alice"
}
},
"channels": ["telegram", "discord"],
"message": "I'm interested in your service.",
"createdAt": "2026-03-18T12:00:00Z"
}
}match_request.accepted
Accepted Payload
{
"event": "match_request.accepted",
"timestamp": "2026-03-18T14:30:00Z",
"test": false,
"data": {
"requestId": "mr_...",
"status": "ACCEPTED",
"listingId": "clx...",
"listingTitle": "AI Agent Developer...",
"requesterId": "usr_...",
"respondedAt": "2026-03-18T14:30:00Z"
}
}match_request.rejected
Rejected Payload
{
"event": "match_request.rejected",
"timestamp": "2026-03-18T14:30:00Z",
"test": false,
"data": {
"requestId": "mr_...",
"status": "REJECTED",
"listingId": "clx...",
"listingTitle": "AI Agent Developer...",
"requesterId": "usr_...",
"reason": "Not a good fit at this time.",
"respondedAt": "2026-03-18T14:30:00Z"
}
}message.new
New Message Payload
{
"event": "message.new",
"timestamp": "2026-03-25T12:01:00Z",
"data": {
"conversationId": "conv_...",
"messageId": "msg_...",
"senderId": "usr_...",
"senderName": "Alex Kim",
"content": "Hello, I'm interested in your service.",
"isApiSent": false,
"createdAt": "2026-03-25T12:01:00Z"
}
}Social Link Keys
| Key | Platform |
|---|---|
x | X (Twitter) |
linkedin | |
github | GitHub |
instagram | |
tiktok | TikTok |
youtube | YouTube |
website | Personal Website |
Request Headers
| Header | Description |
|---|---|
Content-Type | application/json |
X-Webhook-Event | Event name (e.g., match_request.received) |
X-Webhook-Signature | HMAC-SHA256 signature of the body |
Signature Verification
Verify the X-Webhook-Signature header to ensure the request
is authentic:
Node.js
const crypto = require('crypto');
function verifySignature(secret, body, signature) {
const expected = crypto
.createHmac('sha256', secret)
.update(JSON.stringify(body))
.digest('hex');
return expected === signature;
}
app.post('/webhook', (req, res) => {
const sig = req.headers['x-webhook-signature'];
if (!verifySignature(MY_SECRET, req.body, sig)) {
return res.status(401).send('Invalid signature');
}
// Process event...
res.status(200).send('OK');
});Retry & Failure Policy
| Behavior | Detail |
|---|---|
| Timeout | 10 seconds per request |
| Success | HTTP 2xx - failCount resets to 0 |
| Failure | Non-2xx or timeout - failCount +1 |
| Auto-disable | After 5 consecutive failures - active: false |
| Re-enable | Manually toggle back on in Dashboard |