Learn-skills.dev terra-troubleshooting
Terra API troubleshooting and debugging. Use when experiencing connection issues, data sync problems, webhook failures, SDK errors, or provider-specific issues.
git clone https://github.com/NeverSight/learn-skills.dev
T=$(mktemp -d) && git clone --depth=1 https://github.com/NeverSight/learn-skills.dev "$T" && mkdir -p ~/.claude/skills && cp -r "$T/data/skills-md/adaptationio/skrillz/terra-troubleshooting" ~/.claude/skills/neversight-learn-skills-dev-terra-troubleshooting && rm -rf "$T"
data/skills-md/adaptationio/skrillz/terra-troubleshooting/SKILL.mdTerra Troubleshooting
Diagnose and resolve common Terra API issues.
Quick Diagnostics
from terra import Terra def check_terra_health(client: Terra) -> dict: """Run basic health checks.""" results = {} # 1. API connectivity try: integrations = client.integrations.fetch() results["api_connection"] = f"OK - {len(integrations.integrations)} providers" except Exception as e: results["api_connection"] = f"FAILED - {e}" # 2. List connected users try: users = client.user.getsubscriptions() results["connected_users"] = f"OK - {len(users.users)} users" except Exception as e: results["connected_users"] = f"FAILED - {e}" return results # Usage client = Terra(dev_id="...", api_key="...") print(check_terra_health(client))
Common Issues
Authentication Issues
"Invalid API key or dev-id"
Cause: Incorrect credentials or wrong environment.
Solution:
# Check you're using correct environment credentials ENVIRONMENTS = { "testing": { "dev_id": "botaniqalmedtech-testing-SjyfjtG33s", "api_key": "_W7Pm-kAaIf1GA_Se21NnzCaFZjg3Izc" }, "staging": { "dev_id": "botaniqalmedtech-staging-uGKHOPRCi1", "api_key": "fJia30spa-EqB_CMqZBzzrkMWZ_u2pv_" }, "production": { "dev_id": "botaniqalmedtech-prod-yrc99AwsT2", "api_key": "Il4YUTc-e00EcvKGUx63j7YE3MJ-7QIz" } } # Verify connection from terra import Terra client = Terra(**ENVIRONMENTS["testing"]) print(client.integrations.fetch())
Widget session expired
Cause: Session URLs expire after 15 minutes.
Solution: Generate a new widget session:
response = client.authentication.generatewidgetsession( reference_id="user_123", auth_success_redirect_url="https://app.example.com/success", auth_failure_redirect_url="https://app.example.com/failure" ) # Redirect user to response.url immediately
Mobile SDK token invalid
Cause: Token expired (3 min) or already used.
Solution: Generate fresh token for each connection attempt:
# Backend generates new token each time token = client.authentication.generateauthtoken(reference_id="user_123") # Send token.token to mobile app # Token is one-time use - generate new one if connection fails
Connection Issues
User stuck on "connecting"
Cause: OAuth flow interrupted or WebView used.
Solution:
- Never use WebView/iFrame for OAuth
- Open auth URL in real browser
- Handle redirects properly:
// Wrong - WebView blocks OAuth <WebView source={{ uri: authUrl }} /> // Correct - Open in browser import { Linking } from 'react-native'; Linking.openURL(authUrl); // Or use InAppBrowser import { InAppBrowser } from 'react-native-inappbrowser-reborn'; InAppBrowser.open(authUrl);
Provider returns "Access Denied"
Cause: Provider-side issue or insufficient permissions.
Solution:
# Check user's granted scopes user = client.user.getuser(user_id="terra_abc123") print(f"Scopes: {user.user.scopes}") # If missing scopes, user needs to reconnect and grant all permissions
WHOOP / Dexcom connection fails
Cause: These require special activation.
Solution: Contact Terra support at [email protected] for:
- WHOOP access activation
- Dexcom (CGM) access activation
- Freestyle Libre EU dedicated API keys
- Strava dedicated API keys
Data Sync Issues
No data received
Causes:
- User just connected (data takes time to sync)
- User has no data in that date range
- Provider is "polled" type (5-min delay)
Solution:
from datetime import datetime, timedelta def check_user_data(client: Terra, user_id: str) -> dict: """Check if user has any data.""" end = datetime.now() start = end - timedelta(days=7) results = {} # Check each data type for data_type in ["daily", "activity", "sleep", "body"]: try: method = getattr(client, data_type) response = method.get(user_id=user_id, start_date=start, end_date=end) results[data_type] = len(response.data) except Exception as e: results[data_type] = f"Error: {e}" return results print(check_user_data(client, "terra_abc123"))
Duplicate data received
Cause: Daily/body data updates multiple times per day.
Solution: Use UPSERT pattern, not INSERT:
# Wrong - creates duplicates db.insert(data) # Correct - overwrites existing db.upsert( {"user_id": user_id, "date": date}, {"$set": data} )
Historical data missing
Cause: Provider limits historical access.
Reference - Maximum historical data per provider:
| Provider | Limit |
|---|---|
| Garmin | 5 years |
| Fitbit | 10 years |
| Oura | 3 years |
| WHOOP | 2 years |
| Polar | 30 days |
| COROS | 3 months |
Webhook Issues
Webhooks not received
Checklist:
-
Check webhook configured in dashboard:
- Terra Dashboard → Destinations → Webhooks
- Verify URL is correct and HTTPS
-
Check endpoint is accessible:
curl -X POST https://your-webhook-url.com/terra \ -H "Content-Type: application/json" \ -d '{"type": "test"}' -
Check server logs for incoming requests
-
Verify IP not blocked - Terra IPs:
18.133.218.210, 18.169.82.189, 18.132.162.19, 18.130.218.186, 13.43.183.154, 3.11.208.36, 35.214.201.105, 35.214.230.71, 35.214.252.53, 35.214.229.114
Signature verification failing
Causes:
- Wrong signing secret
- Body modified before verification
- Incorrect signature algorithm
Solution:
import hmac import hashlib def debug_signature(header: str, body: bytes, secret: str): """Debug signature verification.""" # Parse header parts = dict(p.split("=") for p in header.split(",")) print(f"Timestamp: {parts['t']}") print(f"Received signature: {parts['v1']}") # Compute expected message = f"{parts['t']}.{body.decode()}" expected = hmac.new(secret.encode(), message.encode(), hashlib.sha256).hexdigest() print(f"Expected signature: {expected}") # Compare match = hmac.compare_digest(expected, parts['v1']) print(f"Match: {match}") return match # Use in webhook handler @app.route("/webhook", methods=["POST"]) def webhook(): header = request.headers.get("terra-signature") body = request.get_data() # Must be raw bytes, not parsed JSON! if not debug_signature(header, body, SIGNING_SECRET): return "Invalid signature", 401 # Now parse JSON payload = request.get_json()
Critical: Get raw body BEFORE parsing JSON.
Webhook timeouts
Cause: Processing takes too long (>5 seconds recommended).
Solution: Process asynchronously:
from celery import Celery celery = Celery() @app.route("/webhook", methods=["POST"]) def webhook(): # Verify signature # Queue for async processing process_webhook.delay(request.get_json()) # Respond immediately return "OK", 200 @celery.task def process_webhook(payload): # Do heavy processing here save_to_database(payload) send_notifications(payload)
SDK Issues
iOS: Apple Health no data
Causes:
- Permissions not granted
- Background delivery not enabled
- App not authorized in Health app
Solution:
// 1. Check permissions in code Terra.checkPermissions { granted in if !granted { // Request permissions again Terra.requestPermissions() } } // 2. Enable background delivery func application(_ app: UIApplication, didFinishLaunchingWithOptions...) { Terra.setUpBackgroundDelivery() } // 3. User must enable in Settings → Privacy → Health → Your App
Android: Samsung Health fails
Causes:
- Samsung Health app not installed
- minSDK < 28
- Missing permissions
Solution:
// 1. Check Samsung Health installed if (!Terra.isSamsungHealthAvailable(context)) { // Prompt user to install Samsung Health showInstallSamsungHealthDialog() } // 2. Verify minSDK in build.gradle android { defaultConfig { minSdkVersion 28 // Required for Terra Android SDK } } // 3. Request permissions <uses-permission android:name="android.permission.ACTIVITY_RECOGNITION"/> <uses-permission android:name="android.permission.BODY_SENSORS"/>
Android: Health Connect issues
Cause: Health Connect not installed or configured.
Solution:
// Check Health Connect availability if (!Terra.isHealthConnectAvailable(context)) { // Prompt to install Health Connect val intent = Intent(Intent.ACTION_VIEW).apply { data = Uri.parse("https://play.google.com/store/apps/details?id=com.google.android.apps.healthdata") } startActivity(intent) }
React Native: Build failures
Common fixes:
# iOS: Clean and rebuild cd ios pod deintegrate pod install cd .. npx react-native run-ios # Android: Clean build cd android ./gradlew clean cd .. npx react-native run-android
Provider-Specific Issues
MyFitnessPal: Gateway timeout
Cause: MyFitnessPal API is slow/unreliable.
Solution: Retry with exponential backoff:
import time def fetch_with_retry(client, user_id, start, end, max_retries=3): for attempt in range(max_retries): try: return client.nutrition.get(user_id, start, end) except Exception as e: if "timeout" in str(e).lower() and attempt < max_retries - 1: time.sleep(2 ** attempt) # 1, 2, 4 seconds continue raise
Garmin: Data delayed
Cause: Garmin is a "polled" provider (~5 min sync).
Solution: Wait for webhook rather than polling API:
# Don't poll repeatedly # Instead, wait for webhook notification
Fitbit: Token revoked
Cause: User revoked access in Fitbit app.
Solution: Handle
access_revoked webhook:
def handle_access_revoked(payload): user_id = payload["user"]["user_id"] # Mark user as disconnected db.terra_users.update_one( {"terra_user_id": user_id}, {"$set": {"status": "access_revoked"}} ) # Notify user to reconnect send_reconnect_notification(user_id)
Debug Mode
Enable detailed logging:
import logging # Enable Terra SDK logging logging.getLogger("terra").setLevel(logging.DEBUG) # Or enable all HTTP logging import http.client http.client.HTTPConnection.debuglevel = 1
Support Escalation
If issues persist:
- Check Terra Status: https://status.tryterra.co
- Documentation: https://docs.tryterra.co
- Email Support: [email protected]
- Include in support request:
- Dev ID (not API key!)
- User ID (if applicable)
- Error message
- Timestamp of issue
- Provider affected
Health Check Script
#!/usr/bin/env python3 """Terra API health check script.""" from terra import Terra from datetime import datetime, timedelta def run_health_check(): print("=" * 50) print("Terra API Health Check") print("=" * 50) # Test each environment envs = { "testing": ("botaniqalmedtech-testing-SjyfjtG33s", "_W7Pm-kAaIf1GA_Se21NnzCaFZjg3Izc"), "staging": ("botaniqalmedtech-staging-uGKHOPRCi1", "fJia30spa-EqB_CMqZBzzrkMWZ_u2pv_"), "production": ("botaniqalmedtech-prod-yrc99AwsT2", "Il4YUTc-e00EcvKGUx63j7YE3MJ-7QIz"), } for env_name, (dev_id, api_key) in envs.items(): print(f"\n{env_name.upper()}:") try: client = Terra(dev_id=dev_id, api_key=api_key) # Check API integrations = client.integrations.fetch() print(f" ✅ API Connected - {len(integrations.integrations)} providers") # Check users users = client.user.getsubscriptions() print(f" ✅ Users: {len(users.users)} connected") except Exception as e: print(f" ❌ Error: {e}") print("\n" + "=" * 50) print("Health check complete") if __name__ == "__main__": run_health_check()
Related Skills
- terra-auth: Credential management
- terra-connections: Connection flows
- terra-webhooks: Webhook handling
- terra-data: Data retrieval
- terra-sdk: SDK integration