{"ok":true,"tool":"webhook-attempt-meter","module_version":"0.1.0","result":{"slug":"webhook-attempt-meter","name":"Webhook Attempt Meter","version":"0.1.0","category":"ephemeral","status":"beta","mode":"ephemeral","summary":"Create a bounded webhook endpoint and retrieve attempt metadata once.","description":"Creates an unguessable temporary endpoint that accepts up to ten POST, PUT, or PATCH attempts. It records timestamps, methods, byte counts, and hashes only; bodies, raw user agents, source IPs, arbitrary headers, and response customization are never stored. Retrieval atomically consumes the meter.","when_to_use":["A webhook sender's attempt count, timing, method, and payload hash must be observed.","A short-lived callback URL with one-time result retrieval is sufficient."],"do_not_use_when":["Webhook bodies, source IPs, raw headers, or production traffic must be retained.","More than ten attempts, 64 KiB per body, or 30 minutes is required."],"tested_with":["HTTP POST","HTTP PUT","HTTP PATCH","parallel attempts"],"input_schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","oneOf":[{"type":"object","properties":{"ttl_seconds":{"type":"integer","minimum":60,"maximum":1800},"max_attempts":{"type":"integer","minimum":1,"maximum":10},"action":{"type":"string","const":"create"}},"required":["ttl_seconds","max_attempts","action"],"additionalProperties":false},{"type":"object","properties":{"retrieval_token":{"type":"string","pattern":"^wamr_[A-Za-z0-9_-]{43}$"},"action":{"type":"string","const":"retrieve"}},"required":["retrieval_token","action"],"additionalProperties":false}]},"output_schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","oneOf":[{"type":"object","properties":{"action":{"type":"string","const":"create"},"meter_url":{"type":"string","format":"uri"},"retrieval_token":{"type":"string"},"created_at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"expires_at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"max_attempts":{"type":"integer","minimum":1,"maximum":10},"capability_entropy_bits":{"type":"number","const":256}},"required":["action","meter_url","retrieval_token","created_at","expires_at","max_attempts","capability_entropy_bits"],"additionalProperties":false},{"type":"object","properties":{"action":{"type":"string","const":"retrieve"},"found":{"type":"boolean"},"attempts":{"maxItems":10,"type":"array","items":{"type":"object","properties":{"observed_at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"method":{"type":"string","enum":["POST","PUT","PATCH"]},"body_bytes":{"type":"integer","minimum":0,"maximum":65536},"body_sha256":{"type":"string","pattern":"^sha256:[a-f0-9]{64}$"},"content_type":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}]},"user_agent_sha256":{"anyOf":[{"type":"string","pattern":"^sha256:[a-f0-9]{64}$"},{"type":"null"}]}},"required":["observed_at","method","body_bytes","body_sha256","content_type","user_agent_sha256"],"additionalProperties":false}},"max_attempts":{"anyOf":[{"type":"integer","minimum":1,"maximum":10},{"type":"null"}]},"exhausted":{"type":"boolean"},"created_at":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"expires_at":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]}},"required":["action","found","attempts","max_attempts","exhausted","created_at","expires_at"],"additionalProperties":false}]},"payment":{"kind":"free"},"side_effects":["Create publishes a temporary unguessable webhook endpoint.","Retrieve irreversibly consumes the meter and disables the endpoint."],"retention":"Derived attempt metadata remains in Valkey for at most 30 minutes and is deleted on first retrieval. Webhook bodies and raw headers are never retained.","limits":{"min_ttl_seconds":60,"max_ttl_seconds":1800,"max_attempts":10,"max_body_bytes":65536,"accepted_methods":"POST,PUT,PATCH","stored_source_ip_bytes":0,"stored_body_bytes":0,"max_client_requests_per_minute":10,"max_global_requests_per_minute":60},"examples":{"input":{"action":"create","ttl_seconds":300,"max_attempts":3},"output":{"action":"create","meter_url":"https://lab.example/v1/webhook-meters/wam_example","retrieval_token":"wamr_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","created_at":"2026-07-25T00:00:00.000Z","expires_at":"2026-07-25T00:05:00.000Z","max_attempts":3,"capability_entropy_bits":256},"negative":[{"scenario":"Webhook bodies, source IPs, raw headers, or production traffic must be retained.","expected_error":"INVALID_INPUT","charged":false}]},"execution":{"errors":[{"code":"INVALID_INPUT","retryable":false,"charged":false,"recovery":"Correct the request to match input_schema."},{"code":"TOOL_PAUSED","retryable":true,"charged":false,"recovery":"Wait for the operator to resume the tool."},{"code":"RATE_LIMITED","retryable":true,"charged":false,"recovery":"Retry after the response Retry-After interval."},{"code":"DEPENDENCY_UNAVAILABLE","retryable":true,"charged":false,"recovery":"Retry with the same idempotency identity."}],"idempotency":{"required":true,"mock_or_unpaid_header":"Idempotency-Key","x402_extension":null,"replay_retention":"up to 24 hours"}},"endpoints":{"describe":"/v1/tools/webhook-attempt-meter","execute":"/v1/tools/webhook-attempt-meter"}},"meta":{"request_id":"req_2cdb037bf12540649f8816a67ce5e09a","observed_at":"2026-07-25T08:29:19.945Z"}}