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.
| Region | Development and Test | Live |
|---|---|---|
| Asia-Pacific | grpc-staging-ap.kodypay.com | grpc-ap.kodypay.com |
| Europe | grpc-staging-eu.kodypay.com | grpc-eu.kodypay.com |
Use the regional staging host that matches your store in the examples below. Replace the following placeholders with your own values:
| Placeholder | Description |
|---|---|
HOSTNAME | Your regional gRPC host, e.g. grpc-staging-eu.kodypay.com (staging) or grpc-eu.kodypay.com (live) |
API_KEY | Your Kody API key |
STORE_ID | Your Kody store identifier |
Endpoints
| # | Endpoint | gRPC call | Description |
|---|---|---|---|
| 1 | Initiate Payment | InitiatePayment | Create a payment and return a hosted payment URL. |
| 2 | Initiate Payment Stream | InitiatePaymentStream | Create a payment and stream status until it completes. |
| 3 | Payment Details | PaymentDetails | Fetch the current status and details of a payment. |
| 4 | Payment Details Stream | PaymentDetailsStream | Stream a payment's details until it completes. |
| 5 | Get Payments | GetPayments | List payments with pagination and filters. |
| 6 | Refund Payment | Refund | Refund 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
| Field | Type | Required | Description |
|---|---|---|---|
store_id | string | Yes | Your Kody store ID. |
payment_reference | string | Yes | Your unique reference for this payment request. |
amount_minor_units | uint64 | Yes | Amount in minor units (e.g. 2000 = GBP 20.00). |
currency | string | Yes | ISO 4217 currency code; must match the store currency. |
order_id | string | Yes | Your order identifier (may be reused across payments). |
order_metadata | string | No | Additional order data (e.g. JSON of checkout items). |
return_url | string | Yes | URL to redirect to after the payment is authorised. |
payer_statement | string | No | Text for the payer's bank statement (max 22 chars). |
payer_email_address | string | No | Payer email; recommended for fraud and 3DS2 checks. |
payer_ip_address | string | No | Payer IP address, used for risk analysis. |
payer_locale | string | No | Locale for the payment pages (e.g. en, zh). |
tokenise_card | bool | No | Tokenise the card for reuse. Defaults to false. |
expiry | ExpirySettings | No | Payment expiry / countdown timer settings. |
capture_options | CaptureOptions | No | Delayed capture / release settings. |
Expiry settings (expiry)
| Field | Type | Required | Description |
|---|---|---|---|
show_timer | bool | No | Display a countdown timer on the payment page. Defaults to false. |
expiring_seconds | uint64 | No | Timeout 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)
- 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();
}
}
import grpc
from uuid import uuid4
import kody_clientsdk_python.ecom.v1.ecom_pb2 as kody_model
import kody_clientsdk_python.ecom.v1.ecom_pb2_grpc as kody_client
def initiate_payment():
hostname = "HOSTNAME"
api_key = "API_KEY"
store_id = "STORE_ID"
with grpc.secure_channel(hostname, grpc.ssl_channel_credentials()) as channel:
client = kody_client.KodyEcomPaymentsServiceStub(channel)
request = kody_model.PaymentInitiationRequest(
store_id=store_id,
payment_reference=f"pay_{uuid4()}",
amount_minor_units=1000, # e.g., 1000 for £10.00
currency="GBP",
order_id=f"order_{uuid4()}",
return_url="https://your-return-url.com",
payer_email_address="customer@example.com" # Optional
)
response = client.InitiatePayment(request, metadata=[("x-api-key", api_key)])
if response.HasField("response"):
print(f"Payment ID: {response.response.payment_id}")
print(f"Payment URL: {response.response.payment_url}")
else:
print(f"Error: {response.error.message}")
if __name__ == "__main__":
initiate_payment()
using System;
using System.Threading.Tasks;
using Grpc.Core;
using Grpc.Net.Client;
using Com.Kodypay.Ecom.V1;
class Program
{
static async Task Main()
{
string hostname = "https://HOSTNAME";
string apiKey = "API_KEY";
var channel = GrpcChannel.ForAddress(hostname);
var client = new KodyEcomPaymentsService.KodyEcomPaymentsServiceClient(channel);
var metadata = new Metadata { { "X-API-Key", apiKey } };
var request = new PaymentInitiationRequest
{
StoreId = "STORE_ID",
PaymentReference = $"pay_{Guid.NewGuid()}",
AmountMinorUnits = 1000, // e.g., 1000 for £10.00
Currency = "GBP",
OrderId = $"order_{Guid.NewGuid()}",
ReturnUrl = "https://your-return-url.com",
PayerEmailAddress = "customer@example.com" // Optional
};
var response = await client.InitiatePaymentAsync(request, metadata);
if (response.ResultCase == PaymentInitiationResponse.ResultOneofCase.Response)
{
Console.WriteLine($"Payment ID: {response.Response.PaymentId}");
Console.WriteLine($"Payment URL: {response.Response.PaymentUrl}");
}
else
{
Console.WriteLine($"Error: {response.Error.Message}");
}
}
}
<?php
require __DIR__ . '/../vendor/autoload.php';
use Com\Kodypay\Ecom\V1\KodyEcomPaymentsServiceClient;
use Com\Kodypay\Ecom\V1\PaymentInitiationRequest;
use Grpc\ChannelCredentials;
$client = new KodyEcomPaymentsServiceClient('HOSTNAME:443', [
'credentials' => ChannelCredentials::createSsl()
]);
$metadata = ['X-API-Key' => ['API_KEY']];
$request = new PaymentInitiationRequest();
$request->setStoreId('STORE_ID');
$request->setPaymentReference('pay_' . uniqid());
$request->setAmountMinorUnits(1000); // e.g., 1000 for £10.00
$request->setCurrency('GBP');
$request->setOrderId('order_' . uniqid());
$request->setReturnUrl('https://your-return-url.com');
// Optionally, set additional fields:
$request->setPayerEmailAddress("customer@example.com");
list($response, $status) = $client->InitiatePayment($request, $metadata)->wait();
if ($status->code !== \Grpc\STATUS_OK) {
echo "Error: " . $status->details . PHP_EOL;
} else if ($response->getResponse()) {
echo "Payment ID: " . $response->getResponse()->getPaymentId() . PHP_EOL;
echo "Payment URL: " . $response->getResponse()->getPaymentUrl() . PHP_EOL;
} else {
echo "Error: " . $response->getError()->getMessage() . PHP_EOL;
}
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
| Field | Type | Required | Description |
|---|---|---|---|
store_id | string | Yes | Your Kody store ID. |
payment_reference | string | Yes | Your unique reference for this payment request. |
amount_minor_units | uint64 | Yes | Amount in minor units (e.g. 2000 = GBP 20.00). |
currency | string | Yes | ISO 4217 currency code. |
order_id | string | Yes | Your order identifier (may be reused across payments). |
order_metadata | string | No | Additional order data (e.g. JSON of checkout items). |
return_url | string | Yes | URL to redirect to after the payment is authorised. |
payer_statement | string | No | Text for the payer's bank statement (max 22 chars). |
payer_email_address | string | No | Payer email; recommended for fraud and 3DS2 checks. |
payer_ip_address | string | No | Payer IP address, used for risk analysis. |
payer_locale | string | No | Locale for the payment pages (e.g. en, zh). |
tokenise_card | bool | No | Tokenise the card for reuse. Defaults to false. |
expiry | ExpirySettings | No | Payment expiry / countdown timer settings. |
capture_options | CaptureOptions | No | Delayed 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)
- 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();
}
}
import grpc
import kody_clientsdk_python.ecom.v1.ecom_pb2 as kody_model
import kody_clientsdk_python.ecom.v1.ecom_pb2_grpc as kody_client
from uuid import uuid4
def initiate_payment():
hostname = "HOSTNAME"
api_key = "API_KEY"
store_id = "STORE_ID"
with grpc.secure_channel(hostname, grpc.ssl_channel_credentials()) as channel:
client = kody_client.KodyEcomPaymentsServiceStub(channel)
request = kody_model.PaymentInitiationRequest(
store_id=store_id,
payment_reference=f"pay_{uuid4()}",
amount_minor_units=1000, # e.g., 1000 for £10.00
currency="GBP",
order_id=f"order_{uuid4()}",
return_url="https://your-return-url.com",
payer_email_address="customer@example.com" # Optional
)
response_iterator = client.InitiatePaymentStream(request, metadata=[("x-api-key", api_key)])
# Process the first response from the stream
for response in response_iterator:
if response.HasField("response"):
details = response.response
print(f"Payment ID: {details.payment_id}")
print(f"Status: {kody_model.PaymentStatus.Name(details.status)}")
# The stream reuses PaymentDetailsResponse; the hosted payment page
# link is returned via payment_data.payment_wallet.payment_link_id.
if details.HasField("payment_data") and details.payment_data.HasField("payment_wallet"):
print(f"Payment page: {details.payment_data.payment_wallet.payment_link_id}")
else:
print(f"Error: {response.error.message}")
if __name__ == "__main__":
initiate_payment()
using System;
using System.Threading.Tasks;
using Grpc.Core;
using Grpc.Net.Client;
using Com.Kodypay.Ecom.V1;
class Program
{
static async Task Main()
{
string hostname = "https://HOSTNAME";
string apiKey = "API_KEY";
var channel = GrpcChannel.ForAddress(hostname);
var client = new KodyEcomPaymentsService.KodyEcomPaymentsServiceClient(channel);
var metadata = new Metadata { { "X-API-Key", apiKey } };
var request = new PaymentInitiationRequest
{
StoreId = "STORE_ID",
PaymentReference = $"pay_{Guid.NewGuid()}",
AmountMinorUnits = 1000, // e.g., 1000 for £10.00
Currency = "GBP",
OrderId = $"order_{Guid.NewGuid()}",
ReturnUrl = "https://your-return-url.com",
PayerEmailAddress = "customer@example.com" // Optional
};
using var call = client.InitiatePaymentStream(request, metadata);
while (await call.ResponseStream.MoveNext())
{
var response = call.ResponseStream.Current;
if (response.ResultCase == PaymentDetailsResponse.ResultOneofCase.Response)
{
var details = response.Response;
Console.WriteLine($"Payment ID: {details.PaymentId}");
Console.WriteLine($"Status: {details.Status}");
// The stream reuses PaymentDetailsResponse; the hosted payment page
// link is returned via payment_data.payment_wallet.payment_link_id.
if (details.PaymentData?.PaymentWallet != null)
{
Console.WriteLine($"Payment page: {details.PaymentData.PaymentWallet.PaymentLinkId}");
}
}
else
{
Console.WriteLine($"Error: {response.Error.Message}");
}
}
}
}
<?php
require __DIR__ . '/../vendor/autoload.php';
use Com\Kodypay\Ecom\V1\KodyEcomPaymentsServiceClient;
use Com\Kodypay\Ecom\V1\PaymentInitiationRequest;
use Grpc\ChannelCredentials;
$client = new KodyEcomPaymentsServiceClient('HOSTNAME:443', [
'credentials' => ChannelCredentials::createSsl()
]);
$metadata = ['X-API-Key' => ['API_KEY']];
$request = new PaymentInitiationRequest();
$request->setStoreId('STORE_ID');
$request->setPaymentReference('pay_' . uniqid());
$request->setAmountMinorUnits(1000); // e.g., 1000 for £10.00
$request->setCurrency('GBP');
$request->setOrderId('order_' . uniqid());
$request->setReturnUrl('https://your-return-url.com');
// Optionally, set additional fields:
$request->setPayerEmailAddress("customer@example.com");
$call = $client->InitiatePaymentStream($request, $metadata);
foreach ($call->responses() as $response) {
if ($response->getResponse()) {
$details = $response->getResponse();
echo "Payment ID: " . $details->getPaymentId() . PHP_EOL;
echo "Status: " . $details->getStatus() . PHP_EOL;
// The stream reuses PaymentDetailsResponse; the hosted payment page
// link is returned via payment_data.payment_wallet.payment_link_id.
if ($details->getPaymentData() && $details->getPaymentData()->getPaymentWallet()) {
echo "Payment page: " . $details->getPaymentData()->getPaymentWallet()->getPaymentLinkId() . PHP_EOL;
}
} else {
echo "Error: " . $response->getError()->getMessage() . PHP_EOL;
}
}
3. Payment Details
Method: KodyEcomPaymentsService.PaymentDetails
Retrieves details of a specific payment using either the payment_id or the payment_reference.
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
| Field | Type | Required | Description |
|---|---|---|---|
store_id | string | Yes | Your Kody store ID. |
payment_id | string | One of | Kody-generated payment identifier. |
payment_reference | string | One of | Your 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)
- 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());
}
}
}
}
import grpc
import time
import kody_clientsdk_python.ecom.v1.ecom_pb2 as kody_model
import kody_clientsdk_python.ecom.v1.ecom_pb2_grpc as kody_client
def get_payment_details(store_id: str, payment_id: str) -> kody_model.PaymentDetailsResponse.PaymentDetails:
with grpc.secure_channel("HOSTNAME:443", grpc.ssl_channel_credentials()) as channel:
client = kody_client.KodyEcomPaymentsServiceStub(channel)
request = kody_model.PaymentDetailsRequest(
store_id=store_id,
payment_id=payment_id
)
while True:
response = client.PaymentDetails(request, metadata=[("x-api-key", "API_KEY")])
if not response.HasField("response"):
raise RuntimeError(f"Error: {response.error.message}")
details = response.response
print(f"Current Status: {kody_model.PaymentStatus.Name(details.status)}")
if details.status != kody_model.PaymentStatus.PENDING:
return details
time.sleep(2)
def print_payment_details(details: kody_model.PaymentDetailsResponse.PaymentDetails) -> None:
if details.HasField("payment_data"):
data = details.payment_data
print(f"PSP Reference: {data.psp_reference}")
print(f"Payment Method: {data.payment_method}")
print(f"Auth Status: {data.auth_status}")
if data.HasField("payment_card"):
card = data.payment_card
print(f"Card Last 4: {card.card_last_4_digits}")
print(f"Auth Code: {card.auth_code}")
print(f"Payment Token: {card.payment_token}")
elif data.HasField("payment_wallet"):
wallet = data.payment_wallet
if wallet.HasField("card_last_4_digits"):
print(f"Wallet Card Last 4: {wallet.card_last_4_digits}")
print(f"Payment Link ID: {wallet.payment_link_id}")
if details.HasField("sale_data"):
sale = details.sale_data
print(f"Amount: {sale.amount_minor_units}")
print(f"Currency: {sale.currency}")
print(f"Order ID: {sale.order_id}")
print(f"Payment Reference: {sale.payment_reference}")
if sale.HasField("order_metadata"):
print(f"Order Metadata: {sale.order_metadata}")
using System;
using System.Threading.Tasks;
using System.Threading;
using Grpc.Core;
using Grpc.Net.Client;
using Com.Kodypay.Ecom.V1;
public class GetPaymentDetailsExample
{
private readonly KodyEcomPaymentsService.KodyEcomPaymentsServiceClient _client;
private readonly Metadata _metadata;
public GetPaymentDetailsExample()
{
var channel = GrpcChannel.ForAddress("https://HOSTNAME");
_client = new KodyEcomPaymentsService.KodyEcomPaymentsServiceClient(channel);
_metadata = new Metadata { { "X-API-Key", "API_KEY" } };
}
public async Task<PaymentDetails> GetPaymentDetails(string storeId, string paymentId)
{
var request = new PaymentDetailsRequest
{
StoreId = storeId,
PaymentId = paymentId
};
while (true)
{
var response = await _client.PaymentDetailsAsync(request, _metadata);
if (response.ResultCase != PaymentDetailsResponse.ResultOneofCase.Response)
{
throw new Exception($"Error: {response.Error.Message}");
}
var details = response.Response;
Console.WriteLine($"Current Status: {details.Status}");
if (details.Status != PaymentStatus.Pending)
return details;
Thread.Sleep(2000);
}
}
public void PrintPaymentDetails(PaymentDetails details)
{
if (details.HasPaymentData)
{
var data = details.PaymentData;
Console.WriteLine($"PSP Reference: {data.PspReference}");
Console.WriteLine($"Payment Method: {data.PaymentMethod}");
Console.WriteLine($"Auth Status: {data.AuthStatus}");
switch (data.PaymentMethodDetailsCase)
{
case PaymentData.PaymentMethodDetailsOneofCase.PaymentCard:
var card = data.PaymentCard;
Console.WriteLine($"Card Last 4: {card.CardLast4Digits}");
Console.WriteLine($"Auth Code: {card.AuthCode}");
Console.WriteLine($"Payment Token: {card.PaymentToken}");
break;
case PaymentData.PaymentMethodDetailsOneofCase.PaymentWallet:
var wallet = data.PaymentWallet;
if (wallet.HasCardLast4Digits)
Console.WriteLine($"Wallet Card Last 4: {wallet.CardLast4Digits}");
Console.WriteLine($"Payment Link ID: {wallet.PaymentLinkId}");
break;
}
}
if (details.HasSaleData)
{
var sale = details.SaleData;
Console.WriteLine($"Amount: {sale.AmountMinorUnits}");
Console.WriteLine($"Currency: {sale.Currency}");
Console.WriteLine($"Order ID: {sale.OrderId}");
Console.WriteLine($"Payment Reference: {sale.PaymentReference}");
if (sale.HasOrderMetadata)
Console.WriteLine($"Order Metadata: {sale.OrderMetadata}");
}
}
}
<?php
require __DIR__ . '/../vendor/autoload.php';
use Com\Kodypay\Ecom\V1\KodyEcomPaymentsServiceClient;
use Com\Kodypay\Ecom\V1\PaymentDetailsRequest;
use Com\Kodypay\Ecom\V1\PaymentStatus;
function get_payment_details($storeId, $paymentId)
{
$client = new KodyEcomPaymentsServiceClient('HOSTNAME:443', [
'credentials' => Grpc\ChannelCredentials::createSsl()
]);
$metadata = ['X-API-Key' => ['API_KEY']];
$request = new PaymentDetailsRequest();
$request->setStoreId($storeId);
$request->setPaymentId($paymentId);
while (true) {
list($response, $status) = $client->PaymentDetails($request, $metadata)->wait();
if ($status->code !== Grpc\STATUS_OK || !$response->getResponse()) {
throw new Exception("Error: " . $response->getError()->getMessage());
}
$details = $response->getResponse();
echo "Current Status: " . $details->getStatus() . PHP_EOL;
if ($details->getStatus() !== PaymentStatus::PENDING) {
return $details;
}
sleep(2);
}
}
function print_payment_details($details)
{
if ($details->hasPaymentData()) {
$data = $details->getPaymentData();
echo "PSP Reference: " . $data->getPspReference() . PHP_EOL;
echo "Payment Method: " . $data->getPaymentMethod() . PHP_EOL;
echo "Auth Status: " . $data->getAuthStatus() . PHP_EOL;
switch ($data->getPaymentMethodDetails()) {
case 'payment_card':
$card = $data->getPaymentCard();
echo "Card Last 4: " . $card->getCardLast4Digits() . PHP_EOL;
echo "Auth Code: " . $card->getAuthCode() . PHP_EOL;
echo "Payment Token: " . $card->getPaymentToken() . PHP_EOL;
break;
case 'payment_wallet':
$wallet = $data->getPaymentWallet();
if ($wallet->hasCardLast4Digits()) {
echo "Wallet Card Last 4: " . $wallet->getCardLast4Digits() . PHP_EOL;
}
echo "Payment Link ID: " . $wallet->getPaymentLinkId() . PHP_EOL;
break;
}
}
if ($details->hasSaleData()) {
$sale = $details->getSaleData();
echo "Amount: " . $sale->getAmountMinorUnits() . PHP_EOL;
echo "Currency: " . $sale->getCurrency() . PHP_EOL;
echo "Order ID: " . $sale->getOrderId() . PHP_EOL;
echo "Payment Reference: " . $sale->getPaymentReference() . PHP_EOL;
if ($sale->hasOrderMetadata()) {
echo "Order Metadata: " . $sale->getOrderMetadata() . PHP_EOL;
}
}
}
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
| Field | Type | Required | Description |
|---|---|---|---|
store_id | string | Yes | Your Kody store ID. |
payment_id | string | One of | Kody-generated payment identifier. |
payment_reference | string | One of | Your 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)
- 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");
}
}
import grpc
import kody_clientsdk_python.ecom.v1.ecom_pb2 as kody_model
import kody_clientsdk_python.ecom.v1.ecom_pb2_grpc as kody_client
def get_payment_details(store_id: str, payment_id: str) -> None:
with grpc.secure_channel("HOSTNAME:443", grpc.ssl_channel_credentials()) as channel:
client = kody_client.KodyEcomPaymentsServiceStub(channel)
request = kody_model.PaymentDetailsRequest(
store_id=store_id,
payment_id=payment_id
)
response_iterator = client.PaymentDetailsStream(request, metadata=[("x-api-key", "API_KEY")])
# Process the first response from the stream
for response in response_iterator:
if response.HasField("response"):
print(f"Payment ID: {response.response.payment_id}")
print(f"Status: {response.response.status}")
# Additional fields (e.g. payment_data) can be inspected as needed
else:
print(f"Error: {response.error.message}")
if __name__ == "__main__":
get_payment_details("STORE_ID", "PAYMENT_ID")
using System;
using System.Threading.Tasks;
using Grpc.Core;
using Grpc.Net.Client;
using Com.Kodypay.Ecom.V1;
public class GetPaymentDetailsExample
{
public async Task GetPaymentDetails(string storeId, string paymentId)
{
var channel = GrpcChannel.ForAddress("https://HOSTNAME");
var client = new KodyEcomPaymentsService.KodyEcomPaymentsServiceClient(channel);
var metadata = new Metadata { { "X-API-Key", "API_KEY" } };
var request = new PaymentDetailsRequest
{
StoreId = storeId,
PaymentId = paymentId
};
using var call = client.PaymentDetailsStream(request, metadata);
while (await call.ResponseStream.MoveNext())
{
var response = call.ResponseStream.Current;
if (response.ResultCase == PaymentDetailsResponse.ResultOneofCase.Response)
{
Console.WriteLine($"Payment ID: {response.Response.PaymentId}");
Console.WriteLine($"Status: {response.Response.Status}");
// Additional fields (e.g. payment_data) can be inspected as needed
}
else
{
Console.WriteLine($"Error: {response.Error.Message}");
}
}
}
}
<?php
require __DIR__ . '/../vendor/autoload.php';
use Com\Kodypay\Ecom\V1\KodyEcomPaymentsServiceClient;
use Com\Kodypay\Ecom\V1\PaymentDetailsRequest;
use Grpc\ChannelCredentials;
$client = new KodyEcomPaymentsServiceClient('HOSTNAME:443', [
'credentials' => ChannelCredentials::createSsl()
]);
$metadata = ['X-API-Key' => ['API_KEY']];
$request = new PaymentDetailsRequest();
$request->setStoreId('STORE_ID');
$request->setPaymentId('PAYMENT_ID');
$call = $client->PaymentDetailsStream($request, $metadata);
foreach ($call->responses() as $response) {
if ($response->getResponse()) {
echo "Payment ID: " . $response->getResponse()->getPaymentId().PHP_EOL;
echo "Payment Link ID: " . $response->getResponse()->getPaymentData()->getPaymentWallet()->getPaymentLinkId().PHP_EOL;
// Additional fields (e.g. payment_data) can be inspected as needed
} else {
echo "Error: " . $response->getError()->getMessage().PHP_EOL;
break;
}
}
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
| Field | Type | Required | Description |
|---|---|---|---|
store_id | string | Yes | Your Kody store ID. |
page_cursor | PageCursor | Yes | Pagination cursor: page and page_size. |
filter | Filter | No | Optional 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)
- 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");
}
}
import grpc
import kody_clientsdk_python.ecom.v1.ecom_pb2 as kody_model
import kody_clientsdk_python.ecom.v1.ecom_pb2_grpc as kody_client
def get_payments(store_id: str) -> None:
with grpc.secure_channel("HOSTNAME:443", grpc.ssl_channel_credentials()) as channel:
client = kody_client.KodyEcomPaymentsServiceStub(channel)
request = kody_model.GetPaymentsRequest(
store_id=store_id,
page_cursor=kody_model.GetPaymentsRequest.PageCursor(page=0, page_size=10)
)
response = client.GetPayments(request, metadata=[("x-api-key", "API_KEY")])
if response.HasField("response"):
print(f"Total payments: {response.response.total}")
for payment in response.response.payments:
print(f"Payment ID: {payment.payment_id}")
print(f"Status: {payment.status}")
else:
print(f"Error: {response.error.message}")
if __name__ == "__main__":
get_payments("STORE_ID")
using System;
using System.Threading.Tasks;
using Grpc.Core;
using Grpc.Net.Client;
using Com.Kodypay.Ecom.V1;
public class GetPaymentsExample
{
public async Task GetPayments(string storeId)
{
var channel = GrpcChannel.ForAddress("https://HOSTNAME");
var client = new KodyEcomPaymentsService.KodyEcomPaymentsServiceClient(channel);
var metadata = new Metadata { { "X-API-Key", "API_KEY" } };
var request = new GetPaymentsRequest
{
StoreId = storeId,
PageCursor = new PageCursor { Page = 1, PageSize = 10 }
};
var response = await client.GetPaymentsAsync(request, metadata);
if (response.ResultCase == GetPaymentsResponse.ResultOneofCase.Response)
{
Console.WriteLine($"Total payments: {response.Response.Total}");
foreach (var payment in response.Response.Payments)
{
Console.WriteLine($"Payment ID: {payment.PaymentId}");
Console.WriteLine($"Status: {payment.Status}");
}
}
else
{
Console.WriteLine($"Error: {response.Error.Message}");
}
}
}
<?php
require __DIR__ . '/../vendor/autoload.php';
use Com\Kodypay\Ecom\V1\KodyEcomPaymentsServiceClient;
use Com\Kodypay\Ecom\V1\GetPaymentsRequest;
use Grpc\ChannelCredentials;
$client = new KodyEcomPaymentsServiceClient('HOSTNAME:443', [
'credentials' => ChannelCredentials::createSsl()
]);
$metadata = ['X-API-Key' => ['API_KEY']];
$request = new GetPaymentsRequest();
$request->setStoreId('STORE_ID');
$pageCursor = new GetPaymentsRequest\PageCursor();
$pageCursor->setPage(0);
$pageCursor->setPageSize(10);
$request->setPageCursor($pageCursor);
list($response, $status) = $client->GetPayments($request, $metadata)->wait();
if ($status->code === \Grpc\STATUS_OK && $response->getResponse()) {
echo "Total payments: " . $response->getResponse()->getTotal() . PHP_EOL;
foreach ($response->getResponse()->getPayments() as $payment) {
echo "Payment ID: " . $payment->getPaymentId() . PHP_EOL;
echo "Status: " . $payment->getStatus() . PHP_EOL;
}
} else {
echo "Error: " . $response->getError()->getMessage() . PHP_EOL;
}
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
| Field | Type | Required | Description |
|---|---|---|---|
store_id | string | Yes | Your store UUID. |
payment_id | string | One of | Kody-generated payment ID. |
psp_reference | string | One of | PSP reference identifier. |
amount | string | Yes | Refund 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)
- 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();
}
}
import grpc
from kody_clientsdk_python.ecom.v1 import ecom_pb2 as kody_model
from kody_clientsdk_python.ecom.v1 import ecom_pb2_grpc as kody_client
def refund_payment(store_id: str, payment_id: str) -> None:
with grpc.secure_channel("HOSTNAME:443", grpc.ssl_channel_credentials()) as channel:
client = kody_client.KodyEcomPaymentsServiceStub(channel)
request = kody_model.RefundRequest(
store_id=store_id,
payment_id=payment_id, # Alternatively, set psp_reference if needed
amount="5.00" # Refund amount as a string, e.g., "5.00"
)
responses = client.Refund(request, metadata=[("x-api-key", "API_KEY")])
for response in responses:
print(f"Refund Status: {response.status}")
if response.status == kody_model.RefundResponse.RefundStatus.FAILED:
print(f"Failure Reason: {response.failure_reason}")
print(f"Total Amount Refunded: {response.total_amount_refunded}")
if __name__ == "__main__":
refund_payment("STORE_ID", "PAYMENT_ID")
using System;
using System.Threading.Tasks;
using Grpc.Core;
using Grpc.Net.Client;
using Com.Kodypay.Ecom.V1;
public class RefundPaymentExample
{
public async Task RefundPayment(string storeId, string paymentId)
{
var channel = GrpcChannel.ForAddress("https://HOSTNAME");
var client = new KodyEcomPaymentsService.KodyEcomPaymentsServiceClient(channel);
var metadata = new Metadata { { "X-API-Key", "API_KEY" } };
var request = new RefundRequest
{
StoreId = storeId,
PaymentId = paymentId, // or set PspReference if needed
Amount = "5.00" // Refund amount as a string
};
using var call = client.Refund(request, metadata);
while (await call.ResponseStream.MoveNext())
{
var response = call.ResponseStream.Current;
Console.WriteLine($"Refund Status: {response.Status}");
if (response.Status == RefundResponse.Types.RefundStatus.Failed)
{
Console.WriteLine($"Failure Reason: {response.FailureReason}");
}
Console.WriteLine($"Total Amount Refunded: {response.TotalAmountRefunded}");
}
}
}
<?php
require __DIR__ . '/../vendor/autoload.php';
use Com\Kodypay\Ecom\V1\KodyEcomPaymentsServiceClient;
use Com\Kodypay\Ecom\V1\RefundRequest;
use Grpc\ChannelCredentials;
$client = new KodyEcomPaymentsServiceClient('HOSTNAME:443', [
'credentials' => ChannelCredentials::createSsl()
]);
$metadata = ['X-API-Key' => ['API_KEY']];
$request = new RefundRequest();
$request->setStoreId('STORE_ID');
// Use payment_id (or alternatively, setPspReference if available)
$request->setPaymentId('PAYMENT_ID');
$request->setAmount("5.00"); // Refund amount as a string
$call = $client->Refund($request, $metadata);
foreach ($call->responses() as $response) {
echo "Refund Status: " . $response->getStatus() . PHP_EOL;
if ($response->getStatus() === \Com\Kodypay\Ecom\V1\RefundResponse\RefundStatus::FAILED) {
echo "Failure Reason: " . $response->getFailureReason() . PHP_EOL;
}
echo "Total Amount Refunded: " . $response->getTotalAmountRefunded() . PHP_EOL;
}
Need help?
For further support or more detailed information, contact the Kody Support team at support@kody.com.