Tokenised Payments
The Tokenised Payments API lets you securely store a customer's card and reuse it for future e-commerce payments, giving returning customers a one-tap checkout while keeping you PCI compliant. Use it to create, retrieve, list, charge, and delete card tokens.
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 |
TOKEN_ID | Token-creation request identifier returned by CreateCardToken |
PAYER_REFERENCE | Your unique, stable identifier for the customer — e.g. a UUID (v4) or your internal customer ID. Reuse the same value for the same customer so their saved cards stay linked. |
PAYMENT_TOKEN | The reusable card token used to take payments |
Endpoints
| # | Endpoint | gRPC call | Description |
|---|---|---|---|
| 1 | Create Card Token | CreateCardToken | Start hosted card tokenisation and return a URL. |
| 2 | Pay With Card Token | PayWithCardToken | Charge a stored card token. |
| 3 | Get Token Payment Details | GetTokenPaymentDetails | Fetch the status and details of a token payment. |
| 4 | Get Card Token | GetCardToken | Retrieve a single stored token. |
| 5 | Get Card Tokens | GetCardTokens | List all stored tokens for a payer. |
| 6 | Delete Card Token | DeleteCardToken | Permanently delete a stored token. |
All calls are methods on KodyEcomPaymentsService.
Tokenised payment flow
Common enums
enum RecurringProcessingModel {
MODEL_UNSPECIFIED = 0; // Default value, not set
CARD_ON_FILE = 1; // Card on file model
SUBSCRIPTION = 2; // Subscription model
UNSCHEDULED_CARD_ON_FILE = 3; // Unscheduled card on file model
}
enum CardTokenStatus {
PENDING = 0;
FAILED = 1;
READY = 2;
DELETED = 3;
PENDING_DELETE = 4; // Token is in the process of being deleted
}
1. Create Card Token
Method: KodyEcomPaymentsService.CreateCardToken
Creates a new card token by initiating a tokenisation process. This returns a URL where the customer can securely enter their card details to create a reusable token.
Request
rpc CreateCardToken(CreateTokenRequest) returns (CreateTokenResponse);
message CreateTokenRequest {
string store_id = 1; // Your Kody store id
string idempotency_uuid = 2; // Idempotency key to ensure the request is processed only once, generated by client.
optional string token_reference = 3; // Your unique reference for this token request, if applicable. This can be used to match the token with your internal systems.
string payer_reference = 4; // The payer for whom the token is being created. This can be a user ID or any unique identifier you use to track users.
optional string metadata = 5; // A data set that can be used to store information about the order and used in the tokenisation process.
string return_url = 6; // The URL that your client application will be redirected to after the tokenisation is authorised. You can include additional query parameters, for example, the user id or order reference.
optional string payer_statement = 7; // The text to be shown on the payer's bank statement. Maximum 22 characters, otherwise banks might truncate the string. If not set it will use the store's terminals receipt printing name. Allowed characters: a-z, A-Z, 0-9, spaces, and special characters . , ' _ - ? + * /
optional string payer_email_address = 8; // We recommend that you provide this data, as it is used in velocity fraud checks. Required for 3D Secure 2 transactions.
optional string payer_phone_number = 9; // We recommend that you provide this data, as it is used in velocity fraud checks. Required for 3D Secure 2 transactions.
optional RecurringProcessingModel recurring_processing_model = 10; // The recurring model to use for the payment, if applicable. Can be 'Subscription', 'UnscheduledCardOnFile' or 'CardOnFile'.
}
Request fields
| Field | Type | Required | Description |
|---|---|---|---|
store_id | string | Yes | Your Kody store ID. |
idempotency_uuid | string | Yes | Client-generated idempotency key. |
token_reference | string | No | Your unique reference for this token request. |
payer_reference | string | Yes | Identifier of the payer the token is created for. |
metadata | string | No | Data set stored against the tokenisation process. |
return_url | string | Yes | URL the client is redirected to after authorisation. |
payer_statement | string | No | Text for the payer's bank statement (max 22 chars). |
payer_email_address | string | No | Payer email; used in fraud checks, required for 3DS2. |
payer_phone_number | string | No | Payer phone; used in fraud checks, required for 3DS2. |
recurring_processing_model | RecurringProcessingModel | No | Recurring model for the stored card. |
Response
message CreateTokenResponse {
oneof result {
Response response = 1;
Error error = 2;
}
message Response {
string token_id = 1; // A unique identifier for the token creation request, used to query the payment token creation result via GetCardToken.
string create_token_url = 2; // The URL to send the customer to for tokenisation
}
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.CreateTokenRequest;
import com.kodypay.grpc.ecom.v1.CreateTokenResponse;
import com.kodypay.grpc.ecom.v1.RecurringProcessingModel;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.Metadata;
import io.grpc.stub.MetadataUtils;
import java.util.UUID;
public class CreateCardTokenExample {
public static final String HOSTNAME = "HOSTNAME";
public static final String API_KEY = "API_KEY";
public static void main(String[] args) {
createCardToken("STORE_ID", "PAYER_REFERENCE");
}
public static void createCardToken(String storeId, String payerReference) {
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));
CreateTokenRequest request = CreateTokenRequest.newBuilder()
.setStoreId(storeId)
.setIdempotencyUuid(UUID.randomUUID().toString())
.setTokenReference("token_ref_" + UUID.randomUUID())
.setPayerReference(payerReference)
.setReturnUrl("https://your-website.com/token-complete")
.setPayerEmailAddress("customer@example.com")
.setRecurringProcessingModel(RecurringProcessingModel.CARD_ON_FILE)
.build();
CreateTokenResponse response = client.createCardToken(request);
if (response.hasResponse()) {
System.out.println("Token ID: " + response.getResponse().getTokenId());
System.out.println("Token Creation URL: " + response.getResponse().getCreateTokenUrl());
System.out.println("Redirect the customer to this URL to complete tokenisation");
} 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 create_card_token(store_id: str, payer_reference: str) -> None:
hostname = "HOSTNAME"
api_key = "API_KEY"
with grpc.secure_channel(hostname, grpc.ssl_channel_credentials()) as channel:
client = kody_client.KodyEcomPaymentsServiceStub(channel)
request = kody_model.CreateTokenRequest(
store_id=store_id,
idempotency_uuid=str(uuid4()),
token_reference=f"token_ref_{uuid4()}",
payer_reference=payer_reference,
return_url="https://your-website.com/token-complete",
payer_email_address="customer@example.com",
recurring_processing_model=kody_model.RecurringProcessingModel.CARD_ON_FILE
)
response = client.CreateCardToken(request, metadata=[("x-api-key", api_key)])
if response.HasField("response"):
print(f"Token ID: {response.response.token_id}")
print(f"Token Creation URL: {response.response.create_token_url}")
print("Redirect the customer to this URL to complete tokenisation")
else:
print(f"Error: {response.error.message}")
if __name__ == "__main__":
create_card_token("STORE_ID", "PAYER_REFERENCE")
using System;
using System.Threading.Tasks;
using Grpc.Core;
using Grpc.Net.Client;
using Com.Kodypay.Ecom.V1;
class CreateCardTokenExample
{
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 CreateTokenRequest
{
StoreId = "STORE_ID",
IdempotencyUuid = Guid.NewGuid().ToString(),
TokenReference = $"token_ref_{Guid.NewGuid()}",
PayerReference = "PAYER_REFERENCE",
ReturnUrl = "https://your-website.com/token-complete",
PayerEmailAddress = "customer@example.com",
RecurringProcessingModel = RecurringProcessingModel.CardOnFile
};
var response = await client.CreateCardTokenAsync(request, metadata);
if (response.ResultCase == CreateTokenResponse.ResultOneofCase.Response)
{
Console.WriteLine($"Token ID: {response.Response.TokenId}");
Console.WriteLine($"Token Creation URL: {response.Response.CreateTokenUrl}");
Console.WriteLine("Redirect the customer to this URL to complete tokenisation");
}
else
{
Console.WriteLine($"Error: {response.Error.Message}");
}
}
}
<?php
require __DIR__ . '/../vendor/autoload.php';
use Com\Kodypay\Ecom\V1\KodyEcomPaymentsServiceClient;
use Com\Kodypay\Ecom\V1\CreateTokenRequest;
use Com\Kodypay\Ecom\V1\RecurringProcessingModel;
use Grpc\ChannelCredentials;
$client = new KodyEcomPaymentsServiceClient('HOSTNAME:443', [
'credentials' => ChannelCredentials::createSsl()
]);
$metadata = ['X-API-Key' => ['API_KEY']];
$request = new CreateTokenRequest();
$request->setStoreId('STORE_ID');
$request->setIdempotencyUuid(uniqid());
$request->setTokenReference('token_ref_' . uniqid());
$request->setPayerReference('PAYER_REFERENCE');
$request->setReturnUrl('https://your-website.com/token-complete');
$request->setPayerEmailAddress('customer@example.com');
$request->setRecurringProcessingModel(RecurringProcessingModel::CARD_ON_FILE);
list($response, $status) = $client->CreateCardToken($request, $metadata)->wait();
if ($status->code === \Grpc\STATUS_OK && $response->getResponse()) {
echo "Token ID: " . $response->getResponse()->getTokenId() . PHP_EOL;
echo "Token Creation URL: " . $response->getResponse()->getCreateTokenUrl() . PHP_EOL;
echo "Redirect the customer to this URL to complete tokenisation" . PHP_EOL;
} else {
echo "Error: " . $response->getError()->getMessage() . PHP_EOL;
}
2. Pay With Card Token
Method: KodyEcomPaymentsService.PayWithCardToken
Processes a payment using a previously stored card token. This allows for instant payments without requiring the customer to re-enter their card details.
Request
rpc PayWithCardToken(PayWithCardTokenRequest) returns (PaymentDetailsResponse);
message PayWithCardTokenRequest {
string store_id = 1; // Your Kody store id
string idempotency_uuid = 2; // Idempotency key to ensure the request is processed only once
string payment_token = 3; // The ID of the payment token to be charged
uint64 amount_minor_units = 4; // Amount in minor units. For example, 2000 means GBP 20.00.
string currency = 5; // ISO 4217 three letter currency code
string payment_reference = 6; // Your unique reference for this payment
optional string order_id = 7; // Your identifier for the order
optional string order_metadata = 8; // Optional order details, not yet implemented.
optional string payer_statement = 9; // Optional text for payer's bank statement
optional PaymentInitiationRequest.CaptureOptions capture_options = 10; // Optional capture settings if the charge is an authorisation
}
Request fields
| Field | Type | Required | Description |
|---|---|---|---|
store_id | string | Yes | Your Kody store ID. |
idempotency_uuid | string | Yes | Client-generated idempotency key. |
payment_token | string | Yes | The stored token to charge. |
amount_minor_units | uint64 | Yes | Amount in minor units (e.g. 2000 = GBP 20.00). |
currency | string | Yes | ISO 4217 currency code. |
payment_reference | string | Yes | Your unique reference for this payment. |
order_id | string | No | Your order identifier. |
order_metadata | string | No | Optional order details (not yet implemented). |
payer_statement | string | No | Text for the payer's bank statement. |
capture_options | CaptureOptions | No | Capture settings if the charge is an authorisation. |
Response
The response follows the same structure as the standard PaymentDetailsResponse from the online payments API, containing payment status, transaction details, and card information.
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.PayWithCardTokenRequest;
import com.kodypay.grpc.ecom.v1.PaymentDetailsResponse;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.Metadata;
import io.grpc.stub.MetadataUtils;
import java.util.UUID;
public class PayWithCardTokenExample {
public static final String HOSTNAME = "HOSTNAME";
public static final String API_KEY = "API_KEY";
public static void main(String[] args) {
payWithCardToken("STORE_ID", "PAYMENT_TOKEN");
}
public static void payWithCardToken(String storeId, String paymentToken) {
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));
PayWithCardTokenRequest request = PayWithCardTokenRequest.newBuilder()
.setStoreId(storeId)
.setIdempotencyUuid(UUID.randomUUID().toString())
.setPaymentToken(paymentToken)
.setAmountMinorUnits(2500) // £25.00
.setCurrency("GBP")
.setPaymentReference("token_pay_" + UUID.randomUUID())
.setOrderId("order_" + UUID.randomUUID()) // optional field
.setPayerStatement("Online Purchase")
.build();
PaymentDetailsResponse response = client.payWithCardToken(request);
if (response.hasResponse()) {
var paymentDetails = response.getResponse();
System.out.println("Payment ID: " + paymentDetails.getPaymentId());
System.out.println("Status: " + paymentDetails.getStatus());
if (paymentDetails.hasPaymentData()) {
var paymentData = paymentDetails.getPaymentData();
System.out.println("Auth Status: " + paymentData.getAuthStatus());
if (paymentData.hasPaymentCard()) {
System.out.println("Card Last 4: " + paymentData.getPaymentCard().getCardLast4Digits());
}
}
} 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 pay_with_card_token(store_id: str, payment_token: str) -> None:
hostname = "HOSTNAME"
api_key = "API_KEY"
with grpc.secure_channel(hostname, grpc.ssl_channel_credentials()) as channel:
client = kody_client.KodyEcomPaymentsServiceStub(channel)
request = kody_model.PayWithCardTokenRequest(
store_id=store_id,
idempotency_uuid=str(uuid4()),
payment_token=payment_token,
amount_minor_units=2500, # £25.00
currency="GBP",
payment_reference=f"token_pay_{uuid4()}",
order_id=f"order_{uuid4()}", # optional field
payer_statement="Online Purchase"
)
response = client.PayWithCardToken(request, metadata=[("x-api-key", api_key)])
if response.HasField("response"):
payment_details = response.response
print(f"Payment ID: {payment_details.payment_id}")
print(f"Status: {payment_details.status}")
if payment_details.HasField("payment_data"):
payment_data = payment_details.payment_data
print(f"Auth Status: {payment_data.auth_status}")
if payment_data.HasField("payment_card"):
print(f"Card Last 4: {payment_data.payment_card.card_last_4_digits}")
else:
print(f"Error: {response.error.message}")
if __name__ == "__main__":
pay_with_card_token("STORE_ID", "PAYMENT_TOKEN")
using System;
using System.Threading.Tasks;
using Grpc.Core;
using Grpc.Net.Client;
using Com.Kodypay.Ecom.V1;
class PayWithCardTokenExample
{
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 PayWithCardTokenRequest
{
StoreId = "STORE_ID",
IdempotencyUuid = Guid.NewGuid().ToString(),
PaymentToken = "PAYMENT_TOKEN",
AmountMinorUnits = 2500, // £25.00
Currency = "GBP",
PaymentReference = $"token_pay_{Guid.NewGuid()}",
OrderId = $"order_{Guid.NewGuid()}", // optional field
PayerStatement = "Online Purchase"
};
var response = await client.PayWithCardTokenAsync(request, metadata);
if (response.ResultCase == PaymentDetailsResponse.ResultOneofCase.Response)
{
var paymentDetails = response.Response;
Console.WriteLine($"Payment ID: {paymentDetails.PaymentId}");
Console.WriteLine($"Status: {paymentDetails.Status}");
if (paymentDetails.HasPaymentData)
{
var paymentData = paymentDetails.PaymentData;
Console.WriteLine($"Auth Status: {paymentData.AuthStatus}");
if (paymentData.PaymentMethodDetailsCase == PaymentData.PaymentMethodDetailsOneofCase.PaymentCard)
{
Console.WriteLine($"Card Last 4: {paymentData.PaymentCard.CardLast4Digits}");
}
}
}
else
{
Console.WriteLine($"Error: {response.Error.Message}");
}
}
}
<?php
require __DIR__ . '/../vendor/autoload.php';
use Com\Kodypay\Ecom\V1\KodyEcomPaymentsServiceClient;
use Com\Kodypay\Ecom\V1\PayWithCardTokenRequest;
use Grpc\ChannelCredentials;
$client = new KodyEcomPaymentsServiceClient('HOSTNAME:443', [
'credentials' => ChannelCredentials::createSsl()
]);
$metadata = ['X-API-Key' => ['API_KEY']];
$request = new PayWithCardTokenRequest();
$request->setStoreId('STORE_ID');
$request->setIdempotencyUuid(uniqid());
$request->setPaymentToken('PAYMENT_TOKEN');
$request->setAmountMinorUnits(2500); // £25.00
$request->setCurrency('GBP');
$request->setPaymentReference('token_pay_' . uniqid());
$request->setOrderId('order_' . uniqid()); // optional field
$request->setPayerStatement('Online Purchase');
list($response, $status) = $client->PayWithCardToken($request, $metadata)->wait();
if ($status->code === \Grpc\STATUS_OK && $response->getResponse()) {
$paymentDetails = $response->getResponse();
echo "Payment ID: " . $paymentDetails->getPaymentId() . PHP_EOL;
echo "Status: " . $paymentDetails->getStatus() . PHP_EOL;
if ($paymentDetails->hasPaymentData()) {
$paymentData = $paymentDetails->getPaymentData();
echo "Auth Status: " . $paymentData->getAuthStatus() . PHP_EOL;
if ($paymentData->hasPaymentCard()) {
echo "Card Last 4: " . $paymentData->getPaymentCard()->getCardLast4Digits() . PHP_EOL;
}
}
} else {
echo "Error: " . $response->getError()->getMessage() . PHP_EOL;
}
3. Get Token Payment Details
Method: KodyEcomPaymentsService.GetTokenPaymentDetails
Retrieves details of a specific token-payment using either the payment_id or the payment_reference.
Request
The request follows the same structure as the standard PaymentDetailsRequest from the online payments API, containing payment id, payment reference.
Response
The response follows the same structure as the standard PaymentDetailsResponse from the online payments API, containing payment status, transaction details, and card information.
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 GetTokenPaymentDetailsExample {
public static void main(String[] args) throws InterruptedException {
PaymentDetails details = getTokenPaymentDetails("STORE_ID", "PAYMENT_ID");
printPaymentDetails(details);
}
public static PaymentDetails getTokenPaymentDetails(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.getTokenPaymentDetails(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_token_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.GetTokenPaymentDetails(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 GetTokenPaymentDetailsExample
{
private readonly KodyEcomPaymentsService.KodyEcomPaymentsServiceClient _client;
private readonly Metadata _metadata;
public GetTokenPaymentDetailsExample()
{
var channel = GrpcChannel.ForAddress("https://HOSTNAME");
_client = new KodyEcomPaymentsService.KodyEcomPaymentsServiceClient(channel);
_metadata = new Metadata { { "X-API-Key", "API_KEY" } };
}
public async Task<PaymentDetails> GetTokenPaymentDetails(string storeId, string paymentId)
{
var request = new PaymentDetailsRequest
{
StoreId = storeId,
PaymentId = paymentId
};
while (true)
{
var response = await _client.GetTokenPaymentDetailsAsync(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_token_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->GetTokenPaymentDetails($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. Get Card Token
Method: KodyEcomPaymentsService.GetCardToken
Retrieves details of a single stored card token by token_id or token_reference.
Request
rpc GetCardToken(GetCardTokenRequest) returns (GetCardTokenResponse);
message GetCardTokenRequest {
string store_id = 1; // Your Kody store id
oneof token_identifier {
string token_id = 2; // The unique identifier for the token creation request, returned from CreateCardToken.
string token_reference = 3; // Your unique payment reference that was set during the initiation
}
}
Request fields
| Field | Type | Required | Description |
|---|---|---|---|
store_id | string | Yes | Your Kody store ID. |
token_id | string | One of | Token-creation request ID returned by CreateCardToken. |
token_reference | string | One of | Your reference set during initiation. |
Response
message GetCardTokenResponse {
oneof result {
Response response = 1;
Error error = 2;
}
message Response {
string token_id = 1; // A unique identifier for the token creation request, used to query the payment token creation result via GetCardToken.
optional string token_reference = 2; // the external payment reference associated with the stored payment method, if applicable
string payment_token = 3; // Kody token for subsequent payments or pre-auths.
string payer_reference = 4; // The payer for whom the token is created, e.g. user id or any unique identifier you use to track users
RecurringProcessingModel recurring_processing_model = 5; // Recurring processing model
CardTokenStatus status = 6;
google.protobuf.Timestamp created_at = 7; // Date when the token was created
PaymentMethods payment_method = 8; // Card brand, e.g. mc, visa and so on
string payment_method_variant = 9; // Card variant, e.g. mccredit, mcdebit, visa, visadebit, etc.
string funding_source = 10; // Funding source of the card, e.g. CREDIT, DEBIT, PREPAID, etc. (aligns with PaymentCard.funding_source)
string card_last_4_digits = 11; // Last four digits of the card number (aligns with PaymentCard.card_last_4_digits)
}
message Error {
Type type = 1;
string message = 2;
enum Type {
UNKNOWN = 0;
PENDING_CREATE = 1; // Token not yet created, still in progress
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.GetCardTokenRequest;
import com.kodypay.grpc.ecom.v1.GetCardTokenResponse;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.Metadata;
import io.grpc.stub.MetadataUtils;
public class GetCardTokenExample {
public static final String HOSTNAME = "HOSTNAME";
public static final String API_KEY = "API_KEY";
public static void main(String[] args) {
getCardToken("STORE_ID", "TOKEN_ID");
}
public static void getCardToken(String storeId, String tokenId) {
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));
GetCardTokenRequest request = GetCardTokenRequest.newBuilder()
.setStoreId(storeId)
.setTokenId(tokenId) // or use .setTokenReference() instead
.build();
GetCardTokenResponse response = client.getCardToken(request);
if (response.hasResponse()) {
var tokenInfo = response.getResponse();
System.out.println("Token ID: " + tokenInfo.getTokenId());
System.out.println("Payment Token: " + tokenInfo.getPaymentToken());
System.out.println("Status: " + tokenInfo.getStatus());
System.out.println("Card Last 4: " + tokenInfo.getCardLast4Digits());
System.out.println("Payment Method: " + tokenInfo.getPaymentMethod());
} 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_card_token(store_id: str, token_id: str) -> None:
hostname = "HOSTNAME"
api_key = "API_KEY"
with grpc.secure_channel(hostname, grpc.ssl_channel_credentials()) as channel:
client = kody_client.KodyEcomPaymentsServiceStub(channel)
request = kody_model.GetCardTokenRequest(
store_id=store_id,
token_id=token_id # or use token_reference instead
)
response = client.GetCardToken(request, metadata=[("x-api-key", api_key)])
if response.HasField("response"):
token_info = response.response
print(f"Token ID: {token_info.token_id}")
print(f"Payment Token: {token_info.payment_token}")
print(f"Status: {token_info.status}")
print(f"Card Last 4: {token_info.card_last_4_digits}")
print(f"Payment Method: {token_info.payment_method}")
else:
print(f"Error: {response.error.message}")
if __name__ == "__main__":
get_card_token("STORE_ID", "TOKEN_ID")
using System;
using System.Threading.Tasks;
using Grpc.Core;
using Grpc.Net.Client;
using Com.Kodypay.Ecom.V1;
class GetCardTokenExample
{
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 GetCardTokenRequest
{
StoreId = "STORE_ID",
TokenId = "TOKEN_ID" // or use TokenReference instead
};
var response = await client.GetCardTokenAsync(request, metadata);
if (response.ResultCase == GetCardTokenResponse.ResultOneofCase.Response)
{
var tokenInfo = response.Response;
Console.WriteLine($"Token ID: {tokenInfo.TokenId}");
Console.WriteLine($"Payment Token: {tokenInfo.PaymentToken}");
Console.WriteLine($"Status: {tokenInfo.Status}");
Console.WriteLine($"Card Last 4: {tokenInfo.CardLast4Digits}");
Console.WriteLine($"Payment Method: {tokenInfo.PaymentMethod}");
}
else
{
Console.WriteLine($"Error: {response.Error.Message}");
}
}
}
<?php
require __DIR__ . '/../vendor/autoload.php';
use Com\Kodypay\Ecom\V1\KodyEcomPaymentsServiceClient;
use Com\Kodypay\Ecom\V1\GetCardTokenRequest;
use Grpc\ChannelCredentials;
$client = new KodyEcomPaymentsServiceClient('HOSTNAME:443', [
'credentials' => ChannelCredentials::createSsl()
]);
$metadata = ['X-API-Key' => ['API_KEY']];
$request = new GetCardTokenRequest();
$request->setStoreId('STORE_ID');
$request->setTokenId('TOKEN_ID'); // or use setTokenReference() instead
list($response, $status) = $client->GetCardToken($request, $metadata)->wait();
if ($status->code === \Grpc\STATUS_OK && $response->getResponse()) {
$tokenInfo = $response->getResponse();
echo "Token ID: " . $tokenInfo->getTokenId() . PHP_EOL;
echo "Payment Token: " . $tokenInfo->getPaymentToken() . PHP_EOL;
echo "Status: " . $tokenInfo->getStatus() . PHP_EOL;
echo "Card Last 4: " . $tokenInfo->getCardLast4Digits() . PHP_EOL;
echo "Payment Method: " . $tokenInfo->getPaymentMethod() . PHP_EOL;
} else {
echo "Error: " . $response->getError()->getMessage() . PHP_EOL;
}
5. Get Card Tokens
Method: KodyEcomPaymentsService.GetCardTokens
Lists all stored card tokens for a specific payer.
Request
rpc GetCardTokens(GetCardTokensRequest) returns (GetCardTokensResponse);
message GetCardTokensRequest {
string store_id = 1;
string payer_reference = 2; // The customer for whom to list tokens
}
Request fields
| Field | Type | Required | Description |
|---|---|---|---|
store_id | string | Yes | Your Kody store ID. |
payer_reference | string | Yes | The payer whose tokens you want to list. |
Response
message GetCardTokensResponse {
oneof result {
Response response = 1;
Error error = 2;
}
message Response {
repeated GetCardTokenResponse.Response tokens = 1;
}
message Error {
Type type = 1;
string message = 2;
enum Type {
UNKNOWN = 0;
INVALID_REQUEST = 1; // e.g. missing store_id or payer_reference
}
}
}
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.GetCardTokensRequest;
import com.kodypay.grpc.ecom.v1.GetCardTokensResponse;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.Metadata;
import io.grpc.stub.MetadataUtils;
public class GetCardTokensExample {
public static final String HOSTNAME = "HOSTNAME";
public static final String API_KEY = "API_KEY";
public static void main(String[] args) {
getCardTokens("STORE_ID", "PAYER_REFERENCE");
}
public static void getCardTokens(String storeId, String payerReference) {
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));
GetCardTokensRequest request = GetCardTokensRequest.newBuilder()
.setStoreId(storeId)
.setPayerReference(payerReference)
.build();
GetCardTokensResponse response = client.getCardTokens(request);
if (response.hasResponse()) {
System.out.println("Found " + response.getResponse().getTokensCount() + " tokens:");
for (var token : response.getResponse().getTokensList()) {
System.out.println("Token ID: " + token.getTokenId());
System.out.println("Card Last 4: " + token.getCardLast4Digits());
System.out.println("Payment Method: " + token.getPaymentMethod());
System.out.println("Status: " + token.getStatus());
System.out.println("---");
}
} 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_card_tokens(store_id: str, payer_reference: str) -> None:
hostname = "HOSTNAME"
api_key = "API_KEY"
with grpc.secure_channel(hostname, grpc.ssl_channel_credentials()) as channel:
client = kody_client.KodyEcomPaymentsServiceStub(channel)
request = kody_model.GetCardTokensRequest(
store_id=store_id,
payer_reference=payer_reference
)
response = client.GetCardTokens(request, metadata=[("x-api-key", api_key)])
if response.HasField("response"):
tokens = response.response.tokens
print(f"Found {len(tokens)} tokens:")
for token in tokens:
print(f"Token ID: {token.token_id}")
print(f"Card Last 4: {token.card_last_4_digits}")
print(f"Payment Method: {token.payment_method}")
print(f"Status: {token.status}")
print("---")
else:
print(f"Error: {response.error.message}")
if __name__ == "__main__":
get_card_tokens("STORE_ID", "PAYER_REFERENCE")
using System;
using System.Threading.Tasks;
using Grpc.Core;
using Grpc.Net.Client;
using Com.Kodypay.Ecom.V1;
class GetCardTokensExample
{
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 GetCardTokensRequest
{
StoreId = "STORE_ID",
PayerReference = "PAYER_REFERENCE"
};
var response = await client.GetCardTokensAsync(request, metadata);
if (response.ResultCase == GetCardTokensResponse.ResultOneofCase.Response)
{
var tokens = response.Response.Tokens;
Console.WriteLine($"Found {tokens.Count} tokens:");
foreach (var token in tokens)
{
Console.WriteLine($"Token ID: {token.TokenId}");
Console.WriteLine($"Card Last 4: {token.CardLast4Digits}");
Console.WriteLine($"Payment Method: {token.PaymentMethod}");
Console.WriteLine($"Status: {token.Status}");
Console.WriteLine("---");
}
}
else
{
Console.WriteLine($"Error: {response.Error.Message}");
}
}
}
<?php
require __DIR__ . '/../vendor/autoload.php';
use Com\Kodypay\Ecom\V1\KodyEcomPaymentsServiceClient;
use Com\Kodypay\Ecom\V1\GetCardTokensRequest;
use Grpc\ChannelCredentials;
$client = new KodyEcomPaymentsServiceClient('HOSTNAME:443', [
'credentials' => ChannelCredentials::createSsl()
]);
$metadata = ['X-API-Key' => ['API_KEY']];
$request = new GetCardTokensRequest();
$request->setStoreId('STORE_ID');
$request->setPayerReference('PAYER_REFERENCE');
list($response, $status) = $client->GetCardTokens($request, $metadata)->wait();
if ($status->code === \Grpc\STATUS_OK && $response->getResponse()) {
$tokens = $response->getResponse()->getTokens();
echo "Found " . count($tokens) . " tokens:" . PHP_EOL;
foreach ($tokens as $token) {
echo "Token ID: " . $token->getTokenId() . PHP_EOL;
echo "Card Last 4: " . $token->getCardLast4Digits() . PHP_EOL;
echo "Payment Method: " . $token->getPaymentMethod() . PHP_EOL;
echo "Status: " . $token->getStatus() . PHP_EOL;
echo "---" . PHP_EOL;
}
} else {
echo "Error: " . $response->getError()->getMessage() . PHP_EOL;
}
6. Delete Card Token
Method: KodyEcomPaymentsService.DeleteCardToken
Permanently deletes a stored card token. This action cannot be undone.
Request
rpc DeleteCardToken(DeleteCardTokenRequest) returns (DeleteCardTokenResponse);
message DeleteCardTokenRequest {
string store_id = 1; // Kody store id
oneof token_identifier {
string token_id = 2; // The unique identifier created by Kody
string token_reference = 3; // Your unique payment reference that was set during the initiation
}
}
Request fields
| Field | Type | Required | Description |
|---|---|---|---|
store_id | string | Yes | Your Kody store ID. |
token_id | string | One of | Kody-generated token ID. |
token_reference | string | One of | Your reference set during initiation. |
Response
message DeleteCardTokenResponse {
oneof result {
Response response = 1;
Error error = 2;
}
message Response {
// Empty response indicates successful deletion
}
message Error {
Type type = 1;
string message = 2;
enum Type {
UNKNOWN = 0;
NOT_FOUND = 1; // Token not found
FAILED = 2; // Deletion failed
INVALID_REQUEST = 3; // Invalid request parameters
}
}
}
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.DeleteCardTokenRequest;
import com.kodypay.grpc.ecom.v1.DeleteCardTokenResponse;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.Metadata;
import io.grpc.stub.MetadataUtils;
public class DeleteCardTokenExample {
public static final String HOSTNAME = "HOSTNAME";
public static final String API_KEY = "API_KEY";
public static void main(String[] args) {
deleteCardToken("STORE_ID", "TOKEN_ID");
}
public static void deleteCardToken(String storeId, String tokenId) {
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));
DeleteCardTokenRequest request = DeleteCardTokenRequest.newBuilder()
.setStoreId(storeId)
.setTokenId(tokenId) // or use .setTokenReference() instead
.build();
DeleteCardTokenResponse response = client.deleteCardToken(request);
if (response.hasResponse()) {
System.out.println("Card token deleted successfully");
} 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 delete_card_token(store_id: str, token_id: str) -> None:
hostname = "HOSTNAME"
api_key = "API_KEY"
with grpc.secure_channel(hostname, grpc.ssl_channel_credentials()) as channel:
client = kody_client.KodyEcomPaymentsServiceStub(channel)
request = kody_model.DeleteCardTokenRequest(
store_id=store_id,
token_id=token_id # or use token_reference instead
)
response = client.DeleteCardToken(request, metadata=[("x-api-key", api_key)])
if response.HasField("response"):
print("Card token deleted successfully")
else:
print(f"Error: {response.error.message}")
if __name__ == "__main__":
delete_card_token("STORE_ID", "TOKEN_ID")
using System;
using System.Threading.Tasks;
using Grpc.Core;
using Grpc.Net.Client;
using Com.Kodypay.Ecom.V1;
class DeleteCardTokenExample
{
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 DeleteCardTokenRequest
{
StoreId = "STORE_ID",
TokenId = "TOKEN_ID" // or use TokenReference instead
};
var response = await client.DeleteCardTokenAsync(request, metadata);
if (response.ResultCase == DeleteCardTokenResponse.ResultOneofCase.Response)
{
Console.WriteLine("Card token deleted successfully");
}
else
{
Console.WriteLine($"Error: {response.Error.Message}");
}
}
}
<?php
require __DIR__ . '/../vendor/autoload.php';
use Com\Kodypay\Ecom\V1\KodyEcomPaymentsServiceClient;
use Com\Kodypay\Ecom\V1\DeleteCardTokenRequest;
use Grpc\ChannelCredentials;
$client = new KodyEcomPaymentsServiceClient('HOSTNAME:443', [
'credentials' => ChannelCredentials::createSsl()
]);
$metadata = ['X-API-Key' => ['API_KEY']];
$request = new DeleteCardTokenRequest();
$request->setStoreId('STORE_ID');
$request->setTokenId('TOKEN_ID'); // or use setTokenReference() instead
list($response, $status) = $client->DeleteCardToken($request, $metadata)->wait();
if ($status->code === \Grpc\STATUS_OK && $response->getResponse()) {
echo "Card token deleted successfully" . PHP_EOL;
} else {
echo "Error: " . $response->getError()->getMessage() . PHP_EOL;
}
Best Practices
Security Considerations
- Use a stable, unique
payer_referencefor each customer — for example a UUID (v4) or your own internal customer ID. Keep it consistent across sessions so a customer's saved tokens stay linked, and avoid guessable or shared values such as email addresses or phone numbers. - Never store actual card details on your servers — use tokens instead
- Implement proper access controls for token management operations
Token Lifecycle Management
- Create tokens only when customers explicitly consent to save their payment method
- Monitor token status regularly using
GetCardTokento ensure tokens remain valid - Delete tokens when customers request removal or close their accounts
- Handle expired tokens gracefully by prompting for new payment method creation
Error Handling
- Implement retry logic for network failures
- Handle
PENDING_CREATEstatus when tokens are still being processed - Validate input parameters before making API calls
- Log errors appropriately for debugging and monitoring
Performance Optimisation
- Use
GetCardTokensto batch-load all tokens for a customer - Implement caching for frequently accessed token information
- Consider using connection pooling for high-volume applications
Need help?
For further support or more detailed information, contact the Kody Support team at support@kody.com.