πŸ“‘ Webhooks: How to use it

πŸ“‘ How WebHooks – Subscribers via Clara API

This guide describes how to manage webhook subscribers using Clara’s /api/v1/subscribers endpoint, and explains the internal execution and consumption logic via WebhookConsumerService.


πŸ” Authentication Requirements

  • Use mutual TLS (MTLS) for secure two-way certificate validation.
  • Obtain an OAuth2 access token via /oauth/token.
  • Use the token in the Authorization: Bearer header for all API requests.

πŸ”— Endpoints

πŸ“₯ Retrieve Subscribers

GET /api/v1/subscribers

Query Parameters:

NameTypeDescription
pageintegerPage index (0-based)
sizeintegerNumber of results per page
uuiduuidFilter by subscriber UUID
namestringName of the subscriber
callbackUrlstringCallback URL
enabledbooleanWhether the subscriber is active
eventsstringComma-separated list of subscribed events
companyUuiduuidOptional UUID of the company

βž• Create a Subscriber

POST /api/v1/subscribers

Body Example:

{
  "name": "Accounting Service",
  "callbackUrl": "https://example.com/webhook",
  "events": ["PAYMENT_PAID", "CARD_CREATION_REQUEST_CREATED"],
  "enabled": true,
  "companyUuid": "1b9d6bcd-bbfd-4b2d-9b5d-ab8dfbbd4bed"
}

πŸ”„ Update a Subscriber

PATCH /api/v1/subscribers/{uuid}

πŸ—‘οΈ Delete a Subscriber

DELETE /api/v1/subscribers/{uuid}

πŸ”§ Manage Events on a Subscriber

  • POST /api/v1/subscribers/add-event
  • DELETE /api/v1/subscribers/delete-event

βš™οΈ Webhook Execution & Processing Flow

The WebHook event lifecycle consists of two key services working together:

πŸ“¬ WebhookConsumerService (Kafka Listener & Subscriber Notifier)

This service listens to the Kafka topic and delivers the webhook to external subscribers. It ensures reliable delivery and avoids duplicate processing. It uses WebhookService:

@KafkaListener(topics = "${clara.kafka.webhook.topic.create.request}",
        containerFactory = "kafkaListenerContainerFactory")
public void consumeWebhookRequest(ConsumerRecord<String, byte[]> input) {
    var webhookRequest = SerdesUtils.deserialize(avroDeserializer, input);
    if (Objects.nonNull(webhookRequest)) {
        webhookRequestEntityRepository.findById(webhookRequest.getId())
            .ifPresentOrElse(webhookRequestEntity -> {}, () -> {
                log.debug("Processing webhook with id: {}", webhookRequest.getId());
                webhookService.saveAndSendWebHook(webhookRequest);
            });
    }
}

βœ… WebhookService

This service delivers Webhooks to external subscribers via a POST call

webhookService.sendWebHook(
    webhookRequest.getCompanyUuid(),
    webhookRequest.getId(),
    webhookRequest.getEvent(),
    webhookRequest.getMetadata(),
    webhookRequest.getErrorCode(),
    webhookRequest.getErrorMessage()
);

Together, these services ensure webhook events are decoupled, auditable, and reliably delivered.

πŸ–ΌοΈ WebHook Architecture Overview

Flow Overview:

  1. An event is triggered by a source system (e.g., Payments, Cards).
  2. WebhookConsumerService subscribes to the topic and consumes the event. It uses WebhookService
  3. The WebhookService service sends a POST request to the configured Subscriber Endpoint.

Flow Diagram:

[Event Source] 
      β”‚
      β–Ό
[WebhookConsumerService]
      β”‚
      β–Ό
  [Kafka Topic]
      β”‚
      β–Ό
[WebhookService]
      β”‚
      β–Ό
[Subscriber Endpoint]

πŸ”š Summary

  • Use /api/v1/subscribers to manage your webhook callback endpoints.
  • Each subscriber can listen to one or more Clara platform events.
  • Events are dispatched by WebhookService (implemented in your API) and delivered by WebhookConsumerService.
  • Clara uses secure, resilient, and decoupled architecture to ensure webhook reliability.

πŸš€ Sending WebHook Events from an API

You can also send WebHook events directly from your service logic or API controller using another WebhookServiceimplemented in your API.

Here's an example using the WebhookRequest builder:

var webhookRequest = WebhookRequest.newBuilder()
    .setId(cardResponse.getId())
    .setCompanyUuid(UUID.fromString(cardResponse.getData().getCard().getCompanyUuid()))
    .setEvent(CARD_CREATION_REQUEST_ERROR.name())
    .setTimestamp(LocalDateTime.now())
    .setErrorCode(cardResponse.getData().getCard().getErrorCode())
    .setErrorMessage(cardResponse.getData().getCard().getErrorMessage())
    .build();

webhookService.send(webhookRequest);

This sends a structured webhook event using the built WebhookRequest. Ensure WebhookService.send(...) is appropriately configured to publish to Kafka or forward via HTTP as needed.

🧩 WebhookService – Implementation Example

Here's how the WebhookService class is implemented to send events using Kafka:

@Slf4j
@Service
public class WebhookService {

    private final KafkaTemplate<String, byte[]> kafkaTemplate;
    private final String requestTopic;

    private static final AvroSerializer<WebhookRequest> webhookRequestAvroSerializer =
        AvroSerializer.of(WebhookRequest.SCHEMA$);

    public WebhookService(KafkaTemplate<String, byte[]> kafkaTemplate,
                          @Value("${clara.data-writer.kafka.webhook.topic.create.request}") String requestTopic) {
        this.kafkaTemplate = kafkaTemplate;
        this.requestTopic = requestTopic;
    }

    public void send(WebhookRequest webhookRequest) {
        KafkaUtils.serializeAndSendNonReactive(
            webhookRequestAvroSerializer,
            webhookRequest,
            webhookRequest.getId(),
            requestTopic,
            kafkaTemplate
        );
    }
}

This service serializes a WebhookRequest object using Avro and sends it to a Kafka topic defined in the application configuration.