Semantic Kernel payment integration.
No Semantic Kernel package needed. Wrap the real blockchain0x client in a KernelFunction (Python or Java), or call the REST API from a C# KernelFunction. Either way the agent moves USDC on Base.
There is no Semantic Kernel package. In Python you wrap the real blockchain0x client in a method decorated with @kernel_function; in C#, where no .NET SDK ships, a [KernelFunction] calls the REST API directly. Register it on your kernel, set FunctionChoiceBehavior to Auto, and the agent can move USDC on Base. The shipped core SDKs are Node, Python, Ruby, Go, and JVM.
The only enterprise-grade .NET agent framework.
If your stack is Microsoft-shaped (Azure, .NET, SQL Server, Teams, Copilot Studio), Semantic Kernel is almost certainly the right agent framework. It is built by Microsoft, it integrates with Azure OpenAI, AKS, and Entra, and it has first-class support across .NET, Python, and Java in a way no other framework matches. And it already gives you the thing you need: a KernelFunction is just a method, so wiring in payments is a method you write, not a package you wait on.
That is why there is no Semantic Kernel adapter to install. In Python and Java you wrap the real blockchain0x SDK in a KernelFunction; in C#, where no .NET SDK ships yet, the KernelFunction calls the REST API directly with HttpClient. You keep idiomatic ergonomics - decorated methods, async, attribute-based parameter validation - and there is no adapter version to track. The core SDKs that exist today are Node, Python, Ruby, Go, and JVM.
Install Semantic Kernel and, in Python, the core SDK.
There is no blockchain0x Semantic Kernel package to add. Python installs Semantic Kernel plus the real blockchain0x SDK; C# installs Microsoft.SemanticKernel and calls the REST API with the built-in HttpClient. Java uses Semantic Kernel for Java plus the com.blockchain0x:sdk-jvm SDK.
pip install semantic-kernel blockchain0xdotnet add package Microsoft.SemanticKernelBLOCKCHAIN0X_API_KEY=sk_test_... # sk_test_ = Base Sepolia, sk_live_ = Base mainnet BLOCKCHAIN0X_API_KEY=sk_test_... # same key, the name the .NET REST example reads OPENAI_API_KEY=sk-...
BLOCKCHAIN0X_API_KEY (the Python client reads this) is a sk_test_ testnet or sk_live_ mainnet key from your dashboard; the C# REST example reads the same value from BLOCKCHAIN0X_API_KEY. OPENAI_API_KEY (or AZURE_OPENAI_* for Azure-hosted models) is your LLM key. The webhook handler additionally needs BLOCKCHAIN0X_WEBHOOK_SECRET.
A wallet KernelFunction, in Python and C#.
Python wraps the real blockchain0x client in a method decorated with @kernel_function. C#, where no .NET SDK ships, exposes a [KernelFunction] that calls POST /v1/payments directly with HttpClient. Both register on the kernel as Wallet.send_usdc; only the surrounding ceremony differs.
from semantic_kernel import Kernel from semantic_kernel.functions import kernel_function from blockchain0x import Client blockchain0x = Client() # reads BLOCKCHAIN0X_API_KEY from the environment class WalletPlugin: @kernel_function(description="Send a USDC payment from an agent wallet.") def send_usdc(self, agent_id: str, to: str, amount_wei: str) -> str: # amount_wei is USDC base units (6 decimals): "10000" = 0.01 USDC return str( blockchain0x.payments.create(body={"agentId": agent_id, "to": to, "amountWei": amount_wei}) ) kernel = Kernel() kernel.add_plugin(WalletPlugin(), plugin_name="Wallet") # Add your chat service, then let the model call Wallet.send_usdc.
using System.ComponentModel;
using System.Net.Http.Json;
using Microsoft.SemanticKernel;
// There is no .NET SDK, so a C# KernelFunction calls the REST API directly.
public class WalletPlugin
{
private static readonly HttpClient Http = new()
{
BaseAddress = new Uri("https://api.blockchain0x.com"),
};
[KernelFunction, Description("Send a USDC payment from an agent wallet. amountWei is USDC base units (6 decimals).")]
public async Task<string> SendUsdc(string agentId, string to, string amountWei)
{
Http.DefaultRequestHeaders.Authorization =
new("Bearer", Environment.GetEnvironmentVariable("BLOCKCHAIN0X_API_KEY"));
var res = await Http.PostAsJsonAsync("/v1/payments", new { agentId, to, amountWei });
return await res.Content.ReadAsStringAsync();
}
}
// builder.Plugins.AddFromType<WalletPlugin>("Wallet");Register the function on the kernel, set FunctionChoiceBehavior to Auto, and when the user's message implies a payment the model calls Wallet.send_usdc with the agent id, recipient, and amount. amountWei is base units, so 0.01 USDC is "10000". The Python path returns the SDK result; the C# path returns the REST response body.
ASP.NET Core minimal API for receiving payment events.
When a payment settles, Blockchain0x POSTs a signed event to your webhook URL. There is no shipped .NET verifier, so the handler verifies by hand against the documented HMAC - which is all a helper would do. .NET example below; Python and Java verify the same way with their own HMAC libraries.
using System.Security.Cryptography;
using System.Text;
using Microsoft.AspNetCore.Builder;
var app = WebApplication.CreateBuilder(args).Build();
var secret = Environment.GetEnvironmentVariable("BLOCKCHAIN0X_WEBHOOK_SECRET")!;
app.MapPost("/webhooks/payment", async (HttpRequest req) =>
{
using var reader = new StreamReader(req.Body);
var raw = await reader.ReadToEndAsync(); // RAW body - verify before parsing
var sig = req.Headers["X-Blockchain0x-Signature"].ToString();
var ts = req.Headers["X-Blockchain0x-Timestamp"].ToString();
var parts = sig.Split(',').Select(p => p.Split('=', 2))
.Where(p => p.Length == 2).ToDictionary(p => p[0], p => p[1]);
var t = parts.GetValueOrDefault("t", ts);
var v1 = parts.GetValueOrDefault("v1", sig);
var want = Convert.ToHexString(new HMACSHA256(Encoding.UTF8.GetBytes(secret))
.ComputeHash(Encoding.UTF8.GetBytes($"{t}.{raw}"))).ToLowerInvariant();
var fresh = Math.Abs(DateTimeOffset.UtcNow.ToUnixTimeSeconds() - long.Parse(t)) <= 300;
if (!fresh || !CryptographicOperations.FixedTimeEquals(
Encoding.UTF8.GetBytes(want), Encoding.UTF8.GetBytes(v1)))
return Results.Unauthorized();
if (req.Headers["X-Blockchain0x-Event-Type"] == "payment.received")
await RunFollowupAsync(); // USDC landed - do the next step
return Results.Ok();
});
app.Run();The algorithm is HMAC-SHA256 over the string t.rawBody, a 300-second replay window, and a constant-time compare. Read the raw body via StreamReader so the signature stays intact; do not deserialize then re-serialize. The shipped events are payment.received, payment.sent, wallet.deployed, and webhook.test. In production the webhook often runs as a separate ASP.NET Core service sharing a database with the agent so the two can coordinate.
The SDKs and the REST surface are open. Read them.
There is no Semantic Kernel starter package to clone - the recipes above are the integration. The blockchain0x core SDKs (Node, Python, Ruby, Go) are open source on GitHub, and their method surface plus the REST routes the C# example calls are documented in the docs.
docs.blockchain0x.com/docs/overviewThe SDK method surface and the REST routes are documented at the docs. Start on a sk_test_ key against Base Sepolia, then switch to sk_live_ when the KernelFunction does what you expect.
Five Semantic Kernel-specific traps to avoid.
Semantic Kernel's plugin model is clean but has cross-language and behavior-default gotchas. Knowing them up front saves time.
There is no Semantic Kernel package, in any language
There is no NuGet, PyPI, or Maven adapter. The shipped core SDKs are Node, Python, Ruby, Go, and JVM - not .NET. So a Python kernel wraps the blockchain0x Python client in a @kernel_function, a Java kernel uses the com.blockchain0x:sdk-jvm SDK, and a C# kernel calls the REST API directly from a KernelFunction (shown above). All three are a few lines.
FunctionChoiceBehavior must be Auto
Semantic Kernel only invokes plugin functions when FunctionChoiceBehavior is set to Auto on the prompt-execution settings. The default is None, so the model never calls your wallet function no matter how clearly the user asks. If the agent ignores the function entirely, check this first.
Amounts are USDC base units, as strings
The payments call takes amountWei: a string of USDC base units (6 decimals), so 0.01 USDC is "10000" and 5 USDC is "5000000". Type the function argument as a string in any language. payments.create also does not retry by default and can answer 503 until the chain adapter is wired for your network - return a clear message rather than letting the agent loop.
Plugin scope across agents
Register the wallet function only on the kernel of the agent that should hold spending authority. The plugin is not global - an agent whose kernel does not have it cannot call it. Give a reviewer agent a kernel without the wallet function, or restrict the allowed functions per agent, so money stays with one role.
Verify webhooks against the raw body
Read the raw request body and verify before deserializing - the HMAC covers the exact bytes, so a parse-then-reserialize round trip breaks it. The .NET handler below implements the documented algorithm: HMAC-SHA256 over t.rawBody, a 300-second window, and a constant-time compare. Python and Java verify the same way with their own HMAC libraries.