Documentation Index Fetch the complete documentation index at: https://docs.spikeapi.com/llms.txt
Use this file to discover all available pages before exploring further.
Your endpoint must respond with HTTP 200 to acknowledge a successful receipt. If the request fails due to a network error, exceeds 30 seconds to complete or returns any status code other than 200, the system will retry the request up to 10 times with exponential backoff.
Retries are timed at first after 5 sec, then 2 min, 30 min, 2 hours and then the rest every 12 hours. After the final attempt, the event will be discarded.
Webhook event Payload
application_user_id The application user ID you’ve provided when getting the access token
timestamp Time of the event
event_type
record_change new or updated data received from the provider
provider_integration_created user has integrated with a provider
provider_integration_deleted user integration has been deleted
metrics metric types involved with the event
activity_types activity types if any involved with the event
provider_slug provider triggering the event
earliest_record_start_at earliest timestamp of records involved with the event in ISO 8601 format
latest_record_end_at latest timestamp of records involved with the event in ISO 8601 format
Example Payload
[
{
"application_user_id" : "User1" ,
"timestamp" : "2025-04-15T13:33:55.271331177Z" ,
"event_type" : "record_change" ,
"metrics" : [ "calories_burned_active" , "distance" , "steps" ],
"activity_types" : [ "sedentary" , "walking" ],
"provider_slug" : "garmin" ,
"earliest_record_start_at" : "2025-04-15T09:30:00Z" ,
"latest_record_end_at" : "2025-04-15T13:33:00Z"
},
{
"application_user_id" : "User2" ,
"timestamp" : "2025-04-15T13:33:55.271331177Z" ,
"event_type" : "record_change" ,
"metrics" : [ "calories_burned_active" ],
"activity_types" : [ "walking" ],
"provider_slug" : "garmin" ,
"earliest_record_start_at" : "2025-04-15T09:30:00Z" ,
"latest_record_end_at" : "2025-04-15T13:33:00Z"
}
]
provider_integration_created
[
{
"application_user_id" : "test" ,
"timestamp" : "2025-08-29T13:21:10.703300387Z" ,
"event_type" : "provider_integration_created" ,
"provider_slug" : "oura"
}
]
Signature
Each webhook event is signed using an HMAC-SHA256 signature for verification. The signature is included in the X-Body-Signature header.
The signature is computed by signing the raw request body as-is using a shared secret key. You can retrieve this key from the admin console.
To verify authenticity:
Compute the HMAC-SHA256 hash of the request body using the shared key.
Compare the result to the value in the X-Body-Signature header.
Code Examples
[Go]
[JavaScript]
[PHP]
[Python]
[TypeScript]
package main
import (
" crypto/hmac "
" crypto/sha256 "
" encoding/hex "
" encoding/json "
" fmt "
" io "
" net/http "
" time "
)
// PushEvent represents a webhook event from the health data provider
const hmacKey = "HMAC_KEY_FROM_ADMIN_CONSOLE"
type PushEvent struct {
ApplicationUserID string `json:"application_user_id"` // ID of the application user
Timestamp time . Time `json:"timestamp"` // Event timestamp
EventType string `json:"event_type"` // Type of event
Metrics [] string `json:"metrics"` // List of metrics
ActivityTypes [] string `json:"activity_types"` // List of activity types
ProviderSlug string `json:"provider_slug"` // Provider identifier
EarliestRecordStartAt time . Time `json:"earliest_record_start_at"` // Start of data range
LatestRecordEndAt time . Time `json:"latest_record_end_at"` // End of data range
}
func main () {
http . HandleFunc ( "/" , func ( w http . ResponseWriter , r * http . Request ) {
// Verify HMAC signature
signature := r . Header . Get ( "X-Body-Signature" )
if signature == "" {
http . Error ( w , "Missing signature" , http . StatusBadRequest )
return
}
// Read and verify the request body
body , err := io . ReadAll ( r . Body )
if err != nil {
http . Error ( w , "Failed to read body" , http . StatusInternalServerError )
return
}
// Calculate HMAC
hm := hmac . New ( sha256 . New , [] byte ( hmacKey ))
hm . Write ( body )
if signature != hex . EncodeToString ( hm . Sum ( nil )) {
http . Error ( w , "Invalid signature" , http . StatusUnauthorized )
return
}
// Parse events
var events [] PushEvent
if err := json . Unmarshal ( body , & events ); err != nil {
http . Error ( w , "Invalid JSON" , http . StatusBadRequest )
return
}
// Process events
for _ , event := range events {
fmt . Printf ( "Received event: %+v \n " , event )
}
w . WriteHeader ( http . StatusOK )
w . Write ([] byte ( "OK" ))
})
fmt . Println ( "Starting server on port 8000" )
http . ListenAndServe ( ":8000" , nil )
}