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.
Asynchronous Processing Overview
Asynchronous processing allows you to upload food images and receive immediate responses while the AI analysis happens in the background. This approach provides better user experience for interactive applications and enables you to handle multiple requests efficiently.
How Asynchronous Processing Works
Upload Image — send a POST request with wait_on_process: false (default)
Immediate Response — receive a response with status: "pending" or status: "processing", and a record_id
Background Processing — AI models analyze the image (typically 4–30 seconds)
Get Results — receive webhook notification with an analysis report when finished
Getting Results
Webhooks
Configure a webhook URL to receive real-time notifications when analysis completes:
Request:
{
"body" : "base64-encoded-image-data" ,
"include_ingredients" : true ,
"include_nutri_score" : true ,
"wait_on_process" : false
}
Immediate Response:
{
"record_id" : "6ba7b810-9dad-11d1-80b4-00c04fd430c8" ,
"status" : "processing" ,
"uploaded_at" : "2025-09-15T10:30:04.521Z"
}
Webhook Notification (when analysis completes):
{
"application_user_id" : "end_user_id1" ,
"record_id" : "6ba7b810-9dad-11d1-80b4-00c04fd430c8" ,
"status" : "completed" ,
"dish_name" : "grilled chicken caesar salad" ,
"dish_description" : "chicken breast, grilled with romaine lettuce, parmesan cheese, and caesar dressing" ,
"nutri_score" : "B" ,
"serving_size" : 275 ,
"unit" : "g" ,
"nutritional_fields" : {
"energy_kcal" : 292 ,
"protein_g" : 42.2 ,
"fat_total_g" : 10.9 ,
"carbohydrate_g" : 4.3 ,
"fiber_total_dietary_g" : 2.1
},
"ingredients" : [
{
"name" : "chicken breast, grilled" ,
"serving_size" : 150.0 ,
"unit" : "g" ,
"nutritional_fields" : {
"energy_kcal" : 165 ,
"protein_g" : 31 ,
"fat_total_g" : 3.6 ,
"carbohydrate_g" : 0 ,
"fiber_total_dietary_g" : 0
}
}
],
"uploaded_at" : "2025-09-15T10:30:04.521Z" ,
"modified_at" : "2025-09-15T10:30:12.132Z" ,
"consumed_at" : "2025-09-15T10:30:04Z"
}
Alternative: Manual Checking
If webhooks are not available in your environment, you can check the status using the GET /nutrition_records/{id} endpoint:
GET /nutrition_records/6ba7b810-9dad-11d1-80b4-00c04fd430c8
Webhook Configuration
Setup
Configure your webhook URL through the admin console . Your endpoint must:
Respond with HTTP 200 to acknowledge receipt
Handle POST requests with JSON payloads
Verify HMAC signatures for security
If requests fail, the system retries up to 10 times with exponential backoff.
Security
All webhook requests include HMAC SHA256 signature verification:
Header — x-body-signature contains the hex-encoded HMAC signature
Key — uses your application’s webhook signature key (configured in the admin console)
Algorithm — HMAC-SHA256(webhook_signature_key, request_body)
See Webhook Signature for more details.
Status Handling
Your webhook handler should handle different status values. For complete status definitions, see Processing Status .
When status is failed, check the failure_reason field for specific details about what prevented successful analysis.
Best Practices
1. Webhook Implementation
Respond quickly — always respond with HTTP 200 immediately, then process data asynchronously
Validate signatures — always verify the HMAC signature before processing webhook data
Handle failures gracefully — check the status field and handle both success and failure cases
Implement idempotency — use the record_id to avoid processing the same webhook multiple times
2. Error Handling
Handle webhook delivery failures gracefully
Store webhook secrets securely and never commit them to version control
Implement retry logic for critical webhook processing
3. User Experience
Show immediate feedback when the image is uploaded (“Analysis in progress…”)
Provide loading indicators during the processing window
Handle both success and failure states in your UI
Use Cases
Asynchronous processing is ideal for:
Mobile applications — immediate feedback while processing happens in the background
Web applications — non-blocking user interfaces with real-time updates
High-volume scenarios — process multiple images concurrently
User-facing tools — food logging apps, dietary tracking applications
Implementation Examples
[Go]
[JavaScript]
[Python]
[PHP]
package main
import (
" crypto/hmac "
" crypto/sha256 "
" encoding/hex "
" encoding/json "
" fmt "
" io "
" net/http "
" time "
)
const webhookSignatureKey = "YOUR_WEBHOOK_SECRET_FROM_ADMIN_CONSOLE"
// NutritionRecord represents the webhook payload structure
type NutritionRecord struct {
ApplicationID int64 `json:"application_id"`
UID string `json:"uid"`
RecordID string `json:"record_id"`
Status string `json:"status"`
DishName string `json:"dish_name"`
NutriScore string `json:"nutri_score"`
UploadedAt time . Time `json:"uploaded_at"`
ModifiedAt time . Time `json:"modified_at"`
// Add other fields as needed
}
func main () {
http . HandleFunc ( "/nutrition-webhook" , 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 the request body
body , err := io . ReadAll ( r . Body )
if err != nil {
http . Error ( w , "Failed to read body" , http . StatusInternalServerError )
return
}
// Calculate and verify HMAC
hm := hmac . New ( sha256 . New , [] byte ( webhookSignatureKey ))
hm . Write ( body )
expectedSignature := hex . EncodeToString ( hm . Sum ( nil ))
if signature != expectedSignature {
http . Error ( w , "Invalid signature" , http . StatusUnauthorized )
return
}
// Parse nutrition record
var record NutritionRecord
if err := json . Unmarshal ( body , & record ); err != nil {
http . Error ( w , "Invalid JSON" , http . StatusBadRequest )
return
}
// Process the nutrition record
fmt . Printf ( "Received nutrition analysis: %s for user %s \n " , record . Status , record . UID )
if record . Status == "completed" {
fmt . Printf ( "Dish: %s , Nutri-Score: %s \n " , record . DishName , record . NutriScore )
// Update your application with the results
} else if record . Status == "failed" {
fmt . Printf ( "Analysis failed for record %s \n " , record . RecordID )
// Handle failure case
}
// Respond with success
w . WriteHeader ( http . StatusOK )
w . Write ([] byte ( "OK" ))
})
fmt . Println ( "Starting nutrition webhook server on port 8000" )
http . ListenAndServe ( ":8000" , nil )
}
For complete API specifications and additional configuration options, see the Implementation Guide .