Hono Pages: Tracking with Hyperdrive
Cloudflare Pages Functions + Hono example for:
- message send via
k-msg(KMsg) - delivery tracking persistence via Hyperdrive (Postgres)
- provider: IWINV
Important
Section titled “Important”- This template currently requires
nodejs_compat. - Reason: the
postgresdriver used for Hyperdrive depends on Node compatibility APIs.
cd examples/hono-pages-tracking-hyperdrivebun installcp .dev.vars.example .dev.varsFill .dev.vars:
IWINV_API_KEY=...IWINV_SMS_API_KEY=...IWINV_SMS_AUTH_KEY=...IWINV_SMS_SENDER_NUMBER=01000000000INTERNAL_CRON_TOKEN=local-cron-tokenINTERNAL_CRON_TOKEN is required for POST /internal/tracking/run-once.
If it is missing or empty, the endpoint returns 500 (misconfigured).
For deployment, set it as a secret:
wrangler secret put INTERNAL_CRON_TOKENHyperdrive binding
Section titled “Hyperdrive binding”Update wrangler.jsonc:
hyperdrive[0].id: your real Hyperdrive IDhyperdrive[0].localConnectionString: local Postgres URL forwrangler pages dev
This template uses postgres (postgres.js) to connect Hyperdrive, so
nodejs_compat is enabled in wrangler.jsonc.
Example local DB URL:
postgres://postgres:postgres@127.0.0.1:5432/kmsg_trackingDeliveryTrackingService.init() will create required tables/indexes automatically.
Tracking schema
Section titled “Tracking schema”Table: kmsg_delivery_tracking
- PK:
message_id - Core:
provider_id,provider_message_id,type,to,from,status - Timing:
requested_at,status_updated_at,next_check_at,sent_at,delivered_at,failed_at,last_checked_at,scheduled_at - Metadata:
attempt_count,provider_status_code,provider_status_message,last_error,raw,metadata
Indexes:
idx_kmsg_delivery_due(status, next_check_at)idx_kmsg_delivery_provider_msg(provider_id, provider_message_id)idx_kmsg_delivery_requested_at(requested_at)
Run local dev
Section titled “Run local dev”bun run devRoutes
Section titled “Routes”POST /send(advanced: rawSendInputsingle/batch)POST /send/smsGET /tracking/:messageIdPOST /internal/tracking/run-once
For batch requests to POST /send, the route always returns 200.
Check per-item success/failure in data.results.
Sample requests
Section titled “Sample requests”Advanced send (single):
curl -X POST http://127.0.0.1:8788/send \ -H "content-type: application/json" \ -d '{ "type":"SMS", "to":"01012345678", "text":"hello from advanced send route", "from":"01000000000", "providerId":"iwinv" }'Advanced send (batch):
curl -X POST http://127.0.0.1:8788/send \ -H "content-type: application/json" \ -d '[ { "type":"SMS", "to":"01012345678", "text":"hello from advanced send route #1", "from":"01000000000", "providerId":"iwinv" }, { "type":"SMS", "to":"01012345679", "text":"hello from advanced send route #2", "from":"01000000000", "providerId":"iwinv" } ]'SMS shortcut send:
curl -X POST http://127.0.0.1:8788/send/sms \ -H "content-type: application/json" \ -d '{ "to":"01012345678", "text":"hello from hyperdrive tracking", "from":"01000000000" }'Get tracking record:
curl http://127.0.0.1:8788/tracking/<MESSAGE_ID>Run one tracking poll pass:
curl -X POST http://127.0.0.1:8788/internal/tracking/run-once \ -H "x-cron-token: local-cron-token"