API Development with nfltr + Postman
Expose your local API to the internet in seconds, test it with Postman from anywhere, and share live endpoints with your team — no deployment required.
Why nfltr + Postman?
Every API developer hits the same wall: your API runs on localhost:3000 but you need to:
- Share it with a teammate for review
- Receive webhooks from Stripe, GitHub, or Twilio
- Run Postman collections from a CI server against your local code
- Demo an API to a client without deploying to staging
- Test OAuth callbacks that require a public URL
nfltr creates a public tunnel to your local port. Postman talks to the public URL exactly as if your API were deployed. Together they give you a production-like API testing workflow without leaving localhost.
┌──────────┐ HTTPS ┌────────────┐ gRPC ┌───────────┐ HTTP ┌─────────────┐
│ Postman │ ───────────────► │ nfltr.xyz │ ──────────────► │ nfltr │ ───────────────► │ Your API │
│ (cloud) │ │ (server) │ │ (agent) │ │ :3000 │
└──────────┘ └────────────┘ └───────────┘ └─────────────┘
Quick Start
1. Start your local API
Any framework — Express, FastAPI, Gin, Rails, Spring Boot, whatever:
# Example: a Node.js API
node server.js # listens on port 3000
2. Expose it with nfltr
nfltr http 3000 --share
Output:
nfltr v1.0.x starting
agent-id: macbook-pro
server: grpc.nfltr.xyz:443 (tls=true)
health: :29501
timeout: 60s
route: (default) → http://localhost:3000
nfltr v1.0.x
Agent ID macbook-pro
Forwarding https://nfltr.xyz/browse/macbook-pro/ → http://localhost:3000
Share URL: https://swift-bay.nfltr.xyz/
Connected — waiting for requests... (press Ctrl+C to stop)
The share URL (https://swift-bay.nfltr.xyz/) is completely public — no API key, no login, no authentication of any kind.
3. Use the share URL in Postman
- Open Postman → create a new request
- Set the URL to
https://swift-bay.nfltr.xyz/api/users - Choose method (GET, POST, PUT, DELETE)
- Add body as needed
- Click Send
💡 Note: Share URLs change every time you restart the tunnel. For a stable URL across restarts, see the Tips section below.
The request travels through nfltr's server, through the gRPC tunnel to your machine, hits localhost:3000/api/users, and the response flows back to Postman. Latency is typically 20–50 ms for a single hop.
Workflow: Share a Live API with Your Team
When working on an API, you want teammates to test it against your running code — not a stale staging deploy. Share URLs are public — no API key or login needed.
nfltr http 3000 --share
Hand the share URL (e.g., https://swift-bay.nfltr.xyz/) to your teammate. They paste it into Postman as the base URL and test immediately — no VPN, no deploy, no firewall rules.
Workflow: Postman Collection + nfltr Base URL
Use a Postman environment variable for the base URL so you can switch between local, tunnel, and production without editing every request.
Set up the environment
Set the share URL as your base URL — no API key needed:
| Variable | Value |
|---|---|
baseUrl | https://swift-bay.nfltr.xyz |
Use it in requests
GET {{baseUrl}}/api/users
POST {{baseUrl}}/api/orders
PUT {{baseUrl}}/api/orders/{{orderId}}
DELETE {{baseUrl}}/api/users/{{userId}}
When your tunnel changes, update the single variable. All requests adapt.
Switch between environments
| Environment | baseUrl |
|---|---|
| Local | http://localhost:3000 |
| Tunnel (share) | https://swift-bay.nfltr.xyz |
| Staging | https://api.staging.example.com |
| Production | https://api.example.com |
Workflow: Receive Webhooks in Postman + nfltr
Third-party services (Stripe, GitHub, Twilio, Razorpay) send webhook callbacks to a URL you configure. During development, that URL needs to reach your local machine.
Step 1: Create a webhook endpoint in your API
# FastAPI example
@app.post("/webhooks/stripe")
async def stripe_webhook(request: Request):
body = await request.body()
sig = request.headers.get("stripe-signature")
# verify & process...
return {"status": "ok"}
Step 2: Expose with nfltr
# Use --share so Stripe can reach your endpoint without an API key
nfltr http 8000 --share
The --share flag is important here: external services like Stripe cannot send an X-API-Key header, so /browse/ URLs won't work for inbound webhooks. The share URL (e.g., https://swift-bay.nfltr.xyz/) is publicly accessible.
Step 3: Configure Stripe dashboard
Set the webhook URL to your share URL (shown in the nfltr output):
https://swift-bay.nfltr.xyz/webhooks/stripe
Step 4: Monitor in Postman
Use Postman's History sidebar to see every webhook that arrived, or create a Postman Monitor that periodically hits your tunnel endpoint to verify it's healthy.
Step 5: Replay webhooks
Stripe and GitHub let you re-send past webhook events from their dashboards. Every replay hits your local code via the nfltr tunnel, letting you debug handler logic in real time.
Workflow: Multi-Backend Routing
Modern apps have multiple services: an API server, a frontend dev server, a WebSocket server. nfltr routes them all through one tunnel:
nfltr http 3000 \
--route /api=8080 \
--route /ws=4000 \
--share
Use the share URL (e.g., https://calm-fox.nfltr.xyz/) in Postman and organize requests into folders: /api/..., /ws/..., root.
| Postman request | Routed to |
|---|---|
GET https://calm-fox.nfltr.xyz/api/users | http://localhost:8080/api/users |
GET https://calm-fox.nfltr.xyz/ws/connect | http://localhost:4000/ws/connect |
GET https://calm-fox.nfltr.xyz/ | http://localhost:3000/ |
Workflow: Run Postman Collections via Newman (CI)
Use Newman to run your Postman collection against a live nfltr tunnel from CI:
# Terminal 1: start your API + tunnel
nfltr http 3000 --share --duration 600 &
# Terminal 2: run the Postman collection (use the share URL from output)
newman run my-collection.json \
--env-var "baseUrl=https://swift-bay.nfltr.xyz" \
--reporters cli,junit \
--reporter-junit-export results.xml
This lets your CI pipeline test the real code running on a developer machine (or a CI runner) through a tunnel — useful for integration tests that need real backends.
Workflow: OAuth Callback Testing
OAuth flows redirect to a callback URL. During development, that callback needs to reach your local server. Use a share URL for the callback — it's publicly accessible, so the OAuth redirect works reliably without any authentication requirements:
nfltr http 3000 --name oauth-dev --share
Output:
Agent ID alice.oauth-dev
Share URL https://swift-bay.nfltr.xyz/
Configure your OAuth provider (Google, GitHub, Auth0) with the share URL:
Callback URL: https://swift-bay.nfltr.xyz/oauth/google/callback
The --name flag gives your agent a stable identity across restarts (useful for the /browse/ URL), while --share generates a public URL that works as an OAuth callback without any auth barriers.
Why not use the/browse/URL for callbacks?
/browse/URLs require authentication (API key header or active dashboard session) on every request. OAuth redirects are plain browser GETs from the provider — they won't carry your nfltr API key or session cookie. Use--shareto get a public URL that works reliably.
The full OAuth flow works end-to-end:
- Postman →
GET {{baseUrl}}/login→ redirects to Google - Google → authenticates → redirects to your share URL callback
- nfltr → tunnels callback to
localhost:3000/oauth/google/callback - Your API → exchanges code for token → responds
Use Postman's Authorization tab with OAuth 2.0 type for automated token management.
Tip: Share URLs change on each restart. For stable callback URLs across restarts, you'll need to update the provider's callback URL each time you reconnect — or keep the tunnel running with --duration.
Workflow: Load Testing with Postman + nfltr
# Use a share URL for easy access
nfltr http 3000 --share
# Use the share URL from the output as your Postman base URL
In Postman:
- Open your collection → Run collection
- Set iterations (e.g., 100)
- Set delay (e.g., 100ms)
- Click Run
nfltr handles concurrent requests through the gRPC tunnel. Monitor your API's response times directly in Postman's run results.
Tips & Best Practices
Use --name for stable URLs (advanced)
nfltr http 3000 --name my-api
With --name my-api, the /browse/ URL stays the same across restarts, which is useful for bookmarked endpoints and personal access from tools that can send an X-API-Key header (like curl or Postman). /browse/ URLs are not suitable for webhooks or OAuth callbacks — external services cannot authenticate.
Your full agent ID is <api-key-prefix>.<name> — for example, if your API key's identity is alice, then --name my-api creates the browse URL /browse/alice.my-api/. Agent IDs are not globally unique — they're scoped to your API key, so different users can safely pick the same --name without conflict. Run nfltr status to see your exact agent ID.
For most Postman workflows, --share is simpler — no auth needed.
Use --share for easy collaboration
nfltr http 3000 --share
Share URLs like https://swift-bay.nfltr.xyz/ expire after the tunnel disconnects — perfect for a code review session or a quick demo. No authentication needed — just share the link.
Set request timeout in Postman
nfltr's default request timeout is 60 seconds. Match it in Postman: Settings → General → Request timeout → 60000 ms.
Use Postman's console for debugging
Open View → Postman Console (⌘+⌥+C) to see raw request/response headers. Useful for verifying nfltr's proxy headers.
Combine with Postman's Mock Server
- Build your contract in Postman (mock server)
- Implement the real API locally
- Expose via nfltr
- Swap the Postman environment from mock to tunnel URL
- Run the same collection — validates real vs. mock parity
Complete Example: REST API Development Session
# 1. Start your API
cd my-api && go run . & # serves on :8080
# 2. Create a tunnel with a share URL
nfltr http 8080 --share
# 3. In Postman, set baseUrl to the share URL from the output
# e.g., baseUrl = https://swift-bay.nfltr.xyz
# 4. Test CRUD operations:
# POST {{baseUrl}}/api/users → Create
# GET {{baseUrl}}/api/users → List
# GET {{baseUrl}}/api/users/123 → Read
# PUT {{baseUrl}}/api/users/123 → Update
# DELETE {{baseUrl}}/api/users/123 → Delete
# 5. Share with teammate — just send the share URL
# 6. Configure Stripe webhooks: paste the share URL + path
# https://swift-bay.nfltr.xyz/webhooks/stripe
# 7. Run full collection:
# newman run api-tests.json --env-var "baseUrl=https://swift-bay.nfltr.xyz"
# 8. Done — Ctrl+C to stop the tunnel
What You Get in This Workflow
| Feature | What NFLTR gives you |
|---|---|
| Stable named URLs | --name gives you a durable endpoint identity you can keep in collections and scripts. |
| Shareable short URLs | --share creates a public URL you can hand to teammates or webhook providers. |
| Multi-route tunnels | --route lets one tunnel front several local services. |
| mTLS auth | Protected endpoints can use built-in mutual TLS instead of only bearer-style access. |
| Webhook verification | The webhook verification module gives you a path from manual Postman tests to signed-provider traffic. |
| ARM / edge agents | The same workflow can run on laptops, ARM hosts, and WASM-based environments. |
Troubleshooting
"Connection refused" in Postman
Your local API isn't running. Verify:
curl http://localhost:3000/
nfltr tunnels to whatever is listening on the port. If nothing is listening, Postman gets a 502 Bad Gateway.
Slow responses (>1s)
Check the hop count: your machine → nfltr.xyz → your machine. If the server is far away, latency adds up.
nfltr logs every request automatically:
[1] GET /api/users → http://localhost:3000/api/users → 200 (1234 bytes, txn=abc123)
[2] POST /api/orders → http://localhost:3000/api/orders → 201 (88 bytes, txn=def456)
Use --verbose to also log heartbeats and full request headers:
nfltr http 3000 --verbose
"503 Service Unavailable" with Retry-After
The agent was recently connected but is temporarily offline. nfltr returns 503 with a Retry-After: 30 header so Postman retries after 30 seconds. If the agent reconnects in time, the next request succeeds.
CORS errors in Postman
Postman doesn't enforce CORS — that's a browser-only restriction. If you see CORS issues, you're testing from a browser, not Postman. Add CORS headers to your API or use Postman directly.
Next Steps
- Go SDK Reference — Embed the nfltr agent in your Go application