Install and configure
One client, four calls: identify, track, batch and emails.send.
npm install @cowliss/sdkimport { Cow } from "@cowliss/sdk";
const cow = new Cow({ apiKey: process.env.COW_KEY!, sourceId: "src_01j2x8q7v9e3atn5m4kd7yz0bp", baseUrl: process.env.COW_API_URL,});| Option | Default | Meaning |
|---|---|---|
apiKey |
required | Your org’s API key, the Bearer credential on every request. One key serves every app. |
sourceId |
none | The source calls arrive through when they do not name one. Set it once per app. |
baseUrl |
local dev | The origin your Cowliss API is served at, with no trailing slash. |
maxRetries |
2 |
Retries after the first attempt, on network errors and 5xx only. |
timeoutMs |
10000 |
How long one call may take before it is abandoned and retried. |
batchTimeoutMs |
30000 |
The same for one batch, which carries up to 500 rows and is slower by design. |
onError |
none | Called with the CowError of any failed call. This is where a call you do not await gets logged. |
fetch |
global | An injectable fetch, for tests and runtimes that do not have one. |
The two ids you hold
Section titled “The two ids you hold”| Id | Looks like | You use it for |
|---|---|---|
| Source id | src_01j2x8q7… |
Every call. It goes in the client config and on every HTTP body. |
| App id | app_my-app |
Segment definitions, journey triggers, filtering the event feed. |
You send the source; you filter on the app. A process writing into two apps names sourceId per call, or holds one client per app. See Apps and sources.
Calling without waiting
Section titled “Calling without waiting”// You need the result: await it, and handle the error.const profile = await cow.identify({ identifiers: { userId: "user_1" } });
// You do not: let it run, and keep serving the request.cow.track({ identifiers: { userId: "user_1" }, event: "checkout_started" });A call you do not wait for never rejects into your process. If Cowliss is unreachable it gives up on its own, within timeoutMs per attempt, and reports through onError:
const cow = new Cow({ apiKey: process.env.COW_KEY!, sourceId: "src_01j2x8q7v9e3atn5m4kd7yz0bp", onError: (error) => logger.warn({ err: error }, "cowliss write dropped"),});Wait when the next thing you do depends on the write: a profile you are about to read back, or a segment you expect the event to move.
Errors
Section titled “Errors”A 4xx surfaces as a typed CowError carrying the API’s error code, and is never retried. Network errors, timeouts and 5xx retry with exponential backoff.
import { CowError } from "@cowliss/sdk";
try { await cow.track({ identifiers: { userId: "user_1" }, event: "checkout_started" });} catch (error) { if (error instanceof CowError && error.code === "over_quota") { // out of credit: the write did not land }}An unknown sourceId, an archived source, a reserved event name and a future timestamp are all refused rather than quietly dropped. Every code and its status is in API conventions.
Without the SDK
Section titled “Without the SDK”Requests and responses use the { data } envelope, and the endpoints are documented in the API reference.
curl -X POST $COW_API_URL/v1/identify \ -H "Authorization: Bearer $COW_KEY" \ -H "Content-Type: application/json" \ -d '{ "data": { "sourceId": "src_01j2x8q7v9e3atn5m4kd7yz0bp", "identifiers": { "userId": "user_1" }, "traits": { "email": "[email protected]", "plan": "pro" } } }'A raw client sends its own messageId on a track.