Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added public/blog/paycode/mqtt.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/blog/paycode/paycode.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/blog/paycode/paymentflow.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/img/pos-demo.mov
Binary file not shown.
54 changes: 54 additions & 0 deletions public/img/user-logos/paycode.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
93 changes: 93 additions & 0 deletions src/app/blog/paycode/page.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import { BlogPostLayout } from '@/components/BlogPostLayout'
import { MQTTDiagram } from '@/components/MQTTDiagram'
import { IrohPaymentDiagram } from '@/components/IrohPaymentDiagram'
import { QRTicketFlow } from '@/components/QRTicketFlow'

export const post = {
draft: false,
author: 'okdistribute',
date: '2026-03-26',
title: 'iroh for payments',
description:
'How Paycode used iroh to connect payment terminals to point of sale systems at highway toll booths, with no additional servers and full compliance.',
}

export const metadata = {
title: post.title,
description: post.description,
openGraph: {
title: post.title,
description: post.description,
images: [{
url: `/api/og?title=Blog&subtitle=${post.title}`,
width: 1200,
height: 630,
alt: post.title,
type: 'image/png',
}],
type: 'article'
}
}

export default (props) => <BlogPostLayout article={post} {...props} />

When people think about next generation payment infrastructure, they usually think fancy iPads, flashy apps, Bluetooth, and paperless receipts. But the reality for most of the world is more humble. You're more likely to be presented with Windows 7, proprietary printers, and ethernet cables.

In this post we look at [Paycode], a team deploying iroh in remote environments in Mexico. Their most recent project: connecting payment terminals and point of sale systems to bring tap-to-pay to highway toll booths.

<IrohPaymentDiagram />


## Why peer-to-peer payments?

Paying for things can be frustrating when the tech breaks. Slow or inoperable point of sale systems cause massive delays, lines, and lost revenue. Connectivity isn't always guaranteed — especially for mobile devices that move out of range, or when the cloud service goes down. Every second saved at the point of sale is a second where people can get on with their lives instead of staring at a loading spinner.

There are plenty of ways to solve connectivity issues: you can add a server to the local WiFi network, use a classic HTTP server, or run an [MQTT] broker. But these server-based approaches come with costs. More on-site hardware means more technicians to service that hardware. And the original problem never fully goes away, because the single point of failure just shifts from the cloud to the local server.

<MQTTDiagram />

With peer-to-peer connectivity, no server is needed. The payment terminal syncs encrypted payloads directly with the point of sale device.

<Note>
One of the most critical requirements for PCI-compliant payment systems is that raw payment data can never flow through anything other than the official compliant software. Peer-to-peer connections act as a blind command and control channel between devices: raw payment data stays on the payment terminal, and any resulting transaction data is encrypted into a secure payload before leaving the device. This separation ensures that even as connectivity improves, compliance and security boundaries remain intact.
</Note>

## Legacy hardware, modern protocols

Paycode chose iroh to implement peer-to-peer connectivity between devices in the field — payment terminals, point of sale systems, and highway toll software. Existing constraints on hardware and budget made server-based options impossible, so a peer-to-peer approach was the only way forward.

The environment is far from modern:
- Touch-based Windows 7 machines
- Dual-core Intel CPUs with up to 8GB of RAM
- A mix of Ethernet (on terminals) and Wi-Fi (across the tollway system)

Despite these constraints, the team integrated iroh by bundling the Rust library inside a .NET 6 SDK.

> "iroh was super easy to use… I started hacking and was able to integrate it into our Kotlin PoS app and have a published .NET NuGet package for our client to use in that month." - Carlos Diez, Head of mobile and front-end development at Paycode

## How it works

Each QR code encodes an [iroh ticket], which contains the endpoint information needed to connect to a remote node. A terminal scans the QR code, registers the remote node as a static provider, and establishes a connection through gossip-based discovery.

<QRTicketFlow />

From there, the terminal can receive commands and send information back through the gossip channel. One such command is the start transaction request: the terminal receives the data needed to charge the user, executes the transaction within the PCI-compliant flow, and sends the outcome back.

<IrohPaymentDiagram />


Because the communication is direct between devices, transactions avoid unnecessary intermediaries. This reduces latency and makes the process reliable. **And since all data is end-to-end encrypted, sensitive data stays protected throughout the entire transaction lifecycle.**

## What makes this interesting

This deployment highlights something we think is important: **innovation doesn't always happen in greenfield environments.** In many cases, the most impactful work happens when you can modernize legacy systems without replacing old hardware: reducing cloud costs and improving connectivity and reliability at the same time.

The Paycode team needed something that could run on constrained devices, handle
unreliable networks, and meet strict compliance requirements. iroh fit because
it's designed to work on any device and adapt to the network conditions it
finds. If you're working on something similar, [let's talk!][book]

[Paycode]: https://paycode.com.mx
[iroh ticket]: https://docs.iroh.computer/concepts/tickets
[MQTT]: https://mqtt.org/
[book]: https://cal.com/team/number-0/iroh-services
5 changes: 4 additions & 1 deletion src/app/layout.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,11 @@ export default async function RootLayout({children}) {
<head>
<link rel="me" href="https://mastodon.social/@n0iroh" />
<link rel="alternate" type="application/rss+xml" title="RSS" href="/rss.xml" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="anonymous" />
<link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&family=Space+Mono&display=swap" rel="stylesheet" />
</head>
<body className="flex min-h-full bg-white antialiased dark:bg-zinc-900">
<body className="flex min-h-full bg-white antialiased dark:bg-zinc-900 font-space">
<Providers>
<div className="w-full overflow-x-hidden">
{children}
Expand Down
25 changes: 18 additions & 7 deletions src/app/page.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import {AnywhereIllustration} from '@/components/AnywhereIllustration';
import { IrohEverywhere } from '@/components/IrohEverywhere';
import {ProtocolHeroList} from '@/components/ProtocolHeroList';
import {LogoCloud} from '@/components/home/LogoCloud';
import {FeatureBentoGrid} from '@/components/FeatureBentoGrid';

import {HomeFeatureTabs} from '@/components/HomeFeatureTabs';

import logoRust from '@/images/language-logos/rust.svg';
import { CodeBlock } from '@/components/CodeBlock';
Expand Down Expand Up @@ -43,7 +44,7 @@ export default function Page() {
<h3 className="text-lg mt-3 leading-normal">Modular networking stack for direct,{' '}
<br />peer-to-peer connections between devices</h3>
<div className='flex mt-3'>
<a href="https://docs.iroh.computer/quickstart" className="my-4 p-3 px-4 transition bg-irohGray-800 text-irohPurple-500 uppercase hover:bg-irohGray-700 hover:text-gray-200 plausible-event-name=Home+Hero+Start+Project+Click">Read the Docs</a>
<a href="https://docs.iroh.computer/quickstart" className="my-4 p-3 px-4 transition bg-irohPurple-500 text-white dark:bg-irohGray-800 dark:text-irohPurple-500 uppercase hover:bg-irohPurple-600 dark:hover:bg-irohGray-700 hover:text-white plausible-event-name=Home+Hero+Start+Project+Click">Read the Docs</a>
</div>
</div>
</div>
Expand All @@ -69,15 +70,14 @@ export default function Page() {
The core peer-to-peer technology is <a href="https://github.com/n0-computer/iroh" className='text-irohPurple-500 hover:underline'>open source</a> and built on open standards, so you&apos;re never locked in.
</p>
</div>
<IrohEverywhere />
</section>


<section className="relative isolate overflow-hidden bg-gray-900 px-6 py-24 sm:py-32 lg:px-8">
<div className="absolute inset-0 -z-10 bg-[radial-gradient(45rem_50rem_at_top,var(--color-indigo-500),transparent)] opacity-10"></div>
<div className="absolute inset-y-0 right-1/2 -z-10 mr-16 w-[200%] origin-bottom-left skew-x-[-30deg] bg-gray-900 shadow-xl ring-1 shadow-indigo-500/5 ring-white/5 sm:mr-28 lg:mr-0 xl:mr-16 xl:origin-center"></div>
<div className="mx-auto max-w-2xl lg:max-w-4xl">
<figure className="mt-10">
<figure className="mt">
<blockquote className="text-center text-xl/8 font-semibold text-white sm:text-2xl/9">
<p>&ldquo;Doubling the network speed halves our compute budget.&rdquo;</p>
</blockquote>
Expand All @@ -95,7 +95,7 @@ export default function Page() {
</div>
</section>

<FeatureBentoGrid />
<HomeFeatureTabs />

{/* Solutions */}
<section id="solutions" className='max-w-7xl mx-auto py-16 px-4'>
Expand Down Expand Up @@ -128,14 +128,25 @@ export default function Page() {
<Link href="/solutions/delta-chat" className="block">
<div className="grid md:grid-cols-3 gap-6 items-center p-6 border border-irohGray-300 dark:border-irohGray-700 rounded-lg hover:border-irohPurple-500 transition-colors">
<div className="md:col-span-2">
<p className="text-xl font-medium text-irohGray-100 dark:text-irohGray-100 mb-2">Data sync & P2P Web Apps</p>
<p className="text-irohGray-600 dark:text-irohGray-300">Powers in-chat apps for hundreds of thousands of devices around the world, even when internet access is precarious.</p>
<p className="text-xl font-medium text-irohGray-800 dark:text-irohGray-100 mb-2">Real-time Sync for Mobile Applications</p>
<p className="text-irohGray-600 dark:text-irohGray-300">Powers apps for hundreds of thousands of devices around the world, even when internet access is precarious.</p>
</div>
<div className="flex items-center justify-center">
<img src="/img/user-logos/delta_chat.png" alt="Delta Chat logo" className="object-contain max-h-16" />
</div>
</div>
</Link>
<Link href="/solutions/pos" className="block">
<div className="grid md:grid-cols-3 gap-6 items-center p-6 border border-irohGray-300 dark:border-irohGray-700 rounded-lg hover:border-irohPurple-500 transition-colors">
<div className="md:col-span-2">
<p className="text-xl font-medium text-irohGray-800 dark:text-irohGray-100 mb-2">Point of Sale Payments</p>
<p className="text-irohGray-600 dark:text-irohGray-300">Connect payment terminals directly to point of sale systems over Bluetooth, LAN, or Wi-Fi with full PCI compliance and no additional servers.</p>
</div>
<div className="flex items-center justify-center">
<img src="/img/user-logos/paycode.svg" alt="Paycode logo" className="object-contain max-h-16" />
</div>
</div>
</Link>
</div>
</section>

Expand Down
10 changes: 5 additions & 5 deletions src/app/solutions/delta-chat/page.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,13 @@ export default function DeltaChatSolutionPage() {
</div>
<div className="container mx-auto max-w-6xl pt-12 relative z-10">
<div className="max-w-3xl">
<p className="text-irohPurple-500 font-medium mb-4 uppercase tracking-wide">Solution: Resilient Apps</p>
<p className="text-irohPurple-500 font-medium mb-4 uppercase tracking-wide">Real-time Sync for Mobile</p>
<h1 className="text-5xl md:text-6xl mb-6 leading-tight font-bold">
Resilient Messaging & P2P Web Apps
Real-time Sync for Mobile & Web Apps
</h1>
<p className="text-xl text-irohGray-600 dark:text-irohGray-300 mb-8 leading-relaxed">
Delta Chat uses iroh for multi-device setup and realtime P2P communication,
powering in-chat apps for hundreds of thousands of devices around the world.
powering apps for hundreds of thousands of devices around the world.
</p>
<div className="flex gap-4 flex-wrap">
<Link href="https://services.iroh.computer/signup?utm_source=website&utm_content=delta-chat-hero">
Expand Down Expand Up @@ -80,7 +80,7 @@ export default function DeltaChatSolutionPage() {
<div>
<h3 className="text-lg font-medium mb-2">Works Everywhere</h3>
<p className="text-irohGray-600 dark:text-irohGray-300">
Proven holepunching keeps users connected even when internet access is precarious.
Proven NAT traversal keeps users connected even when internet access is precarious.
</p>
</div>
</div>
Expand All @@ -102,7 +102,7 @@ export default function DeltaChatSolutionPage() {
<section className="py-20 px-6 border-t border-irohGray-300 dark:border-irohGray-800">
<div className="container mx-auto max-w-4xl text-center">
<h2 className="text-3xl font-bold mb-6">
Ready to Build Resilient Apps?
Ready to Build Real-time Sync?
</h2>
<p className="text-lg text-irohGray-600 dark:text-irohGray-300 mb-8 leading-relaxed">
Get started with iroh and build apps that work everywhere.
Expand Down
35 changes: 24 additions & 11 deletions src/app/solutions/page.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,22 @@ const solutions = [
logo: "rave",
},
{
category: "Resilient Apps",
category: "Real-time Sync for Mobile",
company: "Delta Chat",
headline: "Resilient Messaging & P2P Web Apps",
description: "Power in-chat apps for hundreds of thousands of devices around the world, even when internet access is precarious.",
headline: "Real-time Sync for Mobile Applications",
description: "Power apps for hundreds of thousands of devices around the world, even when internet access is precarious.",
href: "/solutions/delta-chat",
logo: "delta_chat",
},
{
category: "Payments / Point of Sale",
company: "Payments",
headline: "PCI-Compliant Peer-to-Peer Payments",
description: "Connect payment terminals directly to point of sale systems with no additional servers and full PCI compliance.",
href: "/solutions/pos",
logo: "paycode",
logoExt: "svg",
},
]

export default function SolutionsPage() {
Expand Down Expand Up @@ -72,14 +81,18 @@ export default function SolutionsPage() {
</p>
</div>
<div className="flex items-center justify-center p-8">
<ThemeImage
alt={`${solution.company} logo`}
darkSrc={`/img/user-logos/${solution.logo}.png`}
lightSrc={`/img/user-logos/${solution.logo}.png`}
width={300}
height={150}
className="object-contain max-h-32"
/>
{solution.logo ? (
<ThemeImage
alt={`${solution.company} logo`}
darkSrc={`/img/user-logos/${solution.logo}.${solution.logoExt || 'png'}`}
lightSrc={`/img/user-logos/${solution.logo}.${solution.logoExt || 'png'}`}
width={300}
height={150}
className="object-contain max-h-32"
/>
) : (
<p className="text-4xl font-bold text-irohGray-300 dark:text-irohGray-600">{solution.company}</p>
)}
</div>
</div>
</Link>
Expand Down
Loading
Loading