Docs/Start/Making requests

Making requests

Query parameters, JSON bodies, file uploads, timeouts and concurrency — everything that works the same way on every endpoint.

Every endpoint lives under one host and one path segment:

code
https://api.apiverve.com/v1/<endpoint>

GET endpoints take query parameters. POST endpoints take a JSON body. Both authenticate with the same header and return the same envelope, so once one call works, the shape of every other call is already familiar.

GET requests

Most endpoints are GET. Parameters go in the query string:

curl 'https://api.apiverve.com/v1/weather?city=London' \
  -H 'x-api-key: YOUR_API_KEY'

Build query strings with your language's URL encoder rather than string concatenation. Values like New York or a+b break a hand-built URL and produce a confusing 400 rather than an obvious one.

POST requests

Endpoints that take structured input, long text, or a file use POST with a JSON body. These need a Content-Type header; GET requests do not.

curl -X POST 'https://api.apiverve.com/v1/htmltopdf' \
  -H 'x-api-key: YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{ "html": "<h1>Hello</h1>", "options": { "format": "A4" } }'

Which method an endpoint uses is on its reference page — you never have to guess, and calling with the wrong one returns a 405 rather than a silent failure.

Parameters

Each endpoint's reference page lists its parameters with type, whether they are required, and any constraints. Three rules apply everywhere:

  • Required parameters produce a 400 when missing, and the message names the parameter.
  • Optional parameters have documented defaults. Omitting one is not the same as sending it empty; an empty string is a value, and some endpoints will reject it.
  • Premium parameters are accepted on every plan but only take effect on plans that include them. They do not error on a lower plan — they are ignored.
An unrecognised parameter is dropped, not rejected

A parameter the endpoint does not declare is silently discarded. The call still succeeds and still costs a credit; it just ignores your input. So a typo like citty=London on an endpoint where city is optional returns a perfectly valid answer for the wrong question. If a parameter seems to do nothing, check its spelling against the reference page first.

File uploads

Endpoints that accept a file take a multipart/form-data request. Set the field name the endpoint documents, and let your HTTP client set the Content-Type — it has to include the multipart boundary, which you cannot write by hand.

bash
curl -X POST 'https://api.apiverve.com/v1/imagetotext' \
  -H 'x-api-key: YOUR_API_KEY' \
  -F 'file=@receipt.png'

Size limits are plan-based, and an oversized upload is a 400 naming the ceiling:

PlanMaximum upload
Free, Hobby400 KB
Starter and above10 MB, or the endpoint's own limit

Timeouts

Most endpoints answer in well under a second — each reference page shows that endpoint's measured p50. The exceptions are the ones doing real work: rendering a PDF, running OCR, screenshotting a page.

Set a client timeout of 30 seconds for rendering and extraction endpoints, and 10–15 seconds for everything else. Set one explicitly either way: most HTTP clients default to no timeout at all, which turns a slow upstream into a hung process.

js
const res = await fetch(url, {
  headers: { 'x-api-key': KEY },
  signal: AbortSignal.timeout(15_000),
});

Concurrency

Requests in flight at the same moment are capped per plan, separately from the per-minute rate limit:

PlanConcurrent callsRate limit
Free15/min
Starter560/min
Pro20180/min
Mega50No limit

Concurrency is usually what an unbounded Promise.all hits first. A fixed pool sized to your plan gets more throughput than firing everything at once and retrying the failures:

js
async function pool(items, size, fn) {
  const out = [];
  for (let i = 0; i < items.length; i += size) {
    out.push(...(await Promise.all(items.slice(i, i + size).map(fn))));
  }
  return out;
}

const results = await pool(cities, 5, (city) => getWeather(city));

Many inputs at once

For lists, batch requests are better than a pool: one HTTP request carrying many inputs, which counts as one request against your rate limit while charging credits per item.

bash
curl -X POST 'https://api.apiverve.com/v1/emailvalidator/batch' \
  -H 'x-api-key: YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{ "items": [{ "email": "a@example.com" }, { "email": "b@example.com" }] }'

Identifying your client

Set a User-Agent that names your application and version. It is optional, but it is the first thing support looks at when tracing a pattern of calls, and it separates your traffic from the generic HTTP-library default that thousands of other callers also send.

code
User-Agent: acme-billing/2.3 (+https://acme.example.com)

The x-av-client header is accepted for the same purpose by the official SDKs and extensions, which set it automatically. You do not need to set it yourself.

Caching

Responses are not cached by the API, and no endpoint returns a Cache-Control that would let a proxy cache one for you. That is deliberate — a cached response you did not ask for is a wrong answer waiting to happen on the endpoints that change by the second.

Caching on your side is encouraged, and it is the cheapest optimisation available on this API, because a cached response costs zero credits. What is worth caching is decided by how fast the underlying data actually moves:

Endpoint kindReasonable cache
Country, currency, timezone, ISO-code lookupsWeeks — these change on a scale of years
Geocoding, DNS, WHOIS, company recordsHours to a day
Weather, exchange rates, market dataMinutes
Validation, generation, fraud scoringDo not cache — the input is the answer

Key the cache on the endpoint plus the full normalised parameter set, so two calls that differ only in parameter order share an entry.

Retries and idempotency

GET endpoints are read-only and safe to retry freely. POST endpoints on this API are transformations rather than record creation — sending the same body twice produces the same answer and costs two credits, but it does not create anything twice.

That means there is no idempotency key to manage. The only cost of a duplicate call is the credit, which is why the retry guidance in errors is about avoiding pointless retries rather than about preventing double-writes.

Reading the response

Every endpoint returns the same three keys, so one handler covers your whole integration:

json
{
  "status": "ok",
  "error": null,
  "data": { }
}

Check res.ok and body.status before reading data — see errors for the full treatment and response format for what is inside data.

Next

Response format covers the envelope and the premium-field rule. Rate limits covers the ceilings this page assumes. When you are ready to stop hand-writing HTTP, the SDKs wrap all of this.

When the inputs arrive as a list rather than one at a time, batch requests replace the loop. Headers, both sent and returned, are catalogued in request headers.

Was this page helpful?

Last updated