erp

queryErpUpdateEvents

Changed on

Waits for the events of one correlation — the long poll behind interactive registration — and returns the correlation's summary.

Pass the correlation_id returned by POST /v3/erp/updates/events and say what you are waiting for:

  • wait_for_entities — entity slugs, optionally with a selector: contact, contract[billing_account_number=4711].
  • wait_for_use_cases — inbound use case slugs: contract, meter_reading. A meter reading is not an entity, so this is how a wait names one.

The call returns as soon as completion is decided, or after wait seconds. completion is one of:

  • requirements_met — every listed requirement is satisfied. This wins even if an unrelated event of the correlation failed; errors still lists it.
  • complete — the partner closed the correlation (correlation_complete) and every event it sent has finished. Nothing further can arrive, so the wait ends even if a requirement is unmet. A correlation closed with zero events is complete at once: the partner sent nothing and never will. complete is final. From completed_at on, the correlation's answer is frozen: an event that still arrives under it (a late event) is processed and counted in events_received, events_done and late_events, and its errors are listed with after_completion: true, but it adds nothing to use_cases or entities and never changes completion — every later read gives the answer the first one got.
  • error — a requirement can no longer be met because an event it depends on failed: every event of a required use case ended in error, or an entity requirement is still missing when the correlation is complete and one of its events failed. Without requirements, error means the correlation completed with failures. An event that ended partial counts as failed here: a use case requirement is met only by an event that ended done.
  • timeout — the budget ran out first. The body still shows what has landed so far; call again to keep waiting.

When entities_omitted is present, an entity requirement can be undecided. entities lists at most 200 entity writes; the rest are only counted. An entity requirement that no listed entity satisfies may then still have been written, so it is neither met nor missing: it is named in undecided_entity_requirements, it never makes completion error, and the wait still ends complete once the correlation completes (if every other requirement is met, complete rather than requirements_met). Look such an entity up yourself, e.g. by its unique id through the entity API. Use case requirements are never undecided: their counts are never omitted.

Every requirement is met by the first matching event. A use case requirement is satisfied by the first event of that use case to finish, and an entity requirement without a selector by the first entity of that slug; neither says anything about the rest. So, unless the partner sends correlation_complete, requirements_met does not mean the partner has finished: more data for the same customer may still be arriving. correlation_complete is the only signal that nothing further is coming — strongly recommended for every partner, never required. When you know the identifier you are waiting for, an entity requirement with a selector is the precise tool: contract[billing_account_number=4711] is satisfied by that contract and by nothing else.

An event fails when nothing will retry what went wrong, including when its mapping could not run or ran only in part: a disabled or unconfigured use case, an item without its unique identifiers, a field or relation that could not be mapped. Such an event ends error when it wrote nothing and partial when it wrote something, and errors says why. A mapping that writes nothing on purpose (an enabled expression that is false, an empty list) ends done.

A requirement is only as good as the use case configuration it refers to: model one inbound use case per partner event type, and give every use case a slug. A legacy use case without a slug is counted, and can be named, only by its use case id, which differs between environments.

An unknown correlation, or one with no interactive events, reads as events_received: 0, closed: false — "not yet" and "never" look the same, which is why correlation_complete exists. Waiting on a correlation before anything was sent under it is normal — mint the id, hand it to the partner, wait — and the wait picks the correlation up as soon as its first event is ingested.

A correlation belongs to one integration: the one whose event (or close) created it. Events and closes of another integration under the same id are not applied to it — see correlation_complete and the event results.

Waiting holds a connection, so concurrent waits are capped per organization and overall. A wait that starts before anything was sent under its correlation counts against a separate, smaller per-organization cap instead, for its whole duration, so waits on ids nothing is ever sent under cannot crowd out waits on correlations that exist. Over a cap the call is refused with 429 and Retry-After; fall back to calls with wait=0 (they never need a slot) or retry later. Calls that do not have to wait — wait=0, or a correlation that is already decided — are never refused.

Requires integration:view on the correlation's integration. The organization is always the token's own, so no other organization's correlation is ever visible.

get/v3/erp/updates/events

Request

  • Base URL
    https://integration-toolkit.sls.epilot.io
  • URL
    https://integration-toolkit.sls.epilot.io/v3/erp/updates/events
  • Auth
    HTTP bearer

Query parameters

correlation_idstring required

The correlation to wait on, as returned by POST /v3/erp/updates/events: 1-255 characters of letters, digits, hyphens and underscores.

waitinteger

Seconds to wait for completion to be decided, 0 to 25. 0 answers immediately. A value outside the range is a 400 naming the maximum, never a silent clamp: 25 seconds keeps the call inside the 30 second HTTP limit.

wait_for_entitiesstring[]

Entities to wait for: slug or slug[key=value], at most 20.

  • One requirement per occurrence of the parameter: repeat it for several (wait_for_entities=contact&wait_for_entities=contract). An occurrence is never split, so a comma never separates requirements here — only in wait_for_use_cases. Any other form of the parameter — wait_for_entities[]=, wait_for_entities[0]=, wait_for_entities[x]= — is a 400.
  • Encode each occurrence once, as any URL query value (encodeURIComponent, URLSearchParams, curl --data-urlencode). The value is decoded exactly once, so it reaches the selector exactly as you held it: ,, %, =, ] and + need no escaping of their own. contact[customer_number=50%] is sent as wait_for_entities=contact%5Bcustomer_number%3D50%25%5D.
  • Inside the brackets the split is on the first =, and the value runs to the final ], so a value may contain = and ] — but not ],slug[: an occurrence holding selectors joined by a comma (contact[a=1],contract[b=2]) is a 400 telling you to repeat the parameter.
  • A value longer than 256 UTF-16 code units, not counting surrounding whitespace, is a 400: unique ids that long are not recorded, so it could never match. The limit counts code units, not characters: an emoji or another character outside the Basic Multilingual Plane counts 2.
  • More than 20 occurrences of the parameter is a 400 naming the limit. Empty occurrences count towards it; with 20 or fewer, an empty one is dropped.

A selector matches only an attribute that is one of the use case's configured unique_ids for that entity — they are all the toolkit records per entity, and only those it could record: an entity write records its unique ids within a bound of 1,024 bytes, so an id that does not fit (with several long ids, the ones after the first in key order) is not recorded, and a selector on it cannot match. The value is compared after trimming surrounding whitespace and lower-casing, on both sides, with standard Unicode lower-casing (JavaScript trim and toLowerCase), so contact[customer_number=ab-1001] matches a stored AB-1001. For ASCII ids this behaves like entity lookup; letters with special case rules (Turkish İ, Greek final ς) and non-breaking spaces may compare differently from entity lookup. Whitespace inside the value stays significant. A selector whose key is not a unique id of that slug in ANY of the organization's inbound use cases can never match, and is refused with a 400 whose body names the slug, the rejected_key and the allowed_keys. A slug that no inbound use case writes is refused the same way. A meter reading reports the meter and meter_counter it resolves or creates, so meter_counter[external_id=…] names the unique ids of the use case's meter_counter block. _id is never a selector key: an entity's id is in the response, not among its unique ids. Treat that 400 as a configuration error, not a reason to retry. Without a selector, any entity of the slug satisfies the requirement, which is only safe when the bundle cannot contain more than one of that type. A deleted entity never satisfies a requirement.

wait_for_use_casesstring[]

Inbound use case slugs to wait for, repeated, comma-separated or both — a slug never contains a comma. No selectors. Like wait_for_entities, only wait_for_use_cases=… is accepted; a bracketed form (wait_for_use_cases[]=) is a 400. More than 20 occurrences of the parameter is a 400 naming the limit, empty occurrences included, and so is more than 20 slugs once the occurrences are split on commas (empty entries are dropped). Each is met when at least one event of that use case in the correlation has finished (done), not merely been received. An entry that is not a use case slug (upper case, a bracket, a space) is refused with a 400 naming it, as passed, in use_case_slug. A slug that no inbound use case of the organization has can never match and is refused the same way. A correlation belongs to one integration and counts only its events, so once it does, a slug that none of THAT integration's inbound use cases has is refused the same way. A legacy use case without a slug is named by its use case id.

Response

The correlation's summary and the wait's verdict

correlation_idstring required
integration_idstring
closedboolean required

The partner sent correlation_complete.

closed_atstring date-time
completeboolean required

The correlation is complete — closed, and every event it received before completing has finished (or it was closed having received none). FINAL once true: the field to read for "is it done", on the listing as on a wait. Do not derive it from events_done >= events_received: a late event raises events_received after completion without reopening anything.

completed_atstring date-time

When the correlation became complete. Present exactly when complete is true (except on correlations completed before 2026-10-14); the correlation's use_cases, entities and completion are frozen at this instant.

events_receivedinteger required
events_doneinteger required

Events that reached a terminal status, failed ones included.

late_eventsinteger required

Events that arrived after the correlation was closed. Those that arrived after it completed are counted here and in events_received / events_done, but not in use_cases or entities.

first_ingested_atstring date-time

When the first event of the correlation was accepted. Absent while none was — a correlation created by a zero-event close.

last_done_atstring date-time
entities_omittedinteger

Entity writes of the correlation's events that are not in entities, because the list was full (at most 200), or because an event's record could not be written and the event ended error with PROCESSING_STATE_LIMIT. The entities may well have been written; they are only missing from the list, so a wait_for_entities requirement cannot be met by them — one that no listed entity satisfies is undecided instead (see undecided_entity_requirements). Present only when there are any.

errors_totalinteger required

Every failure in the correlation, including those not listed in errors (the first 50 are) and those of events that arrived after completion (after_completion), which do not change the answer.

completion'requirements_met' | 'complete' | 'timeout' | 'error' required

Why the wait ended. See the operation description.

undecided_entity_requirementsstring[]

The wait_for_entities requirements this record cannot decide, each exactly as you passed it. Present only when the correlation omitted entities (entities_omitted) and a requirement is satisfied by none of the listed ones: the list holds at most 200 entity writes, so the entity may well have been written, and an omitted one is never listed later. Such a requirement is neither met nor missing — it never makes completion error, and the wait still ends complete once the correlation completes. Look the entity up yourself, e.g. by its unique id through the entity API.

Example response

{
  "entities": [
    {
      "slug": "contact",
      "unique_ids": {
        "reenumber": "4711"
      }
    }
  ],
  "undecided_entity_requirements": [
    "contract[billing_account_number=4711]"
  ]
}

Changes

    • info

      added the optional property //// to the response with the status

    • info

      added the optional property / to the response with the status

    • info

      added the optional property //// to the response with the status

    • info

      added the optional property ////// to the response with the status

    • info

      added the optional property to the response with the status

    • info

      added the required property //// to the response with the status

    • info

      added the required property //// to the response with the status