API Testing Services in India
API testing services in India for CTOs, founders and engineering managers in the US, UK, Canada, Australia and New Zealand whose APIs other teams depend on. We build contract, schema, authorisation and regression coverage at the API layer, wired into your pipeline, so a change that would break a consumer fails on your branch instead of in their production. This is the interface layer specifically, not browser testing.
Why Does a Green Integration Suite Still Break Your Consumers?
Here is the sequence almost every team recognises. Your service has an integration test suite. It runs on every commit. It is green. You ship on Tuesday afternoon. On Wednesday morning the mobile team files a bug saying a field came back null that has never been null before, and a partner emails to say their nightly sync failed with a parse error at 02:00.
Nothing in your pipeline was wrong. It was answering a different question. An integration suite normally exercises your service against fixtures your own team wrote, asserting the behaviour your own team expects. That proves internal consistency. It says nothing about whether the exact request your consumer sends still produces a response their deserialiser can read. The consumer, meanwhile, is testing against a stub that someone hand wrote nine months ago and has updated twice since. Both suites are green. Neither of them has ever seen the other side.
The breakages that come out of that gap are boringly consistent. A field is renamed and the old name stays in the docs. A type quietly changes from integer to string because an ORM column changed. An enum gains a value that a consumer's switch statement does not handle. A validation rule tightens and requests that used to pass start returning 422. An endpoint starts returning 200 with an empty array where it used to return 404, and a consumer's error handling silently stops firing. None of these are exotic bugs. They are all invisible to a suite that only ever talks to itself.
The cost lands unevenly, which is why it stays unfixed. Your team spends an hour. The consumer team spends a day, plus the meeting about why nobody warned them, plus the trust they no longer extend to your release notes. If the consumer is a paying customer integrating against a public API, the cost is a support queue and a churn conversation. If it is an internal team, the cost is that they start pinning to an old version and copying your data into their own store, which is how a distributed system quietly turns into a set of unreliable copies.
API testing is the layer that answers the question your integration suite does not: given everything that currently depends on this interface, is this change safe to release? That is a different job from clicking through a browser, and it needs different tools, different assertions and a different place in the pipeline.
What an API Testing Engagement Actually Covers
Scope varies with how many consumers you have and how public the API is, but the shape below is what we build and what we hand over. Everything lands in your repository, in your CI, in a language your team already uses.
An inventory of the real surface
Before writing a test we list what actually exists: every route, method, auth requirement, request and response shape, and every known consumer. On a mature service this list is usually longer than anyone expects, and it routinely turns up endpoints nobody remembers writing that are still receiving traffic. Access logs settle the argument about what is live.
Contract coverage between each consumer and provider pair
For the integrations that matter, a consumer-driven contract that the provider verifies in its own pipeline. This is the piece that turns a downstream breakage into a failed build on the branch that caused it.
Schema validation in both directions
Requests validated against the documented schema so your API rejects what it says it rejects, and responses validated so the shape you promise is the shape you send. Where an OpenAPI or JSON Schema document exists, it becomes an executable artifact rather than a wiki page.
Authorisation and authentication cases
A matrix of principals against protected routes, including the object level cases that permission middleware never covers. This is consistently the area with the widest gap between what teams believe is tested and what is.
Error paths, limits and edge behaviour
Malformed payloads, oversized bodies, wrong content types, missing required fields, boundary values, pagination limits, rate limit responses and the shape of the error body itself. Happy path coverage without this is a suite that only ever proves the thing that was never going to break.
Backward compatibility checks tied to your versioning policy
Automated detection of the changes your policy calls breaking, plus replay of recorded old client traffic against the new build.
Pipeline wiring and a lane strategy
Tests split across pull request, post merge and nightly lanes with time budgets, so fast feedback stays fast and slow coverage still runs. Reports land where your engineers already look, not in a separate portal nobody opens.
Handover your team can maintain
A short written guide covering how to add a case, how to update a contract, how test data is provisioned, and what each lane guarantees. If the suite only works while we are on it, we have built a dependency rather than an asset. Definition of done for every batch is the same: tests reviewed by your engineers, running green in your CI on your infrastructure, and documented.
Contract Testing with Pact, and What Consumer-Driven Really Means
Contract testing is the highest value work at this layer and the least understood. The phrase gets used for three different things, so it is worth being precise about the one that actually prevents outages.
How a consumer-driven contract test runs
The consumer team writes a test in their own suite that says: when I call GET /orders/1234 with this token, I expect a 200 with an object containing an id string, a status from this set, and a total that is a number. Pact runs that test against a local mock, and if the consumer code passes, it emits a pact file recording the interaction. That file is the contract. It is not a document somebody wrote. It is a byproduct of the consumer's own test, which is why it stays accurate.
The provider then replays every recorded interaction against a real running build of the provider service and asserts the responses satisfy the recorded expectations. That verification runs in the provider's pipeline. If a developer renames a field that any consumer relies on, their build fails before the merge, with the name of the consumer that would have broken.
The broker, can-i-deploy and why the gate matters
Contracts are stored in a broker, either the open source Pact Broker or the hosted PactFlow. The broker knows which versions of which consumers have been verified against which provider versions. The Pact CLI then gives you can-i-deploy, a command that answers whether a specific version is safe to release given everything currently deployed. Without that gate, you have contract tests. With it, you have a release decision that is automatic and does not depend on somebody remembering.
Provider states, the part teams get wrong
Every interaction assumes the provider is in some state: an order with id 1234 exists and is shipped. Pact expresses that as a provider state, and the provider must implement a hook that puts the system into it before replay. Teams frequently implement those hooks by inserting rows straight into the database, which is fast and wrong, because it lets the test pass while the real creation path is broken. We implement provider states through the service's own API or domain layer wherever the runtime permits.
When Pact is the wrong tool
Pact assumes you can influence the consumer. For a public API with thousands of anonymous integrators, that assumption fails, and you should be running schema based compatibility checks plus recorded traffic replay instead. Pact is also poorly suited to testing behaviour that depends on real data volumes or on a third party you do not control. And it is genuine work for both teams. If the consumer team will not run the tooling, the contract will rot, and a rotted contract is worse than none because it gives false confidence.
Bidirectional contracts and Spring Cloud Contract
Where a consumer will not adopt Pact, bidirectional contract testing compares a consumer's recorded expectations against the provider's own OpenAPI document, which is weaker but needs far less from the provider. In JVM estates, Spring Cloud Contract is often the pragmatic choice because it generates provider tests and consumer stubs from a single contract definition and fits existing Maven and Gradle habits. We pick per pair rather than mandating one tool across an estate.
Schema Validation Against OpenAPI and JSON Schema
Most teams have an OpenAPI document. Very few have one that matches the running service. The gap is not laziness. It is that nothing in the pipeline ever fails when the two disagree.
Spec drift is the default state
A field gets added in code, the annotation is missed, the document falls behind. Six months later the document describes an API that has not existed for two releases, and the client SDK generated from it produces objects with missing fields. The fix is mechanical: make the document an input to the tests. Once a response that does not match the schema fails a build, drift stops being possible.
Validating both directions of the exchange
Response validation is the obvious half. Request validation matters just as much, because a schema that says a field is required is a promise that the API rejects requests without it. We assert that requests violating the documented schema come back with the documented client error, not a 500 from three layers deeper, and not a 200 because a default silently filled the gap.
Property-based testing with Schemathesis
Schemathesis reads an OpenAPI or GraphQL schema and generates cases from it, including the values a human would not think to type: empty strings where a string is allowed, maximum length payloads, unicode in identifiers, nulls in optional fields, integers at the boundary of the declared range. It then checks the responses against the schema and flags undocumented status codes and server errors. In practice the first run against a mature API finds a handful of 500s within minutes, usually on inputs nobody had considered. It is the cheapest first pass we know of, and it needs almost nothing from your team beyond a schema.
additionalProperties, nullability and the fields that lie
Two settings cause most of the false confidence. If additionalProperties is not set to false, a response can carry anything extra and still validate, so a field you thought you removed can still be shipping. And nullability is routinely wrong: a field declared as a string that is null for records created before a migration will pass a loose validator and break a strongly typed consumer. OpenAPI 3.1 aligns with JSON Schema 2020-12, which makes nullable unions expressible properly, and migrating from 3.0 is often worth doing for that reason alone.
Spec-first or code-first
Spec-first, where the document is authored and the server and clients are generated or validated against it, gives the strongest guarantee and needs discipline the team has to actually want. Code-first, where the document is generated from annotations, is easier to adopt and drifts more subtly because the generator only knows what the annotations tell it. Either works. What does not work is a document maintained by hand in a separate repository from the code. If that is your situation, we say so on day two rather than building tests on a foundation that will be wrong by the time we finish.
Versioning and Backward Compatibility Testing
Versioning policy is usually written once and then enforced by hope. Backward compatibility testing is what turns the policy into something the pipeline checks.
What actually counts as a breaking change
The list is longer than most policies admit. Removing a field or an endpoint is obvious. So is renaming one. Less obvious: narrowing a type, adding a required request field, tightening validation on an existing field, removing a value from an enum, changing a status code for an existing condition, changing the default sort order of a collection, reducing a page size limit, and changing the semantics of a field while keeping its name and type. That last one is the worst because no automated check will catch it. We write it down explicitly with your team, then encode everything mechanically detectable.
Replaying old clients against the new build
The most convincing compatibility test is traffic. We capture a representative sample of real requests, scrub anything sensitive, and replay it against the release candidate, comparing responses to the recorded baseline with an allowlist of expected differences such as timestamps and generated identifiers. This catches semantic changes that schema comparison cannot, because it compares what the API did rather than what it declared.
Deprecation, Sunset and the paperwork of removal
Removing anything from a public API is a process, not a commit. The mechanics worth testing are that a deprecated endpoint still works, that it emits the deprecation signalling your policy specifies, and that it appears in the documentation as deprecated. The Sunset HTTP header defined in RFC 8594 gives you a machine readable removal date, and a Deprecation response header field is the companion signal in common use. Tests assert that both are present on the routes your policy says are deprecated, and that they disappear when the route is finally removed. Consult your own counsel on any contractual notice obligations to customers, which are a separate matter from the technical signalling.
Compatibility in protobuf and GraphQL
For gRPC, compatibility is a property of the .proto file, and it is enforceable. Field numbers must never be reused, required semantics must not tighten, and buf breaking will diff a schema against a baseline in CI and fail the build on a violation. For GraphQL, additive change is generally safe and removal is not, so the check is a schema diff against the previously published version combined with field usage data. Apollo schema checks and GraphQL Inspector both do this. If you have usage telemetry, a field with zero queries in ninety days is safe to remove and a field with one query from one important client is not, and that decision should be made from data rather than from a hunch.
Should You Test Against Mocks or the Real Dependency?
This is the trade-off that decides how fast your suite runs and how much it is worth. There is no universally right answer, and the teams that get it wrong usually got it wrong by picking one and applying it everywhere.
What mocks buy you
Speed and determinism. WireMock and Prism can stand in for a dependency in milliseconds, on every developer machine, with no shared environment and no rate limits. They let you test the responses you cannot easily provoke in reality: a 503 from a payment gateway, a timeout, a malformed body, a partner API returning a currency you have never seen. That failure path coverage is difficult to get any other way, and it is where most production incidents actually live.
What mocks cost you
A mock is a statement of belief about someone else's system, and beliefs go stale. The classic failure is a suite that has been green for eight months against a mock of a partner API that changed its date format in March. You did not find out because nothing in your pipeline ever talked to the real thing. Mocks that are not derived from a contract or a schema will drift, and the confidence they give you decays quietly.
Ephemeral environments and Testcontainers
For dependencies you own, the middle path is usually the best one. Testcontainers spins up a real Postgres, a real Kafka, a real Redis for the duration of a test run, so you are exercising real driver behaviour, real SQL and real serialisation rather than an in-memory imitation. It costs seconds of startup, not minutes, and it removes the entire class of bug where an in-memory database accepts something the real one rejects. Where the whole stack can be brought up per branch, an ephemeral environment per pull request is better still, though it costs infrastructure work to make it reliable.
Record and replay
For third party APIs, recording real interactions once and replaying them is a reasonable compromise, provided the recordings have an expiry and a scheduled job re-records them against the live sandbox. Without that refresh, record and replay is just a mock with extra steps and the same decay.
The split we recommend
Own dependencies get real instances via containers. Consumer and provider pairs get contract tests, so the mock the consumer uses is derived from a contract the provider verifies. Third parties get mocks for failure paths plus a small scheduled suite that hits the real sandbox and fails loudly when it drifts. That last suite is the one teams skip, and it is the one that catches the March date format change in March.
Test Data, Idempotency and Suites That Can Run Twice
The most common reason an API suite becomes untrusted is not a bug in the API. It is that the suite passes on a clean database and fails on the second run, so people start rerunning it until it goes green, and at that point it has stopped being a test.
Data that a second run does not poison
Shared seed data is the usual culprit. A test creates a user with a fixed email address, the next run hits a uniqueness constraint, and the failure looks like a bug in registration. Generating identifiers per run fixes it. So does isolating by tenant, which has the useful side effect of exercising your tenant scoping. For read-heavy suites, a small deterministic seed that no test mutates plus per test generated data for anything written is the pattern that has held up best for us.
Idempotency keys and duplicate delivery
Any endpoint that moves money, sends a message or creates a resource needs to answer what happens when the same request arrives twice, because at some point it will. Networks retry, clients retry, queues deliver more than once. If your API accepts an idempotency key, the tests must cover the same key with the same body returning the original result, the same key with a different body being rejected rather than silently overwriting, and concurrent requests with the same key not creating two records. That third case needs genuine concurrency in the test, not two sequential calls, and it is the one that finds real defects.
Webhooks and asynchronous completion
Half of what modern APIs do finishes later. Testing that properly means a receiver the suite controls, assertions on payload shape and signature verification, and explicit coverage of retry behaviour and out of order delivery. It also means killing arbitrary sleeps, which are the main source of flakiness in async tests. Polling with a timeout, or a callback the test can await, keeps the suite honest and fast.
Cleanup, and when not to bother
Cleanup after every test is tidy and slow, and cleanup code that fails mid-run leaves worse state than no cleanup at all. Against a disposable database, dropping the whole thing at the end of the run is simpler and more reliable. Against a shared environment where that is not an option, tag every created record with the run identifier and sweep by tag on a schedule, so a crashed run does not block the next one.
Authentication and Authorisation: The Cases Teams Miss Most
If we could only test one thing on an API, it would be this. The OWASP API Security Top 10 has placed broken object level authorisation at number one, and it stays there because it is invisible to every test that only ever authenticates as one user. Note that this is functional authorisation coverage inside your test suite. A full adversarial security assessment is a different engagement with a different method.
Object level authorisation
The test that matters: create a resource as tenant A, then request it with a valid token belonging to tenant B. The expected result is 404 or 403, and the common actual result is 200, because the handler looked up the record by id and checked only that the caller was logged in. This bug survives code review routinely, because the missing check is an absence rather than a mistake. We generate these cases across every route that takes a resource identifier, which is the only way to get complete coverage.
Function level authorisation
Administrative routes protected by nothing more than not being linked in the UI. The test enumerates every route a non-admin principal should not be able to reach and asserts the rejection. Reversed HTTP verbs are worth covering too: a GET that is protected while the corresponding DELETE on the same path is not is a real pattern, not a hypothetical one.
Token scope, audience and expiry
A token issued for a read scope must be rejected on a write route. A token minted for a different audience or a different client must not be accepted. An expired token must fail, and the test should use a genuinely expired token rather than trusting a mock clock. Clock skew tolerance deserves a case of its own, because a service that accepts tokens several minutes past expiry is a service where revocation does not really work.
The validation itself
Where JWTs are used, the classic failures are worth explicit tests: a token with the algorithm header set to none, a token signed with the wrong key, a token with a valid signature but a tampered payload, and a token whose issuer is not yours. If any of those returns 200, everything downstream of the auth layer is theatre.
Multi-tenant boundaries
Beyond direct object access, the boundary leaks in subtler places. Search endpoints that return counts across tenants. Aggregate figures that include other tenants' rows. Error messages that confirm a record exists in another tenant by returning 403 rather than 404. Bulk endpoints where the identifier list is validated for format but not ownership. Each of those gets an explicit case, because none of them will be caught by testing the happy path as a single user.
Rate Limits, Errors and the Unhappy Paths
Error behaviour is part of your interface whether you documented it or not. Consumers write code against it. When it changes, their code breaks in exactly the same way a renamed field breaks it, with the difference that nobody noticed because errors are rarely in the test suite.
Rate limits, 429 and Retry-After
Three things need asserting. That the limit triggers where the documentation says it does. That the response carries the headers a client needs to behave well, which usually means Retry-After and whatever limit and remaining headers you publish. And that the limit is scoped correctly, so one tenant exhausting their quota does not throttle another. That last case has taken down more than one shared API, and it is trivially testable once you think to test it.
Error bodies are a contract
If your API returns a machine readable error shape, it needs the same schema discipline as a success response. RFC 9457 defines the problem details format for HTTP APIs, superseding RFC 7807, and adopting it means clients can parse errors generically rather than string matching on messages. Whether or not you adopt it, tests should assert that the error type or code for a given condition is stable, because consumers branch on those values. Changing an error code is a breaking change even though nothing in your schema moved.
Timeouts, retries and amplification
A dependency stops responding. What does your API do? Tests using a mock that simply never replies establish whether you time out at a sensible boundary or hold the connection until the load balancer kills it. If you retry, cover the case where retries stack across layers: a client retrying three times against a gateway retrying three times against a service retrying three times is twenty seven requests to a dependency that is already struggling, which is how a slow dependency becomes an outage.
Partial failure and pagination
Batch endpoints need a defined answer for what happens when item seven of ten fails, and it should be documented and tested rather than emergent. Pagination needs coverage at the boundaries: an empty result set, a single page exactly at the limit, a cursor from a deleted record, a page size above the maximum, and a negative offset. These are five minutes of work each and they turn up broken behaviour on most APIs we test.
gRPC and GraphQL Are Not REST With Different Syntax
Testing approaches transfer badly between protocols. If your estate has more than one, the suite needs to reflect that rather than pretending everything is a REST call in a costume.
gRPC
Compatibility moves into the .proto file, which is good news because it is mechanically checkable. Field numbers are the contract, so reusing a number after deleting a field is the cardinal sin, and buf breaking catches it against a baseline in CI. Beyond schema, the runtime specifics need coverage: deadline propagation, so a call that exceeds its deadline actually terminates rather than orphaning work; status codes, since gRPC has its own set and clients branch on them; and streaming, where a server stream that stops emitting without closing will hang a client indefinitely. Test clients are generated from the proto, which makes writing the tests straightforward once the tooling is in place.
GraphQL
The biggest adjustment is that errors arrive inside a 200 response, so any assertion built on status codes is close to useless. Tests must inspect the errors array and the partial data alongside it, including the case where some fields resolved and others did not. Beyond that: field level deprecation with usage data before removal, query depth and complexity limits, since an unbounded nested query is a denial of service vector rather than a performance nuisance, and N+1 resolver behaviour, which needs a test asserting the number of downstream calls rather than only the response body. If you use persisted queries, the allowlist itself needs a test that unlisted queries are rejected.
Asynchronous and event driven interfaces
Where the interface is a message on a queue or topic rather than a request, the contract is the message schema and the compatibility rules of the schema registry. Confluent Schema Registry compatibility modes and, for documentation, AsyncAPI cover most of this ground. The test is that a producer change cannot be published if it breaks a registered consumer's compatibility setting, plus a consumer test asserting behaviour on an unknown field and on a poison message. Teams that have contract tested their REST surface often leave this layer entirely uncovered, and it breaks in exactly the same ways.
The Tools We Use, and When Each One Is Wrong
We do not arrive with a preferred stack to install. The right choice depends on what your engineers already read and maintain, because a suite in a language your team does not use is a suite your team will not fix.
Postman and Newman
Excellent for exploration and for handing a working example to a partner. Newman runs a collection in CI, which makes it a reasonable smoke test lane. It is the wrong choice as the backbone of a large regression suite: assertions live in JavaScript embedded in JSON, which reviews badly and refactors worse, and collections tend to accumulate duplicated setup that nobody dares delete.
REST Assured
For JVM teams, this is usually the right answer for the main suite. Tests sit in the same repository and the same build as the service, engineers review them like any other Java or Kotlin code, and JSON path assertions are compact. It is the wrong choice for a team with no JVM presence, where it imports a toolchain for no benefit.
Karate
Tests are written in a readable domain specific language, so people who are not primarily developers can contribute, and it has useful built in support for parallel execution and for stubbing. The trade-off is real: you are learning a syntax that exists only inside one tool rather than writing in your own language, and complex logic gets awkward. Good fit for a dedicated QA function, weaker for a team where developers own the tests.
Pact
The tool for consumer-driven contracts, with client libraries across JVM, JavaScript, Python, .NET, Go and Ruby. Worth the setup once you have multiple teams releasing independently. Not worth it when the consumer is anonymous or unwilling, or when you have a single team shipping everything together.
Schemathesis
The fastest way to find undocumented behaviour and unhandled inputs from an existing OpenAPI or GraphQL schema. Almost free to run, and it needs a good schema to be useful. Against a stale or permissive document it will find little, which is itself a useful diagnostic.
k6
For API level load and soak work, scripted in JavaScript and comfortable in CI. We use it here for the questions that belong to the API layer, such as whether rate limiting holds under concurrency and whether latency degrades gracefully as request volume rises. Full performance engineering, capacity modelling and profiling under sustained load is a separate discipline and a separate engagement.
WireMock and Prism
WireMock for stubbing dependencies with fault injection and response templating. Prism for standing up a mock server directly from an OpenAPI document, which is particularly useful when a consumer needs to start before the provider is built. Both drift if nothing keeps them aligned with reality, which is the argument for deriving them from contracts or schemas.
The language native option
Often the best answer is no new framework. pytest with httpx, Jest or Vitest with supertest, xUnit with HttpClient. The suite lives with the code, runs with one command, and needs no separate onboarding. We reach for this first for teams who own their own quality and want the tests inside the service repository.
Where API Tests Belong: Pull Request, Merge or Nightly
A suite that runs everywhere runs nowhere, because it gets too slow and someone eventually adds a flag to skip it. Lane strategy is what keeps the fast feedback fast while the expensive coverage still happens.
The pull request lane
Everything that runs against in-process or containerised dependencies: contract verification for affected pairs, schema validation, authorisation matrix cases and error paths for the endpoints the change touches. Target is a few minutes. If the developer waits longer than a coffee, they context switch, and the value of the feedback falls off a cliff. Test impact analysis helps here, running only the contracts and routes affected by the diff, provided the mapping is derived rather than hand maintained.
The merge and pre-deploy lane
The full contract set, the compatibility check against the published baseline, the recorded traffic replay and can-i-deploy against the broker. This is the gate that decides whether an artifact is releasable, so it runs against the built artifact rather than the source, and it is the correct place to be strict. A failure here blocks a deploy rather than a merge, which is a materially different conversation with the team.
The nightly lane
Everything slow or shared: property-based fuzzing across the whole surface, the suite that hits third party sandboxes to detect drift, long running idempotency and concurrency scenarios, and the flakiness detector that reruns the suite against unchanged code to produce a per test failure rate. Nightly results need an owner and a channel, otherwise the run turns into a red badge everybody has learned to ignore within a fortnight.
Time budgets and what happens when they are breached
Each lane gets a documented budget. When a lane exceeds it, that is a defect with an owner, not a fact of life to be absorbed. Usually the fix is moving a test to a slower lane rather than deleting coverage. Flaky tests go to a quarantine lane that still runs and still reports but cannot block a merge, and every quarantined test carries a named owner and a date. If nobody fixes it by then, the test is deleted along with the coverage claim it was making, because a test everyone ignores is worse than an honest gap.
Four Situations We Get Called Into
These are the patterns behind most enquiries at this layer. Details differ. The shape rarely does.
The platform team that keeps breaking the mobile app
A backend team of eight ships several times a week. A mobile team of four ships every two weeks through an app store review. Every few sprints the backend changes something the app depended on, and because the app in the field cannot be updated instantly, the breakage sits in users' hands for days. The backend team is not careless. They simply have no mechanism that tells them what the shipped app relies on. The fix is a contract from the mobile client, verified in the backend pipeline, plus recorded traffic from the two previous app versions replayed against every release candidate. After that, the breaking change is caught on the branch, and the conversation moves from apology to design.
The public API where every release is a support incident
A company with a documented public API and a few hundred integrators. Nobody knows who uses which endpoint. Every release is followed by a nervous week and a handful of tickets from customers whose integration stopped working. Pact does not apply because the consumers are anonymous and unreachable. What does apply: strict schema validation with additionalProperties closed, an automated breaking change diff of the OpenAPI document against the published version, replay of sampled production traffic, and usage telemetry per endpoint so removal decisions are made from evidence. The nervous week becomes a routine deploy.
The migration where the new service must behave exactly like the old one
A monolith endpoint is being reimplemented in a new service. The requirement is that consumers notice nothing. Here the highest value test is a comparison harness: replay identical requests against old and new, diff the responses field by field with an explicit allowlist for known differences, and run it over a large sample of real traffic rather than a handful of hand-picked cases. It reliably finds the things a specification never captured, such as a field that has always been returned in insertion order, or an error case that returned 400 in one path and 422 in another. Teams that skip this step usually find those behaviours after cutover, from a customer.
The estate with sixty services and no idea what talks to what
Microservices, several teams, and a dependency graph that exists only in people's heads. Nobody can say with confidence what a change to a given service affects, so every change gets tested by deploying to a shared environment and waiting. The starting move is not writing tests. It is producing the graph from traffic data, then contract testing the highest traffic pairs first and expanding by risk. Trying to contract test sixty services at once is how this work gets abandoned in month three.
How Does an API Testing Team in India Work Across Your Timezone?
You are handing engineers access to your repository and your test environments while sitting eight to thirteen hours away. That deserves a straight answer rather than a slogan.
The overlap window, honestly
Our standard working day is 09:30 to 18:30 IST. Against UK hours that gives roughly four hours of live overlap in the British afternoon, which is enough for a daily call and same-day back and forth. Sydney and Auckland overlap comfortably through their afternoon. For US Eastern the overlap is close to zero against a normal nine to five, and for Pacific it is zero. Anyone telling you otherwise is describing a shift pattern without mentioning it. A shifted or split team can create real US overlap, and it costs something: fewer engineers available at the same time as their colleagues in India, more handover, and a harder time keeping people on it long term. We agree the overlap window and any shifted hours with you before work starts rather than discovering the mismatch in week three.
Why this particular work tolerates low overlap well
API testing is unusually asynchronous friendly. The artifacts are pull requests, contracts, schemas and pipeline runs, all of which read the same at 09:00 in London and 09:00 in Bengaluru. A failing contract test names the consumer, the interaction and the mismatched field without anyone needing to explain it on a call. Compare that to design work or incident response, where the cost of a nine hour round trip is much higher. Most of the value here lands overnight relative to you, in your CI, whether or not anyone was awake.
How the day actually runs
Written first. A short update at the end of the Indian day covering what moved, what is blocked and what needs a decision from you, posted in your Slack or Teams channel rather than emailed. One live call in the overlap window, kept to fifteen minutes unless there is something to work through. Work tracked in your tracker, not a parallel one we keep. Questions asked in writing with a proposed answer attached, so a blocked question does not cost a full day.
Code review and the definition of done
Every test goes through your pull request process and is reviewed by your engineers. We do not merge to your main branch on our own authority unless you explicitly want that. Done means the test is reviewed, running green in your CI, assigned to a lane with a time budget, and documented well enough that someone on your team can change it next quarter without asking us.
Access, code ownership and data
Least privilege by default. Access is granted by you to the specific repositories and environments needed and revoked by you at the end. We work against scrubbed or synthetic data wherever the environment permits, and where production-like data is genuinely required for a compatibility replay, the handling terms are agreed in writing before anything is copied. Code and IP ownership, confidentiality and data processing terms are set out in the MSA and NDA before work starts, which is where those specifics belong rather than on a web page. If your sector brings regulatory obligations, bring your counsel and your compliance lead into that conversation early.
The talent pool for this specific skill
India's depth in test engineering is genuine, but it skews heavily toward UI automation and manual functional testing, because that is where the volume of work has historically been. Engineers who are fluent in contract testing, schema-driven validation and pipeline design are a much smaller subset. We hire for that subset specifically and screen with a working exercise against a real API rather than a quiz, because someone can hold a certification in a tool and still not know why a green suite let a breaking change through.
What Goes Wrong, and How We Handle It
The honest section. These are the things that actually derail this work, and what we do when they show up.
The spec turns out to be fiction
Common enough that we plan for it. The first week becomes reconciliation: drive the real endpoints, diff observed behaviour against the document, produce a list of divergences and let your team decide per item which side is correct. It delays the first tests by days, not weeks, and skipping it means building on sand.
There is no environment worth testing against
Sometimes the blocker is not testing at all. Staging is stale, the seed data is from 2021, and the third party sandbox has been broken since an upgrade. When that is the situation we say so immediately, because writing tests against an environment nobody trusts produces results nobody trusts. The usual path is containerised dependencies for the pull request lane so progress is not gated on infrastructure, with the shared environment work sequenced separately.
The consumer team will not adopt contract testing
Pact needs work from both sides. If the consumer team has no capacity or no interest, the contract will not stay accurate, and a stale contract is worse than none. Rather than pushing it, we move to provider-side compatibility checking, schema diffs and traffic replay, which is weaker but needs nothing from them. We raise this in the first fortnight, because discovering it in month two wastes everyone's time.
Auth is faked in the test environment
A surprising number of test environments accept any bearer token or run with authorisation middleware disabled for convenience. That makes the entire authorisation matrix meaningless while looking green. When we find it, it becomes a blocker to be fixed rather than a caveat in a report, because it is also usually a sign that nothing has ever verified those checks anywhere.
The suite grows into a second end-to-end suite
The slow drift where API tests start orchestrating six calls to set up a scenario, then assert on a business outcome, then take twelve minutes and start failing for unrelated reasons. We push back on it in review. If a test needs a long orchestration, it usually belongs in a nightly lane or in a different layer entirely. Keeping the API suite about the interface is what keeps it fast enough to be trusted.
Continuity of the people doing the work
People change jobs, in India and everywhere else. The mitigations are structural rather than promissory: at least two engineers familiar with each area, everything in your repository under your review process, no knowledge held only in someone's head, and written handover as a normal part of the work rather than an exit activity. Notice, replacement and handover terms are set out in the MSA before work starts, and we will not quote you a number on a web page that we have not agreed with you.
Engagement Models
Three shapes, chosen by what you actually need rather than by what is easiest to sell.
API test audit
A time-boxed assessment. We inventory the real surface, run schema and property-based checks against it, probe the authorisation matrix and error paths, and report what is uncovered, what is misleading and what we would fix in what order. You get the findings and the reasoning whether or not you continue with us.
Project engagement
A defined outcome with a start and an end. Contract testing across a named set of service pairs, a compatibility gate for a public API before a major version, or a comparison harness for a migration. Scope agreed up front, delivered into your repository and pipeline, with handover documentation as a deliverable rather than an afterthought.
Dedicated engineers
Test engineers embedded in your team, in your standups, working your backlog. Suited to ongoing API surface growth where coverage has to keep pace with delivery. Commercial terms, notice and team composition are agreed with you directly and written into the MSA.
Where This Sits Alongside Our Other Work
API testing rarely arrives on its own. If the underlying problem is that the API itself needs designing or rebuilding rather than testing, that work sits with our API development services, and the tests are better written alongside the endpoints than bolted on afterwards. Where the interfaces being tested are the seams between newly split services, the contract boundaries and the microservices architecture constrain each other and are worth deciding together.
If your wider quality problem is broader than the interface layer, including manual coverage, release process and test strategy across the whole product, start with our QA and testing services and let the API layer be one workstream inside it. The tests only pay for themselves once they run automatically on every change, which is why this work pairs naturally with CI/CD pipeline services in India, especially where lane design and pipeline duration are already a problem. And if what you need is engineers inside your team rather than a scoped engagement, hiring dedicated Python developers in India or Java developers in India gives you the same skill set on a different commercial shape.
Frequently Asked Questions About API Testing in India
Our integration tests all pass. Why do we still break clients on release?
Because an integration suite usually tests your service against fixtures you also wrote. It proves your code is internally consistent, not that the request your consumer actually sends still gets the response their code actually parses. Contract tests close that gap by recording the consumer expectation and replaying it against the real provider build, so the pair is verified rather than each half separately.
Do we need Pact, or is a shared staging environment enough?
Staging catches breakage late, after both sides are deployed, and only if someone happens to exercise the path. Pact catches it in the provider pipeline before the merge. If you have two or three services and one team, staging plus a good schema check is often enough. Once several teams release independently, the coordination cost of finding breakage in staging outweighs the setup cost of contracts.
Can you write API tests if our OpenAPI spec is out of date?
Yes, and the first week usually turns into reconciling the spec with reality. We capture live traffic or drive the real endpoints, diff observed responses against the document, and produce a list of every place the spec lies. You then choose per endpoint whether the code or the document is correct. After that, the spec becomes a test artifact and drift is a pipeline failure.
Which API tests should run on every pull request?
Contract verification, request and response schema checks, authorisation cases and the error paths for the endpoints touched by the change. Those run against in-process or containerised dependencies and should finish in a few minutes. Anything that needs a shared environment, a third party sandbox, long data setup or load generation belongs after merge or in a nightly lane.
How do you test authorisation without a hundred user accounts?
With a small matrix rather than a large fixture set. We define a handful of principals, typically two tenants, an owner, a peer in the same tenant, an admin and an unauthenticated caller, then assert the expected status for each protected route. Object-level checks reuse identifiers created by another principal. That catches the common broken object level authorisation failure without a sprawling account estate.
Do you test gRPC and GraphQL as well as REST?
Yes, and the failure modes differ enough that the suites look different. For gRPC the compatibility question lives in the proto file, so breaking change detection against a baseline matters more than status code assertions. For GraphQL the errors arrive inside a 200 response, so tests must assert on the errors array, on field level deprecation and on query cost limits.
Will API tests replace our end-to-end UI tests?
No, they shrink them. API tests cover behaviour, permissions, validation and error handling far faster and more reliably than a browser can. What remains for the UI layer is genuine interface behaviour: rendering, navigation, form state and accessibility. Teams that push logic coverage down to the API layer usually end up with a much smaller and far less flaky browser suite.
How does an API testing team in India work with our release schedule?
The suite runs in your pipeline, so most of the value arrives without anyone being awake. The Indian working day overlaps the UK afternoon comfortably and Australia and New Zealand for most of their morning. For US Eastern and Pacific the honest answer is a narrow window, so we run written handovers and agree the overlap and any shifted hours with you before work starts.