Agent Skills: Navan Upgrade Migration

|

UncategorizedID: jeremylongshore/claude-code-plugins-plus-skills/navan-upgrade-migration

Install this agent skill to your local

pnpm dlx add-skill https://github.com/jeremylongshore/claude-code-plugins-plus-skills/tree/HEAD/plugins/saas-packs/navan-pack/skills/navan-upgrade-migration

Skill Files

Browse the full folder contents for navan-upgrade-migration.

Download Skill

Loading file tree…

plugins/saas-packs/navan-pack/skills/navan-upgrade-migration/SKILL.md

Skill Metadata

Name
navan-upgrade-migration
Description
|

Navan Upgrade Migration

Overview

Defensive patterns for maintaining Navan API integrations over time. Navan does not publicly version their API, publish a changelog, or guarantee backward compatibility. Every API response should be treated as potentially different from the last.

Prerequisites

  • Existing Navan API integration in production
  • OAuth credentials (client_id, client_secret) stored in a secret manager
  • Baseline API response snapshots for comparison (see Step 1)
  • curl, jq, and diff for schema comparison

Instructions

Step 1 — Capture Response Baselines

Store known-good API responses as reference schemas. Compare against these regularly to detect drift.

TOKEN=$(curl -s -X POST "https://api.navan.com/ta-auth/oauth/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials&client_id=$NAVAN_CLIENT_ID&client_secret=$NAVAN_CLIENT_SECRET" \
  | jq -r '.access_token')

BASELINE_DIR="navan-api-baselines/$(date +%Y%m%d)"
mkdir -p "$BASELINE_DIR"

# Capture response structure (keys only, no values)
for ENDPOINT in users bookings; do
  curl -s -H "Authorization: Bearer $TOKEN" \
    "https://api.navan.com/v1/${ENDPOINT}?page=0&size=1" \
    | jq '[.data[] | keys] | .[0]' > "$BASELINE_DIR/${ENDPOINT}-schema.json" 2>/dev/null
  echo "Captured: $ENDPOINT → $(cat "$BASELINE_DIR/${ENDPOINT}-schema.json" | jq length) fields"
done

Step 2 — Schema Drift Detection

Run this periodically (daily cron or CI pipeline) to detect API changes:

LATEST_BASELINE=$(ls -d navan-api-baselines/*/ | sort | tail -1)

for ENDPOINT in users bookings; do
  CURRENT=$(curl -s -H "Authorization: Bearer $TOKEN" \
    "https://api.navan.com/v1/${ENDPOINT}?page=0&size=1" \
    | jq '[.data[] | keys] | .[0]' 2>/dev/null)

  BASELINE=$(cat "${LATEST_BASELINE}${ENDPOINT}-schema.json" 2>/dev/null)

  # Compare field sets
  ADDED=$(comm -13 <(echo "$BASELINE" | jq -r '.[]' | sort) <(echo "$CURRENT" | jq -r '.[]' | sort))
  REMOVED=$(comm -23 <(echo "$BASELINE" | jq -r '.[]' | sort) <(echo "$CURRENT" | jq -r '.[]' | sort))

  [ -n "$ADDED" ] && echo "WARNING: $ENDPOINT has NEW fields: $ADDED"
  [ -n "$REMOVED" ] && echo "CRITICAL: $ENDPOINT has REMOVED fields: $REMOVED"
  [ -z "$ADDED" ] && [ -z "$REMOVED" ] && echo "OK: $ENDPOINT schema unchanged"
done

Step 3 — Defensive Response Parsing

Never assume a fixed schema. Use defensive patterns that tolerate changes:

# BAD: Assumes exact structure — breaks if fields are renamed or removed
# jq '.trips[0].flight_number'

# GOOD: Defensive parsing with fallbacks
jq '
  if type == "array" then
    .[0] // {} |
    {
      id: (.id // .uuid // .booking_id // "unknown"),
      flight: (.flight_number // .flight_no // .flightNumber // "N/A"),
      status: (.status // .booking_status // "unknown"),
      _extra_fields: (keys - ["id","uuid","booking_id","flight_number","flight_no",
                               "flightNumber","status","booking_status"])
    }
  else
    {error: "unexpected response type", type: type}
  end
' /tmp/navan-trips.json

Key defensive principles:

  • Always provide fallback field names (Navan may rename without notice)
  • Log unknown fields rather than ignoring them — they signal upcoming changes
  • Never hard-code array lengths or object depth assumptions
  • Parse dates permissively (ISO 8601, Unix timestamp, and custom formats)

Step 4 — Deprecation Signal Monitoring

Check HTTP response headers for deprecation or sunset signals:

# Capture and inspect response headers for deprecation notices
curl -s -D - -o /dev/null \
  -H "Authorization: Bearer $TOKEN" \
  "https://api.navan.com/v1/users" \
  | grep -iE "deprecat|sunset|warning|x-api-version|x-deprecated"

# Check response body for deprecation warnings
curl -s -H "Authorization: Bearer $TOKEN" \
  "https://api.navan.com/v1/users" \
  | jq '{
    has_deprecation_warning: (._deprecated // .deprecated // .warning // null),
    has_version_header: (.api_version // ._api_version // null)
  }'

Step 5 — Gradual Rollout Strategy

When you detect or anticipate an API change, use feature flags to roll out handling changes gradually:

# Feature flag pattern for API response handling
# Store flag in environment or config service
export NAVAN_USE_NEW_TRIP_SCHEMA="${NAVAN_USE_NEW_TRIP_SCHEMA:-false}"

# In your integration code, branch on the flag
if [ "$NAVAN_USE_NEW_TRIP_SCHEMA" = "true" ]; then
  # New parsing logic for updated schema
  jq '.[] | {id: .booking_uuid, flight: .flight_number}' /tmp/trips.json
else
  # Legacy parsing logic (current production)
  jq '.[] | {id: .id, flight: .flight_no}' /tmp/trips.json
fi

Rollout procedure:

  1. Deploy new parsing logic behind a feature flag (flag = off)
  2. Enable for 5% of traffic — compare outputs between old and new parsers
  3. If outputs match or new parser handles additional fields, increase to 25%
  4. Monitor error rates at each stage for 24 hours
  5. Full rollout at 100% when confidence is high
  6. Remove old parsing logic and feature flag after 2 weeks at 100%

Step 6 — Automated Regression Testing

Run regression tests against live API responses on a schedule:

# Regression test: verify critical fields still exist
FAILURES=0

USERS_RESPONSE=$(curl -s -H "Authorization: Bearer $TOKEN" \
  "https://api.navan.com/v1/users")

# Check required fields exist
for FIELD in id email; do
  HAS_FIELD=$(echo "$USERS_RESPONSE" | jq ".data[0] | has(\"$FIELD\")")
  if [ "$HAS_FIELD" != "true" ]; then
    echo "REGRESSION: /v1/users missing required field: $FIELD"
    FAILURES=$((FAILURES + 1))
  fi
done

BOOKINGS_RESPONSE=$(curl -s -H "Authorization: Bearer $TOKEN" \
  "https://api.navan.com/v1/bookings?page=0&size=1")

for FIELD in uuid; do
  HAS_FIELD=$(echo "$BOOKINGS_RESPONSE" | jq ".data[0] | has(\"$FIELD\")")
  if [ "$HAS_FIELD" != "true" ]; then
    echo "REGRESSION: /v1/bookings missing required field: $FIELD"
    FAILURES=$((FAILURES + 1))
  fi
done

echo "Regression result: $FAILURES failures"
[ "$FAILURES" -gt 0 ] && exit 1

Step 7 — Change Response Playbook

When a schema change is detected:

| Change Type | Severity | Response | |-------------|----------|----------| | New field added | Low | Log it, update baseline, no code change needed | | Field renamed | High | Add new name as fallback, deploy behind flag | | Field removed | Critical | Identify impact, implement fallback, alert team | | Type changed (string to int) | High | Update parser, add type coercion | | Endpoint URL changed | Critical | Update client config, monitor old URL for redirect | | Auth flow changed | Critical | Immediate attention — test /ta-auth/oauth/token |

Output

  • Baseline schema snapshots stored in version control
  • Drift detection script running on a schedule (cron or CI)
  • Defensive parsing patterns applied to all API response handlers
  • Feature flag configuration for gradual rollout of schema changes
  • Regression test suite covering critical field presence

Error Handling

| Issue | Detection | Response | |-------|-----------|----------| | New unknown fields in response | Drift detection script | Log, update baseline, no action unless field replaces existing | | Required field missing | Regression test failure | Roll back to cached data, alert team, open support ticket | | Response type changed | jq parse error | Add type checking, coerce if possible, alert if not | | Endpoint returns 404 | Health check failure | Check for URL changes, contact Navan support | | Auth endpoint behavior change | Token acquisition failure | Test /ta-auth/oauth/token manually, check Admin > Integrations |

Examples

Quick schema health check:

# One-liner: check if API response structure matches expectations
TOKEN=$(curl -s -X POST "https://api.navan.com/ta-auth/oauth/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials&client_id=$NAVAN_CLIENT_ID&client_secret=$NAVAN_CLIENT_SECRET" \
  | jq -r '.access_token')

echo "Users fields: $(curl -s -H "Authorization: Bearer $TOKEN" \
  "https://api.navan.com/v1/users" | jq '.data[0] | keys | length') keys"
echo "Bookings fields: $(curl -s -H "Authorization: Bearer $TOKEN" \
  "https://api.navan.com/v1/bookings?page=0&size=1" | jq '.data[0] | keys | length') keys"

Resources

Next Steps

  • Use navan-debug-bundle to capture current API state as a baseline
  • Use navan-prod-checklist to verify production hardening after changes
  • Use navan-ci-integration to add regression tests to your CI pipeline