Integrations
Connect ScanOrbit to what you already use
There's no native Zapier app or Slack app yet — what exists is one signed webhook, documented below with working code for the three places people ask for most. If a listed integration matters enough to you that this isn't good enough, say so.
How it works
One webhook, signed, firing on real events
Business plan only. Fires on form.submitted and lead.captured — never on a bare scan, which is a page view, not a person.
Zapier
Any of Zapier's 6,000+ apps, via a generic webhook trigger
Create a Zap starting with the Webhooks by Zapier trigger, event type Catch Hook. Zapier gives you a URL — paste that into ScanOrbit's Settings → Notifications → Webhook URL. From there, verify the signature in a Code step before continuing to Slack, Google Sheets, HubSpot, Salesforce, or anything else Zapier connects to.
// "Code by Zapier" step, after a Webhooks by Zapier
// "Catch Hook" trigger — verifies the signature before
// the zap continues to Slack, Sheets, HubSpot, etc.
const crypto = require('crypto');
const sigHeader = inputData.headers['x-scanorbit-signature'] || '';
const [tPart, v1Part] = sigHeader.split(',');
const t = tPart.split('=')[1];
const v1 = v1Part.split('=')[1];
const expected = crypto
.createHmac('sha256', process.env.SCANORBIT_WEBHOOK_SECRET)
.update(`${t}.${inputData.rawBody}`)
.digest('hex');
if (expected !== v1) throw new Error('Invalid signature — not from ScanOrbit');
output = JSON.parse(inputData.rawBody);Google Sheets
Log every lead or form submission as a row, no Zapier account needed
A Google Sheet can receive the webhook directly through Apps Script's built-in web app hosting — nothing else to sign up for.
// Google Apps Script — Extensions > Apps Script on a
// Sheet, paste this, then Deploy > Web app (execute as
// you, access: Anyone). Paste the /exec URL into
// Dashboard > Settings > Notifications > Webhook URL.
function doPost(e) {
const body = e.postData.contents;
const sigHeader = e.parameter['X-ScanOrbit-Signature'] || '';
// Apps Script cannot read custom headers on inbound requests,
// so verification here is by shared-secret query param instead —
// append ?key=YOUR_SECRET to the webhook URL you paste into ScanOrbit,
// and check it below rather than relying on the signature header.
if (e.parameter.key !== 'YOUR_SHARED_SECRET') {
return ContentService.createTextOutput('unauthorized');
}
const data = JSON.parse(body);
const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
sheet.appendRow([
new Date(data.timestamp),
data.event,
data.qrName,
data.event === 'lead.captured'
? [data.name, data.email, data.phone].filter(Boolean).join(' / ')
: JSON.stringify(data.values || {}),
]);
return ContentService.createTextOutput('ok');
}Slack
Post a message to a channel — via a small forwarder, not a direct URL paste
Slack's Incoming Webhooks only accept { "text": ... }, so ScanOrbit's payload needs reshaping first — pointing ScanOrbit straight at a Slack webhook URL will fail. The honest fix is a tiny forwarding function you host yourself (or the same idea as a Zapier Code step):
// A small forwarder — Slack's Incoming Webhook expects
// {"text": "..."} and nothing else, so ScanOrbit's own
// JSON has to be reshaped before it reaches Slack. Deploy
// this as a Vercel/Cloudflare edge function or a Zapier
// "Code" step; point ScanOrbit's webhook at ITS url, not
// at Slack's, and put the Slack URL in SLACK_WEBHOOK_URL.
export default async function handler(req) {
const body = await req.text();
const sig = req.headers.get('x-scanorbit-signature') || '';
// ...verify HMAC-SHA256 here the same way as the Zapier recipe...
const data = JSON.parse(body);
const line = data.event === 'lead.captured'
? `New lead on *${data.qrName}*: ${data.name} (${data.email})`
: `New form submission on *${data.qrName}*`;
await fetch(process.env.SLACK_WEBHOOK_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ text: line }),
});
return new Response('ok');
}Need something these recipes don't cover?
Tell us which integration you actually need. If enough people ask for the same one, that's what decides what gets built next — not a roadmap slide.
Tell us what you need