Why this guide exists
Most data exchange in Catena-X now runs through automated pipelines rather than people making individual requests — scheduled jobs, ETL flows, orchestration services and application backends calling the connector unattended. That is a sign of a maturing integration, and it is what the dataspace is for.
It also means the interaction pattern is written once, in code, and then repeats thousands of times a day without anyone watching it.
So, this guide is really a prompt to review your pipelines. Logic written when you had a few partners and a handful of assets behaves very differently at today's volumes, and a negotiation loop that was invisible in a pilot becomes the dominant overhead in a production job. The practices below belong in the pipeline code and its scheduling, not in connector configuration — no setting on the EDC will fix a job that asks for a new contract every time it runs.
The patterns in this guide make your integration:
Faster. Removing negotiation from the request path takes several round trips out of every data call.
More reliable. Fewer protocol steps per request means fewer opportunities for a partner's connector, the network, or a token expiry to break your job.
Easier to scale. Efficient patterns grow with your partner count; inefficient ones grow with your request volume, which is usually orders of magnitude larger.
A better neighbour. Every message you send is work for your partner's connector too. Chatty integrations degrade the experience for the counterparties you depend on.
Four changes account for almost all of the available improvement:
Upgrade to Tractus-X EDC 0.12 (Saturn). Cuts the verification work behind every remaining DSP message by roughly two thirds.
Stop catalog polling. A catalog request is a full protocol interaction even when nothing has changed.
Bundle submodels behind one asset, so one negotiation covers many data endpoints instead of one each.
Reuse cached EDRs instead of re-negotiating. Removes the protocol overhead entirely for repeat access within the EDR lifetime.
Step 1: upgrade to Tractus-X EDC 0.12 (Saturn)
Tractus-X EDC 0.12.0 introduces a cache for Verifiable Presentations, which lets the connector reuse already-downloaded Verifiable Presentations to improve performance and reduce wallet interactions. On a warm cache this takes each received DSP message from three credential verification calls down to one — two thirds less work on the identity path you cannot otherwise avoid, and correspondingly less latency on every exchange.
What the three calls are, per received DSP message:
Call | Purpose | Skipped on a cache hit |
Sending participant's STS | Obtain the self-issued token for the counterparty | No |
Receiving participant's STS | Token handling on the verifying side | Yes |
Sending participant's presentation API | Fetch the Verifiable Presentation itself | Yes |
Both connectors cache independently, so each side gets the reduction for the messages it receives. The cache is warm after the first exchange with a given counterparty and stays warm for the credential's validity window, so the benefit grows with how regularly you exchange with the same partners.
Before you upgrade
Read the migration guide and Impact Analysis documents. Upgrades from 0.10.x or 0.11.x carry breaking changes beyond the usual, including a new connector identifier that becomes a mandatory configuration parameter.
Confirm your app or service provider supports 0.12. If a third party operates your connector, raise it with them.
Plan for mixed-version interoperability. Saturn and Jupiter connectors coexist during the transition, and DSP version handling between them is explicit.
Test in Beta before PROD, EDC connectivity first, then your end-to-end data chains.
After you upgrade
Verify the cache is actually being hit. Compare your connector's credential verification count against its DSP message count over a full day of steady traffic. A healthy ratio is close to 1:1. If it stays near 3:1, the cache is not warming and the upgrade has bought you nothing — contact Cofinity-X support before assuming the improvement is banked.
What each interaction involves
A full first-time data exchange — catalog, negotiation, consumer-pull transfer — is seven DSP messages, which is 21 credential verification calls before the cache and seven after. The counts below were traced through the Eclipse EDC 0.15.1 state machines pinned by Tractus-X EDC 0.12.x.
Interaction | DSP messages | Verification calls, no cache | Verification calls, warm cache |
Catalog request | 1 | 3 | 1 |
Contract negotiation | 4 | 12 | 4 |
Transfer, consumer-pull | 2 | 6 | 2 |
Transfer, provider-push | 3 | 9 | 3 |
End-to-end (catalog + negotiation + pull) | 7 | 21 | 7 |
The four negotiation messages are the request, the agreement, the agreement verification, and the finalisation event. Provider-initiated or counter-offer negotiations run to six messages instead of four; terminations and suspensions add more. There is no configuration that reduces these counts — the protocol requires them.
The step that matters is the last one. Once the transfer reaches STARTED, the provider sends the EDR and your connector caches it automatically for later use. Every subsequent data pull against that EDR is zero DSP messages and zero verification round trips — your request goes straight to the provider's data plane.
So the question that shapes your integration is not what one exchange involves. It is how many times you repeat the seven-message handshake before you start pulling data directly.
Practice 1: Bundle submodels behind one asset
One asset covering twenty submodels needs one negotiation. Twenty assets need twenty. The data on the wire is identical.
If you are a data provider, the way you model your offers directly sets how much protocol work your consumers — and your own connector — have to do. Publishing a separate asset per submodel, per part number, or per material forces every consumer into a separate negotiation for each one, and your connector processes every one of those handshakes too.
For providers:
Define assets at the level of a data offering, not a data record. One asset per submodel type per consumer group is usually right; one asset per part instance is almost never right.
Use a single asset with a parameterised endpoint where the access policy is the same across the underlying records. The consumer negotiates once and varies the path or query on the data plane.
Keep contract definitions stable. Changing a policy retires existing agreements and forces every consumer to re-negotiate.
For consumers:
Ask your providers whether a bundled asset exists before building a loop that negotiates per submodel.
Map your EDR cache by asset, not by record. If one EDR serves 500 part numbers, you should be hitting the cache 499 times out of 500.
Practice 2: Reuse cached EDRs, never re-negotiate
Negotiate once per asset per counterparty, then pull against the cached EDR for the next 30 days. This is the single largest improvement available to you, and it is entirely under your control.
Your connector stores every EDR it receives. The /v3/edrs API returns the cached entry and refreshes the access token itself if renewal is needed, so a valid EDR keeps working without any DSP traffic at all.
The pattern to implement:
Query your EDR store for an existing entry matching the asset and counterparty.
If one exists, request the data address with auto_refresh and pull the data. Stop here — no catalog, no negotiation, no transfer messages.
Only if no valid EDR exists, run the negotiation, then cache what comes back.
What this is worth. A consumer pulling one asset 500 times a month runs 500 full negotiations if it re-negotiates each time, or one negotiation and 499 direct pulls if it does not. Every one of those 499 requests skips the catalog lookup, the four-message negotiation handshake and the transfer setup — typically seconds of round trips removed from each call. This does not require the 0.12 upgrade to achieve.
Common mistakes we see:
Treating negotiation as part of the request path. If your code calls POST /v3/edrs on every data request, you are paying a full negotiation every time.
Discarding EDRs on application restart instead of reading them back from the connector.
Treating a 401 or 403 as a signal to re-negotiate. Refresh the token first; only re-negotiate if the agreement itself is gone or retired.
Re-negotiating because the client library makes it easy. The single-call convenience API that collapses negotiation and transfer is meant for the first access, not for every access.
Combined effect. Bundling and EDR reuse multiply. A consumer reading 20 submodels across 1,000 parts daily runs 20,000 full handshakes a day if it negotiates per submodel per part with no caching. With one bundled asset and a reused EDR it runs one handshake, then pulls directly for the rest of the EDR's lifetime.
Practice 3: Treat the catalog as a heavyweight call
A catalog request is a full protocol interaction — three credential verification calls before the cache, one after — every time, whether or not anything changed. Catalogs change rarely; polling them on a timer is one of the clearest sources of avoidable work we see.
Do not poll catalogs on a schedule. Refresh on a business event — a new partner, a failed lookup, a known offer change — or at most daily.
Cache catalog responses in your application with a TTL measured in hours or days, not seconds.
Do not crawl the full catalog to find one dataset. Use the single-dataset request variant when you already know what you want.
Do not request a catalog before every negotiation. If you hold a valid offer ID, negotiate against it directly.
Never request a catalog on the data path. If a catalog call sits in the code path of a user-facing request, it will scale with your traffic rather than with your partner count.
A useful sanity check: your daily catalog requests should be roughly the number of counterparties you deal with, not the number of data requests you serve.
Practice 4: Control retries, schedules and failure loops
A failed negotiation still runs the full protocol handshake. A tight retry loop around a failing counterparty can generate more traffic in an hour than a month of normal operation, against a partner whose connector is already struggling.
Use exponential backoff with a cap, not fixed-interval retries. Start at 30 seconds and back off to hours.
Set a retry ceiling. After a handful of failures, stop and raise an alert rather than retrying indefinitely.
Add a circuit breaker per counterparty. If a partner's connector is down, stop calling it until a probe succeeds.
Make jobs idempotent. A batch job that re-runs after a partial failure should skip work already done, not repeat every negotiation.
Match the schedule to the data. Master data that changes weekly does not need a nightly negotiation sweep. Align the job frequency with how often the underlying data actually changes.
Turn off non-production traffic. Test and staging connectors pointed at production endpoints generate real traffic against your partners' live connectors.
A specific pattern to check for: if your weekend traffic matches your weekday traffic and your overnight traffic matches your business-hours traffic, you have a scheduled job running independently of demand. That job is almost always doing work nobody asked for — and consuming your connector's throughput that real requests could be using.
Need Assistance?
If you experience any issues or are in need of help, please reach out to our support team via Service Desk: https://servicedesk.jira.cofinity-x.com/ or email: [email protected]
