Rex Nutribot API Integration Guide¶
This guide walks you through integrating your application with the Rex Nutribot API. Follow these steps to get started quickly and efficiently.
Prerequisites¶
- Python 3.7+ (for running tests and examples)
- API key from the Rex Nutribot team
Quick Start¶
1. Get Your API Key¶
Contact the Rex Nutribot team to obtain your API key. You'll receive:
- Development API key for testing
- Production API key for live usage
- Custom domain configuration (if applicable)
2. Set Up Authentication¶
All API requests require Bearer token authentication:
# Or include in your code (less secure)
headers = {
"Authorization": "Bearer REX_API_KEY",
"Content-Type": "application/json"
}
3. Choose Your Environment¶
Development Environment:
- Base URL:
https://api.rex.fit/[org-id]/dev/v1 - Use for testing and development
- Safe to experiment with test data
Production Environment:
- Base URL:
https://api.rex.fit/[org-id]/prod/v1 - Use for live applications
- Real user data and billing
Testing Your Integration¶
1. Set Up Test Environment¶
# Install dependencies
pip install requests
# Set up test configuration
export REX_API_KEY="your_dev_api_key"
export REX_TEST_USER_ID="user_456" # Use a valid test user ID
2. Message Webhook Test Example¶
import json
import unittest
from datetime import datetime
from typing import Any, Dict
import requests
class WebhookTest(unittest.TestCase):
def setUp(self):
self.base_url = "https://api.rex.fit/[org]/dev/v1"
self.webhook_endpoint = f"{self.base_url}/message-webhook"
self.api_key = ""
def send_webhook(self, payload: Dict[str, Any]) -> requests.Response:
"""Helper method to send webhook requests"""
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {self.api_key}",
}
try:
response = requests.post(
self.webhook_endpoint, json=payload, headers=headers
)
print(f"Response status: {response.status_code}")
print(f"Response body: {response.text}")
return response
except requests.RequestException as e:
self.fail(f"Request failed: {str(e)}")
def generate_message_id(self) -> str:
"""Generate a unique message ID using timestamp"""
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S_%f")
return f"msg_test_{timestamp}"
def test_webhook_accepts_valid_message(self):
"""Test that webhook accepts a valid message payload"""
payload = {
"from_id": "user_456",
"message_sid": self.generate_message_id(),
"timestamp": "1672531200",
"message_body": "Hello, this is a test message",
"image_urls": [],
"audio_urls": [],
}
response = self.send_webhook(payload)
self.assertEqual(response.status_code, 200)
def test_webhook_accepts_message_with_image(self):
"""Test that webhook accepts a message with an image"""
payload = {
"from_id": "user_456",
"message_sid": self.generate_message_id(),
"timestamp": "1672531200",
"message_body": "i only ate half of my meal",
"image_urls": [""], #send your own public link/signed url
"audio_urls": [],
}
response = self.send_webhook(payload)
self.assertEqual(response.status_code, 200)
def test_webhook_rejects_missing_required_fields(self):
"""Test that webhook rejects payloads with missing required fields"""
payload = {
"message_sid": self.generate_message_id(),
# Missing from_id
"timestamp": "1672531200",
"message_body": "Test message",
}
response = self.send_webhook(payload)
self.assertEqual(response.status_code, 400)
def test_webhook_rejects_invalid_method(self):
"""Test that webhook rejects non-POST methods"""
response = requests.get(self.webhook_endpoint)
self.assertEqual(response.status_code, 405)
def test_webhook_rejects_invalid_user(self):
"""Test that webhook rejects messages from users not in the database"""
payload = {
"from_id": "nonexistent_user_123", # User ID that doesn't exist in the database
"message_sid": self.generate_message_id(),
"timestamp": "1672531200",
"message_body": "This user shouldn't be able to send messages",
"image_urls": [],
"audio_urls": [],
}
response = self.send_webhook(payload)
self.assertEqual(
response.status_code, 404
)
response_data = response.json()
self.assertIn("error", response_data)
self.assertIn("user not found", response_data["error"].lower())
if __name__ == "__main__":
unittest.main(verbosity=2)
3. User Creation Test Example¶
# Test cases for create_user API endpoint
import requests
def test_create_user():
"""Test cases for user creation API"""
# Test Case 1: Valid user with metric measurements
valid_metric_user = {
"from_id": "user_789",
"first_name": "John",
"last_name": "Doe",
"birthdate": "1990-01-01",
"gender": "male",
"language": "en",
"goal": "lose weight",
"timezone": "Kuwait, Kuwait (UTC+03:00)",
"height_cm": 180,
"weight_kg": 80,
"display_name": "JohnD",
}
# Test Case 2: Valid user with imperial measurements
valid_imperial_user = {
"from_id": "user_101",
"first_name": "Jane",
"last_name": "Smith",
"birthdate": "1995-06-15",
"gender": "female",
"language": "en",
"goal": "lose weight",
"timezone": "New York, USA (UTC-05:00)",
"height_ft": "5'7",
"weight_lbs": 150,
}
# Test Case 3: Invalid - Missing required field
missing_required_field = {
"from_id": "user_789",
"first_name": "Bob",
# missing last_name
"birthdate": "1985-12-31",
"gender": "male",
"language": "en",
"goal": "gain muscle",
"timezone": "Sydney, Australia (UTC+10:00)",
"height_cm": 175,
"weight_kg": 70,
}
# Test Case 4: Invalid - Both measurement systems provided
both_measurement_systems = {
"from_id": "user_101",
"first_name": "Alice",
"last_name": "Johnson",
"birthdate": "1988-03-20",
"gender": "female",
"language": "de",
"goal": "maintain",
"timezone": "Berlin, Germany (UTC+01:00)",
"height_cm": 165,
"weight_kg": 60,
"height_ft": "5'5",
"weight_lbs": 132,
}
# Test Case 5: Invalid - Invalid language code
invalid_language = {
"from_id": "user_102",
"first_name": "Maria",
"last_name": "Garcia",
"birthdate": "1992-09-10",
"gender": "female",
"language": "fr", # Invalid language code
"goal": "lose weight",
"timezone": "Madrid, Spain (UTC+01:00)",
"height_cm": 170,
"weight_kg": 65,
}
# Test Case 6: Invalid - Invalid goal
invalid_goal = {
"from_id": "user_103",
"first_name": "Mike",
"last_name": "Wilson",
"birthdate": "1987-11-25",
"gender": "male",
"language": "en",
"goal": "get stronger", # Invalid goal
"timezone": "Toronto, Canada (UTC-05:00)",
"height_cm": 185,
"weight_kg": 90,
}
# Test Case 7: Invalid - Invalid timezone format
invalid_timezone = {
"from_id": "user_104",
"first_name": "Sarah",
"last_name": "Brown",
"birthdate": "1993-07-08",
"gender": "female",
"language": "en",
"goal": "maintain",
"timezone": "London GMT+0", # Invalid timezone format
"height_cm": 168,
"weight_kg": 58,
}
# Test Case 8: Invalid - Invalid date format
invalid_date = {
"from_id": "user_105",
"first_name": "David",
"last_name": "Lee",
"birthdate": "01-01-1990", # Invalid date format
"gender": "male",
"language": "en",
"goal": "gain muscle",
"timezone": "Singapore (UTC+08:00)",
"height_cm": 175,
"weight_kg": 75,
}
# Test Case 9: Invalid - Invalid height_ft format
invalid_height_ft = {
"from_id": "user_106",
"first_name": "Tom",
"last_name": "Clark",
"birthdate": "1991-04-15",
"gender": "male",
"language": "en",
"goal": "maintain",
"timezone": "Chicago, USA (UTC-06:00)",
"height_ft": "5.10", # Invalid format (should be 5'10)
"weight_lbs": 160,
}
# Test Case 10: Invalid - No measurement system provided
no_measurements = {
"from_id": "user_107",
"first_name": "Emma",
"last_name": "Davis",
"birthdate": "1994-08-30",
"gender": "female",
"language": "en",
"goal": "lose weight",
"timezone": "Dublin, Ireland (UTC+00:00)",
# No height/weight measurements provided
}
test_cases = [
(valid_metric_user, 201, "Valid metric user creation"),
(valid_imperial_user, 201, "Valid imperial user creation"),
(missing_required_field, 400, "Missing required field"),
(both_measurement_systems, 400, "Both measurement systems provided"),
(invalid_language, 400, "Invalid language code"),
(invalid_goal, 400, "Invalid goal"),
(invalid_timezone, 400, "Invalid timezone format"),
(invalid_date, 400, "Invalid date format"),
(invalid_height_ft, 400, "Invalid height_ft format"),
(no_measurements, 400, "No measurement system provided"),
]
return test_cases
def run_tests(base_url, api_key):
"""Run all test cases against the API endpoint"""
headers = {"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"}
test_cases = test_create_user()
for payload, expected_status, description in test_cases:
try:
response = requests.post(f"{base_url}", json=payload, headers=headers)
actual_status = response.status_code
result = "PASS" if actual_status == expected_status else "FAIL"
print(f"{result}: {description}")
print(f"Expected status: {expected_status}, Got: {actual_status}")
if result == "FAIL":
print(f"Response: {response.json()}")
print("---")
except Exception as e:
print(f"Error testing {description}: {str(e)}")
print("---")
if __name__ == "__main__":
run_tests(
"https://api.rex.fit/[org]/dev/v1/create-user",
"", #API key here
)
4. Dashboard Test Example¶
import unittest
from typing import Any, Dict
import requests
class DashboardLinkTest(unittest.TestCase):
def setUp(self):
# Configure your test environment
self.endpoint = "https://api.rex.fit/[org]/dev/v1/dashboard-url"
self.api_key = "" # Your API key
def get_dashboard_link(
self, user_id: str = None, api_key: str = None
) -> requests.Response:
"""Helper method to make requests to the dashboard link endpoint"""
headers = {}
if api_key:
headers["Authorization"] = f"Bearer {api_key}"
params = {}
if user_id:
params["user_id"] = user_id
try:
response = requests.get(self.endpoint, headers=headers, params=params)
print(f"Response status: {response.status_code}")
print(f"Response body: {response.text}")
return response
except requests.RequestException as e:
self.fail(f"Request failed: {str(e)}")
def test_valid_request(self):
"""Test getting dashboard link for valid user"""
# Use a known valid user ID from your database
response = self.get_dashboard_link(user_id="user_456", api_key=self.api_key)
self.assertEqual(response.status_code, 200)
data = response.json()
self.assertEqual(data["status"], "success")
self.assertIn("dashboard_url", data)
self.assertTrue(data["dashboard_url"].startswith("https://"))
def test_missing_api_key(self):
"""Test request without API key"""
response = self.get_dashboard_link(user_id="user_456", api_key=None)
self.assertEqual(response.status_code, 401)
data = response.json()
self.assertEqual(data["status"], "error")
self.assertIn("Authorization header", data["message"])
def test_invalid_api_key(self):
"""Test request with invalid API key"""
response = self.get_dashboard_link(user_id="user_456", api_key="invalid_key")
self.assertEqual(response.status_code, 401)
data = response.json()
self.assertEqual(data["status"], "error")
self.assertEqual(data["message"], "Invalid API key")
def test_missing_user_id(self):
"""Test request without user_id parameter"""
response = self.get_dashboard_link(user_id=None, api_key=self.api_key)
self.assertEqual(response.status_code, 400)
data = response.json()
self.assertEqual(data["status"], "error")
self.assertEqual(data["message"], "Missing 'user_id'")
def test_nonexistent_user(self):
"""Test request with user ID that doesn't exist"""
response = self.get_dashboard_link(
user_id="nonexistent_user_999", api_key=self.api_key
)
self.assertEqual(response.status_code, 404)
data = response.json()
self.assertEqual(data["status"], "error")
self.assertEqual(data["message"], "User not found")
def test_malformed_api_key(self):
"""Test request with malformed Authorization header"""
headers = {"Authorization": "InvalidFormat xyz123"}
params = {"user_id": "user_456"}
response = requests.get(self.endpoint, headers=headers, params=params)
self.assertEqual(response.status_code, 401)
data = response.json()
self.assertEqual(data["status"], "error")
self.assertIn("Bearer", data["message"])
if __name__ == "__main__":
unittest.main(verbosity=2)
Support and Resources¶
- Rex Nutribot Support: Contact Rex Nutribot team for technical support
- API Updates: Monitor repository for API changes and updates
Ready to integrate? Start with the test examples above to validate your setup!