Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Java SDK

Status: 🔄 Planned. Not yet available.

Official Java SDK for PYLON is under development. Use direct HTTP integration until released.


Current Integration (Direct HTTP)

Until the SDK is available, use Java’s standard HTTP client (Java 11+):

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Map;

public class PylonExample {
    public static void main(String[] args) throws Exception {
        String apiKey = System.getenv("PYLON_API_KEY");
        
        // Build request
        Map<String, Object> requestBody = Map.of(
            "policy", Map.of("minAge", 18),
            "callbackUrl", "https://app.example.com/webhooks/pylon"
        );
        
        ObjectMapper mapper = new ObjectMapper();
        String json = mapper.writeValueAsString(requestBody);
        
        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create("https://pylonid.eu/v1/verify/age"))
            .header("Content-Type", "application/json")
            .header("Authorization", "Bearer " + apiKey)
            .POST(HttpRequest.BodyPublishers.ofString(json))
            .build();
        
        HttpResponse<String> response = client.send(request, 
            HttpResponse.BodyHandlers.ofString());
        
        Map<String, Object> result = mapper.readValue(response.body(), Map.class);
        System.out.println("Verification ID: " + result.get("verificationId"));
        System.out.println("Wallet URL: " + result.get("walletUrl"));
        // Redirect user to wallet URL
    }
}

Handle Webhooks (Spring Boot)

import org.springframework.web.bind.annotation.*;
import org.springframework.http.ResponseEntity;
import org.springframework.http.HttpStatus;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;

@RestController
public class WebhookController {
    
    private boolean validateSignature(String signature, String body, String secret) {
        try {
            String[] parts = signature.split(",");
            if (parts.length != 2) return false;
            
            String t = parts.replace("t=", "");
            String v1 = parts.replace("v1=", "");
            
            String signedMessage = t + "." + body;
            
            Mac mac = Mac.getInstance("HmacSHA256");
            SecretKeySpec secretKey = new SecretKeySpec(
                secret.getBytes(StandardCharsets.UTF_8), 
                "HmacSHA256"
            );
            mac.init(secretKey);
            
            byte[] hash = mac.doFinal(signedMessage.getBytes(StandardCharsets.UTF_8));
            StringBuilder computed = new StringBuilder();
            for (byte b : hash) {
                computed.append(String.format("%02x", b));
            }
            
            return v1.equals(computed.toString());
        } catch (Exception e) {
            return false;
        }
    }
    
    @PostMapping("/webhooks/pylon")
    public ResponseEntity<?> handlePylonWebhook(
        @RequestHeader("X-Pylon-Signature") String signature,
        @RequestBody String body
    ) {
        String secret = System.getenv("PYLON_WEBHOOK_SECRET");
        
        if (!validateSignature(signature, body, secret)) {
            return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
        }

        if (body.contains("\"result\":\"verified\"")) {
            System.out.println("✅ Verified!");
            return ResponseEntity.ok(Map.of("received", true));
        }

        return ResponseEntity.ok(Map.of("received", true));
    }
}

Idempotency Handling

import org.springframework.data.repository.CrudRepository;
import java.time.Instant;

@RestController
public class WebhookController {
    
    @Autowired
    private WebhookRepository webhookRepo;
    
    @PostMapping("/webhooks/pylon")
    public ResponseEntity<?> handlePylonWebhook(
        @RequestHeader("X-Pylon-Idempotency-Key") String idempotencyKey,
        @RequestHeader("X-Pylon-Signature") String signature,
        @RequestBody String body
    ) {
        
        // Check if already processed
        if (webhookRepo.existsById(idempotencyKey)) {
            return ResponseEntity.ok(Map.of("status", "already_processed"));
        }

        // Validate signature
        String secret = System.getenv("PYLON_WEBHOOK_SECRET");
        if (!validateSignature(signature, body, secret)) {
            return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
        }

        // Store idempotency key
        WebhookRecord record = new WebhookRecord();
        record.setIdempotencyKey(idempotencyKey);
        record.setProcessedAt(Instant.now());
        webhookRepo.save(record);

        // Return 200 immediately
        ResponseEntity.ok(Map.of("received", true));

        // Process asynchronously
        processWebhookAsync(body);

        return ResponseEntity.ok(Map.of("received", true));
    }
    
    @Async
    private void processWebhookAsync(String body) {
        // Do background work here
    }
}

interface WebhookRepository extends CrudRepository<WebhookRecord, String> {}

Error Handling

HttpResponse<String> response = client.send(request, 
    HttpResponse.BodyHandlers.ofString());

switch (response.statusCode()) {
    case 401:
        System.err.println("❌ Invalid API key");
        break;
    case 429:
        System.err.println("❌ Rate limited");
        break;
    case 400:
        System.err.println("❌ Invalid request");
        break;
    default:
        System.err.println("❌ Error: " + response.statusCode());
}

Testing Locally

Start the local emulator:

pylon-cli

Point requests to localhost:

HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("http://localhost:7777/v1/verify/age"))
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString(json))
    .build();

Roadmap

  • Q1 2026: Official Java SDK release with async-first API using Project Reactor

Questions? See Troubleshooting or API Reference