Navan Production Checklist
Overview
Gated production readiness verification for Navan REST API integrations. Navan has no SDK and no sandbox — production is the only environment, making this checklist critical.
Prerequisites
- Navan admin access (Admin > Travel admin > Settings)
- OAuth credentials stored in a secret manager (credentials are viewable only once)
- SSO identity provider configured (Okta, Azure AD, or Google Workspace)
curlandjqfor verification commands
Instructions
Domain 1 — Credential Security
- [ ] Secret storage: OAuth
client_idandclient_secretstored in a secret manager (AWS Secrets Manager, GCP Secret Manager, HashiCorp Vault) — never in environment variables, config files, or source control - [ ] Rotation plan documented: Schedule for rotating credentials (recommend 90-day cycle)
- [ ] Zero-downtime rotation tested: Dual-credential swap procedure validated
# Verify current credentials work
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 '{authenticated: (.access_token != null), error: .error}'
Rotation procedure:
- Generate new credentials in Admin > Integrations (old ones remain valid)
- Deploy new credentials to secret manager
- Update application configuration to reference new secret version
- Verify new credentials with
/ta-auth/oauth/token - Revoke old credentials in Admin > Integrations
- Confirm old credentials return HTTP 401
Domain 2 — Error Handling and Alerting
- [ ] All HTTP error codes handled: 400, 401, 403, 404, 429, 500, 502, 503
- [ ] Retry logic with exponential backoff: For 429 and 5xx responses
- [ ] Alert thresholds configured: Error rate > 5% over 5 minutes triggers alert
- [ ] Dead letter queue: Failed API requests stored for retry or manual review
# Health check endpoint pattern
health_check() {
RESPONSE=$(curl -s -w "%{http_code}" -o /tmp/navan-health.json \
-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")
if [ "$RESPONSE" = "200" ]; then
echo '{"status":"healthy","navan_api":"reachable"}'
elif [ "$RESPONSE" = "429" ]; then
echo '{"status":"degraded","reason":"rate_limited"}'
else
echo "{\"status\":\"unhealthy\",\"http_code\":\"$RESPONSE\"}"
fi
}
Domain 3 — Rate Limiting
- [ ] Client-side rate limiter: Token bucket or sliding window before API calls
- [ ] 429 response handling: Parse
Retry-Afterheader and honor wait time - [ ] Request queuing: Burst requests queued rather than dropped
- [ ] Rate limit monitoring: Dashboard showing API call volume and 429 frequency
Domain 4 — Data Pipeline
- [ ] BOOKING table sync: Weekly full refresh configured (Fivetran, Airbyte, or custom)
- [ ] TRANSACTION table sync: Incremental sync with deduplication by transaction UUID
- [ ] Data backup strategy: Export snapshots stored in cloud storage with retention policy
- [ ] Reconciliation checks: Automated comparison between Navan data and ERP records
Domain 5 — SSO and User Provisioning
- [ ] SAML SSO verified: Login flow tested end-to-end through identity provider
# Verify users are synced via API
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')
curl -s -H "Authorization: Bearer $TOKEN" \
"https://api.navan.com/v1/users" \
| jq '{total_users: (.data | length), sample: .data[0] | {id, email, status}}'
- [ ] SCIM provisioning active: User create/update/deactivate syncing from IdP
- [ ] Deprovisioning tested: Terminated employees removed from Navan within 24 hours
- [ ] Role mapping documented: IdP groups mapped to Navan roles (traveler, approver, admin)
Domain 6 — Compliance and Audit
- [ ] API access logging: All Navan API calls logged with timestamp, endpoint, response code, and user context
- [ ] Audit trail retention: Logs retained per your compliance requirements (SOC 2: 1 year minimum)
- [ ] Data classification: Navan data (PII, payment info) classified and handled per PCI DSS L1
- [ ] Compliance certifications verified: Confirm Navan's SOC 1/2 Type II, ISO 27001, PCI DSS L1, GDPR status at navan.com/security
Output
A completed checklist with:
- Pass/fail status for each domain
- Verification command output proving each check
- Identified gaps with remediation plan and owner
- Sign-off from security and operations leads
Error Handling
| Check Failure | Impact | Remediation | |---------------|--------|-------------| | Credentials in plaintext | Critical — security breach risk | Move to secret manager immediately | | No retry logic on 429 | High — cascading failures under load | Implement exponential backoff | | SCIM not configured | Medium — manual user management overhead | Enable SCIM in IdP and Navan admin | | No audit logging | High — compliance violation | Add structured logging to API client |
Examples
Run a quick pre-launch validation:
# Rapid smoke test — auth + user count + timing
echo "=== Navan Production Smoke Test ==="
curl -s -w "Auth: %{http_code} (%{time_total}s)\n" -o /tmp/navan-auth.json \
-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"
TOKEN=$(jq -r '.access_token' /tmp/navan-auth.json)
curl -s -w "Users: %{http_code} (%{time_total}s)\n" -o /tmp/navan-users.json \
-H "Authorization: Bearer $TOKEN" \
"https://api.navan.com/v1/users"
echo "User count: $(jq '.data | length' /tmp/navan-users.json)"
Resources
- Navan Security — SOC 2, ISO 27001, PCI DSS certifications
- Navan Integrations — Connector catalog and setup guides
- Navan Help Center — Admin documentation
Next Steps
- Use
navan-upgrade-migrationfor ongoing API change management - Use
navan-observabilityfor monitoring stack setup - Use
navan-incident-runbookif production issues arise post-launch