{"openapi":"3.0.3","info":{"title":"WysLeap API","version":"1.0.0","description":"Send page views and custom events to WysLeap: the browser tracker uses the telemetry endpoints, and your servers use the server events API.","contact":{"name":"WysLeap Support","url":"https://wysleap.com/contact"}},"servers":[{"url":"https://wysleap.com","description":"Production"}],"components":{"securitySchemes":{"SecretKeyBearer":{"type":"http","scheme":"bearer","description":"A site secret key (wl_sk_…) from Site Settings, for server-to-server calls. Never use it in a browser."},"ApiKeyHeader":{"type":"apiKey","in":"header","name":"X-API-Key","description":"The site API key from Site Settings, in the X-API-Key header or as `_apiKey` in the JSON body. It ships in your tracker snippet, so it isn't a secret: the endpoints also check the page's domain against your allowed domains."}},"schemas":{"ServerEvent":{"type":"object","required":["eventId"],"properties":{"eventId":{"type":"string","maxLength":128,"description":"Your unique ID for this event, such as your order ID or your payment provider's event ID. Retries with the same eventId are counted once, so it's safe to resend after a timeout."},"type":{"type":"string","enum":["event","pageview"],"default":"event"},"event":{"type":"string","maxLength":100,"description":"Event name in Title Case, e.g. \"Purchase Completed\" (required for type event)."},"timestamp":{"type":"string","format":"date-time","description":"When it happened, up to 72 hours ago. Defaults to now."},"visitorId":{"type":"string","maxLength":100,"description":"The tracker's visitor ID for this person, if your site passed it to your backend."},"sessionId":{"type":"string","maxLength":200},"url":{"type":"string","format":"uri","description":"Page URL; campaign parameters in it are recorded (required for type pageview)."},"title":{"type":"string","maxLength":300},"referrer":{"type":"string","maxLength":2048},"properties":{"type":"object","additionalProperties":true,"description":"JSON metadata, under 8 KB."},"value":{"type":"number","description":"Monetary value of the event."},"currency":{"type":"string","pattern":"^[A-Z]{3}$","description":"ISO 4217 code for value, e.g. USD."},"conversion":{"type":"boolean","description":"Mark the event as a conversion (or not); otherwise decided from its name."}}},"ServerEventsResponse":{"type":"object","properties":{"accepted":{"type":"integer"},"duplicates":{"type":"integer"},"rejected":{"type":"array","items":{"type":"object","properties":{"index":{"type":"integer"},"eventId":{"type":"string"},"error":{"type":"string"}}}}}},"PageviewRequest":{"type":"object","required":["siteId","pageUrl"],"properties":{"siteId":{"type":"string","description":"Your site identifier."},"pageUrl":{"type":"string","description":"Full URL of the page being viewed."},"pageTitle":{"type":"string","description":"Page title (document.title)."},"referrer":{"type":"string","description":"Referring URL."},"visitorId":{"type":"string","description":"Visitor ID — auto-generated if omitted."},"sessionId":{"type":"string","description":"Session ID — auto-generated if omitted."},"userAgent":{"type":"string","description":"Browser user-agent string."},"screenWidth":{"type":"integer","description":"Viewport width in pixels."},"screenHeight":{"type":"integer","description":"Viewport height in pixels."},"language":{"type":"string","description":"Browser language (e.g. en-US)."},"timeZone":{"type":"string","description":"IANA timezone identifier."},"_apiKey":{"type":"string","description":"Site API key (or send it in the X-API-Key header)."}}},"EventRequest":{"type":"object","required":["siteId","eventName"],"properties":{"siteId":{"type":"string","description":"Your site identifier."},"eventName":{"type":"string","description":"Event name in Title Case (e.g. \"Purchase Completed\")."},"eventData":{"type":"object","description":"Any JSON-serializable metadata for the event."},"visitorId":{"type":"string","description":"Visitor ID to associate the event with."},"sessionId":{"type":"string","description":"Session ID to associate the event with."},"pageUrl":{"type":"string","description":"URL where the event occurred."},"_apiKey":{"type":"string","description":"Site API key (or send it in the X-API-Key header)."}}},"ErrorResponse":{"type":"object","properties":{"error":{"type":"string"}}},"TelemetryResponse":{"type":"object","properties":{"success":{"type":"boolean","default":true},"stored":{"type":"boolean","description":"false when the hit was not stored, e.g. a visitor in the EU/EEA, UK or Switzerland without consent."},"reason":{"type":"string","description":"Why the hit was not stored, e.g. consent_required."}}},"LimitErrorResponse":{"type":"object","properties":{"error":{"type":"string","default":"Monthly event limit reached"},"usage":{"type":"object","properties":{"count":{"type":"integer"},"limit":{"type":"integer"},"percentUsed":{"type":"integer"}}}}}}},"paths":{"/api/v1/events":{"post":{"summary":"Send server-side events","description":"Send events from your backend: signups, purchases, subscription changes. Authenticated with a site secret key (`Authorization: Bearer wl_sk_…`); one event per request, or up to 100 as `{ \"events\": [...] }`.\n\nEvery event needs an `eventId` that is unique for your site. Retries with the same `eventId` are counted once.\n\nEvents that fail validation are listed in `rejected` with their index and the reason; the rest are still stored. The response is 400 only when every event was rejected. Limit: 600 requests a minute per secret key.","tags":["Server events"],"security":[{"SecretKeyBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ServerEvent"},{"type":"object","required":["events"],"properties":{"events":{"type":"array","maxItems":100,"items":{"$ref":"#/components/schemas/ServerEvent"}}}}]}}}},"responses":{"200":{"description":"At least one event stored or already known.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServerEventsResponse"},"example":{"accepted":1,"duplicates":0,"rejected":[]}}}},"400":{"description":"Invalid body, or every event was rejected.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing, unknown or revoked secret key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Called from a browser (an Origin header was sent).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"More than 600 requests a minute for this key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"operationId":"sendServerEvents","x-codeSamples":[{"id":"curl","lang":"bash","label":"cURL","source":"curl -X POST https://wysleap.com/api/v1/events \\\n  -H \"Authorization: Bearer $WYSLEAP_SECRET_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"event\": \"Purchase Completed\",\n    \"eventId\": \"order_1042\",\n    \"visitorId\": \"vis_abc123\",\n    \"value\": 49.0,\n    \"currency\": \"USD\",\n    \"properties\": { \"plan\": \"Pro\" }\n  }'"},{"id":"js","lang":"js","label":"JavaScript","source":"// Server-side only (Node 18+ fetch). Never ship a secret key to a browser.\nawait fetch('https://wysleap.com/api/v1/events', {\n  method: 'POST',\n  headers: {\n    Authorization: `Bearer ${process.env.WYSLEAP_SECRET_KEY}`,\n    'Content-Type': 'application/json'\n  },\n  body: JSON.stringify({\n    events: [\n      { event: 'Signup Completed', eventId: 'user_881_signup', visitorId: 'vis_abc123' },\n      { event: 'Trial Started', eventId: 'user_881_trial', properties: { plan: 'Pro' } }\n    ]\n  })\n});"},{"id":"python","lang":"python","label":"Python","source":"import os, requests\n\nrequests.post(\n    \"https://wysleap.com/api/v1/events\",\n    headers={\"Authorization\": f\"Bearer {os.environ['WYSLEAP_SECRET_KEY']}\"},\n    json={\n        \"event\": \"Purchase Completed\",\n        \"eventId\": \"order_1042\",\n        \"visitorId\": \"vis_abc123\",\n        \"value\": 49.0,\n        \"currency\": \"USD\",\n    },\n)"},{"id":"stripe","lang":"js","label":"Stripe webhook (Node.js)","source":"// Stripe webhook: report each paid invoice once (Stripe's event id is the eventId)\napp.post('/stripe/webhook', express.raw({ type: 'application/json' }), async (req, res) => {\n  const event = stripe.webhooks.constructEvent(\n    req.body, req.headers['stripe-signature'], process.env.STRIPE_WEBHOOK_SECRET\n  );\n  if (event.type === 'invoice.paid') {\n    const invoice = event.data.object;\n    await axios.post('https://wysleap.com/api/v1/events', {\n      event: 'Subscription Paid',\n      eventId: event.id,\n      value: invoice.amount_paid / 100,\n      currency: invoice.currency.toUpperCase(),\n      conversion: true\n    }, { headers: { Authorization: `Bearer ${process.env.WYSLEAP_SECRET_KEY}` } });\n  }\n  res.sendStatus(200);\n});"},{"id":"go","lang":"go","source":false},{"id":"java","lang":"java","source":false},{"id":"csharp","lang":"csharp","source":false},{"id":"rust","lang":"rust","source":false}]}},"/api/telemetry/pageview":{"post":{"summary":"Track a page view","description":"Records a page view. This is the endpoint the tracker script uses in the browser; to send data from a server, use [POST /api/v1/events](/docs/api/server-events) with a secret key.","tags":["Telemetry"],"security":[{"ApiKeyHeader":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PageviewRequest"}}}},"responses":{"200":{"description":"Accepted. `stored` is false when the hit was dropped, e.g. no consent for an EU/EEA, UK or Swiss visitor.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TelemetryResponse"},"example":{"success":true}}}},"400":{"description":"Missing or invalid parameters.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"Invalid payload"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"Invalid API key"}}}},"403":{"description":"The page's domain is not one of the site's allowed domains.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"Origin not allowed"}}}},"429":{"description":"The plan's monthly event allowance is used up; resets at the start of next month.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LimitErrorResponse"},"example":{"error":"Monthly event limit reached","usage":{"count":1000000,"limit":1000000,"percentUsed":100}}}}}},"operationId":"trackPageview","x-codeSamples":[{"id":"curl","lang":"bash","label":"cURL","source":"curl -X POST https://wysleap.com/api/telemetry/pageview \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"siteId\": \"your-site-id\",\n    \"pageUrl\": \"https://example.com/products\",\n    \"pageTitle\": \"Products - Example Store\",\n    \"referrer\": \"https://google.com\",\n    \"visitorId\": \"vis_abc123\",\n    \"sessionId\": \"sess_xyz789\",\n    \"userAgent\": \"Mozilla/5.0...\",\n    \"screenWidth\": 1920,\n    \"screenHeight\": 1080,\n    \"language\": \"en-US\",\n    \"timeZone\": \"America/New_York\",\n    \"_apiKey\": \"your-api-key\"\n  }'"},{"id":"js","lang":"js","label":"JavaScript","source":"fetch('https://wysleap.com/api/telemetry/pageview', {\n  method: 'POST',\n  headers: { 'Content-Type': 'application/json' },\n  body: JSON.stringify({\n    siteId: 'your-site-id',\n    pageUrl: window.location.href,\n    pageTitle: document.title,\n    referrer: document.referrer,\n    visitorId: 'vis_123abc', // your own anonymous visitor ID\n    sessionId: getSessionId(),\n    userAgent: navigator.userAgent,\n    screenWidth: window.screen.width,\n    screenHeight: window.screen.height,\n    language: navigator.language,\n    timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone,\n    _apiKey: 'your-api-key'\n  })\n}).then(r => r.json()).then(console.log);"},{"id":"python","lang":"python","label":"Python","source":"import requests\n\nrequests.post(\n    \"https://wysleap.com/api/telemetry/pageview\",\n    json={\n        \"siteId\": \"your-site-id\",\n        \"pageUrl\": \"https://example.com/products\",\n        \"pageTitle\": \"Products - Example Store\",\n        \"referrer\": \"https://google.com\",\n        \"visitorId\": \"vis_abc123\",\n        \"sessionId\": \"sess_xyz789\",\n        \"userAgent\": \"Mozilla/5.0...\",\n        \"screenWidth\": 1920, \"screenHeight\": 1080,\n        \"language\": \"en-US\",\n        \"timeZone\": \"America/New_York\",\n        \"_apiKey\": \"your-api-key\"\n    }\n)"},{"id":"node","lang":"js","label":"Node.js","source":"await axios.post('https://wysleap.com/api/telemetry/pageview', {\n  siteId: 'your-site-id',\n  pageUrl: 'https://example.com/products',\n  pageTitle: 'Products - Example Store',\n  referrer: 'https://google.com',\n  visitorId: 'vis_abc123',\n  sessionId: 'sess_xyz789',\n  userAgent: 'Mozilla/5.0...',\n  screenWidth: 1920, screenHeight: 1080,\n  language: 'en-US', timeZone: 'America/New_York',\n  _apiKey: 'your-api-key'\n});"},{"id":"go","lang":"go","source":false},{"id":"java","lang":"java","source":false},{"id":"csharp","lang":"csharp","source":false},{"id":"rust","lang":"rust","source":false}]}},"/api/telemetry/event":{"post":{"summary":"Track a custom event","description":"Records a custom event: purchases, sign-ups, button clicks, or any other interaction that matters to you. Use Title Case for event names, e.g. `Sign Up Success`, not `sign_up_success`.\n\nThis is the endpoint the tracker uses in the browser (`WysLeap.trackEvent`); to send events from a server, use [POST /api/v1/events](/docs/api/server-events) with a secret key.","tags":["Telemetry"],"security":[{"ApiKeyHeader":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventRequest"}}}},"responses":{"200":{"description":"Accepted. `stored` is false when the hit was dropped, e.g. no consent for an EU/EEA, UK or Swiss visitor.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TelemetryResponse"},"example":{"success":true}}}},"400":{"description":"Missing or invalid parameters.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"Invalid payload"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"Invalid API key"}}}},"403":{"description":"The page's domain is not one of the site's allowed domains.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"Origin not allowed"}}}},"429":{"description":"The plan's monthly event allowance is used up; resets at the start of next month.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LimitErrorResponse"},"example":{"error":"Monthly event limit reached","usage":{"count":1000000,"limit":1000000,"percentUsed":100}}}}}},"operationId":"trackEvent","x-codeSamples":[{"id":"curl","lang":"bash","label":"cURL","source":"curl -X POST https://wysleap.com/api/telemetry/event \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"siteId\": \"your-site-id\",\n    \"eventName\": \"Purchase Completed\",\n    \"eventData\": {\n      \"productId\": \"prod_123\",\n      \"productName\": \"Premium Plan\",\n      \"currency\": \"USD\"\n    },\n    \"visitorId\": \"vis_abc123\",\n    \"pageUrl\": \"https://example.com/checkout/success\",\n    \"_apiKey\": \"your-api-key\"\n  }'"},{"id":"js","lang":"js","label":"JavaScript","source":"// Using the WysLeap SDK (recommended)\nWysLeap.trackEvent('Purchase Completed', {\n  productId: 'prod_123',\n  productName: 'Premium Plan',\n  currency: 'USD'\n});\n\n// Or via fetch\nfetch('https://wysleap.com/api/telemetry/event', {\n  method: 'POST',\n  headers: { 'Content-Type': 'application/json' },\n  body: JSON.stringify({\n    siteId: 'your-site-id',\n    eventName: 'Purchase Completed',\n    eventData: { productId: 'prod_123', currency: 'USD' },\n    visitorId: 'vis_123abc', // your own anonymous visitor ID\n    pageUrl: window.location.href,\n    _apiKey: 'your-api-key'\n  })\n});"},{"id":"python","lang":"python","label":"Python","source":"import requests\n\nrequests.post(\n    \"https://wysleap.com/api/telemetry/event\",\n    json={\n        \"siteId\": \"your-site-id\",\n        \"eventName\": \"Purchase Completed\",\n        \"eventData\": {\n            \"productId\": \"prod_123\",\n            \"productName\": \"Premium Plan\",\n            \"currency\": \"USD\"\n        },\n        \"visitorId\": \"vis_abc123\",\n        \"pageUrl\": \"https://example.com/checkout/success\",\n        \"_apiKey\": \"your-api-key\"\n    }\n)"},{"id":"node","lang":"js","label":"Node.js","source":"await axios.post('https://wysleap.com/api/telemetry/event', {\n  siteId: 'your-site-id',\n  eventName: 'Purchase Completed',\n  eventData: {\n    productId: 'prod_123',\n    productName: 'Premium Plan',\n    currency: 'USD'\n  },\n  visitorId: 'vis_abc123',\n  pageUrl: 'https://example.com/checkout/success',\n  _apiKey: 'your-api-key'\n});"},{"id":"go","lang":"go","source":false},{"id":"java","lang":"java","source":false},{"id":"csharp","lang":"csharp","source":false},{"id":"rust","lang":"rust","source":false}]}},"/api/health":{"get":{"summary":"Health check","description":"Returns the API status. No authentication required.","tags":["System"],"responses":{"200":{"description":"API and database are up.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","default":"healthy"},"message":{"type":"string"}}},"example":{"status":"healthy","message":"MongoDB connection is alive"}}}},"503":{"description":"Database unreachable.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","default":"unhealthy"},"message":{"type":"string"}}},"example":{"status":"unhealthy","message":"MongoDB connection failed"}}}}},"operationId":"getHealth","x-codeSamples":[{"id":"curl","lang":"bash","label":"cURL","source":"curl https://wysleap.com/api/health"},{"id":"js","lang":"js","label":"JavaScript","source":"const res = await fetch(\"https://wysleap.com/api/health\");\nconsole.log(await res.json()); // { status: \"healthy\", message: \"...\" }"},{"id":"python","lang":"python","source":false},{"id":"go","lang":"go","source":false},{"id":"java","lang":"java","source":false},{"id":"csharp","lang":"csharp","source":false},{"id":"rust","lang":"rust","source":false}]}}},"tags":[{"name":"Server events","description":"Server-to-server ingest with a secret key."},{"name":"Telemetry","description":"Browser ingest used by the tracker script."},{"name":"System","description":"Status."}]}