Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 88 additions & 0 deletions openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -14285,6 +14285,94 @@
}
},
"webhooks": {
"sales.completed": {
"post": {
"operationId": "SaleCompletedWebhook",
"tags": [
"Sales"
],
"summary": "Sale completed",
"description": "Sent once per sale when its completion is observed: the sale is closed and has been fully paid. The event created_at is the sale's recorded completion time, rather than the time the notification is delivered. A delayed notification may arrive after subsequent updates, refunds, or chargebacks. Fetch the current sale using object.url with an access token that has the sales.read scope. The sale may briefly be unavailable while the Sales API catches up; retry fetching it after a 404 response. Automatic retries and manual redelivery may deliver the same event more than once; deduplicate by event id.",
"x-object-type": "sale",
"x-object": {
"$ref": "#/components/schemas/Sale"
},
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Event"
},
"examples": {
"completed": {
"summary": "A sale completed webhook event.",
"value": {
"id": "event_01JQCG7EF8F2DA02V31HSEXXCM",
"type": "sales.completed",
"created_at": "2026-10-14T12:00:00Z",
"object": {
"id": "847ed267-c617-4d38-9e5a-4ef728daa5c3",
"type": "sale",
"url": "https://api.sumup.com/v1.0/merchants/MC0DE/sales/847ed267-c617-4d38-9e5a-4ef728daa5c3"
}
}
}
}
}
}
},
"responses": {
"2XX": {
"description": "Return any 2xx response to acknowledge successful delivery."
}
}
}
},
"sales.updated": {
"post": {
"operationId": "SaleUpdatedWebhook",
"tags": [
"Sales"
],
"summary": "Sale updated",
"description": "Sent when a closed, fully paid sale is published or updated, including subsequent refunds and chargebacks. The first notification can occur when the sale becomes fully paid and closed. Fetch the current sale using object.url with an access token that has the sales.read scope. The sale may briefly be unavailable while the Sales API catches up; retry fetching it after a 404 response. Notifications contain the sale identity rather than a snapshot, and delivery order is not guaranteed.",
"x-object-type": "sale",
"x-object": {
"$ref": "#/components/schemas/Sale"
},
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Event"
},
"examples": {
"updated": {
"summary": "A sale updated webhook event.",
"value": {
"id": "event_01JQCG7EF8F2DA02V31HSEXXCM",
"type": "sales.updated",
"created_at": "2026-10-14T12:00:00Z",
"object": {
"id": "847ed267-c617-4d38-9e5a-4ef728daa5c3",
"type": "sale",
"url": "https://api.sumup.com/v1.0/merchants/MC0DE/sales/847ed267-c617-4d38-9e5a-4ef728daa5c3"
}
}
}
}
}
}
},
"responses": {
"2XX": {
"description": "Return any 2xx response to acknowledge successful delivery."
}
}
}
},
"checkouts.created": {
"post": {
"operationId": "CheckoutCreatedWebhook",
Expand Down
24 changes: 24 additions & 0 deletions src/main/java/com/sumup/sdk/events/AsyncEventsHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,30 @@ public AsyncEventsHandler onRoleUpdated(AsyncEventCallback<RoleUpdatedEvent> cal
return this;
}

/**
* Registers the callback for {@code "sales.completed"}, replacing any previous registration.
*
* @param callback callback to complete before acknowledging delivery
* @return this handler for chaining
*/
public AsyncEventsHandler onSaleCompleted(AsyncEventCallback<SaleCompletedEvent> callback) {
Objects.requireNonNull(callback);
callbacks.put("sales.completed", event -> callback.handle((SaleCompletedEvent) event));
return this;
}

/**
* Registers the callback for {@code "sales.updated"}, replacing any previous registration.
*
* @param callback callback to complete before acknowledging delivery
* @return this handler for chaining
*/
public AsyncEventsHandler onSaleUpdated(AsyncEventCallback<SaleUpdatedEvent> callback) {
Objects.requireNonNull(callback);
callbacks.put("sales.updated", event -> callback.handle((SaleUpdatedEvent) event));
return this;
}

/**
* Verifies, parses, and completes when the selected callback finishes.
*
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/com/sumup/sdk/events/EventNotification.java
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ private static EventNotification parseBody(ApiClient client, byte[] body) {
case "roles.created" -> RoleCreatedEvent.class;
case "roles.deleted" -> RoleDeletedEvent.class;
case "roles.updated" -> RoleUpdatedEvent.class;
case "sales.completed" -> SaleCompletedEvent.class;
case "sales.updated" -> SaleUpdatedEvent.class;
default -> EventNotification.class;
};
EventNotification event = MAPPER.treeToValue(root, type);
Expand Down
32 changes: 32 additions & 0 deletions src/main/java/com/sumup/sdk/events/EventsHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,38 @@ public EventsHandler onRoleUpdated(EventCallback<RoleUpdatedEvent> callback) {
return this;
}

/**
* Registers the callback for {@code "sales.completed"}, replacing any previous registration.
*
* @param callback callback to complete before acknowledging delivery
* @return this handler for chaining
*/
public EventsHandler onSaleCompleted(EventCallback<SaleCompletedEvent> callback) {
Objects.requireNonNull(callback);
callbacks.put(
"sales.completed",
event -> {
callback.handle((SaleCompletedEvent) event);
});
return this;
}

/**
* Registers the callback for {@code "sales.updated"}, replacing any previous registration.
*
* @param callback callback to complete before acknowledging delivery
* @return this handler for chaining
*/
public EventsHandler onSaleUpdated(EventCallback<SaleUpdatedEvent> callback) {
Objects.requireNonNull(callback);
callbacks.put(
"sales.updated",
event -> {
callback.handle((SaleUpdatedEvent) event);
});
return this;
}

/**
* Verifies, parses, and invokes the selected callback.
*
Expand Down
21 changes: 21 additions & 0 deletions src/main/java/com/sumup/sdk/events/SaleCompletedEvent.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Code generated by sumup-java/codegen. DO NOT EDIT.
package com.sumup.sdk.events;

import com.fasterxml.jackson.core.type.TypeReference;
import com.sumup.sdk.models.Sale;

/**
* Sent once per sale when its completion is observed: the sale is closed and has been fully paid.
* The event created_at is the sale's recorded completion time, rather than the time the
* notification is delivered. A delayed notification may arrive after subsequent updates, refunds,
* or chargebacks. Fetch the current sale using object.url with an access token that has the
* sales.read scope. The sale may briefly be unavailable while the Sales API catches up; retry
* fetching it after a 404 response. Automatic retries and manual redelivery may deliver the same
* event more than once; deduplicate by event id.
*/
public final class SaleCompletedEvent extends FetchableEvent<Sale> {
@Override
TypeReference<Sale> resourceType() {
return new TypeReference<>() {};
}
}
20 changes: 20 additions & 0 deletions src/main/java/com/sumup/sdk/events/SaleUpdatedEvent.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Code generated by sumup-java/codegen. DO NOT EDIT.
package com.sumup.sdk.events;

import com.fasterxml.jackson.core.type.TypeReference;
import com.sumup.sdk.models.Sale;

/**
* Sent when a closed, fully paid sale is published or updated, including subsequent refunds and
* chargebacks. The first notification can occur when the sale becomes fully paid and closed. Fetch
* the current sale using object.url with an access token that has the sales.read scope. The sale
* may briefly be unavailable while the Sales API catches up; retry fetching it after a 404
* response. Notifications contain the sale identity rather than a snapshot, and delivery order is
* not guaranteed.
*/
public final class SaleUpdatedEvent extends FetchableEvent<Sale> {
@Override
TypeReference<Sale> resourceType() {
return new TypeReference<>() {};
}
}
Loading