Call a vendor's OAuth client credentials API without writing token code

October 27, 2026

The finance team's ERP accepts no API key. It wants the OAuth 2.0 client credentials grant: trade a client ID and secret for an access token, send the token on every call, get a new one before it expires. So every service that posts a paid invoice to it carries the same token code, and the copy nobody has touched in a year is the one that breaks at month-end close. Save the client ID and secret once in EchoRelay as an OAuth client credentials credential instead.

From then on, EchoRelay requests the access token, reuses it, renews it before it runs out and sends it with each delivery. Your services send the invoice and nothing else.

Three values from the vendor replace the token code

The credential asks for what the vendor already gave you: the token URL, the client ID and the client secret, plus a scope or audience if the vendor's documentation names one. You choose whether the client ID and secret go to the token URL in a Basic auth header or in the request body, whichever that vendor accepts.

A target, the address a delivery goes to, uses the saved credential instead of a copy of the secret. Every target that calls the ERP points at the same credential, so there is one place where the secret lives and one place to replace it when the vendor rotates it.

The token is renewed before it expires

The first delivery fetches a token. Later deliveries reuse it until 60 seconds before it expires, and then EchoRelay asks for a new one. Deliveries that need a token at the same moment wait for one token request rather than each sending their own. Each of our servers keeps its own token, so the vendor may see more than one token request.

If the ERP answers a delivery with 401, the token is dropped once it is at least 30 seconds old and the next delivery fetches a fresh one. That covers a token the vendor revoked early, without asking the vendor for a new token on every refused call. Vendors throttle clients that ask too often, and some lock them out.

The secret goes to one address, the token to one host

The client secret is only ever sent to the token URL, and the token URL cannot be changed after you save the credential. Someone with edit access cannot point it at their own server and collect the secret. A different token URL means a new credential and the secret typed in again on purpose. If your project has an outbound host allowlist, the token URL's host must be on it.

The access token is only ever sent over https to the ERP's host, which you name when you save the credential. The secret is sealed when you save it and is never shown again, in the panel, over our API or to an AI agent.

When the vendor refuses, the delivery says so

If the token URL refuses the client ID or secret, cannot be reached, or answers without a usable token, the delivery fails with oauth_token_request_failed and the status the token URL answered, or 0 if it never answered. That tells you in one line whether to look at the credential or at the vendor. A queued delivery is retried on the normal schedule and then waits in Held for retry, so you fix the credential and retry it from there. A synchronous or streaming target answers your caller 502 with the same code and status in the body.

The same credential type covers a carrier's label API, a cloud provider's management API, or any other vendor that issues a client ID and secret instead of a key.

What your team stops maintaining

Token fetching, caching, renewal and dropping a refused token stop being code each service carries and a reviewer has to check. Rotating the vendor's secret is one edit. The OAuth client credentials guide lists each field and what to enter, and keeping partner credentials out of your code shows where it fits.

Connect everything. Deploy nothing.

No credit card required.