# Datoka Hooks — public self-service beta Public UI: / — public agent MCP endpoint: /mcp (Streamable HTTP). No invitation, payment card or manual approval is required. No billing is enabled. Beta quota: 100 new events/day UTC and 20 pending deliveries per public account. Body limit 65536 bytes. ## Register POST /v1/public/register with JSON {"target":"https://your-domain.com/webhook","recoveryKey":"YOUR_RANDOM_SECRET_64_HEX_CHARACTERS"}. Generate recoveryKey with a secure random generator. Keep it private. Repeat the same recoveryKey and target if the registration response is lost. Save the response privately: hookId, scope, token, managementToken, deliverySecret, recoveryKey, challengeUrl and challenge. Replaying registration returns the ORIGINAL response, not a token subsequently rotated. managementToken remains your recovery/admin credential. ## Prove control of the receiver Publish a text file at the exact returned challengeUrl, containing only the returned challenge. Hooks fetches that well-known path over HTTPS, without your access tokens and without following redirects. POST /v1/public/hooks/{hookId}/verify with Authorization: Bearer MANAGEMENT_TOKEN. No deliveries are admitted before verification. Public DNS with at least one public IPv4 is required; IP literals, local/private names, alternate ports and redirects are rejected. GET /v1/public/hooks/{hookId}/status with the management token to inspect status. ## Send and inspect POST /v1/hooks/{hookId}/events with Authorization: Bearer TOKEN, Content-Type: application/json and X-Datoka-Event-Id: your-stable-id. Send the exact payload bytes. HTTP 202 means accepted with an observation, not delivered. Read GET /v1/hooks/{hookId}/deliveries/{deliveryId} with the same token. On a lost response, reuse exactly the same event ID, content type and bytes. Conflicting bodies give 409; quotas give 429. Receiver: verify HMAC-SHA256 over UTF-8 "datoka.hooks.delivery.v1\n" + timestamp + "\n" + deliveryId + "\n", then raw body bytes, with deliverySecret. Read X-Datoka-Timestamp, X-Datoka-Delivery-Id and X-Datoka-Signature. Enforce a five-minute tolerance and constant-time comparison. Use verifyDelivery from the reference implementation. Deduplicate delivery IDs transactionally before business effects. Return 2xx after durable acceptance. ## Agents Connect to /mcp without a pre-existing account. Tools: register_destination, verify_destination, get_destination_status, revoke_destination, accept_hook_event, get_hook_delivery, verify_hook_receipt. Credential arguments are secrets; never include them in public transcripts or logs. Alternatively connect /v1/hooks/{hookId}/mcp with Authorization: Bearer TOKEN after setup for the three delivery tools. accept_hook_event needs eventId, contentType and canonical standard bodyBase64. The public gateway also needs hookId and token. ## Manage access POST /v1/public/hooks/{hookId}/rotate with the management token returns a new delivery token. Save it immediately. POST /v1/public/hooks/{hookId}/revoke with the management token permanently blocks customer requests. Already accepted work finishes. There is no email account recovery. Preserve the downloaded credentials and recoveryKey. ## Meaning, privacy and limits Signed proofs attest relay observations, not business truth. A delivered state means an HTTP 2xx was observed, not that downstream processing completed. Delivery is not exactly once. Maximum five attempts and a 24-hour queue lifetime. No native Stripe/GitHub ingress signature validation. Payloads and access configuration are encrypted at rest. Active payloads are removed after the signed terminal observation. Backups may retain earlier encrypted payloads for up to seven rotating daily slots. Proofs, hashed event fingerprints and deduplication records are retained; no automatic history purge is enabled. Operator diagnostics are private and contain no raw payloads or destination URLs. Registration throttles use salted IP hashes expiring after one day, not raw IP storage. Registration is limited to three new accesses/hour per IP, 30/hour globally and 2000 registered accesses for this initial beta. Verification is limited to ten attempts/hour per access. HTTPS delivery uses Cloudflare public fetch without private network bindings. DNS is checked before verification and each delivery; DNS is not pinned between the preflight and fetch, and private destination blocking also relies on the Cloudflare public network boundary. Public beta has no contractual availability guarantee or automatic production failover. Core signing keys are published at /public-keys; establish trust separately for independent verification.