Linkbreakers Java SDK: Complete Integration Guide

Learn how to integrate the Linkbreakers Java SDK in your backend application for programmatic link management, visitor tracking, QR code generation, and analytics. Includes installation with Maven/Gradle, authentication, and real code examples for Spring Boot and other frameworks.

Developer
4 min read
By Laurent Schaffner
Updated March 31, 2025

Short answer

The Linkbreakers Java SDK enables programmatic link management, visitor identification, QR code generation, and analytics access from your Java backend applications. Install it with Maven or Gradle, authenticate with a secret API key, and start creating trackable links for your campaigns, products, or events.

Installation

Maven

Add the dependency to your pom.xml:

XML
<dependency>
    <groupId>com.linkbreakers</groupId>
    <artifactId>linkbreakers-java</artifactId>
    <version>1.0.0</version>
</dependency>

Gradle

Add the dependency to your build.gradle:

GROOVY
dependencies {
    implementation 'com.linkbreakers:linkbreakers-java:1.0.0'
}

Or for Kotlin DSL (build.gradle.kts):

Kotlin
dependencies {
    implementation("com.linkbreakers:linkbreakers-java:1.0.0")
}

Understanding API keys for Java

The Java SDK is designed for backend/server-side use only and requires a secret API key with full workspace access.

Secret keys

Backend-only. These JWT tokens grant full API access and must never be exposed in public repositories or client-side code.

What they allow:

  • Create, update, and delete links
  • Generate and customize QR codes
  • Identify and track visitors
  • Access analytics and metrics
  • Manage workspace resources
  • Full API access

Where to use:

  • Spring Boot applications
  • Jakarta EE / Java EE applications
  • Microservices (Micronaut, Quarkus)
  • Background jobs and schedulers
  • CLI tools
  • Enterprise applications

Security note: Java applications typically run on servers, making them perfect for secret key usage. Never log keys, commit them to git, or expose them in error messages.

Creating a secret API key

Create your API key from the dashboard:

  1. Log in to app.linkbreakers.com
  2. Navigate to Dashboard → API Tokens
  3. Click Create API Token
  4. Select Secret Key (full API access)
  5. Give it a descriptive name (e.g., "Production Backend" or "Java Service")
  6. Copy the generated JWT token immediately

Important: You won't see the key again after creation. Store it in environment variables or a secret management system (AWS Secrets Manager, HashiCorp Vault, etc.).

Quick start

Initialize the client and create your first shortened link:

Java
package com.example.linkbreakers;

import com.linkbreakers.ApiClient;
import com.linkbreakers.ApiException;
import com.linkbreakers.Configuration;
import com.linkbreakers.api.LinksApi;
import com.linkbreakers.model.CreateLinkRequest;
import com.linkbreakers.model.CreateLinkResponse;

import java.util.Arrays;

public class QuickStart {
    public static void main(String[] args) {
        // Configure API client with your secret key
        String apiKey = System.getenv("LINKBREAKERS_SECRET_KEY");

        ApiClient apiClient = Configuration.getDefaultApiClient();
        apiClient.setBasePath("https://api.linkbreakers.com");
        apiClient.setBearerToken(apiKey);

        LinksApi linksApi = new LinksApi(apiClient);

        try {
            // Create a shortened link
            CreateLinkRequest request = new CreateLinkRequest()
                .destination("https://example.com/product")
                .name("Product Launch - Spring 2025")
                .tags(Arrays.asList("marketing", "product-launch"));

            CreateLinkResponse response = linksApi.linksServiceCreate(request);

            System.out.println("Short URL: " + response.getLink().getShortlink());
            System.out.println("Link ID: " + response.getLink().getId());
            System.out.println("QR Code: " + response.getLink().getQrcodeSignedUrl());

        } catch (ApiException e) {
            System.err.println("API Error: " + e.getMessage());
            e.printStackTrace();
        }
    }
}

Environment variables (best practice)

Never hardcode API keys. Use environment variables:

Java
package com.example.linkbreakers;

import com.linkbreakers.ApiClient;
import com.linkbreakers.Configuration;

public class ApiClientFactory {
    private static ApiClient apiClient;

    public static ApiClient getClient() {
        if (apiClient == null) {
            String apiKey = System.getenv("LINKBREAKERS_SECRET_KEY");

            apiClient = Configuration.getDefaultApiClient();
            apiClient.setBasePath("https://api.linkbreakers.com");
            apiClient.setBearerToken(apiKey);
        }
        return apiClient;
    }
}

Set your environment variable:

Bash
# .env file or export directly
export LINKBREAKERS_SECRET_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ3b3Jrc3BhY2VfaWQiOiIxMjM0IiwidHlwZSI6InNlY3JldCJ9...

Loading with Spring Boot (application.properties):

PROPERTIES
linkbreakers.secret-key=${LINKBREAKERS_SECRET_KEY}
Java
@Value("${linkbreakers.secret-key}")
private String linkbreakersSecretKey;
Java
package com.example.linkbreakers;

import com.linkbreakers.ApiException;
import com.linkbreakers.api.LinksApi;
import com.linkbreakers.model.CreateLinkRequest;
import com.linkbreakers.model.CreateLinkResponse;

import java.util.Arrays;

public class LinkCreation {
    public void createBasicLink(LinksApi linksApi) {
        try {
            CreateLinkRequest request = new CreateLinkRequest()
                .destination("https://example.com/summer-sale")
                .name("Summer Sale 2025")
                .tags(Arrays.asList("campaign", "summer", "email"));

            CreateLinkResponse response = linksApi.linksServiceCreate(request);

            System.out.println("Created: " + response.getLink().getShortlink());

        } catch (ApiException e) {
            e.printStackTrace();
        }
    }
}
Java
package com.example.linkbreakers;

import com.linkbreakers.ApiException;
import com.linkbreakers.api.LinksApi;
import com.linkbreakers.model.CreateLinkRequest;
import com.linkbreakers.model.CreateLinkResponse;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

public class AdvancedLinkCreation {
    public void createAdvancedLinks(LinksApi linksApi) {
        try {
            // Create link with custom shortlink
            CreateLinkRequest customRequest = new CreateLinkRequest()
                .destination("https://example.com/docs")
                .shortlink("docs") // Creates lbr.ai/docs
                .name("Documentation Portal")
                .fallbackDestination("https://example.com/404")
                .tags(Arrays.asList("internal", "docs"));

            CreateLinkResponse customLink = linksApi.linksServiceCreate(customRequest);

            // Create link with metadata for tracking
            Map<String, String> metadata = new HashMap<>();
            metadata.put("product_id", "123");
            metadata.put("campaign_id", "spring-2025");
            metadata.put("utm_source", "email");
            metadata.put("utm_medium", "newsletter");
            metadata.put("utm_campaign", "product-launch");

            CreateLinkRequest trackedRequest = new CreateLinkRequest()
                .destination("https://example.com/product/123")
                .name("Product 123 - Email Campaign")
                .metadata(metadata)
                .tags(Arrays.asList("product", "email"));

            CreateLinkResponse trackedLink = linksApi.linksServiceCreate(trackedRequest);

            // Create link with QR code (wait for generation)
            CreateLinkRequest qrRequest = new CreateLinkRequest()
                .destination("https://example.com/event-registration")
                .name("Conference 2025 Registration")
                .waitForQrcode(true) // Blocks until QR is generated
                .tags(Arrays.asList("event", "conference", "qr-code"));

            CreateLinkResponse qrLink = linksApi.linksServiceCreate(qrRequest);

            System.out.println("Download QR code: " + qrLink.getLink().getQrcodeSignedUrl());

        } catch (ApiException e) {
            e.printStackTrace();
        }
    }
}
Java
package com.example.linkbreakers;

import com.linkbreakers.ApiException;
import com.linkbreakers.api.LinksApi;
import com.linkbreakers.model.Link;
import com.linkbreakers.model.Linkbreakersv1LinksSortField;
import com.linkbreakers.model.Linkbreakersv1SortDirection;
import com.linkbreakers.model.ListLinksResponse;

import java.util.Arrays;
import java.util.List;

public class LinkListing {
    public void listLinks(LinksApi linksApi) {
        try {
            ListLinksResponse response = linksApi.linksServiceList(
                50, // pageSize
                null, // pageToken
                Arrays.asList("marketing", "email"), // tags
                "campaign", // search
                Linkbreakersv1LinksSortField.UPDATED_AT, // sortBy
                Linkbreakersv1SortDirection.DESC, // sortDirection
                null, // directoryId
                null, // includeAllDirectories
                null  // include
            );

            List<Link> links = response.getLinks();
            for (Link link : links) {
                System.out.println(link.getName() + ": " + link.getShortlink());
                System.out.println("  Tags: " + link.getTags());
                System.out.println("  Created: " + link.getCreatedAt());
            }

        } catch (ApiException e) {
            e.printStackTrace();
        }
    }
}
Java
package com.example.linkbreakers;

import com.linkbreakers.ApiException;
import com.linkbreakers.api.LinksApi;
import com.linkbreakers.model.GetLinkResponse;
import com.linkbreakers.model.UpdateLinkRequest;

import java.util.Arrays;

public class LinkManagement {
    public void updateAndDeleteLink(LinksApi linksApi, String linkId) {
        try {
            // Get a specific link
            GetLinkResponse linkResponse = linksApi.linksServiceGet(
                linkId,
                Arrays.asList("tags", "qrcodeSignedUrl")
            );

            // Update link
            UpdateLinkRequest updateRequest = new UpdateLinkRequest()
                .name("Updated Campaign Name")
                .tags(Arrays.asList("marketing", "q2-2025", "updated"));

            linksApi.linksServiceUpdate(linkId, updateRequest);

            // Delete link
            linksApi.linksServiceDelete(linkId);

        } catch (ApiException e) {
            e.printStackTrace();
        }
    }
}

Create hundreds of links efficiently in a single API call:

Java
package com.example.linkbreakers;

import com.linkbreakers.ApiException;
import com.linkbreakers.api.LinksApi;
import com.linkbreakers.model.CreateBulkLinksRequest;
import com.linkbreakers.model.CreateBulkLinksResponse;
import com.linkbreakers.model.CreateLinkRequest;
import com.linkbreakers.model.Link;

import java.util.*;

class Product {
    String id;
    String name;
    String url;

    Product(String id, String name, String url) {
        this.id = id;
        this.name = name;
        this.url = url;
    }
}

public class BulkLinkCreation {
    public void createBulkLinks(LinksApi linksApi) {
        try {
            // Prepare bulk links (e.g., from a product catalog)
            List<Product> products = Arrays.asList(
                new Product("001", "Widget A", "https://example.com/products/001"),
                new Product("002", "Widget B", "https://example.com/products/002"),
                new Product("003", "Widget C", "https://example.com/products/003")
            );

            List<CreateLinkRequest> linksToCreate = new ArrayList<>();

            for (Product product : products) {
                Map<String, String> metadata = new HashMap<>();
                metadata.put("product_id", product.id);
                metadata.put("sku", "SKU-" + product.id);

                CreateLinkRequest request = new CreateLinkRequest()
                    .destination(product.url)
                    .name("Product: " + product.name)
                    .tags(Arrays.asList("product", "catalog"))
                    .metadata(metadata);

                linksToCreate.add(request);
            }

            // Create all links in one request
            CreateBulkLinksRequest bulkRequest = new CreateBulkLinksRequest()
                .links(linksToCreate);

            CreateBulkLinksResponse response = linksApi.linksServiceCreateBulk(bulkRequest);

            System.out.println("Created " + response.getLinks().size() + " links");
            for (Link link : response.getLinks()) {
                System.out.println("  " + link.getName() + ": " + link.getShortlink());
            }

        } catch (ApiException e) {
            e.printStackTrace();
        }
    }
}

When to use bulk creation:

  • Importing product catalogs
  • Generating links from database records
  • Campaign setup with many URLs
  • Automated link generation pipelines

Visitor identification and tracking

Track and identify visitors using their LBID (Linkbreakers ID) from click/scan events:

Java
package com.example.linkbreakers;

import com.linkbreakers.ApiException;
import com.linkbreakers.api.VisitorsApi;
import com.linkbreakers.model.IdentifyRequest;
import com.linkbreakers.model.IdentifyResponse;
import com.linkbreakers.model.VisitorInput;

import java.util.HashMap;
import java.util.Map;

public class VisitorIdentification {
    public void identifyVisitor(VisitorsApi visitorsApi, String lbid) {
        try {
            // Prepare visitor data
            Map<String, Object> visitorData = new HashMap<>();

            // System fields (prefixed with "$")
            visitorData.put("$email", "john.doe@example.com");
            visitorData.put("$phone", "+14155551234");
            visitorData.put("$firstName", "John");
            visitorData.put("$lastName", "Doe");

            // Custom attributes (no "$" prefix)
            visitorData.put("company", "Acme Corporation");
            visitorData.put("jobTitle", "Product Manager");
            visitorData.put("plan", "enterprise");
            visitorData.put("signupDate", "2024-01-15");
            visitorData.put("industry", "SaaS");
            visitorData.put("leadScore", 85);

            VisitorInput visitorInput = new VisitorInput()
                .data(visitorData);

            IdentifyRequest identifyRequest = new IdentifyRequest()
                .lbid(lbid)
                .visitor(visitorInput)
                .setOnce(false); // true = only update empty fields

            IdentifyResponse response = visitorsApi.visitorsServiceIdentify(identifyRequest);

            System.out.println("New profile created: " + response.getCreated());
            System.out.println("Visitor ID: " + response.getVisitor().getId());
            System.out.println("Email: " + response.getVisitor().getEmail());

        } catch (ApiException e) {
            e.printStackTrace();
        }
    }
}

Understanding LBID:

When visitors click your Linkbreakers links with conversion tracking enabled, a ?lbid=... parameter is added to the destination URL. This LBID connects the visitor to the specific link click, enabling attribution and analytics.

Extract LBID from incoming requests and pass it to the identification API to build visitor profiles. Learn more in our What is LBID? guide.

Working with visitor data

Java
package com.example.linkbreakers;

import com.linkbreakers.ApiException;
import com.linkbreakers.api.VisitorsApi;
import com.linkbreakers.model.*;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

public class VisitorDataManagement {
    public void workWithVisitors(VisitorsApi visitorsApi, String visitorId) {
        try {
            // Get visitor details
            GetVisitorResponse visitor = visitorsApi.visitorsServiceGet(
                visitorId,
                Arrays.asList("devices", "events", "links")
            );

            System.out.println("Visitor: " + visitor.getEmail());
            System.out.println("Devices: " + (visitor.getDevices() != null ? visitor.getDevices().size() : 0));
            System.out.println("Events: " + (visitor.getEvents() != null ? visitor.getEvents().size() : 0));

            // List visitors with filtering
            ListVisitorsResponse visitorsList = visitorsApi.visitorsServiceList(
                100, // pageSize
                null, // pageToken
                "user@example.com", // email
                "link-uuid", // linkId
                "Acme Corp", // search
                null, // include
                null  // responseFormat
            );

            // Update visitor attributes
            Map<String, Object> updateData = new HashMap<>();
            updateData.put("$email", "updated@example.com");
            updateData.put("plan", "enterprise");
            updateData.put("lastActivity", "2025-03-31");

            VisitorInput visitorUpdate = new VisitorInput()
                .data(updateData);

            VisitorsServiceUpdateBody updateBody = new VisitorsServiceUpdateBody()
                .visitor(visitorUpdate);

            visitorsApi.visitorsServiceUpdate(visitorId, updateBody);

        } catch (ApiException e) {
            e.printStackTrace();
        }
    }
}

Accessing analytics and metrics

Retrieve event data and workspace metrics:

Java
package com.example.linkbreakers;

import com.linkbreakers.ApiException;
import com.linkbreakers.api.EventsApi;
import com.linkbreakers.api.MetricsApi;
import com.linkbreakers.model.Event;
import com.linkbreakers.model.GetWorkspaceMetricsResponse;
import com.linkbreakers.model.ListEventsResponse;

import java.time.OffsetDateTime;
import java.util.Arrays;

public class Analytics {
    public void getAnalytics(EventsApi eventsApi, MetricsApi metricsApi, String linkId) {
        try {
            // Get events for a specific link (last 30 days)
            OffsetDateTime endDate = OffsetDateTime.now();
            OffsetDateTime startDate = endDate.minusDays(30);

            ListEventsResponse eventsResponse = eventsApi.eventsServiceList(
                startDate, // startDate
                endDate,   // endDate
                1000,      // pageSize
                null,      // pageToken
                linkId,    // linkId
                Arrays.asList("visitor", "device", "link"), // include
                null       // responseFormat
            );

            System.out.println("Total events: " + eventsResponse.getEvents().size());

            int count = 0;
            for (Event event : eventsResponse.getEvents()) {
                if (count >= 10) break;
                System.out.println("  " + event.getAction() + " - " + event.getCreatedAt());
                count++;
            }

            // Get workspace metrics
            GetWorkspaceMetricsResponse metrics = metricsApi.metricsServiceGetWorkspaceMetrics();

            System.out.println("\nWorkspace Stats:");
            System.out.println("  Total links: " + metrics.getTotalLinks());
            System.out.println("  Total clicks: " + metrics.getTotalClicks());
            System.out.println("  Total visitors: " + metrics.getTotalVisitors());

        } catch (ApiException e) {
            e.printStackTrace();
        }
    }
}

Framework integration

Spring Boot

Configuration class:

Java
package com.example.linkbreakers.config;

import com.linkbreakers.ApiClient;
import com.linkbreakers.Configuration;
import com.linkbreakers.api.LinksApi;
import com.linkbreakers.api.VisitorsApi;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;

@org.springframework.context.annotation.Configuration
public class LinkbreakersConfig {

    @Value("${linkbreakers.secret-key}")
    private String secretKey;

    @Bean
    public ApiClient apiClient() {
        ApiClient apiClient = Configuration.getDefaultApiClient();
        apiClient.setBasePath("https://api.linkbreakers.com");
        apiClient.setBearerToken(secretKey);
        return apiClient;
    }

    @Bean
    public LinksApi linksApi(ApiClient apiClient) {
        return new LinksApi(apiClient);
    }

    @Bean
    public VisitorsApi visitorsApi(ApiClient apiClient) {
        return new VisitorsApi(apiClient);
    }
}

Controller example:

Java
package com.example.linkbreakers.controller;

import com.linkbreakers.ApiException;
import com.linkbreakers.api.LinksApi;
import com.linkbreakers.model.CreateLinkRequest;
import com.linkbreakers.model.CreateLinkResponse;
import com.linkbreakers.model.ListLinksResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/api")
public class LinksController {

    @Autowired
    private LinksApi linksApi;

    @PostMapping("/create-link")
    public ResponseEntity<Map<String, Object>> createLink(@RequestBody CreateLinkRequestDto dto) {
        try {
            CreateLinkRequest request = new CreateLinkRequest()
                .destination(dto.getDestination())
                .name(dto.getName())
                .tags(dto.getTags());

            CreateLinkResponse response = linksApi.linksServiceCreate(request);

            Map<String, Object> result = new HashMap<>();
            result.put("success", true);
            result.put("shortlink", response.getLink().getShortlink());
            result.put("qr_code", response.getLink().getQrcodeSignedUrl());

            return ResponseEntity.ok(result);

        } catch (ApiException e) {
            Map<String, Object> error = new HashMap<>();
            error.put("success", false);
            error.put("error", e.getMessage());
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(error);
        }
    }

    @GetMapping("/links")
    public ResponseEntity<?> listLinks(@RequestParam(required = false) List<String> tags) {
        try {
            ListLinksResponse response = linksApi.linksServiceList(
                50, null, tags, null, null, null, null, null, null
            );

            return ResponseEntity.ok(response.getLinks());

        } catch (ApiException e) {
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                .body(Map.of("error", e.getMessage()));
        }
    }
}

class CreateLinkRequestDto {
    private String destination;
    private String name;
    private List<String> tags;

    // Getters and setters
    public String getDestination() { return destination; }
    public void setDestination(String destination) { this.destination = destination; }

    public String getName() { return name; }
    public void setName(String name) { this.name = name; }

    public List<String> getTags() { return tags; }
    public void setTags(List<String> tags) { this.tags = tags; }
}

Service class pattern:

Java
package com.example.linkbreakers.service;

import com.linkbreakers.ApiException;
import com.linkbreakers.api.LinksApi;
import com.linkbreakers.model.CreateLinkRequest;
import com.linkbreakers.model.Link;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class LinkService {

    @Autowired
    private LinksApi linksApi;

    public Link createShortLink(String destination, String name) throws ApiException {
        CreateLinkRequest request = new CreateLinkRequest()
            .destination(destination)
            .name(name);

        return linksApi.linksServiceCreate(request).getLink();
    }
}

Error handling

Implement proper error handling for production:

Java
package com.example.linkbreakers;

import com.linkbreakers.ApiException;
import com.linkbreakers.api.LinksApi;
import com.linkbreakers.model.CreateLinkRequest;
import com.linkbreakers.model.CreateLinkResponse;

public class ErrorHandling {
    public void createLinkWithErrorHandling(LinksApi linksApi) {
        try {
            CreateLinkRequest request = new CreateLinkRequest()
                .destination("https://example.com/page")
                .name("My Link");

            CreateLinkResponse response = linksApi.linksServiceCreate(request);

            System.out.println("Success: " + response.getLink().getShortlink());

        } catch (ApiException e) {
            System.err.println("API Error: Status " + e.getCode());
            System.err.println("Response body: " + e.getResponseBody());
            e.printStackTrace();
        }
    }
}

Frequently asked questions

Can I use the Java SDK with Spring Boot?

Yes! The SDK works seamlessly with Spring Boot, Jakarta EE, Micronaut, Quarkus, and any Java framework. See the Spring Boot integration section above.

How do I handle rate limits?

The SDK will throw ApiException if you exceed rate limits. Implement exponential backoff retry logic for production applications.

Does the SDK support async operations?

The SDK uses synchronous HTTP calls. For async frameworks like Spring WebFlux, wrap SDK calls in reactive publishers or use thread pools.

How do I get the LBID for visitor identification?

The LBID appears as a ?lbid= query parameter when visitors click your links with conversion tracking enabled. Extract it from request parameters and pass it to visitorsServiceIdentify().

Can I create bulk links efficiently?

Yes, use linksServiceCreateBulk() to create up to 1000 links in a single API call, which is much more efficient than individual requests.

What Java versions are supported?

The SDK supports Java 8+ with full support for modern Java features including records, var, and functional programming patterns.

How do I test without affecting production data?

Create test mode API keys from your dashboard. They operate on isolated test data separate from production analytics. You can identify test vs production keys by decoding the JWT and checking the environment claim.

Sources

Last reviewed

This article was last reviewed on March 31, 2025.

About the Author

LS

Laurent Schaffner

Founder & Engineer at Linkbreakers

Passionate about building tools that help businesses track and optimize their digital marketing efforts. Laurent founded Linkbreakers to make QR code analytics accessible and actionable for companies of all sizes.