Skip to main content

Online Payments - E-Commerce Payments API

The Online Payments service enables integration with the Kody Payments API for e-commerce transactions. This API now supports additional fields for payment initiation (such as payer details, card tokenisation, expiry, and capture options) as well as enhanced refund functionality. You can use it to initiate payments, retrieve payment details, fetch payment histories, get card tokens, and issue refunds.

Note: Every service call requires an X-API-Key header with your API key.

Here's a sequence diagram illustrating the payment flow for e-commerce transactions:


Common Enums

enum PaymentMethods {
VISA = 0;
MASTERCARD = 1;
AMEX = 2;
BAN_CONTACT = 3;
CHINA_UNION_PAY = 4;
MAESTRO = 5;
DINERS = 6;
DISCOVER = 7;
JCB = 8;
ALIPAY = 9;
WECHAT = 10;
}

enum PaymentStatus {
PENDING = 0;
SUCCESS = 1;
FAILED = 2;
CANCELLED = 3;
EXPIRED = 4;
}

1. Initiate Payment

Service Call: KodyEcomPaymentsService.InitiatePayment

Initiates an online payment and returns a payment_url for the user to complete the transaction. After payment, the user is redirected to the specified return_url.

Request

rpc InitiatePayment(PaymentInitiationRequest) returns (PaymentInitiationResponse);

message PaymentInitiationRequest {
string store_id = 1; // Your Kody store id
string payment_reference = 2; // Your unique reference for this payment request.
uint64 amount_minor_units = 3; // Amount in minor units. For example, 2000 means GBP 20.00.
string currency = 4; // ISO 4217 three letter currency code (e.g., GBP, HKD), must be the same as store currency
string order_id = 5; // Your identifier for the order. (May be reused if the same order has multiple payments)
optional string order_metadata = 6; // Additional order data (e.g., JSON with checkout items)
string return_url = 7; // URL to redirect after the payment is authorised
optional string payer_statement = 8; // Text for the payer's bank statement (max 22 characters)
optional string payer_email_address = 9; // Payer's email address (recommended for fraud and 3D Secure 2 checks)
optional string payer_ip_address = 10; // Payer's IP address (for risk analysis)
optional string payer_locale = 11; // Locale (e.g., en and zh) to display the payment pages in the desired language
optional bool tokenise_card = 12; // Flag to tokenise the card; defaults to false
optional ExpirySettings expiry = 13; // Settings for payment expiry
optional CaptureOptions capture_options = 14; // Optional capture/release settings

message ExpirySettings {
bool show_timer = 1; // Display a countdown timer on the payment page (default false)
uint64 expiring_seconds = 2; // Timeout duration in seconds (default: 1800 seconds)
}

message CaptureOptions {
CaptureSettings capture_settings = 1;
optional ReleaseSettings release_settings = 2;

message CaptureSettings {
bool delayed_capture = 1; // If true, capture is delayed until manually triggered (default false)
optional int32 auto_capture_interval_mins = 2; // Automatically capture after the specified interval (in minutes)
bool auto_capture_store_close_time = 3; // Automatically capture at the store's closing time
}

message ReleaseSettings { // If not set, funds are released automatically by the card issuer
bool delayed_release = 1; // If true, release is delayed until manually triggered
optional int32 auto_release_interval_mins = 2; // Automatically release funds after the specified interval (in minutes)
bool auto_release_store_close_time = 3; // Automatically release at the store's closing time
}
}
}

Response

message PaymentInitiationResponse {
oneof result {
Response response = 1;
Error error = 2;
}

message Response {
string payment_id = 1; // The unique identifier created by Kody
string payment_url = 2; // URL for the user to complete the payment
}

message Error {
Type type = 1;
string message = 2;

enum Type {
UNKNOWN = 0;
DUPLICATE_ATTEMPT = 1;
INVALID_REQUEST = 2;
}
}
}

Examples

package com.kody;

import com.kodypay.grpc.ecom.v1.KodyEcomPaymentsServiceGrpc;
import com.kodypay.grpc.ecom.v1.PaymentInitiationRequest;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.Metadata;
import io.grpc.stub.MetadataUtils;
import java.util.UUID;

public class ExampleNewPayment {
public static final String HOSTNAME = "grpc-staging.kodypay.com";
public static final String API_KEY = "API_KEY";

public static void main(String[] args) {
String storeId = "STORE_ID";
initiateEcomPayment(storeId);
}

public static void initiateEcomPayment(String storeId) {
// Create a managed channel and attach the API key metadata.
ManagedChannel channel = ManagedChannelBuilder.forAddress(HOSTNAME, 443)
.useTransportSecurity()
.build();
Metadata metadata = new Metadata();
metadata.put(Metadata.Key.of("X-API-Key", Metadata.ASCII_STRING_MARSHALLER), API_KEY);
var paymentClient = KodyEcomPaymentsServiceGrpc.newBlockingStub(channel)
.withInterceptors(MetadataUtils.newAttachHeadersInterceptor(metadata));

String orderId = "order_" + UUID.randomUUID();
String paymentReference = "pay_" + UUID.randomUUID();

PaymentInitiationRequest request = PaymentInitiationRequest.newBuilder()
.setStoreId(storeId)
.setPaymentReference(paymentReference)
.setAmountMinorUnits(1000) // e.g., 1000 for £10.00
.setCurrency("GBP")
.setOrderId(orderId)
.setReturnUrl("https://your-return-url.com")
// Optionally, set additional fields:
.setPayerEmailAddress("customer@example.com")
.build();

var response = paymentClient.initiatePayment(request);
if (response.hasResponse()) {
System.out.println("Payment URL: " + response.getResponse().getPaymentUrl());
System.out.println("Payment ID: " + response.getResponse().getPaymentId());
} else {
System.err.println("Error: " + response.getError().getMessage());
}
channel.shutdownNow();
}
}

2. Initiate Payment Stream

Service Call: KodyEcomPaymentsService.InitiatePaymentStream

Initiates an online payment and returns an interim response with a payment_url for the user to complete the transaction. It will wait until the transaction is complete and then return a full response. After payment, the user is redirected to the specified return_url.

Request

rpc InitiatePaymentStream(PaymentInitiationRequest) returns (stream PaymentDetailsResponse);

message PaymentInitiationRequest {
string store_id = 1; // Your Kody store id
string payment_reference = 2; // Your unique reference for this payment request.
uint64 amount_minor_units = 3; // Amount in minor units. For example, 2000 means GBP 20.00.
string currency = 4; // ISO 4217 three letter currency code (e.g., GBP, HKD)
string order_id = 5; // Your identifier for the order. (May be reused if the same order has multiple payments)
optional string order_metadata = 6; // Additional order data (e.g., JSON with checkout items)
string return_url = 7; // URL to redirect after the payment is authorised
optional string payer_statement = 8; // Text for the payer's bank statement (max 22 characters)
optional string payer_email_address = 9; // Payer's email address (recommended for fraud and 3D Secure 2 checks)
optional string payer_ip_address = 10; // Payer's IP address (for risk analysis)
optional string payer_locale = 11; // Locale (e.g., en, zh) to display the payment pages in the desired language
optional bool tokenise_card = 12; // Flag to tokenise the card; defaults to false
optional ExpirySettings expiry = 13; // Settings for payment expiry
optional CaptureOptions capture_options = 14; // Optional capture/release settings

message ExpirySettings {
bool show_timer = 1; // Display a countdown timer on the payment page (default false)
uint64 expiring_seconds = 2; // Timeout duration in seconds (default: 1800 seconds)
}

message CaptureOptions {
CaptureSettings capture_settings = 1;
optional ReleaseSettings release_settings = 2;

message CaptureSettings {
bool delayed_capture = 1; // If true, capture is delayed until manually triggered (default false)
optional int32 auto_capture_interval_mins = 2; // Automatically capture after the specified interval (in minutes)
bool auto_capture_store_close_time = 3; // Automatically capture at the store's closing time
}

message ReleaseSettings { // If not set, funds are released automatically by the card issuer
bool delayed_release = 1; // If true, release is delayed until manually triggered
optional int32 auto_release_interval_mins = 2; // Automatically release funds after the specified interval (in minutes)
bool auto_release_store_close_time = 3; // Automatically release at the store's closing time
}
}
}

Response

message PaymentDetailsResponse {
oneof result {
PaymentDetails response = 1;
Error error = 2;
}

message PaymentDetails {
string payment_id = 1; // Kody-generated payment identifier
PaymentStatus status = 5;
google.protobuf.Timestamp date_created = 7;

// Detailed payment data (if available)
optional PaymentData payment_data = 11;
// Sale-related data (if applicable)
optional SaleData sale_data = 12;
}

message Error {
Type type = 1;
string message = 2;

enum Type {
UNKNOWN = 0;
NOT_FOUND = 1;
INVALID_REQUEST = 2;
}
}
}

// PaymentData contains detailed information about the payment method and authorization
message PaymentData {
string psp_reference = 1; // Payment service provider reference
PaymentMethods payment_method = 2; // Payment method (VISA, MASTERCARD, etc.)
string payment_method_variant = 3; // Variant of the payment method
PaymentAuthStatus auth_status = 4; // Authorization status
google.protobuf.Timestamp auth_status_date = 5; // Date/time of the auth status change

enum PaymentAuthStatus {
PENDING = 0;
AUTHORISED = 1;
FAILED = 2;
CAPTURED = 3;
RELEASED = 4;
EXPIRED = 5;
}

oneof payment_method_details {
PaymentCard payment_card = 6; // Card payment details
PaymentWallet payment_wallet = 7; // Digital wallet payment details
}

message PaymentCard {
string card_last_4_digits = 1; // Last 4 digits of the card
string auth_code = 2; // Authorization code
string payment_token = 3; // Card token (if tokenization was requested)
}

message PaymentWallet {
optional string card_last_4_digits = 1; // Last 4 digits (if available)
string payment_link_id = 2; // Wallet payment link identifier
}
}

// SaleData contains information about the sale/order
message SaleData {
uint64 amount_minor_units = 1; // Amount in minor units (e.g., 2000 for £20.00)
string currency = 2; // ISO 4217 currency code
string order_id = 3; // Your order identifier
string payment_reference = 4; // Your payment reference
optional string order_metadata = 5; // Additional order data
}

Examples

package com.kody;

import com.kodypay.grpc.ecom.v1.KodyEcomPaymentsServiceGrpc;
import com.kodypay.grpc.ecom.v1.PaymentInitiationRequest;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.Metadata;
import io.grpc.stub.MetadataUtils;
import java.util.UUID;

public class ExampleNewPayment {
public static final String HOSTNAME = "grpc-staging.kodypay.com";
public static final String API_KEY = "API_KEY";

public static void main(String[] args) {
String storeId = "STORE_ID";
initiateEcomPayment(storeId);
}

public static void initiateEcomPaymentStream(String storeId) {
// Create a managed channel and attach the API key metadata.
ManagedChannel channel = ManagedChannelBuilder.forAddress(HOSTNAME, 443)
.useTransportSecurity()
.build();
Metadata metadata = new Metadata();
metadata.put(Metadata.Key.of("X-API-Key", Metadata.ASCII_STRING_MARSHALLER), API_KEY);
var paymentClient = KodyEcomPaymentsServiceGrpc.newBlockingStub(channel)
.withInterceptors(MetadataUtils.newAttachHeadersInterceptor(metadata));

String orderId = "order_" + UUID.randomUUID();
String paymentReference = "pay_" + UUID.randomUUID();

PaymentInitiationRequest request = PaymentInitiationRequest.newBuilder()
.setStoreId(storeId)
.setPaymentReference(paymentReference)
.setAmountMinorUnits(1000) // e.g., 1000 for £10.00
.setCurrency("GBP")
.setOrderId(orderId)
.setReturnUrl("https://your-return-url.com")
// Optionally, set additional fields:
.setPayerEmailAddress("customer@example.com")
.build();

// Since InitiatePaymentStream returns a stream, get the first response from the iterator
var response = paymentClient.initiatePaymentStream(request).next();

if (response.hasResponse()) {
System.out.println("Payment URL: " + response.getResponse().getPaymentUrl());
System.out.println("Payment ID: " + response.getResponse().getPaymentId());
// Additional fields (e.g. payment_data) can be inspected as needed
} else {
System.err.println("Error: " + response.getError().getMessage());
}
channel.shutdownNow();
}
}

3. Payment Details

Service Call: KodyEcomPaymentsService.PaymentDetails

Retrieves details of a specific payment using either the payment_id or the payment_reference.

💡 Best Practice

It is recommended to poll every 2–5 seconds rather than too frequently, to avoid excessive load on the API server while still ensuring timely updates to the payment status.

Request

rpc PaymentDetails(PaymentDetailsRequest) returns (PaymentDetailsResponse);

message PaymentDetailsRequest {
string store_id = 1; // Your Kody store id
oneof payment_identifier {
string payment_id = 2; // Kody-generated payment identifier
string payment_reference = 3; // Your unique payment reference from initiation
}
}

Response

message PaymentDetailsResponse {
oneof result {
PaymentDetails response = 1;
Error error = 2;
}

message PaymentDetails {
string payment_id = 1; // Kody-generated payment identifier
PaymentStatus status = 5;
google.protobuf.Timestamp date_created = 7;

// Detailed payment data (if available)
optional PaymentData payment_data = 11;
// Sale-related data (if applicable)
optional SaleData sale_data = 12;
}

message Error {
Type type = 1;
string message = 2;

enum Type {
UNKNOWN = 0;
NOT_FOUND = 1;
INVALID_REQUEST = 2;
}
}
}

// PaymentData contains detailed information about the payment method and authorization
message PaymentData {
string psp_reference = 1; // Payment service provider reference
PaymentMethods payment_method = 2; // Payment method (VISA, MASTERCARD, etc.)
string payment_method_variant = 3; // Variant of the payment method
PaymentAuthStatus auth_status = 4; // Authorization status
google.protobuf.Timestamp auth_status_date = 5; // Date/time of the auth status change

enum PaymentAuthStatus {
PENDING = 0;
AUTHORISED = 1;
FAILED = 2;
CAPTURED = 3;
RELEASED = 4;
EXPIRED = 5;
}

oneof payment_method_details {
PaymentCard payment_card = 6; // Card payment details
PaymentWallet payment_wallet = 7; // Digital wallet payment details
}

message PaymentCard {
string card_last_4_digits = 1; // Last 4 digits of the card
string auth_code = 2; // Authorization code
string payment_token = 3; // Card token (if tokenization was requested)
}

message PaymentWallet {
optional string card_last_4_digits = 1; // Last 4 digits (if available)
string payment_link_id = 2; // Wallet payment link identifier
}
}

// SaleData contains information about the sale/order
message SaleData {
uint64 amount_minor_units = 1; // Amount in minor units (e.g., 2000 for £20.00)
string currency = 2; // ISO 4217 currency code
string order_id = 3; // Your order identifier
string payment_reference = 4; // Your payment reference
optional string order_metadata = 5; // Additional order data
}

Examples

package com.kody;

import com.kodypay.grpc.ecom.v1.KodyEcomPaymentsServiceGrpc;
import com.kodypay.grpc.ecom.v1.PaymentDetailsRequest;
import com.kodypay.grpc.ecom.v1.PaymentDetailsResponse;
import com.kodypay.grpc.ecom.v1.PaymentDetailsResponse.PaymentDetails;
import com.kodypay.grpc.ecom.v1.PaymentDetailsResponse.PaymentData;
import com.kodypay.grpc.ecom.v1.PaymentDetailsResponse.SaleData;
import com.kodypay.grpc.ecom.v1.PaymentStatus;
import com.kodypay.grpc.ecom.v1.PaymentData.PaymentCard;
import com.kodypay.grpc.ecom.v1.PaymentData.PaymentWallet;
import com.kodypay.grpc.ecom.v1.PaymentData.PaymentMethodDetailsCase;

import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.Metadata;
import io.grpc.stub.MetadataUtils;

public class ExampleGetPaymentDetails {
public static PaymentDetails getPaymentDetails(String storeId, String paymentId) throws InterruptedException {
ManagedChannel channel = ManagedChannelBuilder.forAddress("grpc-staging.kodypay.com", 443)
.useTransportSecurity()
.build();

Metadata metadata = new Metadata();
metadata.put(Metadata.Key.of("X-API-Key", Metadata.ASCII_STRING_MARSHALLER), "API_KEY");

KodyEcomPaymentsServiceGrpc.KodyEcomPaymentsServiceBlockingStub client =
KodyEcomPaymentsServiceGrpc.newBlockingStub(channel)
.withInterceptors(MetadataUtils.newAttachHeadersInterceptor(metadata));

PaymentDetailsRequest request = PaymentDetailsRequest.newBuilder()
.setStoreId(storeId)
.setPaymentId(paymentId)
.build();

PaymentDetails details;
PaymentStatus status;

do {
PaymentDetailsResponse response = client.paymentDetails(request);
if (!response.hasResponse()) {
throw new RuntimeException("Error: " + response.getError().getMessage());
}

details = response.getResponse();
status = details.getStatus();
System.out.println("Current Status: " + status);

if (status == PaymentStatus.PENDING) {
Thread.sleep(2000);
}
} while (status == PaymentStatus.PENDING);

channel.shutdownNow();
return details;
}

public static void printPaymentDetails(PaymentDetails details) {
if (details.hasPaymentData()) {
PaymentData paymentData = details.getPaymentData();
System.out.println("PSP Reference: " + paymentData.getPspReference());
System.out.println("Payment Method: " + paymentData.getPaymentMethod());
System.out.println("Auth Status: " + paymentData.getAuthStatus());

PaymentMethodDetailsCase methodCase = paymentData.getPaymentMethodDetailsCase();
switch (methodCase) {
case PAYMENT_CARD -> {
PaymentCard card = paymentData.getPaymentCard();
System.out.println("Card Last 4: " + card.getCardLast4Digits());
System.out.println("Auth Code: " + card.getAuthCode());
System.out.println("Payment Token: " + card.getPaymentToken());
}
case PAYMENT_WALLET -> {
PaymentWallet wallet = paymentData.getPaymentWallet();
if (wallet.hasCardLast4Digits()) {
System.out.println("Wallet Card Last 4: " + wallet.getCardLast4Digits());
}
System.out.println("Payment Link ID: " + wallet.getPaymentLinkId());
}
default -> System.out.println("Unknown payment method details.");
}
}

if (details.hasSaleData()) {
SaleData sale = details.getSaleData();
System.out.println("Amount: " + sale.getAmountMinorUnits());
System.out.println("Currency: " + sale.getCurrency());
System.out.println("Order ID: " + sale.getOrderId());
System.out.println("Payment Reference: " + sale.getPaymentReference());
if (sale.hasOrderMetadata()) {
System.out.println("Order Metadata: " + sale.getOrderMetadata());
}
}
}
}

4. Payment Details Stream

Service Call: KodyEcomPaymentsService.PaymentDetailsStream

Retrieves details of a specific payment using either the payment_id or the payment_reference. It will wait until the transaction is complete and then return a full response.

Request

rpc PaymentDetailsStream(PaymentDetailsRequest) returns (stream  PaymentDetailsResponse);

message PaymentDetailsRequest {
string store_id = 1; // Your Kody store id
oneof payment_identifier {
string payment_id = 2; // Kody-generated payment identifier
string payment_reference = 3; // Your unique payment reference from initiation
}
}

Response

message PaymentDetailsResponse {
oneof result {
PaymentDetails response = 1;
Error error = 2;
}

message PaymentDetails {
string payment_id = 1; // Kody-generated payment identifier
PaymentStatus status = 5;
google.protobuf.Timestamp date_created = 7;

// Detailed payment data (if available)
optional PaymentData payment_data = 11;
// Sale-related data (if applicable)
optional SaleData sale_data = 12;
}

// PaymentData contains detailed information about the payment method and authorization
message PaymentData {
string psp_reference = 1; // Payment service provider reference
PaymentMethods payment_method = 2; // Payment method (VISA, MASTERCARD, etc.)
string payment_method_variant = 3; // Variant of the payment method
PaymentAuthStatus auth_status = 4; // Authorization status
google.protobuf.Timestamp auth_status_date = 5; // Date/time of the auth status change

enum PaymentAuthStatus {
PENDING = 0;
AUTHORISED = 1;
FAILED = 2;
CAPTURED = 3;
RELEASED = 4;
EXPIRED = 5;
}

oneof payment_method_details {
PaymentCard payment_card = 6; // Card payment details
PaymentWallet payment_wallet = 7; // Digital wallet payment details
}

message PaymentCard {
string card_last_4_digits = 1; // Last 4 digits of the card
string auth_code = 2; // Authorization code
string payment_token = 3; // Card token (if tokenization was requested)
}

message PaymentWallet {
optional string card_last_4_digits = 1; // Last 4 digits (if available)
string payment_link_id = 2; // Wallet payment link identifier
}
}

// SaleData contains information about the sale/order
message SaleData {
uint64 amount_minor_units = 1; // Amount in minor units (e.g., 2000 for £20.00)
string currency = 2; // ISO 4217 currency code
string order_id = 3; // Your order identifier
string payment_reference = 4; // Your payment reference
optional string order_metadata = 5; // Additional order data
}

message Error {
Type type = 1;
string message = 2;

enum Type {
UNKNOWN = 0;
NOT_FOUND = 1;
INVALID_REQUEST = 2;
}
}
}

Examples

package com.kody;

import com.kodypay.grpc.ecom.v1.KodyEcomPaymentsServiceGrpc;
import com.kodypay.grpc.ecom.v1.PaymentDetailsRequest;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.Metadata;
import io.grpc.stub.MetadataUtils;

public class ExampleGetPaymentDetails {
public static void getPaymentDetails(String storeId, String paymentId) {
ManagedChannel channel = ManagedChannelBuilder.forAddress("grpc-staging.kodypay.com", 443)
.useTransportSecurity()
.build();
Metadata metadata = new Metadata();
metadata.put(Metadata.Key.of("X-API-Key", Metadata.ASCII_STRING_MARSHALLER), "API_KEY");
var client = KodyEcomPaymentsServiceGrpc.newBlockingStub(channel)
.withInterceptors(MetadataUtils.newAttachHeadersInterceptor(metadata));

PaymentDetailsRequest request = PaymentDetailsRequest.newBuilder()
.setStoreId(storeId)
.setPaymentId(paymentId)
.build();

//Since PaymentDetailsStream returns a stream, get the first response from the iterator
var response = paymentClient.paymentDetailsStream(request).next();

if (response.hasResponse()) {
System.out.println("Payment URL: " + response.getResponse().getPaymentUrl());
System.out.println("Payment ID: " + response.getResponse().getPaymentId());
// Additional fields (e.g. payment_data) can be inspected as needed
} else {
System.err.println("Error: " + response.getError().getMessage());
}
channel.shutdownNow();
}
}

5. Get Payments

Service Call: KodyEcomPaymentsService.GetPayments

Retrieves a paginated list of payments with optional filters.

Request

message GetPaymentsRequest {
string store_id = 1;
PageCursor page_cursor = 2;
Filter filter = 3;

message PageCursor {
int64 page = 1;
int64 page_size = 2;
}

message Filter {
optional string order_id = 1;
optional google.protobuf.Timestamp created_before = 2;
}
}

Response

message GetPaymentsResponse {
oneof result {
Response response = 1;
Error error = 2;
}

message Response {
int64 total = 2;
repeated PaymentDetailsResponse.PaymentDetails payments = 3;
}

message Error {
Type type = 1;
string message = 2;

enum Type {
UNKNOWN = 0;
NOT_FOUND = 1;
INVALID_ARGUMENT = 2;
}
}
}

Examples

package com.kody;

import com.kodypay.grpc.ecom.v1.KodyEcomPaymentsServiceGrpc;
import com.kodypay.grpc.ecom.v1.GetPaymentsRequest;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.Metadata;
import io.grpc.stub.MetadataUtils;

public class ExampleGetPayments {
public static void getPayments(String storeId) {
ManagedChannel channel = ManagedChannelBuilder.forAddress("grpc-staging.kodypay.com", 443)
.useTransportSecurity()
.build();
Metadata metadata = new Metadata();
metadata.put(Metadata.Key.of("X-API-Key", Metadata.ASCII_STRING_MARSHALLER), "API_KEY");
var client = KodyEcomPaymentsServiceGrpc.newBlockingStub(channel)
.withInterceptors(MetadataUtils.newAttachHeadersInterceptor(metadata));

var request = GetPaymentsRequest.newBuilder()
.setStoreId(storeId)
.setPageCursor(GetPaymentsRequest.PageCursor.newBuilder().setPage(1).setPageSize(10))
.build();

var response = client.getPayments(request);
if (response.hasResponse()) {
System.out.println("Total payments: " + response.getResponse().getTotal());
for (var payment : response.getResponse().getPaymentsList()) {
System.out.println("Payment ID: " + payment.getPaymentId());
System.out.println("Status: " + payment.getStatus());
System.out.println("Created: " + payment.getDateCreated());
}
} else {
System.err.println("Error: " + response.getError().getMessage());
}
channel.shutdownNow();
}
}

6. Refund Payment

Service Call: KodyEcomPaymentsService.Refund

Issues a refund for a specific payment. You may specify a full or partial refund. The refund request uses a oneof for the payment identifier, and the refund amount is provided as a string (formatted as a decimal with 2dp, e.g., "10.00").

Request

rpc Refund(RefundRequest) returns (stream RefundResponse);

message RefundRequest {
string store_id = 1; // Your store UUID
oneof id {
string payment_id = 2; // Kody-generated payment id
string psp_reference = 4; // PSP reference identifier
}
string amount = 3; // Refund amount in BigDecimal/2.dp (e.g., "10.00")
}

Response

message RefundResponse {
RefundStatus status = 1;
optional string failure_reason = 2; // Populated on failure
string payment_id = 3;
google.protobuf.Timestamp date_created = 4;
string total_paid_amount = 5;
string total_amount_refunded = 6;
string remaining_amount = 7;
string total_amount_requested = 8;
string paymentTransactionId = 9;

enum RefundStatus {
PENDING = 0;
REQUESTED = 1;
FAILED = 2;
}
}

Examples

package com.kody;

import com.kodypay.grpc.ecom.v1.KodyEcomPaymentsServiceGrpc;
import com.kodypay.grpc.ecom.v1.RefundRequest;
import com.kodypay.grpc.ecom.v1.RefundResponse;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.Metadata;
import io.grpc.stub.MetadataUtils;

public class ExampleRefundPayment {
public static void refundPayment(String storeId, String paymentId) {
ManagedChannel channel = ManagedChannelBuilder.forAddress("grpc-staging.kodypay.com", 443)
.useTransportSecurity()
.build();
Metadata metadata = new Metadata();
metadata.put(Metadata.Key.of("X-API-Key", Metadata.ASCII_STRING_MARSHALLER), "API_KEY");
var client = KodyEcomPaymentsServiceGrpc.newBlockingStub(channel)
.withInterceptors(MetadataUtils.newAttachHeadersInterceptor(metadata));

RefundRequest request = RefundRequest.newBuilder()
.setStoreId(storeId)
// Use payment_id (or alternatively setPspReference if available)
.setPaymentId(paymentId)
.setAmount("5.00") // Refund amount as a string (e.g., "5.00")
.build();

var responseIterator = client.refund(request);
while (responseIterator.hasNext()) {
RefundResponse response = responseIterator.next();
System.out.println("Refund Status: " + response.getStatus());
if (response.getStatus() == RefundResponse.RefundStatus.FAILED) {
System.err.println("Failure Reason: " + response.getFailureReason());
}
System.out.println("Total Amount Refunded: " + response.getTotalAmountRefunded());
}
channel.shutdownNow();
}
}

Remember to replace the following placeholders with your actual values:

  • HOSTNAME: Use either grpc-staging.kodypay.com (for development and test) or grpc.kodypay.com (for live)
  • API_KEY: Your API key
  • STORE_ID: Your store identifier

For further support or more detailed information, please contact our support team.