Drains
Send the data where you work
Forward operational logs and per-number Analytics to your own HTTPS endpoints. Signed, deduplicable and retried until accepted.
- Drains per project
- 5
- Ordered sampling rules
- 20
- Delivery attempts within 24 h
- 6
- Analytics windows
- 1 to 168 h
Sources
Logs and Analytics, never content.
Pick one source per drain. Neither carries message text, contacts or credentials.
Delivery
A delivery contract you can build on.
JSON or NDJSON over HTTPS POST, HMAC-signed, at least once, with your own headers if you want them.
In your code
Your receiver, in a few lines.
Verify, deduplicate and acknowledge. Or read the same metrics from the API.
app/drain/route.ts
import { createHmac, timingSafeEqual } from "node:crypto";
const MAX_AGE_SECONDS = 300; // Retries are re-signed with a fresh timestamp.
export async function POST(request: Request) {
const body = Buffer.from(await request.arrayBuffer());
const timestamp = request.headers.get("x-polymorfa-timestamp") ?? "";
const age = Math.abs(Date.now() / 1000 - Number(timestamp));
if (!/^\d+$/.test(timestamp) || age > MAX_AGE_SECONDS) {
return new Response(null, { status: 401 });
}
const expected = "sha256=" + createHmac("sha256", drainSecret)
.update(timestamp + "." + body)
.digest("hex");
const given = request.headers.get("x-polymorfa-signature") ?? "";
if (given.length !== expected.length ||
!timingSafeEqual(Buffer.from(given), Buffer.from(expected))) {
return new Response(null, { status: 401 });
}
// Take the delivery ID from the signed body, not a header. NDJSON
// carries it on every line; retries keep it, so store once.
const ndjson = request.headers.get("content-type")?.startsWith("application/x-ndjson");
const envelope = JSON.parse(ndjson ? body.toString().split("\n")[0] : body.toString());
await warehouse.insertOnce(envelope.deliveryId, body);
return new Response(null, { status: 204 });
}API surface
The delivery contract.
Set drains up in the Console. Every delivery reaches your endpoint with these headers and one of these bodies.
Request
- POST
https:/One HTTPS POST per delivery, 10 s timeout/ your-endpoint - Header
X-Polymorfa-TimestampUnix seconds of this attempt - Header
X-Polymorfa-Signaturesha256=HMAC(timestamp + "." + body) - Header
Idempotency-KeyThe delivery ID, the same on every retry
Bodies
- Body
application/{ version, deliveryId, records }json - Body
application/One line of { version, deliveryId, record }x-ndjson
Pull instead
- GET
/Metrics for your collectorplatform/ analytics/ metrics - GET
/Request logs, with logs:readplatform/ projects/ {projectId}/ request-logs
Start with a free number
Your first real number is free. Add more numbers on Pay-As-You-Go.