Java SDK
com.github.ekoindia:eps-sdk-java is a client for every EPS API built on the
JDK's own java.net.http. One generic call(slug, params) covers all of them:
the endpoint catalog, each endpoint's params and which of them are required are
packaged from the same surface these docs are built from, so the client
validates your input before it signs and sends anything.
Backend only. accessKey signs every request — it must never ship in an Android
app or any artifact a user can decompile.
Install
com.github.ekoindia:eps-sdk-java
- Package
com.github.ekoindia:eps-sdk-java- Requires
- Java 17 or newer
- Dependencies
- One: Gson, because Java has no JSON parser in the standard library. HTTP uses the JDK's own
java.net.http. - Source
- GitHub
- Published through JitPack from a git tag — add the JitPack repository alongside Maven Central.
- Gradle:
maven { url 'https://jitpack.io' }, thenimplementation 'com.github.ekoindia:eps-sdk-java:<tag>'. - Maven: a
<repository>with idjitpack.ioand urlhttps://jitpack.io, then thecom.github.ekoindia:eps-sdk-javadependency.
Your first call
Read the two keys from the environment, pick an environment, and call an endpoint by its slug:
import in.eko.eps.EpsClient;import java.util.Map;EpsClient client = EpsClient.builder().developerKey(System.getenv("EPS_DEVELOPER_KEY")).accessKey(System.getenv("EPS_ACCESS_KEY")).initiatorId("9962981729").environment("sandbox").build();Map<String, Object> result = client.call("pan-lite", Map.of("pan_number", "ABCDE1234F","name", "Rajesh Kumar","dob", "1994-08-29"));System.out.println(result);
initiatorId and userCode are near-constant per developer, so set them once
on the builder. They are injected into every call as the wire params
initiator_id and user_code — pass either in the params map to override it
for a single call.
Client options
The client is built through a fluent builder; every option below is a builder method.
| Option | Type | Required | Notes |
|---|---|---|---|
.developerKey(…) | String | Yes | Your EPS developer key, sent as the developer_key header. |
.accessKey(…) | String | Yes | Server-side secret used to sign every request. Never ships to a browser. |
.environment(…) | "sandbox" | "production" | Yes | Selects the base URL from the embedded surface. |
.initiatorId(…) | String | No | Default initiator_id (registered mobile of the API user) injected into every call. |
.userCode(…) | String | No | Default user_code (retailer/agent code) injected into every call. |
.httpClient(…) | HttpClient | No | Control timeouts, proxies or redirects by supplying your own client. (default: 30s connect + 30s per request) |
.retries(…) | int | No | Extra attempts for a GET whose outcome was indeterminate (timeout, transport failure, HTTP 429/5xx). Non-GET calls are never retried. 0 disables. (default 2) |
.retryBaseDelay(…) | Duration | No | Backoff base: attempt n waits a random slice of min(base × 2^(n-1), 2s). (default 200ms) |
.autoStatusCheck(…) | boolean | No | After an indeterminate failure on a money-moving endpoint, look the transaction up by its client_ref_id and attach the result to the indeterminate error. (default true) |
API surface
The SDK is deliberately small. There is no method per endpoint — call() takes
the slug, and the packaged surface supplies the method, path, and validation
rules.
| Member | Signature | What it does |
|---|---|---|
in.eko.eps.EpsClientclass | EpsClient.builder()…build() | The client, built through a fluent builder. |
callmethod | client.call(String slug, Map<String, Object> params): Map<String, Object> | Validates, signs and sends one endpoint call; returns the decoded envelope. |
resolveTargetmethod | client.resolveTarget(String slug, Map<String, Object> params): Target | The signed request for a call, without sending it. |
buildHeadersmethod | client.buildHeaders(boolean multipart): Map<String, String> | The four auth headers for a single request. |
signmethod | EpsClient.sign(String accessKey, String timestamp): String | Static. The raw signing primitive, exposed for debugging. |
EpsClient.EpsFiletype | record EpsFile(String name, byte[] content) | An in-memory upload. |
EpsClient.MULTIPART_JSON_FIELDconstant | MULTIPART_JSON_FIELD = "form-data" | Name of the single form field carrying the JSON envelope on file-upload endpoints. |
EpsClient.generateClientRefIdmethod | static String generateClientRefId(long nowMs) | The 15-char client_ref_id generator call() uses for a non-GET call that did not supply one — exported so you can mint refs the same way. |
Authentication
You never compute a signature yourself. On every request the client derives
secret-key = base64(HMAC-SHA256(timestamp, base64(accessKey))) and sends it
with secret-key-timestamp and developer_key. EpsClient.sign is public only
so you can reproduce a signature while debugging a 403.
File uploads
A single type: "file" param flips the whole request to multipart/form-data.
You still pass every parameter flat; on the wire the SDK packs them the way the
API expects — one form field named form-data holding all the non-file params
as a single JSON object, plus one part per upload. A null param is dropped (a
form field has no null encoding), while a null nested inside a map value is
preserved.
File params accept:
- A
Stringpath, ajava.nio.file.Path, or ajava.io.File - An
EpsClient.EpsFile(name, content)for an in-memory upload
Errors and timeouts
Every failure is an unchecked exception, so nothing forces a try/catch you
do not want. A non-2xx response throws EpsHttpException — the decoded envelope
is on body.
| Type | Raised when | Fields |
|---|---|---|
EpsClient.EpsIndeterminateException | A money-moving (financial) non-GET call ended with no confirmed outcome — timeout, transport failure, HTTP 429/5xx. The SDK did not re-send it; it looked the transaction up by its client_ref_id and attached the result. Reconcile before retrying. | slug, clientRefId, status (or null), statusCheck, statusCheckError, getCause() |
EpsClient.EpsTransportException | The request produced no response at all (DNS, connect, TLS, timeout). Retried on GET; wraps the native error. | — |
EpsClient.EpsHttpException | Any non-2xx response. | status, url, body (decoded envelope or null), raw |
EpsClient.EpsException | Unknown slug, missing required param, wrong param type, transport failure, or a 2xx body that is not JSON. Unchecked — it extends RuntimeException. | — |
| HTTP status | Meaning |
|---|---|
200 | OK — response returned by our system. |
403 | Forbidden — incorrect secret-key or timestamp. |
404 | Not Found — wrong request URL. |
405 | Method Not Allowed — incorrect HTTP method. |
415 | Unsupported Media Type — wrong Content-Type header. |
500 | Internal Server Error — connectivity or URL misconfiguration. |
Environments
Switch with .environment(...); there is no base-URL override.
| Environment | Base URL | Notes |
|---|---|---|
sandboxUAT / Sandbox | https://staging.eko.in/ekoapi/v3 | Self-serve credentials available immediately on signup. |
productionProduction | https://api.eko.in/ekoicici/v3 | Credentials issued after organizational KYC. |
Java-specific notes
- Upload parts are sent as
application/octet-stream; the MIME type is not sniffed. - Gson is configured with
serializeNulls()— required for wire conformance, since every other SDK keeps explicit nulls.
Every endpoint
call() accepts every slug in the EPS catalog. Each endpoint's reference page
shows its parameters, response fields and a ready-to-paste Java snippet.