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
- 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 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();
}
}
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 = "grpc-staging.kodypay.com"
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://grpc-staging.kodypay.com";
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('grpc-staging.kodypay.com: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
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
- 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 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();
}
}
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 = "grpc-staging.kodypay.com"
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"):
print(f"Payment ID: {response.response.payment_id}")
print(f"Payment URL: {response.response.payment_url}")
# Additional fields (e.g. payment_data) can be inspected as needed
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://grpc-staging.kodypay.com";
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.InitiatePaymentStreamAsync(request, metadata);
if (response.ResultCase == PaymentInitiationResponse.ResultOneofCase.Response)
{
Console.WriteLine($"Payment ID: {response.Response.PaymentId}");
Console.WriteLine($"Payment URL: {response.Response.PaymentUrl}");
// 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\PaymentInitiationRequest;
use Grpc\ChannelCredentials;
$client = new KodyEcomPaymentsServiceClient('grpc-staging.kodypay.com: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)->wait();
foreach ($call->responses() as $response) {
if ($response->getResponse()) {
echo "Payment ID: " . $response->getResponse()->getPaymentId() . PHP_EOL;
echo "Payment URL: " . $response->getResponse()->getPaymentUrl() . PHP_EOL;
// Additional fields (e.g. payment_data) can be inspected as needed
} else {
echo "Error: " . $response->getError()->getMessage() . PHP_EOL;
}
}
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
- 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.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());
}
}
}
}
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("grpc-staging.kodypay.com: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 ExampleGetPaymentDetails
{
private readonly KodyEcomPaymentsService.KodyEcomPaymentsServiceClient _client;
private readonly Metadata _metadata;
public ExampleGetPaymentDetails()
{
var channel = GrpcChannel.ForAddress("https://grpc-staging.kodypay.com");
_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('grpc-staging.kodypay.com: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
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
- 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 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();
}
}
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("grpc-staging.kodypay.com: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"Payment URL: {response.response.payment_url}")
# 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 ExampleGetPaymentDetails
{
public async Task GetPaymentDetails(string storeId, string paymentId)
{
var channel = GrpcChannel.ForAddress("https://grpc-staging.kodypay.com");
var client = new KodyEcomPaymentsService.KodyEcomPaymentsServiceClient(channel);
var metadata = new Metadata { { "X-API-Key", "API_KEY" } };
var request = new PaymentDetailsRequest
{
StoreId = storeId,
PaymentId = paymentId
};
var response = await client.PaymentDetailsStreamAsync(request, metadata);
if (response.ResultCase == PaymentDetailsResponse.ResultOneofCase.Response)
{
Console.WriteLine($"Payment ID: {response.Response.PaymentId}");
Console.WriteLine($"Payment URL: {response.Response.PaymentUrl}");
// 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('grpc-staging.kodypay.com: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 URL: " . $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
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
- 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 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();
}
}
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("grpc-staging.kodypay.com: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=1, 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 ExampleGetPayments
{
public async Task GetPayments(string storeId)
{
var channel = GrpcChannel.ForAddress("https://grpc-staging.kodypay.com");
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('grpc-staging.kodypay.com:443', [
'credentials' => ChannelCredentials::createSsl()
]);
$metadata = ['X-API-Key' => ['API_KEY']];
$request = new GetPaymentsRequest();
$request->setStoreId('STORE_ID');
$pageCursor = new GetPaymentsRequest\PageCursor();
$pageCursor->setPage(1);
$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
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
- 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 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();
}
}
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("grpc-staging.kodypay.com: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 ExampleRefundPayment
{
public async Task RefundPayment(string storeId, string paymentId)
{
var channel = GrpcChannel.ForAddress("https://grpc-staging.kodypay.com");
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('grpc-staging.kodypay.com: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;
}
Remember to replace the following placeholders with your actual values:
HOSTNAME
: Use eithergrpc-staging.kodypay.com
(for development and test) orgrpc.kodypay.com
(for live)API_KEY
: Your API keySTORE_ID
: Your store identifier
For further support or more detailed information, please contact our support team.