Skip to main content

Online Payments

The Online Payments API lets you take card and wallet payments for e-commerce checkouts. Use it to initiate a payment and redirect the customer to a hosted payment page, track the payment to completion, list past payments, and issue refunds. It also supports payer details, card tokenisation, expiry, and delayed capture/release.

Before you begin

Every endpoint on this page is a gRPC call secured with TLS. Authenticate each call by attaching your API key to the request metadata using the X-API-Key header.

Connect to the host closest to your store's region. See the Payments API Overview for the full list of regional hostnames (Asia-Pacific and Europe), authentication, shared conventions, and how to install the client SDK.

RegionDevelopment and TestLive
Asia-Pacificgrpc-staging-ap.kodypay.comgrpc-ap.kodypay.com
Europegrpc-staging-eu.kodypay.comgrpc-eu.kodypay.com

Use the regional staging host that matches your store in the examples below. Replace the following placeholders with your own values:

PlaceholderDescription
HOSTNAMEYour regional gRPC host, e.g. grpc-staging-eu.kodypay.com (staging) or grpc-eu.kodypay.com (live)
API_KEYYour Kody API key
STORE_IDYour Kody store identifier

Endpoints

#EndpointgRPC callDescription
1Initiate PaymentInitiatePaymentCreate a payment and return a hosted payment URL.
2Initiate Payment StreamInitiatePaymentStreamCreate a payment and stream status until it completes.
3Payment DetailsPaymentDetailsFetch the current status and details of a payment.
4Payment Details StreamPaymentDetailsStreamStream a payment's details until it completes.
5Get PaymentsGetPaymentsList payments with pagination and filters.
6Refund PaymentRefundRefund all or part of a payment.

All calls are methods on KodyEcomPaymentsService.

Payment flow

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

Method: KodyEcomPaymentsService.InitiatePayment

Initiates an online payment and returns a payment_url for the customer to complete the transaction. After payment, the customer 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
}
}
}

Request fields

FieldTypeRequiredDescription
store_idstringYesYour Kody store ID.
payment_referencestringYesYour unique reference for this payment request.
amount_minor_unitsuint64YesAmount in minor units (e.g. 2000 = GBP 20.00).
currencystringYesISO 4217 currency code; must match the store currency.
order_idstringYesYour order identifier (may be reused across payments).
order_metadatastringNoAdditional order data (e.g. JSON of checkout items).
return_urlstringYesURL to redirect to after the payment is authorised.
payer_statementstringNoText for the payer's bank statement (max 22 chars).
payer_email_addressstringNoPayer email; recommended for fraud and 3DS2 checks.
payer_ip_addressstringNoPayer IP address, used for risk analysis.
payer_localestringNoLocale for the payment pages (e.g. en, zh).
tokenise_cardboolNoTokenise the card for reuse. Defaults to false.
expiryExpirySettingsNoPayment expiry / countdown timer settings.
capture_optionsCaptureOptionsNoDelayed capture / release settings.

Expiry settings (expiry)

FieldTypeRequiredDescription
show_timerboolNoDisplay a countdown timer on the payment page. Defaults to false.
expiring_secondsuint64NoTimeout duration in seconds. Defaults to 1800.

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 customer to complete the payment
}

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

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

Examples

Show code examples (Java · Python · .NET · PHP)
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 InitiateEcomPaymentExample {
public static final String HOSTNAME = "HOSTNAME";
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

Method: KodyEcomPaymentsService.InitiatePaymentStream

Initiates an online payment and streams status updates until the transaction completes. The first (interim) message carries the hosted payment page link at payment_data.payment_wallet.payment_link_id — redirect the customer there to pay. The stream reuses PaymentDetailsResponse, so there is no top-level payment_url field. After payment, the customer 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
}
}
}

Request fields

FieldTypeRequiredDescription
store_idstringYesYour Kody store ID.
payment_referencestringYesYour unique reference for this payment request.
amount_minor_unitsuint64YesAmount in minor units (e.g. 2000 = GBP 20.00).
currencystringYesISO 4217 currency code.
order_idstringYesYour order identifier (may be reused across payments).
order_metadatastringNoAdditional order data (e.g. JSON of checkout items).
return_urlstringYesURL to redirect to after the payment is authorised.
payer_statementstringNoText for the payer's bank statement (max 22 chars).
payer_email_addressstringNoPayer email; recommended for fraud and 3DS2 checks.
payer_ip_addressstringNoPayer IP address, used for risk analysis.
payer_localestringNoLocale for the payment pages (e.g. en, zh).
tokenise_cardboolNoTokenise the card for reuse. Defaults to false.
expiryExpirySettingsNoPayment expiry / countdown timer settings.
capture_optionsCaptureOptionsNoDelayed capture / release settings.

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 authorisation
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; // Authorisation 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; // Authorisation code
string payment_token = 3; // Card token (if tokenisation 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

Show code examples (Java · Python · .NET · PHP)
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 InitiatePaymentStreamExample {
public static final String HOSTNAME = "HOSTNAME";
public static final String API_KEY = "API_KEY";

public static void main(String[] args) {
String storeId = "STORE_ID";
initiateEcomPaymentStream(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()) {
var details = response.getResponse();
System.out.println("Payment ID: " + details.getPaymentId());
System.out.println("Status: " + details.getStatus());
// The stream reuses PaymentDetailsResponse; the hosted payment page
// link is returned via payment_data.payment_wallet.payment_link_id.
if (details.hasPaymentData() && details.getPaymentData().hasPaymentWallet()) {
System.out.println("Payment page: " + details.getPaymentData().getPaymentWallet().getPaymentLinkId());
}
} else {
System.err.println("Error: " + response.getError().getMessage());
}
channel.shutdownNow();
}
}

3. Payment Details

Method: KodyEcomPaymentsService.PaymentDetails

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

Best practice

Poll every 2–5 seconds to avoid excessive load while still getting timely status updates.

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
}
}

Request fields

FieldTypeRequiredDescription
store_idstringYesYour Kody store ID.
payment_idstringOne ofKody-generated payment identifier.
payment_referencestringOne ofYour 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 authorisation
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; // Authorisation 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; // Authorisation code
string payment_token = 3; // Card token (if tokenisation 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

Show code examples (Java · Python · .NET · PHP)
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.PaymentDetailsResponse.PaymentData.PaymentCard;
import com.kodypay.grpc.ecom.v1.PaymentDetailsResponse.PaymentData.PaymentWallet;
import com.kodypay.grpc.ecom.v1.PaymentDetailsResponse.PaymentData.PaymentMethodDetailsCase;

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

public class GetPaymentDetailsExample {
public static PaymentDetails getPaymentDetails(String storeId, String paymentId) throws InterruptedException {
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");

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 main(String[] args) throws InterruptedException {
String storeId = "STORE_ID";
String paymentId = "PAYMENT_ID";
PaymentDetails details = getPaymentDetails(storeId, paymentId);
printPaymentDetails(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

Method: KodyEcomPaymentsService.PaymentDetailsStream

Retrieves details of a specific payment using either the payment_id or the payment_reference. Streams updates until the transaction reaches a terminal state, then returns the final result.

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
}
}

Request fields

FieldTypeRequiredDescription
store_idstringYesYour Kody store ID.
payment_idstringOne ofKody-generated payment identifier.
payment_referencestringOne ofYour 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 authorisation
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; // Authorisation 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; // Authorisation code
string payment_token = 3; // Card token (if tokenisation 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

Show code examples (Java · Python · .NET · PHP)
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 GetPaymentDetailsExample {
public static void getPaymentDetails(String storeId, String paymentId) {
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 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 = client.paymentDetailsStream(request).next();

if (response.hasResponse()) {
System.out.println("Status: " + response.getResponse().getStatus());
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();
}

public static void main(String[] args) {
getPaymentDetails("STORE_ID", "PAYMENT_ID");
}
}

5. Get Payments

Method: 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;
}
}

Request fields

FieldTypeRequiredDescription
store_idstringYesYour Kody store ID.
page_cursorPageCursorYesPagination cursor: page and page_size.
filterFilterNoOptional filters: order_id, created_before.

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

Show code examples (Java · Python · .NET · PHP)
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 GetPaymentsExample {
public static void getPayments(String storeId) {
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 client = KodyEcomPaymentsServiceGrpc.newBlockingStub(channel)
.withInterceptors(MetadataUtils.newAttachHeadersInterceptor(metadata));

var request = GetPaymentsRequest.newBuilder()
.setStoreId(storeId)
.setPageCursor(GetPaymentsRequest.PageCursor.newBuilder().setPage(0).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();
}

public static void main(String[] args) {
getPayments("STORE_ID");
}
}

6. Refund Payment

Method: KodyEcomPaymentsService.Refund

Issues a refund for a specific payment, either in full or in part. Identify the payment with either a payment_id or a psp_reference, and provide amount as a decimal string with two decimal places (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")
}

Request fields

FieldTypeRequiredDescription
store_idstringYesYour store UUID.
payment_idstringOne ofKody-generated payment ID.
psp_referencestringOne ofPSP reference identifier.
amountstringYesRefund amount as a 2dp decimal string (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

Show code examples (Java · Python · .NET · PHP)
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 RefundPaymentExample {
public static void main(String[] args) {
refundPayment("STORE_ID", "PAYMENT_ID");
}

public static void refundPayment(String storeId, String paymentId) {
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 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();
}
}

Need help?

For further support or more detailed information, contact the Kody Support team at support@kody.com.