Skip to content

Limits and rules

Some of the rules the Integration API works by cannot be read from the machine-readable description — it says which fields exist, but not how many requests are allowed, in what order the lists arrive, how to pull only what has changed, nor how long the protection against duplicates lasts. Those things are written down here.

RuleValue
traffic limitper key; the number comes from the plan
document sizeper organization; the ceiling comes from the plan
paging100 by default, 500 at most
list ordernewest first
incremental pullingby=updated + nextFrom
idempotency windowone hour
waiting for the answer when submitting (Prefer: wait)at most 30 seconds

Requests are counted per key — not per the address they come from. That means two things, and both matter when planning your schedule:

  • One key used from several servers shares a single quota. If the same key is used by three instances of your product, their requests add up into the same count. The limit does not multiply by the number of servers.
  • Several keys behind one outbound address do NOT share a quota. If two of your clients work from the same network and go out through the same address, each has its own count. One cannot use up the other’s quota.

When the limit is reached, the request is rejected with EARH-1006 · 429 and repeated after the time the Retry-After header states — neither the key nor the address is changed.

The number is not the same for everyone. It comes from the plan of the organization that owns the key, and the key’s owner may lower it further for that one key. The smaller of the two applies.

PlanRequests per minute
Freethe Integration API is not included
Starter60
Professional300
Enterpriseunlimited

So the value that applies to you is known to the organization whose key you use. If you are not sure, ask them — it cannot be derived from the responses.

Two states are not a limit but a closed door, and both answer 403 on every call:

CodeWhat it meansWhere it is resolved
EARH-1010the organization’s plan does not include integration accesswith the organization, through its subscription
EARH-1011the key has been switched off by its ownerwith the key’s owner

Neither carries Retry-After, and that is deliberate: waiting changes nothing, so retrying in a loop only burns calls. That is also the difference from EARH-1006, where time is the answer.

If the number, the basis it is counted on, or which plan carries how much changes, the change goes through the Changelog with an announced date before it takes effect. There is no silent change to the limit: what is published here holds until a new date for it appears in the Changelog.

The traffic limit from the previous section applies equally to every address — no operation has a quota of its own and none is cheaper than another. What does differ per operation is how much a single request may carry:

OperationWhat is limitedWhen it is exceeded
POST outboundthe size of the documentEARH-2012 · 413
GET outbound · GET inboundpage size — 100 by default, 500 at mostEARH-3005 · 400
GET codelists/{type}⛔ no paging — the whole active list is returned—
all the othersthe traffic limit onlyEARH-1006 · 429

You do not have to know the number in advance. For both limits the response carries the allowed value inside it — EARH-2012 states how many MB are allowed, EARH-3005 how many records per page. So a single rejected call is enough to learn the limit; it is not guessed and not asked of us.

What is measured is the body of POST outbound — the UBL XML itself. The excess usually comes from embedded attachments and images, not from the invoice data.

As with traffic, two numbers apply: the ceiling that comes from the organization’s plan, and the working limit its owner may lower below it. The smaller of the two applies.

PlanCeiling
Freethe Integration API is not included
Starter2 MB
Professional10 MB
Enterprise50 MB

Incremental pulling — by=updated and nextFrom

Section titled “Incremental pulling — by=updated and nextFrom”

The lists take a by parameter, which says what dateFrom and dateTo measure:

ValueWhat it measures
created — defaultthe time the document was created
updatedthe time we last recorded a change to it

The difference is what updated solves: a document created last month whose status changed yesterday is returned by by=updated and is not returned by by=created. With the parameter omitted the behaviour is as before — existing calls do not change.

When you ask for by=updated, the answer also carries a nextFrom field: the point to continue from next time. You pass it back as dateFrom in the following call, again with by=updated. With by=created the field is null.

Your next call will return some of the documents you have already seen. That is a contract, not a defect, and it has two reasons:

  • the lower bound dateFrom is inclusive
  • nextFrom is deliberately set slightly in the past — a margin of 5 minutes

The margin exists because no source is monotonic with respect to the moment of writing: a record that commits after your read can carry an older timestamp. Without the margin, exactly those records would be lost silently.

So the client drops the repeats by docUid. That is all that is asked of it.

Inbound documents have both, and they are not interchangeable:

QuestionParameter
“What have I not fetched yet?”onlyNotImported=true
“What has changed since my last pull?”by=updated

A document you already fetched and that was then approved comes back only with by=updated — for onlyNotImported it no longer exists, because it has been fetched.

Resubmission and protection against duplicates

Section titled “Resubmission and protection against duplicates”

Every request that creates a document is marked with the X-Idempotency-Key header. You choose the mark yourself, and it is what tells the API that two requests are in fact one and the same.

What you sendWhat you get
the first time, with a new mark201 — the document has been created
again, same mark and same content200 — the same answer as the first time, without a second document
same mark, different contentEARH-2010 · 409

The difference between 201 and 200 is how you tell whether the document was created now or already existed. Both answers carry the same document, so repeating after a broken connection is safe.

The third row is an error, not a repetition: the same mark with different content means either a new document under an old mark, or a document changed after the first submission. What exactly to do about it is at EARH-2010 in the error catalogue.

The idempotency window lasts one hour. After it, the same mark counts as a new one.

By default POST outbound answers at once, with status 210: the document is received and processing runs in the background. With the header Prefer: wait=N the answer waits up to N seconds for our processing to reach the outcome of the submission to UJP, then returns that state — together with ujp.euid, the number UJP assigned to the document, and ujp.qrLink, the QR code link UJP returned.

RuleValue
longest wait30 seconds — a larger value is reduced to 30
what is waited foronly the submission to UJP, not later changes on UJP’s side
when the time runs outthe same 201, with status 210 or 220 and "ujp": null — continue with GET outbound/{docUid}
how you know it was appliedthe header Preference-Applied: wait=N in the answer

Waiting changes nothing in the processing itself. An interrupted request does not interrupt the processing — it goes on, and the outcome is read with GET outbound/{docUid}. The same header also applies to a repeated call with the same idempotency mark.

⚠️ A request that waits counts against the traffic limit like any other — one, however many seconds it waited.

Documents created before the docUid identifier was introduced do not appear through the Integration API. They have no identifier the API can address them by, so no list returns them and no request by docUid reaches them.

Those documents are not counted in the total (totalCount) the lists return either. So the number in the response is not the client’s total number of documents — it is the number of documents available through the Integration API. If your product compares that number with what the client sees in eArhiva, the difference is expected and is not an error.

The older documents remain available through the application itself; what this limits is only the Integration API.