📡 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: Bearerheader for all API requests.
🔗 Endpoints
📥 Retrieve Subscribers
GET /api/v1/subscribers
Query Parameters:
| Name | Type | Description |
|---|---|---|
| page | integer | Page index (0-based) |
| size | integer | Number of results per page |
| uuid | uuid | Filter by subscriber UUID |
| name | string | Name of the subscriber |
| callbackUrl | string | Callback URL |
| enabled | boolean | Whether the subscriber is active |
| events | string | Comma-separated list of subscribed events |
| companyUuid | uuid | Optional 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-eventDELETE /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)
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
WebhookServiceThis 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:
- An event is triggered by a source system (e.g., Payments, Cards).
WebhookConsumerServicesubscribes to the topic and consumes the event. It usesWebhookService- The
WebhookServiceservice sends aPOSTrequest to the configured Subscriber Endpoint.
Flow Diagram:
[Event Source]
│
▼
[WebhookConsumerService]
│
▼
[Kafka Topic]
│
▼
[WebhookService]
│
▼
[Subscriber Endpoint]
🔚 Summary
- Use
/api/v1/subscribersto 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 byWebhookConsumerService. - 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.
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.
