Meal Tracking
Learn how to track meals and food items to award PlanetPoints for sustainable food choices.
Overview
Food tracking enables users to earn PlanetPoints by logging their meals and food consumption. When a user tracks food through your app, you send the data to Reewild for carbon and health scoring, and points are awarded based on the environmental and nutritional impact.
There are two tracking endpoints:
- Meal Tracking (
/track/meals) - For logging meals with multiple ingredients - Food Tracking (
/track/food) - For logging single food items
| Scenario | Endpoint |
|---|---|
| Single snack or packaged product | /track/food |
| Recipe or homemade meal | /track/meals |
| Packaged combo meal | /track/meals |
| Multiple items from different merchants | /track/meals |
Both endpoints accept data asynchronously and return results via webhooks.
Meal Tracking
Use this endpoint when users log a meal containing multiple food items.
Endpoint: POST /track/meals
Headers:
| Header | Value |
|---|---|
Content-Type | application/json |
x-client-id | Your client ID |
x-client-secret | Your client secret |
Query Parameters:
| Parameter | Required | Description |
|---|---|---|
api-version | Yes | API version (e.g., 1.0) |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
userId | String | Yes | User's Reewild ID |
transactionId | String | Yes | Your unique transaction reference |
mealName | String | Yes | Name of the meal |
imageUrl | String | Yes | Image URL of the meal |
loggedAt | String (ISO 8601) | Yes | When the meal was logged |
mealType | String | Yes | breakfast, lunch, dinner, snack, or other |
country | String | No | ISO country code |
location | String | No | Free-text location |
metadata | Object | No | Optional metadata |
ingredients | Array | No | Array of ingredient objects |
Ingredient Object
| Field | Type | Required | Description |
|---|---|---|---|
foodId | String | Yes | Unique ID of the food item |
name | String | Yes | Name of the food item |
imageUrl | String | No | Image URL of the food |
merchant | Object | No | Merchant details |
weight | Number | No | Weight of the food |
unit | String | No | Unit of measure (e.g., g, ml) |
quantity | Number | No | Quantity (default: 1) |
amount | Number | No | Monetary value (default: £1) |
currency | String | No | Currency code (required if amount provided) |
nutrition | Object | No | Nutritional information |
Merchant Object
| Field | Type | Required | Description |
|---|---|---|---|
name | String | No | Merchant name |
logo | String | No | Logo URL |
website | String | No | Merchant website |
domain | String | No | Merchant domain |
country | String | No | Merchant country |
Nutrition Object
| Field | Type | Description |
|---|---|---|
energyKcal | Number | Calories |
proteinG | Number | Protein in grams |
carbsG | Number | Carbohydrates in grams |
fatG | Number | Fat in grams |
sugarG | Number | Sugar in grams |
fiberG | Number | Fiber in grams |
saltG | Number | Salt in grams |
Example Request
{
"userId": "08FE9Q",
"transactionId": "meal-20251126-002",
"mealName": "Avocado Quinoa Bowl",
"imageUrl": "https://example.com/images/meals/avocado-quinoa-bowl.jpg",
"loggedAt": "2025-11-26T19:40:00Z",
"mealType": "dinner",
"country": "GBR",
"location": "London, UK",
"metadata": {
"source": "mobile_app",
"appVersion": "4.2.1"
},
"ingredients": [
{
"foodId": "FOOD-221",
"name": "Quinoa",
"imageUrl": "https://example.com/images/foods/quinoa.jpg",
"merchant": {
"name": "Whole Foods",
"domain": "wholefoods.com",
"country": "GBR"
},
"weight": 150,
"unit": "g",
"quantity": 1,
"amount": 2.80,
"currency": "GBP",
"nutrition": {
"energyKcal": 110,
"proteinG": 4,
"carbsG": 20,
"fatG": 2,
"sugarG": 0,
"fiberG": 3,
"saltG": 0
}
},
{
"foodId": "FOOD-874",
"name": "Avocado",
"imageUrl": "https://example.com/images/foods/avocado.jpg",
"merchant": {
"name": "Local Market",
"country": "GBR"
},
"weight": 100,
"unit": "g",
"quantity": 1,
"amount": 3.40,
"currency": "GBP",
"nutrition": {
"energyKcal": 160,
"proteinG": 2,
"carbsG": 9,
"fatG": 15,
"sugarG": 0,
"fiberG": 7,
"saltG": 0
}
}
]
}Response
{
"trackId": "5765279d-0e9b-4f16-b462-0f75d06d0c7a",
"message": "Meal accepted for scoring"
}| Field | Type | Description |
|---|---|---|
trackId | String | Reewild's internal tracking ID |
message | String | Confirmation message |
Response Codes
| Code | Description |
|---|---|
202 | Meal accepted for processing |
400 | Invalid request parameters |
500 | Internal server error |
Food Tracking
Use this endpoint when users log a single food item.
Endpoint: POST /track/food
Headers:
| Header | Value |
|---|---|
Content-Type | application/json |
x-client-id | Your client ID |
x-client-secret | Your client secret |
Query Parameters:
| Parameter | Required | Description |
|---|---|---|
api-version | Yes | API version (e.g., 1.0) |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
userId | String | Yes | User's Reewild ID |
transactionId | String | Yes | Your unique transaction reference |
foodId | String | Yes | Unique ID of the food item |
name | String | Yes | Name of the food item |
imageUrl | String | Yes | Image URL of the food |
merchant | Object | Yes | Merchant details |
weight | Number | Yes | Weight of the food |
unit | String | Yes | Unit of measure |
nutrition | Object | Yes | Nutritional information |
quantity | Number | No | Quantity (default: 1) |
amount | Number | No | Monetary value (default: £1) |
currency | String | No | Currency code |
Example Request
{
"userId": "08FE9Q",
"transactionId": "food-20251126-038",
"foodId": "FOOD-44521",
"name": "Grilled Chicken Quinoa Bowl",
"imageUrl": "https://example.com/foods/grilled-chicken-quinoa.jpg",
"merchant": {
"name": "Health Kitchen",
"logo": "https://example.com/logos/health-kitchen.png",
"website": "https://www.healthkitchen.co.uk",
"domain": "healthkitchen.co.uk",
"country": "GBR"
},
"weight": 420,
"unit": "g",
"quantity": 1,
"amount": 8.40,
"currency": "GBP",
"nutrition": {
"energyKcal": 610,
"proteinG": 38,
"carbsG": 54,
"fatG": 22,
"sugarG": 5,
"fiberG": 8,
"saltG": 1.1
}
}Response
{
"trackId": "5765279d-0e9b-4f16-b462-0f75d06d0c7a",
"message": "Food accepted for scoring"
}Response Codes
| Code | Description |
|---|---|
202 | Food accepted for processing |
400 | Invalid request parameters |
500 | Internal server error |
Webhook Events
After submitting a meal or food item, Reewild processes the data asynchronously and sends webhook notifications as processing progresses.
| Event | Description |
|---|---|
intake.received | Meal/food payload accepted for processing |
intake.scored | Carbon and health metrics calculated |
intake.completed | PlanetPoints awarded |
intake.failed | Processing failed |
intake.received
Sent when Reewild receives and queues the submission for processing.
{
"event": "intake.received",
"source": "meal",
"transactionId": "meal-20251126-002",
"trackId": "5765279d-0e9b-4f16-b462-0f75d06d0c7a",
"userId": "08FE9Q",
"loggedAt": "2025-11-26T19:45:00Z",
"country": "GBR",
"createdAt": "2025-11-26T19:45:02Z"
}intake.scored
Sent when carbon and health metrics have been calculated.
{
"event": "intake.scored",
"source": "meal",
"transactionId": "meal-20251126-002",
"trackId": "5765279d-0e9b-4f16-b462-0f75d06d0c7a",
"name": "Avocado Quinoa Bowl",
"imageUrl": "https://example.com/images/meals/avocado-quinoa-bowl.jpg",
"userId": "08FE9Q",
"mealType": "dinner",
"ingredients": [
{
"foodId": "FOOD-221",
"name": "Quinoa",
"imageUrl": "https://example.com/images/foods/quinoa.jpg",
"weight": 150,
"unit": "g",
"quantity": 1,
"amount": 2.80,
"currency": "GBP",
"carbonImpactRating": 2,
"healthImpactRating": 1,
"co2e": 0.45
},
{
"foodId": "FOOD-874",
"name": "Avocado",
"imageUrl": "https://example.com/images/foods/avocado.jpg",
"weight": 100,
"unit": "g",
"quantity": 1,
"amount": 3.40,
"currency": "GBP",
"carbonImpactRating": 3,
"healthImpactRating": 2,
"co2e": 0.68
}
],
"loggedAt": "2025-11-26T19:40:00Z",
"country": "GBR",
"totalAmount": 6.20,
"currency": "GBP",
"totalCo2e": 1.13,
"carbonImpactRating": 2,
"healthImpactRating": 1,
"createdAt": "2025-11-26T19:45:20Z"
}intake.completed
Sent when PlanetPoints have been credited.
{
"event": "intake.completed",
"source": "meal",
"transactionId": "meal-20251126-002",
"trackId": "5765279d-0e9b-4f16-b462-0f75d06d0c7a",
"userId": "08FE9Q",
"totalAmount": 6.20,
"currency": "GBP",
"ingredients": [
{
"foodId": "FOOD-221",
"name": "Quinoa",
"imageUrl": "https://example.com/images/foods/quinoa.jpg",
"weight": 150,
"unit": "g",
"quantity": 1,
"amount": 2.80,
"currency": "GBP",
"carbonImpactRating": 2,
"healthImpactRating": 1,
"co2e": 0.45,
"totalPoints": 40,
"totalCarbonPoints": 10,
"totalHealthPoints": 30
},
{
"foodId": "FOOD-874",
"name": "Avocado",
"imageUrl": "https://example.com/images/foods/avocado.jpg",
"weight": 100,
"unit": "g",
"quantity": 1,
"amount": 3.40,
"currency": "GBP",
"carbonImpactRating": 3,
"healthImpactRating": 2,
"co2e": 0.68,
"totalPoints": 22,
"totalHealthPoints": 16,
"totalCarbonPoints": 6
}
],
"totalPoints": 62,
"totalGreenProducts": 2,
"totalHealthyProducts": 2,
"totalCo2e": 1.13,
"totalHealthPoints": 40,
"totalCarbonPoints": 22,
"createdAt": "2025-11-26T19:45:25Z"
}intake.failed
Sent when processing fails.
{
"event": "intake.failed",
"source": "meal",
"transactionId": "meal-20251126-002",
"trackId": "5765279d-0e9b-4f16-b462-0f75d06d0c7a",
"userId": "08FE9Q",
"errorType": "DATA_INCOMPLETE",
"errorMessage": "Missing nutrition.energyKcal for ingredient FOOD-442",
"failedAt": "2025-11-26T19:47:10Z"
}Error types:
| Error Type | Description |
|---|---|
NO_VALID_FOOD_ITEMS | No valid food items found |
OLD_MEAL_LOG | Meal logged outside allowed time window |
DUPLICATE_MEAL | Duplicate transaction ID |
DATA_INCOMPLETE | Required data missing |
INTERNAL_ERROR | Server error |
Impact Ratings
Carbon and health impact ratings use a 1-5 scale:
| Rating | Grade | Meaning |
|---|---|---|
| 1 | A | Best |
| 2 | B | Good |
| 3 | C | Average |
| 4 | D | Below average |
| 5 | E | Worst |
Products rated A or B are counted as "green" (carbon) or "healthy" (health) products.