Testing with Postman
Testing with Postman
This guide explains how to configure Postman to authenticate against the bloqr-backend API using either a Clerk JWT or an API key. It covers environment setup, obtaining tokens, pre-request scripts for automatic token refresh, and ready-to-use request examples for every major endpoint.
Table of Contents
- Prerequisites
- Postman Environment Setup
- Authentication Methods
- Collection Setup
- Request Examples
- Testing All Tiers
- Common Errors & Troubleshooting
Prerequisites
- Postman desktop app (v10+) or Postman Web
- An account registered at the bloqr-backend web UI (
https://api.bloqr.dev/)
or a locally running worker (http://localhost:8787) - (Optional) Clerk account access for your bloqr-backend application — see Clerk Dashboard Setup
Postman Environment Setup
Create a dedicated Postman environment to avoid hard-coding values into requests.
Step 1: Create the Environment
- Open Postman → Environments (left sidebar) → +
- Name it
bloqr-backend(orbloqr-backend-localfor local dev) - Add the following variables:
| Variable | Type | Initial / Current Value | Notes |
|---|---|---|---|
baseUrl | default | https://api.bloqr.dev | Change to http://localhost:8787 for local dev |
apiKey | secret | (your abc_... key) | Obtained from Settings → API Keys in the web UI |
clerkJwt | secret | (leave blank — populated automatically) | Set by pre-request script or manually |
clerkPublishableKey | default | pk_test_... or pk_live_... | From Clerk Dashboard → API Keys |
adminKey | secret | (your admin key) | Only needed for /admin/* endpoints — see Admin Access |
- Click Save
- Select
bloqr-backendas the Active Environment (top-right dropdown)
Step 2: Activate the Environment
Ensure the environment is selected in the top-right Environment dropdown before sending any requests.
Authentication Methods
The bloqr-backend supports three authentication methods. For Postman testing, API Key is the simplest option. Use Clerk JWT when you need to test tier-specific behaviour or user-scoped endpoints.
Method 1: API Key (Recommended for Testing)
API keys are the easiest way to authenticate in Postman because they never expire (unless you set an expiration) and don’t require a browser sign-in flow.
Step 1: Create an API Key
- Sign in to the web UI
- Go to Settings → API Keys
- Click “Create API Key”
- Fill in:
- Name:
Postman Testing - Scopes: Select all that apply —
compile,rules,admin - Expiration: Optional
- Name:
- Copy the key (starts with
abc_) — it’s only shown once
Step 2: Add the Key to Postman
Paste the key into the apiKey environment variable created above.
Step 3: Configure Authorization
In any request (or at the collection level — see Collection Setup):
- Open the request → Authorization tab
- Select Type:
Bearer Token - Set Token:
{{apiKey}}
All requests using {{apiKey}} will automatically send:
Authorization: Bearer abc_Xk9mP2...Method 2: Clerk JWT (Manual Token)
Use this method when you need a real Clerk JWT (e.g., to test tier enforcement or user-specific features) but don’t want to set up a script.
Step 1: Sign in to the Web UI and Copy the JWT
-
Open the web UI in your browser and sign in
-
Open DevTools → Application tab → Session Storage or Local Storage
— look for keys prefixed with__clerk_db_jwtor__session
or use DevTools Network tab:- Filter requests for
Authorization: Bearer - Copy the token value (a long JWT string starting with
eyJ...)
Tip: The easiest method is to use the browser DevTools console:
// Paste this in the browser console while on the web UIconst session = window.Clerk?.session;session?.getToken().then(t => console.log(t));Copy the printed token.
- Filter requests for
-
Paste the JWT into the
clerkJwtenvironment variable in Postman
Step 2: Configure Authorization
In your request → Authorization tab:
- Type:
Bearer Token - Token:
{{clerkJwt}}
Note: Clerk JWTs are short-lived (typically 60 seconds). You will need to refresh this token frequently. Consider using the pre-request script method instead.
Method 3: Clerk JWT (Automatic via Pre-Request Script)
Status: Clerk’s hosted sign-in flow requires browser interaction, so fully headless JWT retrieval is not natively supported in Postman without the Clerk Frontend API. This script uses the Clerk Frontend API to obtain a session token from existing credentials.
Best for: Teams with a dedicated test account where the session can be refreshed programmatically.
See Pre-Request Script for Automatic JWT Refresh for the full script.
Collection Setup
Creating the Collection
- In Postman, click Collections (left sidebar) → + → Blank Collection
- Name it
bloqr-backend - Add a description:
Testing collection for the bloqr-backend API
Collection-Level Authorization
Set authorization once at the collection level so all requests inherit it automatically.
- Click the collection name → Authorization tab
- Configure:
- Type:
Bearer Token - Token:
{{apiKey}}
- Type:
- Click Save
All requests in the collection will default to Inherit auth from parent, which picks up {{apiKey}} automatically. Override on individual requests as needed.
Pre-Request Script for Automatic JWT Refresh
Add this script to the collection’s Pre-request Script tab to automatically fetch and cache a fresh Clerk JWT before each request. This uses the Clerk Frontend API with a long-lived session token.
Setup required: This script requires a
clerkSessionTokenenvironment variable containing a long-lived Clerk session token. Obtain it by signing in to the Clerk-powered web UI and copying the__clientcookie value, or by calling Clerk’s/v1/clientendpoint from a signed-in browser session.
// Collection Pre-request Script — Automatic Clerk JWT Refresh// Refreshes the JWT if it is missing or expires within the next 30 seconds.
const jwt = pm.environment.get('clerkJwt');const jwtExpiry = pm.environment.get('clerkJwtExpiry');const now = Math.floor(Date.now() / 1000);
// Skip refresh if the cached JWT is still valid for > 30 secondsif (jwt && jwtExpiry && parseInt(jwtExpiry) > now + 30) { console.log('[Clerk] Using cached JWT, expires in', parseInt(jwtExpiry) - now, 's'); return;}
// Derive the Clerk Frontend API URL from the publishable key// pk_test_<base64(domain)> → decode to get the Clerk Frontend API hostconst publishableKey = pm.environment.get('clerkPublishableKey');if (!publishableKey) { console.warn('[Clerk] clerkPublishableKey not set — skipping JWT refresh'); return;}
const sessionToken = pm.environment.get('clerkSessionToken');if (!sessionToken) { console.warn('[Clerk] clerkSessionToken not set — cannot refresh JWT'); console.warn('[Clerk] Set clerkSessionToken to your __client cookie value from a signed-in browser session'); return;}
// Decode the Clerk Frontend API host from the publishable keyconst keyPart = publishableKey.replace(/^pk_(test|live)_/, '');let clerkFapiHost;try { clerkFapiHost = atob(keyPart).replace(/\$$/, '');} catch (e) { console.error('[Clerk] Failed to decode publishable key:', e.message); return;}
const fapiUrl = `https://${clerkFapiHost}/v1/client/sessions/{{clerkSessionId}}/tokens`;
pm.sendRequest( { url: fapiUrl, method: 'POST', header: { 'Content-Type': 'application/x-www-form-urlencoded', 'Cookie': `__client=${sessionToken}`, }, }, (err, res) => { if (err) { console.error('[Clerk] JWT refresh failed:', err); return; } if (res.code !== 200) { console.error('[Clerk] JWT refresh returned', res.code, res.text()); return; } const body = res.json(); const newJwt = body?.jwt; if (!newJwt) { console.error('[Clerk] No JWT in response:', body); return; } // Decode expiry from JWT payload (middle segment) try { const payload = JSON.parse(atob(newJwt.split('.')[1])); pm.environment.set('clerkJwtExpiry', String(payload.exp)); } catch (_) { // If decode fails, assume 60s expiry pm.environment.set('clerkJwtExpiry', String(now + 60)); } pm.environment.set('clerkJwt', newJwt); console.log('[Clerk] JWT refreshed successfully'); });Simpler alternative: For most Postman testing, use the
{{apiKey}}variable instead. API keys are long-lived and require no scripting.
Request Examples
Import the examples below by creating new requests in the bloqr-backend collection. All examples assume the bloqr-backend environment is active.
Health & Version (Public — No Auth)
These endpoints require no authentication and are useful to verify connectivity.
GET /health
| Field | Value |
|---|---|
| Method | GET |
| URL | {{baseUrl}}/health |
| Auth | No auth |
Expected Response (200 OK):
{ "status": "ok", "timestamp": "2026-03-13T00:00:00.000Z"}GET /api/version
| Field | Value |
|---|---|
| Method | GET |
| URL | {{baseUrl}}/api/version |
| Auth | No auth |
Compile Filter List
POST /compile — Compile with API Key
| Field | Value |
|---|---|
| Method | POST |
| URL | {{baseUrl}}/compile |
| Auth | Bearer Token → {{apiKey}} |
| Content-Type | application/json |
Body (raw JSON):
{ "sources": [ "https://raw.githubusercontent.com/AdguardTeam/FiltersRegistry/master/filters/filter_2_Base/filter.txt" ], "transformations": ["validate", "deduplicate"]}Expected Response (200 OK):
{ "success": true, "rules": ["...", "..."], "stats": { "total": 1234, "deduplicated": 56 }}POST /compile — Unauthenticated (Anonymous)
| Field | Value |
|---|---|
| Method | POST |
| URL | {{baseUrl}}/compile |
| Auth | No auth |
| Content-Type | application/json |
Note: Anonymous access is rate-limited to 10 req/min and will be removed in a future release. Expect a
429 Too Many Requestsif you exceed the limit. See Removing Anonymous Access.
Expected Response Headers:
X-Auth-Warning: Anonymous access will be removed. Please register for continued access.X-RateLimit-Limit: 10X-RateLimit-Remaining: 9POST /compile/batch — Batch Compile
| Field | Value |
|---|---|
| Method | POST |
| URL | {{baseUrl}}/compile/batch |
| Auth | Bearer Token → {{apiKey}} (requires compile scope) |
| Content-Type | application/json |
Body:
{ "jobs": [ { "id": "job-1", "sources": ["https://example.com/list1.txt"], "transformations": ["validate"] }, { "id": "job-2", "sources": ["https://example.com/list2.txt"], "transformations": ["deduplicate", "compress"] } ]}API Key Management
These endpoints require a valid Clerk JWT (not an API key — you can’t manage API keys using an API key).
GET /api/keys — List Your API Keys
| Field | Value |
|---|---|
| Method | GET |
| URL | {{baseUrl}}/api/keys |
| Auth | Bearer Token → {{clerkJwt}} |
Expected Response (200 OK):
{ "success": true, "keys": [ { "id": "key_abc123", "name": "Postman Testing", "scopes": ["compile", "rules"], "createdAt": "2026-01-01T00:00:00.000Z", "expiresAt": null, "lastUsedAt": "2026-03-13T00:00:00.000Z" } ]}POST /api/keys — Create an API Key
| Field | Value |
|---|---|
| Method | POST |
| URL | {{baseUrl}}/api/keys |
| Auth | Bearer Token → {{clerkJwt}} |
| Content-Type | application/json |
Body:
{ "name": "My New Key", "scopes": ["compile"], "expiresInDays": 90}Expected Response (201 Created):
{ "success": true, "key": { "id": "key_xyz789", "name": "My New Key", "token": "abc_Xk9mP2...", "scopes": ["compile"], "expiresAt": "2026-06-11T00:00:00.000Z" }}Important: Copy the
tokenvalue immediately — it is only returned once.
PATCH /api/keys/:id — Update an API Key
| Field | Value |
|---|---|
| Method | PATCH |
| URL | {{baseUrl}}/api/keys/key_xyz789 |
| Auth | Bearer Token → {{clerkJwt}} |
| Content-Type | application/json |
Body:
{ "name": "Renamed Key", "scopes": ["compile", "rules"]}DELETE /api/keys/:id — Revoke an API Key
| Field | Value |
|---|---|
| Method | DELETE |
| URL | {{baseUrl}}/api/keys/key_xyz789 |
| Auth | Bearer Token → {{clerkJwt}} |
Expected Response (200 OK):
{ "success": true, "message": "API key revoked"}Admin Endpoints
Admin endpoints require both the X-Admin-Key header and (if Cloudflare Access is configured) a valid CF-Access-JWT-Assertion header. See Admin Access for full details.
GET /admin/storage/stats
| Field | Value |
|---|---|
| Method | GET |
| URL | {{baseUrl}}/admin/storage/stats |
| Auth | No auth (uses custom header instead) |
| Custom Header | X-Admin-Key: {{adminKey}} |
To add the custom header:
- Open the request → Headers tab
- Add a new header:
- Key:
X-Admin-Key - Value:
{{adminKey}}
- Key:
Expected Response (200 OK):
{ "success": true, "stats": { "totalUsers": 42, "totalApiKeys": 108 }}Unauthorized Response (401 Unauthorized):
{ "success": false, "error": "Unauthorized"}Testing All Tiers
To verify tier-based rate limiting and access control, test with credentials for each tier:
| Tier | How to Get Credentials | Rate Limit | Test Strategy |
|---|---|---|---|
| Anonymous | No auth | 10 req/min | Send 11+ requests in a minute — expect 429 on the 11th |
| Free | Sign up → {{clerkJwt}} or API key with compile scope | 60 req/min | Same as above with higher limit |
| Pro | Set tier: pro in Clerk public metadata | 300 req/min | Same |
| Admin | Set tier: admin, role: admin in Clerk metadata | Unlimited | Test /admin/* endpoints |
Setting Up a Test User’s Tier (via Clerk Dashboard)
- Go to dashboard.clerk.com → your application → Users
- Find the test user → click their name
- Scroll to Public metadata → click Edit
- Set:
{"tier": "pro"}
- Click Save
- The webhook fires a
user.updatedevent, syncing the tier to PostgreSQL - Obtain a fresh JWT (the old JWT may still carry the old tier until it expires)
Common Errors & Troubleshooting
| HTTP Status | Error | Likely Cause | Fix |
|---|---|---|---|
401 Unauthorized | "Authentication required" | Missing or malformed Authorization header | Ensure Bearer {{apiKey}} or Bearer {{clerkJwt}} is set correctly |
401 Unauthorized | "Invalid token" | Expired or invalid JWT | Refresh {{clerkJwt}} — Clerk JWTs are short-lived (~60s) |
403 Forbidden | "Insufficient tier" | Your account tier is too low for the endpoint | Upgrade tier in Clerk metadata, or use an API key with the required scope |
403 Forbidden | "Missing required scope" | API key lacks a required scope (e.g., admin) | Create a new API key with the correct scopes |
429 Too Many Requests | "Rate limit exceeded" | Exceeded your tier’s request-per-minute limit | Wait 60 seconds, or use a higher-tier account |
401 Unauthorized (admin) | "Unauthorized" | Missing or incorrect X-Admin-Key header | Check {{adminKey}} environment variable |
400 Bad Request | "Invalid request body" | Malformed JSON or missing required fields | Validate your JSON body — check sources is an array |
Verifying the Authorization Header is Set
In Postman, after sending a request:
- Click Console (bottom bar) → find the request
- Expand Request Headers
- Confirm
Authorization: Bearer abc_...(oreyJ...for JWT) is present
JWT Claims Inspection
To inspect a Clerk JWT’s claims (tier, expiry, user ID):
- Copy the value of
{{clerkJwt}}from the environment - Paste it into jwt.io
- The Payload section shows:
sub— Clerk user IDexp— expiry timestamp (Unix)metadata.tier— user’s tier (if JWT template is configured — see Clerk Setup)
Further Reading
- API Authentication Guide — Full auth method reference
- Clerk Dashboard Setup — Creating and configuring the Clerk application
- Configuration Guide — All environment variables
- Admin Access Guide — Admin endpoint authentication
- Removing Anonymous Access — Migration timeline
Bloqr AI™ — The privacy you didn't know you needed.
© 2026 Bloqr AI™, a trademark of Bloqr Systems™. Created by Bloqr Systems™, founded by Jayson Knight.
Internet Hygiene (n.) — the ongoing practices that keep your digital life clean, private, and safe.
Our product repos live in the BloqrAI org, part of the Bloqr Systems GitHub Enterprise. Product repos are internal-visibility — enterprise membership is required to view them.