Skip to main content
Ask your AI

Server API Destination

Server Source code Package

The server API destination sends events from Node.js to any HTTP(S) endpoint using fetch. It 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 `fetch` 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": "10164e844d5ed1d8",
  "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",
    "value": 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": "235d0d7bd7a213f2",
  "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.value",
      "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": "f0cc5f6fec3d8eeb",
  "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,
        },
      },
    },
  },
});

A request that fails, times out or gets an error status is reported as a failed push: the event reaches the dead-letter queue and the collector logs one ERROR line per cause and minute with the HTTP status. A 429 and a 5xx answer are retryable, other 4xx answers are not. Without settings.url the destination fails to start with a config error.

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',
          // data is the mapped data, or the event without a mapping
          transform: (data) =>
            JSON.stringify({ sent_at: Date.now(), payload: data }),
        },
      },
    },
  },
});

With batching​

Set config.batch to send events in one request per flush instead of one request per event. The options are in Batch scheduling.

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, and its return value becomes the element as is: a transform that returns a JSON string, like the one above, adds that string to the array, not the object it encodes.

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',
        },
      },
    },
  },
});
💡 Need implementation support?
elbwalker offers hands-on support: setup review, measurement planning, destination mapping, and live troubleshooting. Book a 2-hour session (€399)