Beepclick / Take your links further
Build with Beepclick.
Links, conversion events and signed webhooks.
Getting started
Create a scoped key in your workspace. Keep sk_ keys on your server. Pro: 60 requests/minute. Elite: 600. read allows GET, write allows link mutations, events allows server-side event ingestion.
Manage keysOpenAPI 3.1 (JSON)Supported endpoints: GET/POST /v1/links, GET/PATCH/DELETE /v1/links/{id}, GET /v1/links/{id}/stats, POST /v1/events, GET /v1/conversions/analytics. Other workspace routes require a session.
Pagination uses limit and nextCursor. Mutations accept Idempotency-Key for 24 hours. Reusing it with a different request returns 409. A 429 response includes Retry-After. Errors use application/problem+json and a stable code.
JavaScript
const response = await fetch('https://beepclick.app/v1/links', {
method: 'POST',
headers: {Authorization: 'Bearer ' + process.env.BEEP_API_KEY,
'Content-Type': 'application/json', 'Idempotency-Key': 'order-123-link'},
body: JSON.stringify({destination: 'https://example.com/offer'})
});
console.log(await response.json());Python
import os, requests
response = requests.post('https://beepclick.app/v1/links',
headers={'Authorization': 'Bearer ' + os.environ['BEEP_API_KEY'],
'Idempotency-Key': 'order-123-link'},
json={'destination': 'https://example.com/offer'})
response.raise_for_status()
print(response.json())PHP
<?php
$ch = curl_init('https://beepclick.app/v1/links');
curl_setopt_array($ch, [CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer '.getenv('BEEP_API_KEY'),
'Content-Type: application/json', 'Idempotency-Key: order-123-link'],
CURLOPT_POSTFIELDS => json_encode(['destination' => 'https://example.com/offer'])]);
echo curl_exec($ch);
curl_close($ch);beep.js & consent
<script>window.beep=window.beep||function(){(window.beep.q=window.beep.q||[]).push(arguments)};</script>
<script defer src="https://beepclick.app/beep.js" data-key="pk_YOUR_PUBLIC_KEY"></script>
// Only after explicit consent from your CMP:
beep('consent', true);
beep('track', 'sale', {value: 49, currency: 'EUR'});
// Withdrawal:
beep('consent', false);Public keys only collect events from exact allowed origins. The default mode records anonymous page views without cookies. Add data-cookieless="true" to force that mode. Consent is never inferred. lead, sale, signup, subscription and custom:name require consent. Enable tracking separately for each link.
{
"eventId": "a1b2c3d4-0000-4000-8000-000000000001",
"name": "sale",
"cid": "SIGNED_BEEP_CID",
"visitor": "your-consented-visitor-id",
"value": 49,
"currency": "EUR",
"consent": true
}Send this JSON to POST /v1/events with an events-scoped server key. Reuse eventId when retrying. Amounts are grouped by currency and never summed across currencies.
Verify webhook signatures
Beepclick-Signature contains t=UNIX_SECONDS,v1=HEX_HMAC. Compute HMAC-SHA256 with your whsec_ secret over timestamp + '.' + the exact request body. Compare in constant time, reject timestamps older than 5 minutes, and deduplicate the event id. Delivery is at least once, with eight attempts and exponential backoff. 3xx responses are not followed.
import {createHmac, timingSafeEqual} from 'node:crypto';
const expected = createHmac('sha256', process.env.BEEP_WEBHOOK_SECRET)
.update(timestamp + '.' + rawBody).digest();
const received = Buffer.from(signatureHex, 'hex');
const valid = received.length === expected.length &&
timingSafeEqual(received, expected) &&
Math.abs(Date.now()/1000 - Number(timestamp)) < 300;