Skip to content
Try Free →

API recipes

Last updated: · 5 min read

Recipe 1: WordPress webhook receiver

Receive AskVault events in WordPress for custom handling:

<?php
// In your WP theme or plugin
add_action('rest_api_init', function() {
register_rest_route('askvault/v1', '/webhook', [
'methods' => 'POST',
'callback' => 'askvault_webhook_handler',
'permission_callback' => '__return_true',
]);
});
function askvault_webhook_handler($request) {
$signature = $request->get_header('X-AskVault-Signature');
$timestamp = $request->get_header('X-AskVault-Timestamp');
$body = $request->get_body();
$secret = get_option('askvault_webhook_secret');
$expected = 'sha256=' . hash_hmac('sha256', $timestamp . '.' . $body, $secret);
if (!$signature || !hash_equals($expected, $signature)) {
return new WP_Error('invalid_signature', 'Bad signature', ['status' => 401]);
}
$data = json_decode($body, true);
// Process based on $data['event']
return ['status' => 'received'];
}

Add the endpoint as a webhook subscription in AskVault.

Recipe 2: Slack alerts on knowledge gaps

Notify your content team in Slack when a question the bot can't answer keeps recurring. This event fires once per new knowledge-gap suggestion and only when auto-train is set to Suggest or Auto; its fields are top-level, not inside data:

from flask import Flask, request, jsonify
import requests
app = Flask(__name__)
SLACK_WEBHOOK = 'https://hooks.slack.com/services/...'
@app.route('/askvault-webhook', methods=['POST'])
def webhook():
event = request.json
if event['event'] == 'knowledge.gap_detected':
message = f":mag: Knowledge gap: '{event['question']}' asked {event['occurrences']}x"
requests.post(SLACK_WEBHOOK, json={'text': message})
return jsonify({'status': 'ok'})
if __name__ == '__main__':
app.run(port=5000)

Run as your webhook endpoint.

Recipe 3: Zendesk ticket auto-create

Create a Zendesk ticket when a conversation is escalated. The conversation.escalated payload carries conversation_id, channel_type and message_count, so the ticket links back to the chat rather than copying it:

const express = require('express');
const fetch = require('node-fetch');
const app = express();
app.use(express.json());
const ZENDESK_SUBDOMAIN = 'yourco';
const ZENDESK_USER = '[email protected]/token';
const ZENDESK_TOKEN = 'xxx';
app.post('/askvault-webhook', async (req, res) => {
const event = req.body;
if (event.event === 'conversation.escalated') {
const conv = event.data;
await fetch(`https://${ZENDESK_SUBDOMAIN}.zendesk.com/api/v2/tickets.json`, {
method: 'POST',
headers: {
'Authorization': 'Basic ' + Buffer.from(`${ZENDESK_USER}:${ZENDESK_TOKEN}`).toString('base64'),
'Content-Type': 'application/json',
},
body: JSON.stringify({
ticket: {
subject: `AskVault chat needs a person (${conv.channel_type})`,
comment: { body: `Conversation ${conv.conversation_id}, ${conv.message_count} messages. Open it in the AskVault inbox.` },
external_id: conv.conversation_id,
}
})
});
}
res.json({ status: 'ok' });
});
app.listen(5000);

Recipe 4: HubSpot lead sync

Push captured leads to HubSpot Contacts:

from flask import Flask, request, jsonify
import requests
app = Flask(__name__)
HUBSPOT_KEY = 'xxx'
@app.route('/askvault-webhook', methods=['POST'])
def webhook():
event = request.json
if event['event'] == 'lead.captured':
lead = event['data']
requests.post(
'https://api.hubapi.com/crm/v3/objects/contacts',
headers={'Authorization': f'Bearer {HUBSPOT_KEY}'},
json={
'properties': {
'email': lead['email'],
'firstname': lead['name'].split()[0] if lead.get('name') else '',
'lead_source': 'AskVault Chat',
}
}
)
return jsonify({'status': 'ok'})

Common patterns

Every receiver should:

  • Verify the signature over the X-AskVault-Timestamp value, a dot and the raw body (see webhooks). Recipes 2 to 4 leave it out for brevity; add it before going live.
  • Filter by event type and ignore the rest.
  • Drop duplicates using the X-AskVault-Delivery header.
  • Return 2xx once accepted. A 5xx is retried; a 4xx is not.

Limits

  • Webhook delivery timeout. 10 seconds.
  • Attempts. Up to 3, on 5xx or timeout only, with the pause doubling up to 30 seconds.

Common pitfalls

Recipe runs but ticket not created. Check upstream (Zendesk) credentials.

Slack message not arriving. Check incoming-webhook URL valid.

Duplicate tickets created. Store each X-AskVault-Delivery id and skip repeats.

FAQ

Can I customize these?

Yes. They're starting points; adapt to your workflow.

Will the AskVault team review my custom recipe?

Support can help with questions about AskVault's side, such as payloads and signatures.

Are these recipes open-source?

The patterns are. Your specific implementation is yours.

Was this page helpful?