{"version":"1.1.0","schema":"https://oneagentaday.com/api/schema.json","agent":{"title":"Webhook Contract Writer","slug":"webhook-contract-writer","date":"2026-09-30","issue":26,"category":"automation","categoryLabel":"Automation","tags":["webhooks","api","automation"],"difficulty":"advanced","runtimes":["Claude","ChatGPT","Cursor"],"excerpt":"Paste a sample webhook body. Get required fields, the idempotency key, retry behavior, and how you will verify the signature.","problem":"A sample payload arrived in a ticket, and the integration is a handler that trusts whatever POST shows up next.","videoUrl":null,"url":"https://oneagentaday.com/agents/webhook-contract-writer","apiUrl":"https://oneagentaday.com/api/agents/webhook-contract-writer.json","promptUrl":"https://oneagentaday.com/agents/webhook-contract-writer/prompt.txt","configUrl":"https://oneagentaday.com/agents/webhook-contract-writer/config.json","configFilename":"webhook-contract.defaults.json","license":"CC-BY-4.0","howItWorks":"A sample payload is not a contract until you decide which fields are required, which field makes a retry harmless, and how you know the body came from the vendor. You paste the sample and the vendor's own words about signatures and retries.\n\nThe signature section is a check you perform: compute the MAC over the raw body with the secret stored in your tool, compare it to the header, and stop if it does not match. It is not a guide to forging a header. The idempotency key is the id the vendor said is stable. A duplicate returns success and does not repeat the side effect.\n\nWrite the handler in that order. If the vendor's docs disagree with the sample, the contract names the disagreement instead of guessing.","steps":[{"name":"Paste one real sample","text":"Use a payload from the vendor's docs or a redacted delivery. Include the headers they document and what they said about retries. Remove any secret."},{"name":"Say what a duplicate must not do","text":"If a retry must not create a second refund, write that down. The contract's idempotency section depends on it."},{"name":"Paste the prompt","text":"You get required fields, the key you will store, the signature check in defensive terms, and the response code for a duplicate."},{"name":"Implement the check before the side effect","text":"Verify the signature on the raw body, then look up the event id, then do the work. The agent describes that order. It does not give you a way to forge a signature."}],"demo":[{"second":0,"label":"The sample","detail":"evt_1844, type refund.requested, order 1844, amount 40. Signature header documented as HMAC-SHA256 of the raw body. Retries for 24 hours."},{"second":8,"label":"Required","detail":"id, type, data.order_id, data.amount, data.currency. created is optional for the side effect."},{"second":16,"label":"Idempotency","detail":"Store evt_1844. A second delivery with the same id returns 200 and does not refund again."},{"second":24,"label":"The check","detail":"Compute HMAC-SHA256 over the raw body with the stored secret and compare to X-Signature. Mismatch is 401 and no side effect. No bypass is described."}],"sampleInput":"Sample POST body from the form vendor, sent to us:\n{\n  \"id\": \"evt_1844\",\n  \"type\": \"refund.requested\",\n  \"created\": \"2026-09-30T10:00:00Z\",\n  \"data\": { \"order_id\": \"1844\", \"amount\": 40, \"currency\": \"eur\" }\n}\nHeaders they document: X-Signature is hex HMAC-SHA256 of the raw body using a signing secret we store. They retry for 24 hours on non-2xx. The id is stable across retries.\nWe must not treat a second delivery as a second refund.\nDo not write a bypass. Write the check we should perform.","prompt":"You write a webhook contract from a sample payload and the vendor notes the human pasted. You describe how to verify a signature. You do not describe how to forge one.\n\nINPUTS\n- Sample body.\n- Documented headers and retry behavior.\n- The side effect a duplicate must not repeat.\n\nRULES\n- Required fields are the ones the side effect needs. Mark the rest optional.\n- The idempotency key is a field they said is stable across retries. If they did not, ask and stop.\n- Signature: say which header, which algorithm they named, and that the MAC is over the raw body using a secret stored on our side. Compare in constant time if you mention comparison. A mismatch means no side effect.\n- Do not provide a bypass, a test secret from a real vendor, or steps to craft a valid signature for someone else's endpoint.\n- Retry behavior is quoted from their notes. If missing, write \"not in the notes.\"\n- Response codes: 2xx only after the event id is stored or recognized. 401 on a bad signature. Say what a duplicate returns.\n\nOUTPUT\n## Required\n## Optional\n## Idempotency\nKey, and what a duplicate returns.\n\n## Verify\nThe check, in order, before the side effect.\n\n## Retries\nFrom their notes, or \"not in the notes.\"\n\n## Out of scope\nForging, bypassing, and anything you refused.","config":"{\n  \"version\": 1,\n  \"verifyBeforeSideEffect\": true,\n  \"duplicateRepeatsSideEffect\": false,\n  \"forgeSignature\": false\n}\n"}}