Canonical Java server SDK for Qredex machine-to-machine integrations.
qredex for Java is built for backend systems that need to create creators and links, issue IITs, lock PITs, and record paid orders and refunds without dealing with raw HTTP plumbing.
- Java 8+
- Maven 3.6+ or Gradle 7+
- Kotlin/JVM projects are supported (this SDK is a standard JVM library).
Maven Central:
<dependency>
<groupId>com.qredex</groupId>
<artifactId>qredex-java</artifactId>
<version>0.1.1</version>
</dependency>Gradle:
implementation 'com.qredex:qredex-java:0.1.1'Gradle Kotlin DSL:
implementation("com.qredex:qredex-java:0.1.1")Local build (optional, for local-only testing):
ota run setup
ota run buildThen consume the artifact from your local Maven repository.
Set:
QREDEX_CLIENT_IDQREDEX_CLIENT_SECRET
Then run the canonical server-side flow:
Qredex qredex = Qredex.bootstrap();
String storeId = System.getenv("QREDEX_STORE_ID");
CreatorResponse creator = qredex.creators().create(
CreateCreatorRequest.builder()
.handle("alice")
.displayName("Alice")
.build());
LinkResponse link = qredex.links().create(
CreateLinkRequest.builder()
.storeId(storeId)
.creatorId(creator.getId())
.linkName("spring-launch")
.destinationPath("/products/spring-launch")
.build());
InfluenceIntentResponse iit = qredex.intents().issueInfluenceIntentToken(
IssueInfluenceIntentTokenRequest.builder()
.linkId(link.getId())
.landingPath("/products/spring-launch")
.build());
PurchaseIntentResponse pit = qredex.intents().lockPurchaseIntent(
LockPurchaseIntentRequest.builder()
.token(iit.getToken())
.source("backend-cart")
.build());
OrderAttributionResponse order = qredex.orders().recordPaidOrder(
RecordPaidOrderRequest.builder()
.storeId(storeId)
.externalOrderId("order-100045")
.currency("USD")
.totalPrice(110.00)
.purchaseIntentToken(pit.getToken())
.build());
qredex.refunds().recordRefund(
RecordRefundRequest.builder()
.storeId(storeId)
.externalOrderId("order-100045")
.externalRefundId("refund-100045-1")
.refundTotal(25.00)
.build());Kotlin/JVM usage is the same API surface:
val qredex = Qredex.bootstrap()
val creator = qredex.creators().create(
CreateCreatorRequest.builder()
.handle("alice")
.displayName("Alice")
.build()
)- automatic client-credentials auth with token caching
- typed request objects instead of raw maps or long parameter lists
- typed responses that preserve canonical Qredex field names (
token_integrity,integrity_reason,resolution_status) - structured exception hierarchy with
status,errorCode,requestId, andtraceId - deterministic behavior aligned with the canonical machine integration flow: IIT → PIT → order → refund
- zero framework dependencies — works in any Java 8+ backend
Three equivalent paths, choose the one that fits your service:
// 1. Bootstrap from environment variables — preferred for environment-configured services
Qredex qredex = Qredex.bootstrap();
// 2. Explicit config object — preferred when you manage config programmatically
Qredex qredex = Qredex.init(
QredexConfig.builder()
.clientId("your-client-id")
.clientSecret("your-client-secret")
.environment(QredexEnvironment.PRODUCTION)
.build()
);
// 3. Fluent builder — convenience alias for Qredex.init()
Qredex qredex = Qredex.builder()
.clientId("your-client-id")
.clientSecret("your-client-secret")
.build();Qredex.bootstrap() reads QREDEX_CLIENT_ID, QREDEX_CLIENT_SECRET, optional QREDEX_SCOPE, and optional QREDEX_ENVIRONMENT, then delegates to Qredex.init().
Create one shared Qredex instance per process. It is thread-safe and manages its own token cache.
// Creators
qredex.creators().create(request);
qredex.creators().get(creatorId);
qredex.creators().list(filters);
// Links
qredex.links().create(request);
qredex.links().get(linkId);
qredex.links().list(filters);
qredex.links().getStats(linkId);
// Intents
qredex.intents().issueInfluenceIntentToken(request);
qredex.intents().lockPurchaseIntent(request);
// Orders
qredex.orders().recordPaidOrder(request);
qredex.orders().list(filters);
qredex.orders().getDetails(orderAttributionId);
// Refunds
qredex.refunds().recordRefund(request);
// Auth (explicit — normally automatic)
qredex.auth().issueToken();
qredex.auth().clearTokenCache();| Resource | Methods | Typical scopes |
|---|---|---|
creators() |
create, get, list |
CREATORS_WRITE, CREATORS_READ |
links() |
create, get, list, getStats |
LINKS_WRITE, LINKS_READ |
intents() |
issueInfluenceIntentToken, lockPurchaseIntent |
INTENTS_WRITE |
orders() |
recordPaidOrder, list, getDetails |
ORDERS_WRITE, ORDERS_READ |
refunds() |
recordRefund |
ORDERS_WRITE |
| Variable | Required | Description |
|---|---|---|
QREDEX_CLIENT_ID |
Yes | Integration client ID |
QREDEX_CLIENT_SECRET |
Yes | Integration client secret |
QREDEX_ENVIRONMENT |
No | production, staging, or development |
QREDEX_SCOPE |
No | Space-delimited OAuth scope string |
Use QREDEX_ENVIRONMENT only when you need staging or development. Most integrations can omit it.
For local testing against a non-Qredex base URL, use Qredex.builder().baseUrl(...) instead of treating localhost as a platform environment.
The SDK supports typed scope enums for explicit permission control:
Qredex qredex = Qredex.builder()
.clientId("...")
.clientSecret("...")
.scopes(QredexScope.LINKS_WRITE, QredexScope.INTENTS_WRITE, QredexScope.ORDERS_WRITE)
.build();When no scope is specified, the server assigns the default scope for your client credentials. Most integrations can omit explicit scopes.
Available scopes: API, LINKS_READ, LINKS_WRITE, CREATORS_READ, CREATORS_WRITE, ORDERS_READ, ORDERS_WRITE, INTENTS_READ, INTENTS_WRITE.
| Option | Default | Description |
|---|---|---|
clientId |
— | Required. Integration client ID |
clientSecret |
— | Required. Integration client secret |
environment |
PRODUCTION |
Target environment |
baseUrl |
env default | Override base URL (useful in tests) |
timeoutMs |
10000 |
HTTP timeout in milliseconds |
maxAuthRetries |
3 |
Retry attempts for auth token issuance |
userAgentSuffix |
null |
Appended to the User-Agent header |
scope / scopes |
null |
OAuth scope — accepts a raw string or typed QredexScope enum values |
logger |
null |
QredexLogger implementation for diagnostic logging |
Auth is automatic. The SDK fetches a client-credentials token on the first call and caches it until close to expiry. You do not need to manage tokens.
For explicit control on the same client instance:
// Warm the cache or inspect the issued token
OAuthTokenResponse token = qredex.auth().issueToken();
System.out.println(token.getExpiresIn());
// Force a fresh token on the next API call
qredex.auth().clearTokenCache();Qredex write operations achieve idempotency through stable external identifiers:
- Paid orders are idempotent on
(store_id, external_order_id). - Refunds are idempotent on
(store_id, external_refund_id).
Safe to retry on timeout — submitting the same external IDs produces an IDEMPOTENT decision (HTTP 200), not a duplicate.
// Safe to retry: same (store_id, external_order_id) is idempotent
RecordPaidOrderRequest request = RecordPaidOrderRequest.builder()
.storeId(storeId)
.externalOrderId("order-100045") // stable external ID = idempotency key
.currency("USD")
.totalPrice(110.00)
.purchaseIntentToken(pitToken)
.build();
qredex.orders().recordPaidOrder(request);Use stable, deterministic external IDs from your platform. Do not generate random IDs per retry attempt.
Use QredexCallOptions when you need request-scoped operational controls without mutating the shared client:
OrderAttributionResponse order = qredex.orders().recordPaidOrder(
request,
QredexCallOptions.builder()
.requestId("req-123")
.traceId("trace-456")
.idempotencyKey("order-100045-v1")
.timeoutMs(5_000)
.build()
);Supported controls:
requestIdtraceIdidempotencyKeytimeoutMs- additional non-reserved headers via
header(...)
- auth token issuance retries internally with exponential backoff
- read operations (
GET) are not retried by default — configuremaxAuthRetriesonly - writes are never retried automatically
- when the server sends a
Retry-Afterheader (HTTP 429), the value is available onQredexRateLimitException.getRetryAfterSeconds()
import com.qredex.exceptions.*;
try {
qredex.orders().recordPaidOrder(request);
} catch (QredexConflictException e) {
// errorCode is "REJECTED_SOURCE_POLICY" or "REJECTED_CROSS_SOURCE_DUPLICATE"
System.err.println("Conflict: " + e.getErrorCode() + " requestId=" + e.getRequestId());
} catch (QredexValidationException e) {
System.err.println("Validation: " + e.getMessage());
} catch (QredexAuthenticationException e) {
System.err.println("Auth failed — check credentials");
} catch (QredexRateLimitException e) {
System.err.println("Rate limited — retry after " + e.getRetryAfterSeconds() + "s");
} catch (QredexNetworkException e) {
System.err.println("Network error: " + e.getMessage());
} catch (QredexApiException e) {
System.err.println("API error " + e.getStatus() + ": " + e.getMessage()
+ " traceId=" + e.getTraceId());
}All exceptions extend QredexException. QredexApiException and its subclasses carry:
getStatus()— HTTP status codegetErrorCode()— canonical Qredex error code stringgetRequestId()—X-Request-Idfrom the responsegetTraceId()—X-Trace-Idfrom the response
See docs/ERRORS.md for the full exception hierarchy and ingestion decision table.
The shortest safe backend path is:
- Create a creator.
- Create a link for a store and creator.
- Issue an IIT for the backend click event.
- Lock the IIT into a PIT at cart time.
- Record the paid order with the PIT.
- Record refunds later with a stable external refund ID.
- AuthAndCreateCreator.java
- CreateLink.java
- IssueIit.java
- LockPit.java
- RecordPaidOrder.java
- ListOrders.java
- GetOrderDetails.java
- RecordRefund.java
- CanonicalFlow.java
ota run test runs unit and WireMock-based HTTP integration tests only. No network access is required.
Live integration tests are opt-in and skipped unless QREDEX_LIVE_ENABLED=1 and the required credentials are set. Tag: @Tag("live").
# Run the test suite
ota run test
# Run the full verification suite
ota run ciThis SDK covers the Integrations API only:
POST /api/v1/auth/token/api/v1/integrations/creators/**/api/v1/integrations/links/**/api/v1/integrations/intents/**/api/v1/integrations/orders/**
It does not include:
/api/v1/merchant/**— Merchant dashboard API/api/v1/internal/**— internal admin API- Shopify OAuth or embedded app flows
- browser/runtime agent logic
- webhook receiver frameworks
- Website: https://qredex.com
- X: https://x.com/qredex
- Email: os@qredex.com