Skip to main content

POST /poll/events

Drains pending invoice-state-change events for the authenticated owner. Each call returns events queued since the last successful drain — once consumed, events are removed from the queue. Suitable for serverless cron jobs and any client that can't hold a long-lived WebSocket open.

Request

POST /poll/events
x-session-nonce: <millisecond timestamp>
x-session-signature: <EIP-191 sig over sess:{nonce}:{sha256("")}>

The body is empty. The session signature alone identifies the owner — no ownerAddress field is required.

Response

200 OK

{
"ownerAddress": "0xMerchantAddress…",
"events": [
{
"guid": "29f3b386-7c4a-4f6e-9d2b-1a8e3c5f7d09",
"createdAt": 1730393820,
"deadline": 1730480220,
"status": "paid",
"value": "100",
"token": "1:0xdac17f958d2ee523a2206206994597c13d831ec7",
"chainId": 1,
"data": { "description": "Hosting plan XLarge", "sku": "XL-2024" },
"description": "Hosting plan XLarge",
"address": "0x1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b",
"owner": "0xMerchantAddress…",
"paidAmount": "100",
"payments": [
{
"txHash": "0x4d5e6f…2d3e4f",
"logIndex": 0,
"chainId": "1",
"token": "0xdac17f958d2ee523a2206206994597c13d831ec7",
"from": "0xfeedbeef…0000beef",
"amount": "100",
"vsValue": 100.0,
"timestamp": 1730393900
}
],
"acceptedTokens": ["1:0xdac17f958d2ee523a2206206994597c13d831ec7"]
}
]
}

Each event is the full Invoice record at the time of the change. There's no separate "delta" payload: compare status against your locally stored copy to decide what changed.

Examples

import { Wallet, sha256 } from 'ethers';

const SESSION_PRIVATE_KEY = '0x...';
const nonce = Date.now();
const hash = sha256('0x').slice(2); // sha256 of empty body
const sig = await new Wallet(SESSION_PRIVATE_KEY)
.signMessage(`sess:${nonce}:${hash}`);

const r = await fetch('https://api.feemaker.io/poll/events', {
method: 'POST',
headers: {
'x-session-nonce': String(nonce),
'x-session-signature': sig,
'x-encryption': 'none',
},
});
const { events } = await r.json();

Polling cadence

The server holds events in-memory per session key — there's no long-poll window. Drive the loop yourself; once every 2–5 seconds is the recommended range for active payment flows. Idle merchants can poll less often without losing events: each event is stored until consumed, capped by the operator's configured retention.

Legacy bearer-token flow

A separate path exists for older Telegram-bot-style integrations that registered an opaque token via POST /poll/register. Those clients omit session headers and pass ownerAddress + token in the JSON body instead. Modern integrations should use the session-key flow above.