Skip to main content
Ask your AI

API

Server Source code Package

Read-only store that reads one JSON record per key from a third-party HTTP API, such as your CRM, a product catalog or a pricing service. It uses raw fetch with zero runtime dependencies: get sends one GET request to settings.url with the URL-encoded key in place of {key}, an Accept: application/json header and an optional bearer token, and hands back the parsed JSON body. Pair it with a state get on a transformer to enrich events with what the API knows about a user or a product.

Installation​

npm install @walkeros/server-store-api
import { startFlow } from '@walkeros/collector';
import { storeApiInit } from '@walkeros/server-store-api';

await startFlow({
  stores: {
    crm: {
      code: storeApiInit,
      config: {
        settings: { url: 'https://crm.example.com/customers/{key}' },
        // Omit credentials for an API without a token; an empty token
        // stops the flow at startup.
        credentials: { token: process.env.CRM_API_TOKEN ?? '' },
      },
    },
  },
});

Configuration​

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

Settings​

PropertyTypeDescriptionMore
url*stringAbsolute http or https URL with exactly one {key} placeholder after the host, such as https://crm.example.com/customers/{key} or https://crm.example.com/customers?id={key}. The URL-encoded key is the only variable part.
* 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

Read a record

Read the customer record of a known id from the API and receive its parsed JSON body

Event
{
  "operation": "get",
  "key": "cust-42"
}
Out
get("cust-42", {
  "ltv": 420,
  "segment": "loyal"
})

Unknown id

The API answers 404 for an id it does not know: get answers a miss, so the mapping fallbacks apply

Event
{
  "operation": "get",
  "key": "cust-404"
}
Out
get("cust-404", null)

When it fails

  • unauthorized: The API refuses the request (401, 403, 429 or 5xx): get throws a StepError with the status instead of answering a miss, and the collector reports it. Reported as failed with code transport.

Enrich events with a lookup​

A state get reads the record of the event's user id and merges the fields its mapping picks into event.user. On a miss, the mapping's fallbacks apply:

{
  "stores": {
    "crm": {
      "package": "@walkeros/server-store-api",
      "config": {
        "settings": { "url": "https://crm.example.com/customers/{key}" },
        "credentials": { "token": "$secret.CRM_API_TOKEN" }
      },
      "cache": { "rules": [{ "ttl": 300 }] }
    }
  },
  "transformers": {
    "loadUser": {
      "state": {
        "mode": "get",
        "store": "crm",
        "key": "event.user.id",
        "value": "event.user",
        "mapping": {
          "map": {
            "ltv": "ltv",
            "segment": { "key": "segment", "value": "unknown" }
          }
        }
      }
    }
  }
}

Wire loadUser into a chain (collector.next, a destination's before) like any transformer. An order from cust-42, whose record is { "ltv": 420, "segment": "loyal" }, reaches the destinations with user: { id: 'cust-42', ltv: 420, segment: 'loyal' }; an id the API answers 404 for gets segment: 'unknown' and no ltv.

The URL and the key​

settings.url is an absolute http: or https: URL with exactly one {key} placeholder, after the host: in the path (https://crm.example.com/customers/{key}) or in the query (https://crm.example.com/customers?id={key}), never after a #, since the fragment is never sent. The key is URL-encoded as one segment, so a /, ?, # or % in it never changes which resource is asked, and it is the only variable part of the request. A URL that breaks one of these rules, such as https://{key}.crm.example.com/, stops the flow at startup with a config error.

Use an https: URL whenever you send a token.

A key that is empty or has a . or .. segment (split on / and \) is a miss without a request. The store never logs the key, a URL carrying it or the token, and its error messages name none of them.

Authentication​

Put the token in config.credentials.token and back it with a managed secret, $secret.NAME as the whole value. Never use $env for it, and never put it in settings or in the URL. The store sends it as Authorization: Bearer <token>; without credentials it sends no Authorization header.

  • An unset secret stops the flow at startup with required secret "CRM_API_TOKEN" is not set.
  • Credentials that are not { "token": "<a non-empty string>" }, a bare string included, stop the flow at startup with a config error.
  • Requests refuse redirects: a redirect fails the read instead of carrying the token to another origin.

What a read answers​

The API answersgetReported
2xx with a JSON bodythe parsed bodyno
404, 204, or a 200 with the JSON body nulla missno; a state get applies its fallbacks
any other status (401, 403, 429, 5xx)throws a transport StepError with statusonce per cause at ERROR under store.<id>
a network error, a timeout after 5 seconds, a redirectthrows a transport StepErroronce per cause at ERROR under store.<id>
a 2xx body that is not JSON, the empty body includedthrows a decode StepErroronce per cause at ERROR under store.<id>

A read that throws never fails the event: a state get treats it as a miss for that event, applies its fallbacks and the event goes on.

Caching and rate limits​

The store has no cache of its own; add the store cache block (see Cache) to keep hits in memory for the rule's ttl. Misses are never cached, so when the keys come from the client, such as a user id in the request, every unknown id costs one API request. Put a gateway with a rate limit in front of the API when that matters.

Check the URL before you go live​

A wrong path on the right host answers 404 for every key. The store reads each one as a miss, so nothing is reported at ERROR and every lookup quietly falls back. Check the URL with a known id and the token before you deploy:

curl -i -H "Authorization: Bearer $CRM_API_TOKEN" \
  https://crm.example.com/customers/cust-42

Expect 200 with the record. A simulation (walkeros push --simulate) runs the store on the package's mock API and cannot show this.

Read only​

set and delete throw a config StepError (API store is read-only), so a state set against this store logs at ERROR for every event. The store holds structured JSON only: file: true stops the flow at startup.

Next steps​

  • State: read and write stores from a step
  • Cache: cache rules for a store
  • Stores: every store package
💡 Need implementation support?
elbwalker offers hands-on support: setup review, measurement planning, destination mapping, and live troubleshooting. Book a 2-hour session (€399)