Management API
Webhooks
9 min
introduction the toro management api offers webhooks to notify you in real time when certain events happen in your account at their core they are just a post request to a pre determined endpoint the endpoint can be whatever you want, and you can register them through our api for example, if you receive webhooks from acme inc , you can structure your url like https //www example com/acme/webhooks/ the way to indicate that a webhook has been processed is by returning a 2xx (status code 200 299) response to the webhook message within a reasonable time frame (15s) it's also important to disable csrf protection for this endpoint if the framework you use enables them by default another important aspect of handling webhooks is to verify the signature and timestamp when processing them you can learn more about it in the signature verification section event catalog our webhooks functionality is still in early development we intend to support more event types in due course if there are any event types you'd like us to prioritise, please feel free to let us know true 186,100 unhandled content type unhandled content type unhandled content type unhandled content type creating an endpoint in order to start listening to events, you will need to register your endpoint through our api as below curl request post \\ \ url https //mgmt api torogateway dev/v1/webhook endpoints \\ \ header 'api key \<key>' \\ \ header 'content type application/json' \\ \ data '{ "name" "my wonderful webhook endpoint", "url" "https //www example com/toro/webhooks", "event types" \[ "receipt created" ] }'{ "id" "whe cbe36c6a645512bda96f99", "name" "my wonderful webhook endpoint", "url" "https //www example com/toro/webhooks", "event types" \[ "receipt created" ], "is active" true, "provider" "svix", "provider endpoint id" "ep 2zs3zvclk4pbid9hfi1eeakfagnzm", "provider customer id" "app 2zdooagnuo5l1mom2jaqlvfbyvu", "signing secret" "whsec yhg131zhbvrycgrjdmr8aym23wcdnda6mc+a9z6leqs=", "created at" "2025 07 14t16 16 55 302003", "updated at" "2025 07 14t16 16 55 302003" } testing endpoints once you've added an endpoint, you'll want to make sure its working the easiest way to do this is by creating a dashboard session, which can then be accessed through the browser where you can send test events to your api on demand curl request post \\ \ url https //mgmt api torogateway dev/v1/webhook endpoints/dashboard sessions \\ \ header 'api key \<key>' \\ }'{ "token" "testsk app yourtoken", "url" "https //app svix com/login?readonly=true#key=yourtoken" } you should see the endpoint you just created under "endpoints" on the dashboard dashboard endpoints list you can then click on your endpoint and go to the "testing" tab endpoint testing screen from here, select the event type you want to test out and press the "send example" button message attempts you should now see that a "message attempt" has been created, which you can retry as needed until it has been successfully delivered (your api has responded with a 2xx status code) signature verification webhook signatures let you verify that webhook messages are actually sent by us and not a malicious actor for a more detailed explanation, check out this article on https //docs svix com/receiving/verifying payloads/why our webhook partner svix offers a set of useful libraries that make verifying webhooks very simple here is a an example using javascript import { webhook } from "svix"; const secret = process env webhook secret // this was in the response when you created the endpoint // these were all sent from the server const headers = { "svix id" "msg p5jxn8aqm9lwm0d4lokwxjek", "svix timestamp" "1614265330", "svix signature" "v1,g0hm9sse+otpjtgt/tmiktsyzle3ufjelvlniolj1oe=", }; const payload = '{"test" 2432232314}'; const wh = new webhook(secret); // throws on error, returns the verified content on success const payload = wh verify(payload, headers); for more instructions and examples of how to verify signatures, check out their https //docs svix com/receiving/verifying payloads/how retries we attempts to deliver each webhook message based on a retry schedule with exponential backoff the schedule each message is attempted based on the following schedule, where each period is started following the failure of the preceding attempt immediately 5 seconds 5 minutes 30 minutes 2 hours 5 hours 10 hours 10 hours (in addition to the previous) if an endpoint is removed or disabled delivery attempts to the endpoint will be disabled as well for example, an attempt that fails three times before eventually succeeding will be delivered roughly 35 minutes and 5 seconds following the first attempt manual retries you can also use the application portal to manually retry each message at any time, or automatically retry ("recover") all failed messages starting from a given date troubleshooting there are some common reasons why your webhook endpoint is failing 1 not using the raw payload body this is the most common issue when generating the signed content, we use the raw string body of the message payload if you convert json payloads into strings using methods like stringify, different implementations may produce different string representations of the json object, which can lead to discrepancies when verifying the signature it's crucial to verify the payload exactly as it was sent, byte for byte or string for string, to ensure accurate verification 2 missing the secret key from time to time we see people simple using the wrong secret key remember that keys are unique to endpoints 3 sending the wrong response codes when we receive a response with a 2xx status code, we interpret that as a successful delivery even if you indicate a failure in the response payload make sure to use the right response status codes so we know when message are supposed to succeed vs fail 4 responses timing out we will consider any message that fails to send a response within 15s a failed message if your endpoint is also processing complicated workflows, it may timeout and result in failed messages we suggest having your endpoint simply receive the message and add it to a queue to be processed asynchronously so you can respond promptly and avoiding getting timed out
