Open zmoog opened 1 year ago
Toggl sends a ping HTTP request to validate the endpoin;: here is an example:
Headers
Host: enoee7ejthhcr.x.pipedream.net
X-Amzn-Trace-Id: Root=1-63cbba4f-5facd01376c5856720b4efa4
Content-Length: 351
content-type: application/json
x-webhook-signature-256: sha256=8631c55075f1c7c9a
accept-encoding: gzip
user-agent: Go-http-client/2.0
Body
{
"event_id": 0,
"created_at": "2023-01-21T10:11:27.53461377Z",
"creator_id": 2621333,
"metadata": {
"request_type": "POST",
"event_user_id": 2621333
},
"payload": "ping",
"subscription_id": 8,
"validation_code": "0f0d7013",
"validation_code_url": "https://track.toggl.com/webhooks/api/v1/validate/118/4438/0f0"
}
Next step is URL Endpoint Validation.
We have two validation options:
In he synchronous validation option the target HTTP endpoint is responsible to return back a response with {"validation_code": "<validation_code>"}
using the same validation_code
value sent in the ping request.
In the asynchronous option, we can send a simple GET
request to a dedicated validate endpoint. If the endpoint answers with OK
the validation is complete.
I can continue using requestbin.com to test the webhooks before writing any code.
The plan is:
I registered to https://requestbin.com and created a private bin for this exploration.
Customize the JS step to return the validation_code
sent in the HTTP request:
// To return a custom HTTP response, use $.respond() [requires HTTP trigger]
export default defineComponent({
async run({ steps, $ }) {
await $.respond({
status: 200,
headers: {
"content-type": "application/json"
},
body: JSON.stringify({
"validation_code": steps.trigger.event.body.validation_code
}),
})
},
})
Trying to send the sample payload I collected before:
curl -H "Content-Type: application/json" -X POST -d '{ "event_id": 0, "created_at": "2023-01-21T10:11:27.53461377Z", "creator_id": 456, "metadata": { "request_type": "POST", "event_user_id": 456 }, "payload": "ping", "subscription_id": 8, "validation_code": "0f0d7013", "validation_code_url": "https://track.toggl.com/webhooks/api/v1/validate/118/4438/0f0" }' https://eo4sf6wa6nmc4w.m.pipedream.net
{"validation_code":"0f0d7013"}%
Voilà, we are ready to go to the next step.
Created a new webhook to forward the events to the request bin:
Started a new time entry:
{
"event_id": 6680087045722268,
"created_at": "2023-01-22T06:12:22.929Z",
"creator_id": 456,
"metadata": {
"action": "created",
"event_user_id": "456",
"model": "time_entry",
"model_owner_id": "456",
"path": "/api/v9/time_entries",
"project_id": "789",
"project_is_private": "true",
"request_body": "{\"created_with\":\"Snowball\",\"pid\":789,\"tid\":null,\"billable\":false,\"description\":\"toggl bridge\",\"tags\":[],\"wid\":987,\"at\":\"2023-01-22T06:12:22.382Z\",\"start\":\"2023-01-22T06:12:22.000Z\",\"duration\":-1674367942}",
"request_type": "POST",
"time_entry_id": "123",
"workspace_id": "987"
},
"payload": {
"at": "2023-01-22T06:12:22+00:00",
"billable": false,
"description": "toggl bridge",
"duration": -1674367942,
"duronly": true,
"id": 123,
"pid": 789,
"project_id": 789,
"server_deleted_at": null,
"start": "2023-01-22T06:12:22Z",
"stop": null,
"tag_ids": null,
"tags": [],
"task_id": null,
"uid": 456,
"user_id": 456,
"wid": 987,
"workspace_id": 987
},
"subscription_id": 4438
}
Stopped a running time entry:
{
"event_id": 6680126864605492,
"created_at": "2023-01-22T06:17:23.879Z",
"creator_id": 456,
"metadata": {
"action": "updated",
"event_user_id": "456",
"model": "time_entry",
"model_owner_id": "456",
"path": "/api/v9/time_entries/123",
"project_id": "789",
"project_is_private": "true",
"request_body": "{\"id\":123,\"billable\":false,\"start\":\"2023-01-22T06:12:22.000Z\",\"stop\":\"2023-01-22T06:17:23.000Z\",\"duration\":301,\"description\":\"toggl bridge\",\"tags\":[],\"duronly\":true,\"at\":\"2023-01-22T06:12:22.775281Z\",\"server_deleted_at\":null,\"user_id\":456,\"uid\":456,\"wid\":987,\"pid\":789,\"groupBy\":\"2023-01-22\"}",
"request_type": "PUT",
"time_entry_id": "123",
"workspace_id": "987"
},
"payload": {
"at": "2023-01-22T06:17:23+00:00",
"billable": false,
"description": "toggl bridge",
"duration": 301,
"duronly": true,
"id": 123,
"pid": 789,
"project_id": 789,
"server_deleted_at": null,
"start": "2023-01-22T06:12:22Z",
"stop": "2023-01-22T06:17:23Z",
"tag_ids": null,
"tags": [],
"task_id": null,
"uid": 456,
"user_id": 456,
"wid": 987,
"workspace_id": 987
},
"subscription_id": 4438
}
Adding an example for deleting a time entry:
{
"event_id": 6680092444081150,
"created_at": "2023-01-22T06:32:18.509Z",
"creator_id": 123,
"metadata": {
"action": "deleted",
"event_user_id": "123",
"model": "time_entry",
"model_owner_id": "123",
"path": "/api/v9/time_entries/789",
"request_type": "DELETE",
"time_entry_id": "789",
"workspace_id": "456"
},
"payload": {
"at": "2023-01-22T06:31:59+00:00",
"billable": false,
"description": "test",
"duration": 2700,
"duronly": true,
"id": 789,
"project_id": null,
"server_deleted_at": null,
"start": "2023-01-21T06:15:00+00:00",
"stop": "2023-01-21T07:00:00+00:00",
"tag_ids": null,
"tags": null,
"task_id": null,
"user_id": 123,
"workspace_id": 456
},
"subscription_id": 4438
}
Research how Toggl webhooks work to build a bridge. The end goal is to collect data to run analytics on my peculiar way to use time tracking.
Starting point: https://developers.track.toggl.com/docs/webhooks_start