From navan-pack
Generates GitHub Actions workflows to validate Navan API integrations: OAuth token checks, booking data health, and compliance reports.
How this skill is triggered — by the user, by Claude, or both
Slash command
/navan-pack:navan-ci-integrationThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Navan has no SDK — all CI integration uses raw REST calls against `https://api.navan.com` with OAuth 2.0 client_credentials authentication. This skill generates GitHub Actions workflows that validate your Navan integration on every push: token health checks, booking data schema validation, and travel policy compliance reports. Secrets (client_id, client_secret) are stored in GitHub Actions secr...
Navan has no SDK — all CI integration uses raw REST calls against https://api.navan.com with OAuth 2.0 client_credentials authentication. This skill generates GitHub Actions workflows that validate your Navan integration on every push: token health checks, booking data schema validation, and travel policy compliance reports. Secrets (client_id, client_secret) are stored in GitHub Actions secrets, never in code.
NAVAN_CLIENT_ID, NAVAN_CLIENT_SECREThttps://api.navan.comNavigate to your GitHub repo > Settings > Secrets and variables > Actions. Add:
NAVAN_CLIENT_ID — from Navan Admin > API SettingsNAVAN_CLIENT_SECRET — from Navan Admin > API Settings# .github/workflows/navan-integration-check.yml
name: Navan Integration Health Check
on:
push:
branches: [main]
pull_request:
schedule:
- cron: '0 6 * * 1' # Weekly Monday 6am UTC
jobs:
navan-health:
runs-on: ubuntu-latest
env:
NAVAN_BASE_URL: https://api.navan.com
steps:
- uses: actions/checkout@v4
- name: Authenticate with Navan OAuth 2.0
id: auth
run: |
TOKEN_RESPONSE=$(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" \
-d "client_id=${{ secrets.NAVAN_CLIENT_ID }}" \
-d "client_secret=${{ secrets.NAVAN_CLIENT_SECRET }}")
ACCESS_TOKEN=$(echo "$TOKEN_RESPONSE" | jq -r '.access_token')
if [ "$ACCESS_TOKEN" = "null" ] || [ -z "$ACCESS_TOKEN" ]; then
echo "::error::OAuth authentication failed"
echo "$TOKEN_RESPONSE" | jq .
exit 1
fi
echo "::add-mask::$ACCESS_TOKEN"
echo "token=$ACCESS_TOKEN" >> "$GITHUB_OUTPUT"
- name: API Health Check — Fetch Bookings
run: |
HTTP_CODE=$(curl -s -o /tmp/bookings.json -w "%{http_code}" \
"$NAVAN_BASE_URL/v1/bookings?page=0&size=5" \
-H "Authorization: Bearer ${{ steps.auth.outputs.token }}")
echo "Health check status: $HTTP_CODE"
if [ "$HTTP_CODE" != "200" ]; then
echo "::error::API health check failed with HTTP $HTTP_CODE"
cat /tmp/bookings.json
exit 1
fi
- name: Validate Booking Data Schema
run: |
# Response structure: records in .data array, primary key uuid
REQUIRED_FIELDS='["uuid","traveler","status","created_at"]'
echo "$REQUIRED_FIELDS" | jq -r '.[]' | while read field; do
if ! jq -e ".data[0].$field" /tmp/bookings.json > /dev/null 2>&1; then
echo "::warning::Missing expected field: $field"
fi
done
- name: Generate Compliance Report
run: |
curl -s "$NAVAN_BASE_URL/v1/bookings?page=0&size=50" \
-H "Authorization: Bearer ${{ steps.auth.outputs.token }}" \
-o /tmp/compliance.json
echo "## Navan Compliance Report" >> "$GITHUB_STEP_SUMMARY"
jq -r '"| Metric | Value |\n|--------|-------|\n| Total Bookings | \(.total_bookings) |\n| In Policy | \(.in_policy) |\n| Out of Policy | \(.out_of_policy) |"' \
/tmp/compliance.json >> "$GITHUB_STEP_SUMMARY" 2>/dev/null || echo "Report data unavailable" >> "$GITHUB_STEP_SUMMARY"
#!/usr/bin/env bash
# scripts/navan-smoke-test.sh — Run locally or in CI
set -euo pipefail
BASE_URL="${NAVAN_BASE_URL:-https://api.navan.com}"
# Obtain token
TOKEN=$(curl -sf -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')
# Test endpoints (records returned in .data array)
ENDPOINTS=("v1/bookings?page=0&size=1")
FAILED=0
for ep in "${ENDPOINTS[@]}"; do
CODE=$(curl -s -o /dev/null -w "%{http_code}" \
"$BASE_URL/$ep" -H "Authorization: Bearer $TOKEN")
if [ "$CODE" = "200" ]; then
echo "PASS: $ep ($CODE)"
else
echo "FAIL: $ep ($CODE)"
FAILED=$((FAILED + 1))
fi
done
exit $FAILED
The CI workflow produces:
| HTTP Code | Meaning | CI Action |
|---|---|---|
200 | Success | Continue |
401 | Invalid or expired OAuth token | Fail build, alert on credential rotation |
403 | Insufficient API scopes | Fail build, check OAuth app permissions |
404 | Endpoint not found (API version change) | Fail build, review API changelog |
429 | Rate limit exceeded | Retry with exponential backoff (max 3 attempts) |
500-503 | Navan server error | Warn but do not fail (transient) |
Parallel endpoint validation with matrix strategy:
jobs:
validate-endpoints:
runs-on: ubuntu-latest
strategy:
matrix:
endpoint: [bookings, expenses, users, invoices]
steps:
- name: Check ${{ matrix.endpoint }}
run: |
CODE=$(curl -s -o /dev/null -w "%{http_code}" \
"https://api.navan.com/v1/${{ matrix.endpoint }}?page=0&size=1" \
-H "Authorization: Bearer $TOKEN")
[ "$CODE" = "200" ] || exit 1
navan-deploy-integration for production deployment patternsnavan-observability for runtime monitoring of the endpoints validated herenavan-rate-limits to configure retry policies in CInpx claudepluginhub fleet-to-force/claude-code-plugins-plus --plugin navan-pack5plugins reuse this skill
First indexed Jul 10, 2026
Generates GitHub Actions workflows to validate Navan API integrations, run booking data health checks, and produce compliance reports.
Guides collaborative design exploration before implementation: explores context, asks clarifying questions, proposes approaches, and writes a design doc for user approval.
Creates structured, bite-sized implementation plans from specs or requirements before writing code. Useful for breaking down multi-step tasks into testable steps with file structure and task boundaries.