GUIDE / api
How to Test an API Without Documentation
Learn how to test an API without documentation: discover endpoints, reverse engineer contracts, design cases, validate auth, and avoid common blind spots.
Releases do not pause because Swagger is stale or a mobile backend never published a public contract. How to test an API without documentation is the practical skill of rebuilding contracts from traffic, examples, and experiments while still covering status codes, payloads, auth, and business rules.
This guide shows a practical discovery-first workflow: find endpoints, reconstruct behavior, design test cases from evidence, validate auth and errors, capture a living contract, and avoid the mistakes that create false confidence. For foundational service-layer skills, pair this with the API testing tutorial. When you are ready to formalize cases, use how to write API test cases.
Why APIs Lose Documentation (and Why Testers Still Own Quality)
Documentation debt is common for several reasons:
- The team moved fast and never wrote OpenAPI.
- The public docs describe v1 while clients call v2.
- Internal services were "temporary" and became permanent.
- Mobile or SPA traffic is the only living contract.
- Partners shared a PDF two years ago and never updated it.
- Auth and edge cases live only in developer memory.
None of these excuses change user risk. An undocumented checkout API can still double-charge. An undocumented admin endpoint can still leak PII. Testing without docs is not about guessing forever. It is about turning observation into a testable model faster than the product breaks.
What "Without Documentation" Actually Means
Before you start, classify the gap. "No docs" is rarely absolute.
| Situation | What you still have | Testing implication |
|---|---|---|
| No OpenAPI, but active UI | Browser traffic, UI labels, user flows | Capture and map requests from real journeys |
| Partial portal docs | Some endpoints, missing errors/auth | Validate documented paths, discover gaps |
| Internal service with logs | Request logs, metrics, error traces | Use logs as a discovery source |
| Partner API with sample JSON | Sample payloads only | Treat samples as seeds, not full contracts |
| Truly dark service | Host, maybe one path, no client | Careful probing plus stakeholder interviews |
Your strategy should match the gap. A mobile backend with rich client traffic needs traffic capture first. A brand new microservice with no clients needs interviews, code review (if allowed), and careful exploratory probing.
Principles for Testing Undocumented APIs
1. Treat observation as a hypothesis
A response you saw once is not yet a contract. Promote patterns to expectations only after they repeat under controlled conditions, or after a product owner confirms the rule.
2. Prefer non-destructive discovery first
Start with OPTIONS, GET, and safe reads. Delay writes, deletes, and bulk operations until you understand identifiers, auth, and side effects.
3. Rebuild a living contract continuously
Every session should improve a collection, OpenAPI draft, or notes file. If discovery stays in chat threads, the next tester starts from zero.
4. Separate "what exists" from "what should exist"
You may discover an endpoint that returns data it should not. Testing without docs still includes security and authorization judgment, not only happy-path mirroring of the client.
5. Risk first, completeness second
You will not map every field on day one. Cover money, identity, auth, data integrity, and high-traffic flows before obscure admin filters.
Step-by-Step: How to Test an API Without Documentation
Step 1: Define scope and constraints
Write down:
- Environment: staging, sandbox, production-read-only, local.
- Permission: what probing is allowed.
- Data sensitivity: PII, payments, secrets.
- Goal: smoke coverage, regression suite, security pass, partner onboarding.
Without scope, discovery becomes endless surfing.
Step 2: Inventory known entry points
Collect anything that hints at an API surface:
- Base URLs from config files, env vars, or mobile app settings.
- Reverse proxy paths (
/api,/v1,/graphql). - Client repositories if accessible.
- Gateway dashboards, WAF logs, or APM traces.
- Error emails and support tickets that quote endpoints.
Even a single base URL plus a login flow is enough to begin.
Step 3: Capture real client traffic
This is usually the highest value discovery method.
Browser apps
- Open DevTools Network panel.
- Filter XHR/Fetch.
- Exercise major UI journeys: login, list, create, update, delete, search, export.
- Export HAR or copy as cURL into Postman.
Mobile apps
- Route traffic through a trusted proxy in a test build.
- Capture HTTPS with certificate pinning disabled only in non-production builds you control.
- Map each screen action to request sequences.
Desktop or third-party clients
- Use a proxy or packet capture where policy allows.
- Note headers, cookies, tokens, and retry behavior.
Build a table as you capture:
| Journey | Method | Path | Auth | Notable headers | Sample status |
|---|---|---|---|---|---|
| Login | POST | /auth/login | none | Content-Type | 200 |
| List orders | GET | /orders?page=1 | Bearer | Accept | 200 |
| Create order | POST | /orders | Bearer | Idempotency-Key | 201 |
Step 4: Reconstruct the resource model
From captured traffic, identify nouns and relationships:
- Resources: users, orders, items, invoices.
- Identifiers:
id,uuid,slug, composite keys. - Relationships: order has line items, user has addresses.
- Lifecycle: draft -> submitted -> paid -> cancelled.
Draw a simple model:
User
└── Orders
└── LineItems
└── Payments
This model drives test design even before formal docs exist.
Step 5: Probe methods and content negotiation
For each discovered path, carefully check:
- Allowed methods: GET, POST, PUT, PATCH, DELETE, OPTIONS, HEAD.
- Content types:
application/json, form data, multipart. - Version headers or path versions:
/v1,/v2,Accept-Version. - Query conventions: filter, sort, page, limit, include.
Example exploratory checks:
OPTIONS /orders HTTP/1.1
Host: api.example.test
GET /orders HTTP/1.1
Host: api.example.test
Accept: application/json
Authorization: Bearer <token>
GET /orders HTTP/1.1
Host: api.example.test
Accept: application/xml
Authorization: Bearer <token>
Record which methods return 200/201, which return 405, and which unexpectedly succeed.
Step 6: Reverse engineer authentication and authorization
Auth is where undocumented APIs hide the most risk. Study:
- Login request and token shape (JWT, opaque token, session cookie).
- Token refresh flow.
- Required scopes or roles in responses.
- Difference between missing token, expired token, and wrong role.
- Admin-only paths that the UI never exposes to normal users.
Build a matrix:
| Actor | Endpoint | Expected outcome |
|---|---|---|
| Anonymous | GET /orders | 401 |
| Buyer | GET /orders | 200 own data |
| Buyer | GET /orders/{otherUserOrder} | 403 or 404 |
| Admin | GET /orders/{any} | 200 |
For deeper auth patterns, see API authentication testing.
Step 7: Infer validation rules from errors
Send controlled invalid inputs and capture messages carefully.
Examples:
- Omit required fields.
- Send wrong types (
"quantity": "two"). - Exceed length limits.
- Use future dates where only past dates make sense.
- Reuse unique keys.
Error bodies often reveal the real schema:
{
"error": "validation_failed",
"details": [
{ "field": "email", "code": "invalid_format" },
{ "field": "quantity", "code": "must_be_positive_integer" }
]
}
Turn each detail into a negative test case and a schema constraint note.
Step 8: Map status codes to behaviors
Do not assume textbook status codes. Observe and document actual behavior, then challenge unsafe choices.
Useful reference while interpreting responses: REST API status codes.
| Observed | Likely meaning | Test idea |
|---|---|---|
| 200 on create | Non-standard but possible | Assert body and side effect, note inconsistency |
| 201 on create | Standard create | Assert Location/id |
| 204 on delete | Success no body | Assert resource gone |
| 400 on bad JSON | Client error | Invalid payload suite |
| 401/403 mix | Auth vs authz | Separate missing vs forbidden |
| 404 for hidden resources | Security through obscurity | IDOR checks still needed |
| 429 | Rate limit | Burst and recovery tests |
| 500 on edge input | Server bug | Reproduce and file defect |
Step 9: Design test cases from the reconstructed model
Once you have resources, auth, and validation hints, write cases the same way you would with docs, but mark confidence levels.
| ID | Title | Confidence | Source of truth |
|---|---|---|---|
| TC-ORD-001 | Buyer creates valid order | High | UI + repeated 201 |
| TC-ORD-002 | Missing productId rejected | Medium | Error detail observed |
| TC-ORD-003 | Buyer cannot read other buyer order | High | Security requirement + probe |
| TC-ORD-004 | Pagination default page size | Low | Observed only once |
Promote low-confidence cases after confirmation. Do not silently treat every observation as guaranteed product law.
Step 10: Verify side effects, not only response bodies
Undocumented APIs often look fine in JSON while breaking downstream state.
Check:
- Database or admin UI state (when allowed).
- Emails, webhooks, queue messages.
- Inventory decrements.
- Idempotency keys preventing duplicates.
- Cache staleness after updates.
A create endpoint that returns 201 with an id but never persists is a critical defect.
Step 11: Capture a living contract
Convert learning into one of:
- Postman/Bruno collection with examples and tests.
- Draft OpenAPI from traffic or manual authoring.
- Markdown endpoint catalog in the repo.
- Contract tests once consumer/provider boundaries are clear.
Minimal OpenAPI sketch from discovery:
openapi: 3.0.3
info:
title: Discovered Orders API
version: "0.1.0-draft"
paths:
/orders:
get:
summary: List orders for current user
parameters:
- in: query
name: page
schema: { type: integer, minimum: 1 }
responses:
"200":
description: Paginated order list
post:
summary: Create order
responses:
"201":
description: Order created
"400":
description: Validation error
Mark it draft. Version it. Update it when production clients teach you something new.
Step 12: Automate the stable core
Automate only after expectations stabilize:
- Auth smoke.
- Critical CRUD happy paths.
- High-risk negatives (authz, payment validation).
- Schema checks for key responses.
- A few idempotency and pagination invariants.
Keep exploratory sessions for new builds. Discovery is continuous when docs remain weak.
Discovery Techniques Toolkit
Traffic-first discovery
Best when a client already exists. Fastest path to real field names and sequences.
Code-assisted discovery
If you can read the service code or client SDK:
- Route tables and controllers list endpoints.
- DTOs reveal required fields.
- Middleware shows auth requirements.
- Tests in the repo are accidental documentation.
Use code as a hint, still verify runtime behavior.
Error-message mining
Verbose errors in lower environments leak schema and business rules. Capture them, then confirm whether production is stricter or quieter.
Sequence diagram reconstruction
For multi-step flows (checkout, onboarding), record ordered calls:
1. POST /cart/items
2. POST /cart/coupons
3. GET /cart/totals
4. POST /checkout/sessions
5. POST /payments/confirm
6. GET /orders/{id}
Failures often live between steps, not inside a single call.
Differential analysis across roles
Call the same endpoint as guest, user, manager, and admin. Diff status codes and body fields. Authorization bugs show up as unexpected 200s or extra fields.
Parameter fuzzing with guardrails
Once a path is known, vary:
- IDs (valid, invalid, other-tenant, SQL-ish strings carefully in test envs)
- Enums (known values plus unknown)
- Booleans as strings
- Empty arrays vs null
- Unicode and long strings
Fuzz to learn constraints, not to vandalize shared environments.
Worked Example: Undocumented Inventory Service
Imagine a warehouse SPA. There is no Swagger. You only know https://staging.example.test.
Session notes
- Login via UI captures
POST /api/sessionreturning{ "token": "...", "role": "clerk" }. - Inventory page calls
GET /api/skus?limit=50. - Editing quantity calls
PATCH /api/skus/SKU-100with{ "onHand": 12 }. - Export button calls
GET /api/skus/export.csv. - Admin user sees
DELETE /api/skus/SKU-100in a different build flavor.
Reconstructed expectations
| Case | Request | Expected |
|---|---|---|
| Clerk list | GET /api/skus | 200 array, no cost fields |
| Clerk patch valid | PATCH onHand 12 | 200, onHand updated |
| Clerk patch negative | onHand -1 | 400 validation |
| Clerk delete | DELETE | 403 |
| Admin delete | DELETE | 204 and item gone |
| No token list | GET | 401 |
| CSV export | GET export.csv | 200 text/csv with header row |
First automated smoke
// pseudo-test
test("clerk can list skus", async () => {
const res = await api.get("/api/skus?limit=50", clerkToken);
expect(res.status).toBe(200);
expect(Array.isArray(res.body)).toBe(true);
expect(res.body[0]).toHaveProperty("sku");
expect(res.body[0]).not.toHaveProperty("unitCost");
});
You now have documentation in executable form.
Designing Coverage Without a Spec
Use risk-based categories:
Functional correctness
- Create/read/update/delete where applicable.
- Search/filter/sort.
- Pagination defaults and bounds.
- State transitions (cancel, approve, ship).
Contract shape
- Required fields present.
- Types stable.
- Nullability consistent.
- Unexpected breaking renames caught early.
Security and tenancy
- Authn failures.
- Authz matrix.
- Object-level authorization (IDOR).
- Mass assignment of privileged fields (
role,price,isAdmin).
Resilience and abuse
- Rate limits.
- Oversized payloads.
- Duplicate submits.
- Partial failure retries.
Compatibility
- Old clients vs new fields.
- Optional headers.
- Version routing.
Comparison: Documented vs Undocumented Testing Effort
| Activity | With solid docs | Without docs |
|---|---|---|
| Endpoint inventory | Hours | Days of capture/probing |
| Expected results | Mostly given | Hypotheses then confirmation |
| Auth matrix | Often partial | Must reverse engineer |
| Automation start | Faster | Delayed until stable observations |
| Defect style | Deviations from spec | Discoveries of missing rules and unsafe defaults |
| Ongoing cost | Maintain suite | Maintain suite + living contract |
Undocumented work is heavier up front. The payoff is that your test assets often become the best documentation the company has.
Collaboration Tactics When Specs Are Missing
Testers should not reverse engineer alone forever.
- Schedule short contract interviews with backend owners.
- Share your draft OpenAPI as a review artifact.
- File "missing documentation" issues with severity based on consumer risk.
- Ask product to confirm business rules you inferred from errors.
- Propose consumer-driven contracts if multiple clients depend on the service.
A useful question in standups: "Which undocumented endpoint changed this sprint?" That alone prevents silent breakages.
Checklist: Testing an API Without Documentation
Use this before you call discovery "done enough" for a release:
- Base URLs and environments listed
- Major client journeys captured as requests
- Resource model sketched
- Auth mechanism and roles understood
- Critical happy paths have expected results
- High-risk negatives defined (authz, validation, money)
- Status code map recorded for key endpoints
- Side effects verified for create/update/delete
- Living collection or OpenAPI draft updated
- Smoke automation covers the top risks
- Open questions escalated to owners
Common Mistakes When You Test APIs Without Documentation
Mistake 1: Copying the UI as if it were the full API
The UI may never call admin routes, bulk endpoints, or legacy methods still exposed publicly. Client coverage is a starting set, not the complete attack or integration surface.
Mistake 2: Turning one sample response into a rigid schema too early
Optional fields appear on some records only. Over-strict assertions then flake. Start with required core fields, then tighten after broader sampling.
Mistake 3: Ignoring authorization because happy paths work
If a buyer can complete flows, that does not mean object-level checks are safe. Always test access to other users' IDs.
Mistake 4: Testing only GET endpoints
Reads feel safe and easy. Many production incidents come from write paths, webhooks, and delete semantics.
Mistake 5: Leaving discovery notes outside the suite
Screenshots in a personal folder expire. Collections, contract drafts, and automated checks survive handoffs.
Mistake 6: Aggressive probing in production
Undocumented production APIs can still trigger real charges, emails, or legal issues. Prefer staging. If production is required, use read-only accounts and approved test tenants.
Mistake 7: Assuming 404 means "secure"
Some systems hide existence with 404 while still leaking timing or secondary endpoints. Combine status checks with broader tenancy tests.
Mistake 8: Never confirming inferred business rules
If you inferred "quantity must be positive" from one error, confirm whether zero is allowed for backorders. Wrong expected results create invalid bugs and missed bugs.
FAQ-Oriented Mini Patterns
"I only have a base URL. Now what?"
Start with GET /, GET /health, GET /api, GET /v1, and OPTIONS where allowed. Then search client bundles for path strings. Without a client or code, escalate for access to logs or a smoke UI.
"Responses are inconsistent. How do I write cases?"
Document variants. Example: order responses include payment only when status is paid. Parameterize expectations by state instead of forcing one universal body.
"Should I fail the build if the living OpenAPI drifts?"
Yes for critical consumers, once the draft is reviewed. Early in discovery, warn instead of fail. After agreement, treat breaking changes as release blockers.
Practice Path on QABattle
Theory sticks when you practice under constraints. Open QABattle battles or start free at sign-up and pick API challenges where the prompt is incomplete on purpose. Force yourself to:
- List only what you can observe.
- Write five cases with confidence tags.
- Automate two smokes.
- Record three open questions for a fictional API owner.
That workflow mirrors undocumented services at work.
Putting It All Together
To master how to test an API without documentation, stop waiting for a perfect Swagger file and build evidence systems instead:
- Capture traffic and inventory endpoints.
- Reconstruct resources, auth, and validation rules.
- Design risk-based cases with confidence levels.
- Verify side effects and authorization, not only JSON.
- Publish a living contract and automate the stable core.
- Keep discovering as clients and versions change.
Undocumented APIs punish teams that rely on memory. They reward teams that turn every probe into shared, executable knowledge. Use the API testing tutorial for fundamentals, how to write API test cases for case structure, and API authentication testing when tokens and roles get messy. Then keep sharpening on real battles in the app.
When you leave a service better documented than you found it, you did more than test. You reduced operational risk for every engineer who comes next.
FAQ
Questions testers ask
How do you test an API that has no documentation?
Start with discovery: capture traffic from the client, list reachable routes, probe HTTP methods, inspect auth flows, and rebuild a draft contract from real requests and responses. Then design cases for happy paths, validation, auth, errors, and side effects, and refine the contract as you learn.
What tools help when testing an undocumented API?
Use browser DevTools, proxy tools such as Charles or mitmproxy, Postman or Bruno for exploration, OpenAPI generators from traffic, and coded clients for automation. Logs, server error messages, and database state (when allowed) also reveal structure that docs would normally provide.
Is it safe to reverse engineer a production API for testing?
Prefer staging or dedicated test environments. If you must use production-like systems, stick to read-only probes first, avoid destructive writes, respect rate limits, and get permission. Undocumented does not mean unrestricted. Security and data rules still apply.
How do you know expected results without a formal contract?
Derive expectations from UI behavior, business rules, stable observed responses, error messages, status codes, and stakeholder confirmation. Treat early observations as hypotheses. Promote them to documented expectations only after repeated, consistent behavior or explicit product sign-off.
Should you write OpenAPI after reverse engineering?
Yes when the API will be reused or automated. A living draft OpenAPI or collection becomes the missing documentation, reduces tribal knowledge, and makes schema and status code checks maintainable. Keep it versioned and update it whenever reality diverges.
What is the biggest risk when testing undocumented APIs?
False confidence. You may cover the paths you observed while missing rare methods, hidden fields, auth edge cases, or destructive side effects. Pair discovery with risk-based prioritization, negative testing, and continuous capture of new client traffic.
RELATED GUIDES
Continue the route
API Testing Tutorial: A Beginner's Complete Guide
API testing tutorial for beginners: learn REST API checks, CRUD test cases, tools, status codes, and a practical checklist for reliable API quality.
How to Write API Test Cases
How to write API test cases with practical templates, CRUD examples, auth checks, negative paths, and a review checklist for reliable service coverage.
REST API Status Codes: The Complete Reference for Testers
Master REST API status codes with a complete tester cheat sheet for 2xx, 4xx, and 5xx responses, error validation, and practical test design.
API Authentication Testing: OAuth, JWT, and API Keys
Learn API authentication testing for OAuth 2.0, JWT expiry and refresh flows, API keys vs bearer tokens, and broken authentication test cases.