Webhooks25 events across 7 categories

Webhook Events

Receive real-time HTTP POST notifications when events happen in your Viraly workspace. Signed with HMAC-SHA256 for security, with automatic retries for reliability.

HMAC-SHA256 Signed
3 Automatic Retries
Real-Time Delivery
7-Day Delivery Log

Getting Started

Webhooks allow your application to receive real-time HTTP POST notifications when events happen in your Viraly workspace. Instead of polling the API for changes, webhooks push data to your server the moment something happens.

Setup in 3 Steps

  1. 1Go to Settings → Webhooks and click Add Endpoint.
  2. 2Enter your HTTPS endpoint URL and select which events to receive. Copy the signing secret — it's shown only once.
  3. 3Implement an HTTP POST handler on your server. Verify the signature, parse the JSON payload, and return a 2xx status.

Webhooks are available on the Agency and Enterprise plans. Each workspace can configure up to 5 webhook endpoints.

Payload Format

Every webhook sends a consistent JSON envelope. The data field varies by event type.

Standard Webhook Envelope
{
  "id": "wh_a8Kf3mN9p",
  "event": "post.published",
  "created_at": "2026-04-14T12:00:00Z",
  "workspace": {
    "id": "YNFoJ08S",
    "name": "My Brand"
  },
  "data": {
    "...": "event-specific payload"
  }
}

Headers Included

  • X-Viraly-Signature — HMAC-SHA256 signature
  • X-Viraly-Timestamp — Unix timestamp
  • X-Viraly-Event — Event type
  • X-Viraly-Delivery-Id — Unique delivery ID

Response Requirements

  • Return any 2xx status to acknowledge
  • Respond within 10 seconds
  • Non-2xx or timeout triggers a retry
  • Idempotency recommended using id field

Signature Verification

Every webhook is signed with HMAC-SHA256 using the signing secret you received when creating the endpoint. Always verify the signature before processing.

Node.js — Verify Webhook Signature
const crypto = require('crypto');

function verifyWebhook(secret, signature, timestamp, body) {
  // Reject requests older than 5 minutes (replay protection)
  const now = Math.floor(Date.now() / 1000);
  if (Math.abs(now - parseInt(timestamp)) > 300) {
    return false;
  }

  const signedContent = timestamp + '.' + body;
  const expected = 'sha256=' + crypto
    .createHmac('sha256', secret)
    .update(signedContent)
    .digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  );
}

// In your webhook handler:
app.post('/webhooks', (req, res) => {
  const isValid = verifyWebhook(
    process.env.VIRALY_WEBHOOK_SECRET,
    req.headers['x-viraly-signature'],
    req.headers['x-viraly-timestamp'],
    req.body // raw body string
  );

  if (!isValid) return res.status(401).send('Invalid signature');

  const event = JSON.parse(req.body);
  console.log('Received:', event.event, event.data);

  res.status(200).send('OK');
});

Retry Policy

If your endpoint returns a non-2xx status or times out, Viraly retries delivery with exponential backoff.

AttemptDelayOn Failure
1st attemptImmediateRetry after 60 seconds
2nd attempt~60 secondsRetry after 5 minutes
3rd attempt~5 minutesMarked as failed

Failed deliveries are visible in your webhook delivery log for 7 days.

Event Reference

Posts

Events related to social media post lifecycle.

MethodEvent Type
POSTpost.created
POSTpost.updated
POSTpost.scheduled
POSTpost.published
POSTpost.failed
POSTpost.deleted
POSTpost.rescheduled
POSTpost.created

Fired when a new post is created (draft, scheduled, or publish-now).

Example Payload
{
  "id": "wh_a8Kf3mN9p",
  "event": "post.created",
  "created_at": "2026-04-14T12:00:00Z",
  "workspace": {
    "id": "YNFoJ08S",
    "name": "My Brand"
  },
  "data": {
    "id": "abc12345",
    "title": "Summer sale announcement",
    "status": "Scheduled",
    "scheduled_at": "2026-04-20T14:00:00Z",
    "channel_id": "ch123456",
    "channel_type": "Instagram"
  }
}
POSTpost.updated

Fired when an existing post is modified (caption, schedule, attachments).

Example Payload
{
  "id": "wh_b9Lg4nO0q",
  "event": "post.updated",
  "created_at": "2026-04-14T12:30:00Z",
  "workspace": {
    "id": "YNFoJ08S",
    "name": "My Brand"
  },
  "data": {
    "id": "abc12345",
    "title": "Summer sale — updated!",
    "status": "Scheduled",
    "scheduled_at": "2026-04-21T10:00:00Z",
    "channel_id": "ch123456",
    "channel_type": "Instagram"
  }
}
POSTpost.scheduled

Fired when a post transitions to Scheduled status.

Example Payload
{
  "id": "wh_c0Mh5oP1r",
  "event": "post.scheduled",
  "created_at": "2026-04-14T12:00:00Z",
  "workspace": {
    "id": "YNFoJ08S",
    "name": "My Brand"
  },
  "data": {
    "id": "abc12345",
    "title": "Summer sale announcement",
    "scheduled_at": "2026-04-20T14:00:00Z",
    "channel_id": "ch123456",
    "channel_type": "Instagram"
  }
}
POSTpost.published

Fired when a post is successfully published to the social platform.

Example Payload
{
  "id": "wh_d1Ni6pQ2s",
  "event": "post.published",
  "created_at": "2026-04-20T14:00:15Z",
  "workspace": {
    "id": "YNFoJ08S",
    "name": "My Brand"
  },
  "data": {
    "notification_id": "ntf12345",
    "message": "Your post has been published to Instagram.",
    "details": {
      "post_id": "abc12345",
      "channel_name": "My Instagram",
      "external_url": "https://instagram.com/p/ABC123"
    }
  }
}
POSTpost.failed

Fired when a post fails to publish (processing or publishing error).

Example Payload
{
  "id": "wh_e2Oj7qR3t",
  "event": "post.failed",
  "created_at": "2026-04-20T14:00:15Z",
  "workspace": {
    "id": "YNFoJ08S",
    "name": "My Brand"
  },
  "data": {
    "notification_id": "ntf12346",
    "message": "Failed to publish post to Instagram.",
    "details": {
      "post_id": "abc12345",
      "channel_name": "My Instagram",
      "error": "Instagram token expired. Please reconnect."
    }
  }
}
POSTpost.deleted

Fired when a post is deleted.

Example Payload
{
  "id": "wh_f3Pk8rS4u",
  "event": "post.deleted",
  "created_at": "2026-04-14T15:00:00Z",
  "workspace": {
    "id": "YNFoJ08S",
    "name": "My Brand"
  },
  "data": {
    "id": "abc12345",
    "channel_id": "ch123456"
  }
}
POSTpost.rescheduled

Fired when a post's scheduled time is changed.

Example Payload
{
  "id": "wh_g4Ql9sT5v",
  "event": "post.rescheduled",
  "created_at": "2026-04-14T16:00:00Z",
  "workspace": {
    "id": "YNFoJ08S",
    "name": "My Brand"
  },
  "data": {
    "id": "abc12345",
    "title": "Summer sale announcement",
    "status": "Scheduled",
    "scheduled_at": "2026-04-22T09:00:00Z",
    "channel_id": "ch123456"
  }
}

Approvals

Events related to the post approval workflow.

MethodEvent Type
POSTpost.approval_requested
POSTpost.approved
POSTpost.rejected
POSTpost.approval_cancelled
POSTpost.approval_requested

Fired when a post is sent for approval.

Example Payload
{
  "id": "wh_h5Rm0tU6w",
  "event": "post.approval_requested",
  "created_at": "2026-04-14T10:00:00Z",
  "workspace": {
    "id": "YNFoJ08S",
    "name": "My Brand"
  },
  "data": {
    "id": "abc12345",
    "title": "Summer sale announcement",
    "status": "PendingApproval",
    "channel_id": "ch123456",
    "approvers": [
      "usr001",
      "usr002"
    ]
  }
}
POSTpost.approved

Fired when a post meets its approval threshold and transitions to Scheduled.

Example Payload
{
  "id": "wh_i6Sn1uV7x",
  "event": "post.approved",
  "created_at": "2026-04-14T11:00:00Z",
  "workspace": {
    "id": "YNFoJ08S",
    "name": "My Brand"
  },
  "data": {
    "id": "abc12345",
    "title": "Summer sale announcement",
    "status": "Scheduled",
    "approver": {
      "id": "usr001",
      "name": "Jane Doe"
    }
  }
}
POSTpost.rejected

Fired when a post is rejected and reverts to Draft.

Example Payload
{
  "id": "wh_j7To2vW8y",
  "event": "post.rejected",
  "created_at": "2026-04-14T11:30:00Z",
  "workspace": {
    "id": "YNFoJ08S",
    "name": "My Brand"
  },
  "data": {
    "id": "abc12345",
    "title": "Summer sale announcement",
    "status": "Draft",
    "approver": {
      "id": "usr002",
      "name": "John Smith"
    }
  }
}
POSTpost.approval_cancelled

Fired when an approval request is withdrawn by the post creator or workspace owner.

Example Payload
{
  "id": "wh_k8Up3wX9z",
  "event": "post.approval_cancelled",
  "created_at": "2026-04-14T12:00:00Z",
  "workspace": {
    "id": "YNFoJ08S",
    "name": "My Brand"
  },
  "data": {
    "id": "abc12345",
    "title": "Summer sale announcement",
    "status": "Draft"
  }
}

Channels

Events related to connected social media accounts.

MethodEvent Type
POSTchannel.connected
POSTchannel.disconnected
POSTchannel.updated
POSTchannel.connected

Fired when a new social media account is connected.

Example Payload
{
  "id": "wh_l9Vq4xY0a",
  "event": "channel.connected",
  "created_at": "2026-04-14T09:00:00Z",
  "workspace": {
    "id": "YNFoJ08S",
    "name": "My Brand"
  },
  "data": {
    "id": "ch123456",
    "name": "My Instagram",
    "type": "Instagram",
    "username": "@mybrand"
  }
}
POSTchannel.disconnected

Fired when a social media account is removed.

Example Payload
{
  "id": "wh_m0Wr5yZ1b",
  "event": "channel.disconnected",
  "created_at": "2026-04-14T09:30:00Z",
  "workspace": {
    "id": "YNFoJ08S",
    "name": "My Brand"
  },
  "data": {
    "id": "ch123456",
    "name": "My Instagram",
    "type": "Instagram"
  }
}
POSTchannel.updated

Fired when a channel's settings are modified.

Example Payload
{
  "id": "wh_n1Xs6zA2c",
  "event": "channel.updated",
  "created_at": "2026-04-14T10:00:00Z",
  "workspace": {
    "id": "YNFoJ08S",
    "name": "My Brand"
  },
  "data": {
    "id": "ch123456",
    "name": "My Instagram (Rebranded)",
    "type": "Instagram"
  }
}

Team

Events related to workspace team members.

MethodEvent Type
POSTteam.member_invited
POSTteam.member_joined
POSTteam.member_removed
POSTteam.member_role_changed
POSTteam.member_invited

Fired when a team member invitation is sent.

Example Payload
{
  "id": "wh_s6Cx1EF7h",
  "event": "team.member_invited",
  "created_at": "2026-04-14T07:00:00Z",
  "workspace": {
    "id": "YNFoJ08S",
    "name": "My Brand"
  },
  "data": {
    "id": "usr003",
    "role": "Member"
  }
}
POSTteam.member_joined

Fired when an invited team member accepts and joins the workspace.

Example Payload
{
  "id": "wh_t7Dy2FG8i",
  "event": "team.member_joined",
  "created_at": "2026-04-14T07:30:00Z",
  "workspace": {
    "id": "YNFoJ08S",
    "name": "My Brand"
  },
  "data": {
    "id": "usr003",
    "name": "Alex Johnson",
    "role": "Member"
  }
}
POSTteam.member_removed

Fired when a team member is removed from the workspace.

Example Payload
{
  "id": "wh_u8Ez3GH9j",
  "event": "team.member_removed",
  "created_at": "2026-04-14T08:00:00Z",
  "workspace": {
    "id": "YNFoJ08S",
    "name": "My Brand"
  },
  "data": {
    "id": "usr003"
  }
}
POSTteam.member_role_changed

Fired when a team member's role or permissions are updated.

Example Payload
{
  "id": "wh_v9Fa4HI0k",
  "event": "team.member_role_changed",
  "created_at": "2026-04-14T08:30:00Z",
  "workspace": {
    "id": "YNFoJ08S",
    "name": "My Brand"
  },
  "data": {
    "id": "usr003",
    "role": "Owner"
  }
}

Workspace

Events related to workspace-level changes.

MethodEvent Type
POSTworkspace.plan_changed
POSTworkspace.plan_changed

Fired when the workspace subscription plan changes (upgrade, downgrade, or cancellation).

Example Payload
{
  "id": "wh_w0Gb5IJ1l",
  "event": "workspace.plan_changed",
  "created_at": "2026-04-14T06:00:00Z",
  "workspace": {
    "id": "YNFoJ08S",
    "name": "My Brand"
  },
  "data": {
    "old_plan": "Business",
    "new_plan": "Agency"
  }
}

Content

Events related to content creation tools.

MethodEvent Type
POSTidea.created
POSTmedia.uploaded
POSTidea.created

Fired when a new content idea is saved to an idea board.

Example Payload
{
  "id": "wh_x1Hc6JK2m",
  "event": "idea.created",
  "created_at": "2026-04-14T05:00:00Z",
  "workspace": {
    "id": "YNFoJ08S",
    "name": "My Brand"
  },
  "data": {
    "id": "idea12345",
    "title": "Behind the scenes video",
    "board_id": "board001"
  }
}
POSTmedia.uploaded

Fired when a new media file is uploaded to the media library.

Example Payload
{
  "id": "wh_y2Id7KL3n",
  "event": "media.uploaded",
  "created_at": "2026-04-14T05:30:00Z",
  "workspace": {
    "id": "YNFoJ08S",
    "name": "My Brand"
  },
  "data": {
    "id": "att12345",
    "file_name": "summer-banner.png",
    "mime_type": "image/png",
    "url": "https://cdn.viraly.io/media/summer-banner.png"
  }
}