Skip to main content

Server API Destination

Server Source code Package

The server API destination sends events from Node.js to any HTTP(S) endpoint using native HTTP/HTTPS modules. It auto-selects HTTP or HTTPS from the URL, supports configurable timeouts (default 5000ms), custom transforms, and dependency injection for testing.

Where this fits

Server API is a server destination in the walkerOS flow:

Sends events server-side to any HTTP endpoint using Node.js native modules with configurable request formatting and batching.

Installation

npm install @walkeros/server-destination-api

Configuration

This destination uses the standard destination config wrapper (consent, data, env, id, ...). For the shared fields see destination configuration. Package-specific fields live under config.settings and are listed below.

Settings

PropertyTypeDescriptionMore
url*stringThe API endpoint URL to send events to
headersRecord<string, string>Custom HTTP headers to include with requests
methodstringHTTP method to use (default: POST)
transformfunctionFunction to transform event data before sending
timeoutnumberRequest timeout in milliseconds (default: 5000)
* Required fields

Mapping

This package does not define custom rule-level settings. For the standard rule fields (consent, condition, data, batch, name, policy) see mapping.

Examples

Custom headers

A form submission is sent to the API with custom request headers such as an API key for authentication.

Event
{
  "name": "form submit",
  "data": {
    "type": "contact",
    "email": "user@example.com"
  },
  "context": {
    "dev": [
      "test",
      1
    ]
  },
  "globals": {
    "lang": "elb"
  },
  "custom": {
    "completely": "random"
  },
  "user": {
    "id": "us3r",
    "device": "c00k13",
    "session": "s3ss10n"
  },
  "nested": [
    {
      "entity": "child",
      "data": {
        "is": "subordinated"
      }
    }
  ],
  "consent": {
    "functional": true
  },
  "id": "0076c4a2bfb15038",
  "trigger": "test",
  "entity": "form",
  "action": "submit",
  "timestamp": 1700000801,
  "timing": 3.14,
  "source": {
    "count": 1,
    "trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
    "type": "express",
    "platform": "server"
  }
}
Mapping
{
  "data": "data"
}
Out
sendServer("https://api.example.com/events", "{\"type\":\"contact\",\"email\":\"user@example.com\"}", {
  "headers": {
    "X-API-Key": "YOUR_API_KEY"
  }
})

Custom payload

An order event is reshaped via a data mapping into a custom JSON payload with renamed fields for the API.

Event
{
  "name": "order complete",
  "data": {
    "id": "ORD-500",
    "total": 199.99,
    "currency": "USD"
  },
  "context": {
    "shopping": [
      "complete",
      0
    ]
  },
  "globals": {
    "pagegroup": "shop"
  },
  "custom": {
    "completely": "random"
  },
  "user": {
    "id": "buyer-42"
  },
  "nested": [
    {
      "entity": "product",
      "data": {
        "id": "ers",
        "name": "Everyday Ruck Snack",
        "color": "black",
        "size": "l",
        "price": 420
      },
      "context": {
        "shopping": [
          "complete",
          0
        ]
      },
      "nested": []
    },
    {
      "entity": "product",
      "data": {
        "id": "cc",
        "name": "Cool Cap",
        "size": "one size",
        "price": 42
      },
      "context": {
        "shopping": [
          "complete",
          0
        ]
      },
      "nested": []
    },
    {
      "entity": "gift",
      "data": {
        "name": "Surprise"
      },
      "context": {
        "shopping": [
          "complete",
          0
        ]
      },
      "nested": []
    }
  ],
  "consent": {
    "functional": true
  },
  "id": "212621e06d12575e",
  "trigger": "load",
  "entity": "order",
  "action": "complete",
  "timestamp": 1700000802,
  "timing": 3.14,
  "source": {
    "count": 1,
    "trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
    "type": "express",
    "platform": "server"
  }
}
Mapping
{
  "data": {
    "map": {
      "order_id": "data.id",
      "amount": "data.total",
      "currency": "data.currency",
      "customer_id": "user.id",
      "event_type": "name"
    }
  }
}
Out
sendServer("https://api.example.com/events", "{\"order_id\":\"ORD-500\",\"amount\":199.99,\"currency\":\"USD\",\"customer_id\":\"buyer-42\",\"event_type\":\"order complete\"}", {})

Forward event data

A page view is POSTed to the configured endpoint with the event data serialized as the JSON body.

Event
{
  "name": "page view",
  "data": {
    "title": "Docs",
    "url": "https://example.com/docs"
  },
  "context": {
    "dev": [
      "test",
      1
    ]
  },
  "globals": {
    "pagegroup": "docs"
  },
  "custom": {
    "completely": "random"
  },
  "user": {
    "id": "us3r",
    "device": "c00k13",
    "session": "s3ss10n"
  },
  "nested": [
    {
      "entity": "child",
      "data": {
        "is": "subordinated"
      }
    }
  ],
  "consent": {
    "functional": true
  },
  "id": "2ab6d1374bb009be",
  "trigger": "load",
  "entity": "page",
  "action": "view",
  "timestamp": 1700000800,
  "timing": 3.14,
  "source": {
    "count": 1,
    "trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
    "type": "express",
    "platform": "server"
  }
}
Mapping
{
  "data": "data"
}
Out
sendServer("https://api.example.com/events", "{\"title\":\"Docs\",\"url\":\"https://example.com/docs\"}", {})

Usage

Basic usage

import { startFlow } from '@walkeros/collector';
import { destinationAPI } from '@walkeros/server-destination-api';

await startFlow({
  destinations: {
    api: {
      code: destinationAPI,
      config: {
        settings: {
          url: 'https://api.example.com/events',
        },
      },
    },
  },
});

With headers and timeout

import { startFlow } from '@walkeros/collector';
import { destinationAPI } from '@walkeros/server-destination-api';

await startFlow({
  destinations: {
    api: {
      code: destinationAPI,
      config: {
        settings: {
          url: 'https://api.example.com/events',
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
            'Authorization': 'Bearer your-token',
          },
          timeout: 5000,
        },
      },
    },
  },
});

With custom transform

import { startFlow } from '@walkeros/collector';
import { destinationAPI } from '@walkeros/server-destination-api';

await startFlow({
  destinations: {
    api: {
      code: destinationAPI,
      config: {
        settings: {
          url: 'https://api.example.com/events',
          transform: (event, config, mapping) => {
            return JSON.stringify({
              timestamp: Date.now(),
              event_name: event.name,
              properties: event.data,
            });
          },
        },
      },
    },
  },
});

With batching

Set config.batch to send every event in one shared batch instead of one request per event. A bare number is the debounce wait window; an object tunes wait, size, and age. No '* *' wildcard mapping rule is needed.

Each flush is a single request whose body is a JSON array, one element per event. Mapping still applies per event, so an element is the event's mapped data when a rule produced some and the raw event otherwise. A transform runs per element, not once for the whole array.

import { startFlow } from '@walkeros/collector';
import { destinationAPI } from '@walkeros/server-destination-api';

await startFlow({
  destinations: {
    api: {
      code: destinationAPI,
      config: {
        batch: { wait: 1000, size: 100 },
        settings: {
          url: 'https://api.example.com/events',
        },
      },
    },
  },
});

Use cases

Webhook integration

import { startFlow } from '@walkeros/collector';
import { destinationAPI } from '@walkeros/server-destination-api';

await startFlow({
  destinations: {
    webhook: {
      code: destinationAPI,
      config: {
        settings: {
          url: 'https://hooks.example.com/webhook',
          headers: {
            'X-Webhook-Secret': process.env.WEBHOOK_SECRET,
          },
        },
      },
    },
  },
});

Custom analytics backend

import { startFlow } from '@walkeros/collector';
import { destinationAPI } from '@walkeros/server-destination-api';

await startFlow({
  destinations: {
    analytics: {
      code: destinationAPI,
      config: {
        settings: {
          url: 'https://analytics.internal.com/ingest',
          method: 'PUT',
          headers: {
            'X-API-Key': process.env.ANALYTICS_API_KEY,
          },
          timeout: 10000,
        },
      },
    },
  },
});

With event mapping

import { startFlow } from '@walkeros/collector';
import { destinationAPI } from '@walkeros/server-destination-api';

await startFlow({
  destinations: {
    api: {
      code: destinationAPI,
      config: {
        settings: {
          url: 'https://api.example.com/events',
        },
        mapping: {
          page: {
            view: {
              data: {
                map: {
                  pageUrl: 'data.path',
                  pageTitle: 'data.title',
                },
              },
            },
          },
        },
      },
    },
  },
});
💡 Need implementation support?
elbwalker offers hands-on support: setup review, measurement planning, destination mapping, and live troubleshooting. Book a 2-hour session (€399)