Code Examples
Ready-to-use webhook implementations for popular backend frameworks and CI/CD integration patterns.
Get started quickly with these webhook implementation examples. All examples include proper security validation and error handling.
Backend Framework Examples
app.use('/webhook', express.raw({type: 'application/json'}));
function validateSignature(payload, signature, secret) {
const expectedSignature = 'sha256=' +
crypto.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
}
app.post('/webhook', async (req, res) => {
const signature = req.headers['x-statused-signature'];
const secret = process.env.WEBHOOK_SECRET;
if (!validateSignature(req.body, signature, secret)) {
return res.status(401).send('Unauthorized');
}
const event = JSON.parse(req.body);
const { type, data } = event;
switch (type) {
case 'com.statused.app.status.updated':
await handleAppStatusChange(data);
break;
case 'com.statused.build.status.updated':
await handleBuildStatusChange(data);
break;
}
res.status(200).send('OK');
});
async function handleAppStatusChange(data) {
switch (data.status) {
case 'Ready for Sale':
await notifyTeam(`🎉 ${data.app_name} v${data.version} is live!`);
break;
case 'In Review':
await toggleFeatureFlags(data.app_name, false);
break;
case 'Rejected':
await createIncident(data);
break;
}
}
class WebhooksController < ApplicationController
skip_before_action :verify_authenticity_token
before_action :validate_signature
def statused
event = JSON.parse(request.raw_post)
case event['type']
when 'com.statused.app.status.updated'
handle_app_status_change(event['data'])
when 'com.statused.build.status.updated'
handle_build_status_change(event['data'])
end
head :ok
end
private
def validate_signature
signature = request.headers['X-Statused-Signature']
secret = Rails.application.credentials.webhook_secret
body = request.raw_post
expected_signature = 'sha256=' + OpenSSL::HMAC.hexdigest('SHA256', secret, body)
unless ActiveSupport::SecurityUtils.secure_compare(signature, expected_signature)
head :unauthorized and return
end
end
def handle_app_status_change(data)
case data['status']
when 'Ready for Sale'
NotificationService.notify_team("🎉 #{data['app_name']} is live!")
when 'In Review'
FeatureFlagService.toggle(data['app_name'], enabled: false)
when 'Rejected'
IncidentService.create_from_rejection(data)
end
end
end
post '/webhooks/statused', to: 'webhooks#statused'
@csrf_exempt
@require_http_methods(["POST"])
def statused_webhook(request):
signature = request.META.get('HTTP_X_STATUSED_SIGNATURE')
if not validate_signature(request.body, signature):
return HttpResponseBadRequest("Invalid signature")
event = json.loads(request.body)
event_type = event.get('type')
data = event.get('data', {})
if event_type == 'com.statused.app.status.updated':
handle_app_status_change(data)
elif event_type == 'com.statused.build.status.updated':
handle_build_status_change(data)
return HttpResponse("OK")
def validate_signature(payload, signature):
if not signature:
return False
secret = settings.WEBHOOK_SECRET
expected_signature = 'sha256=' + hmac.new(
secret.encode(),
payload,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(signature, expected_signature)
def handle_app_status_change(data):
status = data.get('status')
if status == 'Ready for Sale':
notify_release.delay(data.get('app_name'))
elif status == 'In Review':
toggle_features.delay(data.get('app_name'), False)
elif status == 'Rejected':
create_incident.delay(data)
path('webhooks/statused/', views.statused_webhook, name='statused_webhook'),
CI/CD System Integration
Most CI/CD systems don’t natively accept generic webhooks from external services like Statused. However, you can integrate Statused with popular mobile-focused CI/CD platforms using their APIs or plugin systems:
Platform | Native Webhook Support | Integration Method | Documentation |
---|---|---|---|
Bitrise | ❌ No | Use Bitrise REST API to trigger builds (requires API token) | Triggering Builds via API – Bitrise Docs |
GitHub Actions | ❌ No | External trigger via Repository Dispatch event (GitHub REST API) | Repository Dispatch API – GitHub Docs |
Jenkins | ✅ Yes (with plugin) | Direct webhook trigger using a plugin (e.g. Generic Webhook Trigger) or via intermediate service | Generic Webhook Trigger Plugin – Jenkins |
GitLab CI | ✅ Yes | Built-in Pipeline Triggers (trigger token & API call) | Pipeline Triggers – GitLab Docs |
Azure DevOps | ✅ Yes | Incoming Webhook triggers (YAML pipeline webhook resource) | Webhook Resource Triggers – Azure DevOps Docs |
CircleCI | ❌ No | Trigger via CircleCI API (e.g. Pipeline Trigger endpoint) | Trigger Pipeline via API – CircleCI Docs |
Each “No” above means you’ll need to set up a small backend (or use a serverless function) to receive the Statused webhook and then call the CI/CD’s API. For platforms marked “Yes”, you can configure them to accept incoming webhooks directly without an extra proxy in between.
Recommended Integration Pattern
For platforms without native webhook support, we recommend implementing a backend proxy:
- Statused → Your Backend → CI/CD Platform API
- Your backend receives the webhook, validates it, and triggers the appropriate CI/CD action
- This gives you full control over authentication, filtering, error handling, and custom logic
Backend Proxy Example
async function handleBuildStatusChange(data) {
if (data.status === 'Valid') {
// Build is valid - trigger GitHub Actions to submit for review
await fetch(`https://api.github.com/repos/${process.env.GITHUB_OWNER}/${process.env.GITHUB_REPO}/dispatches`, {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.GITHUB_TOKEN}`,
"Accept": "application/vnd.github+json",
"X-GitHub-Api-Version": "2022-11-28",
"Content-Type": "application/json",
},
body: JSON.stringify({
event_type: "submit-for-review",
client_payload: {
app_name: data.app_name,
build_version: data.build_version,
}
})
});
} else {
// Build failed - notify team via Slack/Teams
await notifyTeam(`⚠️ Build processing failed for ${data.app_name} v${data.build_version}. Please investigate.`);
}
}
class WebhooksController < ApplicationController
skip_before_action :verify_authenticity_token
# …
def handle_build_status_change(data)
if data['status'] == 'Valid'
# Build is valid - trigger GitHub Actions to submit for review
trigger_github_actions(data)
else
# Build failed - notify team via Slack/Teams
NotificationService.notify_team("⚠️ Build processing failed for #{data['app_name']} v#{data['build_version']}. Please investigate.")
end
end
private
def trigger_github_actions(data)
uri = URI("https://api.github.com/repos/#{ENV['GITHUB_OWNER']}/#{ENV['GITHUB_REPO']}/dispatches")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer #{ENV['GITHUB_TOKEN']}"
req["Accept"] = "application/vnd.github+json"
req["X-GitHub-Api-Version"] = "2022-11-28"
req.content_type = "application/json"
req.body = {
event_type: "submit-for-review",
client_payload: {
app_name: data["app_name"],
build_version: data["build_version"],
}
}.to_json
Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
end
end
def handle_build_status_change(data):
if data.get('status') == 'Valid':
# Build is valid - trigger GitHub Actions to submit for review
trigger_github_actions(data)
else:
# Build failed - notify team via Slack/Teams
notify_team.delay(f"⚠️ Build processing failed for {data.get('app_name')} v{data.get('build_version')}. Please investigate.")
def trigger_github_actions(data):
url = f"https://api.github.com/repos/{settings.GITHUB_OWNER}/{settings.GITHUB_REPO}/dispatches"
headers = {
"Authorization": f"Bearer {settings.GITHUB_TOKEN}",
"Accept": "application/vnd.github+json",
"X-GitHub-Api-Version": "2022-11-28"
}
payload = {
"event_type": "submit-for-review",
"client_payload": {
"app_name": data["app_name"],
"build_version": data["build_version"],
}
}
requests.post(url, json=payload, headers=headers, timeout=10)
GitHub Actions workflow
name: Submit App for Review
on:
repository_dispatch:
types: [submit-for-review]
jobs:
submit-for-review:
runs-on: ubuntu-latest
steps:
- name: Submit app for review
run: |
echo "🚀 Submitting ${{ github.event.client_payload.app_name }} \
v${{ github.event.client_payload.build_version }} for review..."
# e.g. fastlane deliver --submit_for_review
Key references if you need further details or up-to-date API information:
- Create a repository dispatch event – GitHub REST API
- Events that trigger workflows (
repository_dispatch
) - GitHub Docs
Feature Flag Integration
You can use your backend to toggle feature flags based on app status changes. Check your feature flagging service documentation for their API or SDK usage.
Support
Want direct CI/CD integration?
Missing your CI/CD platform or want us to build a direct integration? Reach out to us — we prioritize new integrations based on user demand and can help you get set up quickly.
Need help with implementation?
These examples should get you started, but every integration is unique. If you need help adapting these examples to your specific use case, reach out to us — we're happy to help with your webhook implementation.