SDK de Java
El SDK de Java conecta sus servicios con la API de bb-sign: gestiona los tokens, reintenta de
forma segura y verifica las firmas de los webhooks. Las coordenadas son
co.binarybridges.sign:bb-sign-sdk-java:0.1.0-SNAPSHOT.
Esta página reúne el README.md del SDK y su README-INSTALL.md.
Requiere Java 17 o superior.
Instalación
Sección titulada «Instalación»El SDK se entrega en cuatro archivos: el jar, su pom, un .sha256 y la guía de instalación. También
puede compilarlo desde el código fuente (ver Compilar desde el código fuente).
Instale el jar en su repositorio local de Maven y declárelo como dependencia.
-
Verifique la integridad del archivo recibido:
Ventana de terminal shasum -a 256 -c bb-sign-sdk-java-0.1.0-SNAPSHOT.jar.sha256 -
Instálelo.
-DpomFilees obligatorio:Ventana de terminal mvn install:install-file \-Dfile=bb-sign-sdk-java-0.1.0-SNAPSHOT.jar \-DpomFile=bb-sign-sdk-java-0.1.0-SNAPSHOT.pom -
Declárelo como dependencia:
<dependency><groupId>co.binarybridges.sign</groupId><artifactId>bb-sign-sdk-java</artifactId><version>0.1.0-SNAPSHOT</version></dependency>
Dependencias
Sección titulada «Dependencias»El build debe tener acceso a Maven Central. El SDK es un jar simple, no shaded: su build resuelve okhttp, Retrofit y Jackson y los unifica con las versiones que ya usa. Esto evita conflictos con Jackson, presente en la mayoría de los servicios Java.
Si su build no tiene acceso a Maven Central, contáctenos antes de comenzar la integración para recibir una variante shaded del SDK.
Inicio rápido
Sección titulada «Inicio rápido»El ejemplo completo cabe en un solo archivo. Las credenciales se crean en Configuración, pestaña Credenciales de API, de bb-sign; el secreto se muestra una sola vez, al crearlas.
import co.binarybridges.sign.sdk.BbSignClient;import co.binarybridges.sign.sdk.generated.model.*;import java.time.OffsetDateTime;import java.util.List;
try (BbSignClient client = BbSignClient.builder() .baseUrl(System.getenv("BBSIGN_BASE_URL")) .tokenUrl(System.getenv("BBSIGN_TOKEN_URL")) .clientCredentials(System.getenv("BBSIGN_CLIENT_ID"), System.getenv("BBSIGN_CLIENT_SECRET")) .build()) {
CreateEnvelopeRequest request = new CreateEnvelopeRequest() .title("Q3 Agreement") .otpRequired(false) .expiresAt(OffsetDateTime.now().plusHours(72)) .signers(List.of(new CreateSignerSpec() .email("signer@example.com") .name("A Signer") .signOrder(1)));
EnvelopeResponse envelope = client.execute(client.envelopes().createEnvelope(request)); System.out.println("Created " + envelope.getId());}Lea las credenciales desde variables de entorno, fuera del código fuente. El secreto se almacena
solo en Keycloak y bb-sign no conserva copia; si se pierde, rótelo, lo que invalida el anterior
de inmediato. El cliente expone envelopes(), documents() y verification().
Listar por páginas
Sección titulada «Listar por páginas»client.eachPage( page -> client.envelopes().listEnvelopes(page, 50, null, null, null, null, null, null), PagedEnvelopeResponse::getContent) .forEach(envelope -> System.out.println(envelope.getTitle()));Las páginas se obtienen bajo demanda durante la iteración, de modo que recorrer miles de sobres no los carga todos en memoria.
Verificar un webhook
Sección titulada «Verificar un webhook»Webhooks.verify comprueba la firma sobre el cuerpo tal como se recibió. Declare el cuerpo como
byte[] en su handler:
import co.binarybridges.sign.sdk.Webhooks;
@PostMapping("/webhooks/bb-sign")public ResponseEntity<Void> receive( @RequestHeader("X-BBSign-Signature") String signature, @RequestBody byte[] rawBody) { // byte[], NOT a DTO
if (!Webhooks.verify(signature, rawBody, System.getenv("BBSIGN_WEBHOOK_SECRET"))) { return ResponseEntity.status(401).build(); }
WebhookEvent event = new ObjectMapper().readValue(rawBody, WebhookEvent.class); switch (event.getType()) { case "envelope.completed" -> onCompleted(event.getData().getEnvelope()); case "signer.signed" -> onSigned(event.getData().getSigner()); default -> { /* ignore unknown types: more will be added */ } } return ResponseEntity.ok().build();}Capturar el cuerpo original
Sección titulada «Capturar el cuerpo original»La firma cubre los bytes exactos recibidos. Si el parámetro se declara como un DTO, Spring interpreta el JSON y entrega un objeto; volver a serializarlo produce bytes distintos (cambian el orden de las claves y los espacios) y la verificación falla aunque el objeto sea correcto.
- Spring MVC:
@RequestBody byte[]o@RequestBody String, o unContentCachingRequestWrappersi además necesita la forma interpretada. - Jakarta Servlet: lea
request.getInputStream()una sola vez, antes que cualquier otro componente.
El SDK recibe byte[] en lugar de String de forma intencional: el tipo orienta hacia el uso
correcto.
Responder de inmediato y procesar después
Sección titulada «Responder de inmediato y procesar después»Devuelva 2xx en cuanto la firma sea válida y procese el evento de forma asíncrona. bb-sign reintenta con una secuencia que abarca aproximadamente 15 horas, y tras 3 secuencias consecutivas agotadas desactiva el endpoint; el procesamiento asíncrono mantiene la respuesta rápida bajo carga.
Eliminar duplicados por id de evento
Sección titulada «Eliminar duplicados por id de evento»X-BBSign-Event-Id es estable entre reintentos y reentregas del mismo evento. La entrega es al
menos una vez, de modo que un evento puede llegar dos veces; use el id como clave de idempotencia.
Rotación del secreto
Sección titulada «Rotación del secreto»Mientras la ventana de rotación está abierta, el encabezado lleva dos valores v1=.
Webhooks.verify acepta cualquiera de los dos, lo que le permite desplegar el nuevo secreto sin
interrupción y sin configuración adicional.
Probar el handler
Sección titulada «Probar el handler»La verificación depende del tiempo: una firma con más de 300 s de antigüedad se rechaza, de modo que un fixture fijo en una prueba unitaria deja de ser válido. Use la sobrecarga que recibe el reloj:
Webhooks.verify(signature, rawBody, secret, Duration.ofSeconds(300), Instant.ofEpochSecond(1760000000L));Reintentos
Sección titulada «Reintentos»Las solicitudes GET se reintentan ante errores 5xx y timeouts de conexión, con backoff
exponencial y jitter completo.
Un POST cuya respuesta no se recibió no se reintenta. Si createEnvelope agota el tiempo de
espera, el resultado es desconocido: el sobre puede existir ya, y un reintento crearía un segundo
acuerdo enviado a las mismas personas. La API no usa claves de idempotencia.
Si una creación agota el tiempo de espera, liste antes de reintentar:
try { client.execute(client.envelopes().createEnvelope(request));} catch (BbSignException e) { if (e.statusCode() == 0) { // Never reached bb-sign, or the answer was lost. Check before sending again. }}429 y 503 se reintentan también en POST, porque indican que el servidor no procesó la
solicitud.
Errores
Sección titulada «Errores»Toda respuesta distinta de 2xx lanza BbSignException, que expone statusCode(). 0 indica que la
solicitud no obtuvo respuesta.
| Estado | Significado |
|---|---|
| 400 | Solicitud mal formada o con errores de validación |
| 401 | Credenciales rechazadas. El SDK renueva el token y reintenta una vez antes de reportarlo |
| 403 | Autenticado, pero esta credencial no tiene el permiso de la organización |
| 404 | El recurso no existe, o pertenece a otra organización o a un espacio de trabajo que la credencial no puede ver. No se distinguen, de forma intencional |
| 409 | El recurso no está en un estado que permita la operación, por ejemplo enviar un sobre ya enviado |
| 429 | Una cuota de la organización está agotada |
Los mensajes de las excepciones nunca incluyen su secreto ni su token de acceso, aunque la respuesta de bb-sign los contenga. Errores incluye la tabla completa y el cuerpo del error.
Garantías de seguridad
Sección titulada «Garantías de seguridad»- Credenciales fuera de los logs. El SDK no incluye interceptor de logging ni punto para
instalar uno. Evite agregar por su cuenta el
HttpLoggingInterceptorde okhttp en nivelBODY: imprime el encabezadoAuthorizationy el cuerpo del formulario del token tal cual. - TLS siempre verificado. La verificación de certificados no se puede desactivar.
- Escrituras sin duplicados. Una escritura con resultado desconocido no se reintenta (ver Reintentos).
Compilar desde el código fuente
Sección titulada «Compilar desde el código fuente»cd sdk-javamvn verify # regenerates the client, compiles, runs the tests./verify.sh # the CI gate: drift, Jackson-not-Gson, plugin survivalmvn package # writes the handover artifact to target/handover/El cliente en src/main/java/co/binarybridges/sign/sdk/generated/ es código generado y
versionado: regenérelo en lugar de editarlo. Se versiona para que cada cambio en la
especificación aparezca como un diff revisable.