Skip to content
Open
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
3 changes: 3 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": ["next/core-web-vitals"]
}
12 changes: 12 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
.next/
node_modules/
out/
dist/
.env*
!.env.example
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
.DS_Store
tsconfig.tsbuildinfo
26 changes: 25 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,26 @@
# x402-directory
# x402 Directory

A curated, agent-maintained directory of x402 payment-enabled applications and endpoints. Browse, search, and discover services that accept x402 micropayments. Agents can contribute by adding new listings, verifying endpoint liveness, and categorizing services.

## Getting Started

Install dependencies:

```bash
npm install
```

Run the development server:

```bash
npm run dev
```

Open [http://localhost:3000](http://localhost:3000) to view the app.

## Scripts

- `npm run dev` starts the local Next.js server.
- `npm run build` creates a production build.
- `npm run typecheck` runs TypeScript without emitting files.
- `npm run lint` runs the Next.js lint checks.
33 changes: 33 additions & 0 deletions app/globals.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

:root {
--background: #f7fbfb;
--foreground: #1b1f23;
}

* {
box-sizing: border-box;
}

html {
min-height: 100%;
}

body {
min-height: 100vh;
margin: 0;
background: var(--background);
color: var(--foreground);
}

a {
color: inherit;
text-decoration: none;
}

button,
input {
font: inherit;
}
24 changes: 24 additions & 0 deletions app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import type { Metadata } from "next";
import { Inter } from "next/font/google";
import "./globals.css";

const inter = Inter({ subsets: ["latin"], variable: "--font-inter" });

export const metadata: Metadata = {
title: "x402 Directory",
description: "Browse and discover x402 payment-enabled applications and endpoints.",
};

export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en">
<body className={`${inter.variable} font-sans antialiased`}>
{children}
</body>
</html>
);
}
114 changes: 114 additions & 0 deletions app/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import { PageShell } from "@/components/page-shell";
import { placeholderListings } from "@/data/placeholder-listings";

export default function Home() {
return (
<PageShell>
<section className="mx-auto grid w-full max-w-6xl gap-10 px-6 pb-16 pt-12 md:grid-cols-[1.08fr_0.92fr] md:items-center md:px-8 md:pt-20">
<div>
<p className="text-sm font-semibold uppercase text-emerald-700">
x402 endpoint discovery
</p>
<h1 className="mt-4 max-w-3xl text-4xl font-semibold leading-tight text-stone-950 md:text-6xl">
Find applications and APIs that accept x402 payments.
</h1>
<p className="mt-5 max-w-2xl text-lg leading-8 text-stone-700">
A curated directory for agents, developers, and services building
with HTTP-native micropayments.
</p>
<div className="mt-8 flex flex-col gap-3 sm:flex-row">
<a
className="inline-flex min-h-11 items-center justify-center rounded-md bg-stone-950 px-5 text-sm font-semibold text-white transition hover:bg-stone-800"
href="#directory-preview"
>
Browse preview
</a>
<a
className="inline-flex min-h-11 items-center justify-center rounded-md border border-stone-300 bg-white/70 px-5 text-sm font-semibold text-stone-900 transition hover:border-stone-400 hover:bg-white"
href="https://www.x402.org/"
rel="noreferrer"
target="_blank"
>
Learn about x402
</a>
</div>
</div>

<div className="rounded-lg border border-stone-200 bg-white/78 p-5 shadow-sm">
<div className="flex items-center justify-between border-b border-stone-200 pb-4">
<div>
<p className="text-sm font-semibold text-stone-950">
Endpoint liveness
</p>
<p className="text-sm text-stone-600">Placeholder status panel</p>
</div>
<span className="rounded-full bg-emerald-100 px-3 py-1 text-xs font-semibold text-emerald-800">
Preview
</span>
</div>
<dl className="mt-5 grid grid-cols-3 gap-3 text-center">
<div className="rounded-md bg-stone-100 p-4">
<dt className="text-xs font-medium text-stone-600">Apps</dt>
<dd className="mt-2 text-2xl font-semibold text-stone-950">24</dd>
</div>
<div className="rounded-md bg-stone-100 p-4">
<dt className="text-xs font-medium text-stone-600">APIs</dt>
<dd className="mt-2 text-2xl font-semibold text-stone-950">18</dd>
</div>
<div className="rounded-md bg-stone-100 p-4">
<dt className="text-xs font-medium text-stone-600">Live</dt>
<dd className="mt-2 text-2xl font-semibold text-emerald-700">92%</dd>
</div>
</dl>
</div>
</section>

<section
className="border-y border-stone-200 bg-white/62"
id="directory-preview"
>
<div className="mx-auto w-full max-w-6xl px-6 py-12 md:px-8">
<div className="flex flex-col justify-between gap-4 md:flex-row md:items-end">
<div>
<h2 className="text-2xl font-semibold text-stone-950">
Directory preview
</h2>
<p className="mt-2 max-w-2xl text-stone-650">
Example cards for the first searchable directory experience.
</p>
</div>
<div className="rounded-md border border-stone-200 bg-stone-50 px-4 py-2 text-sm text-stone-600">
Search and filters can land in the next iteration.
</div>
</div>

<div className="mt-8 grid gap-4 md:grid-cols-3">
{placeholderListings.map((listing) => (
<article
className="rounded-lg border border-stone-200 bg-white p-5 shadow-sm"
key={listing.name}
>
<div className="flex items-start justify-between gap-3">
<div>
<h3 className="text-lg font-semibold text-stone-950">
{listing.name}
</h3>
<p className="mt-1 text-sm text-stone-600">
{listing.category}
</p>
</div>
<span className="rounded-full bg-emerald-50 px-3 py-1 text-xs font-semibold text-emerald-700">
{listing.status}
</span>
</div>
<p className="mt-4 text-sm leading-6 text-stone-700">
{listing.description}
</p>
</article>
))}
</div>
</div>
</section>
</PageShell>
);
}
44 changes: 44 additions & 0 deletions components/page-shell.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
type PageShellProps = {
children: React.ReactNode;
};

export function PageShell({ children }: PageShellProps) {
return (
<div className="flex min-h-screen flex-col">
<header className="border-b border-stone-200 bg-white/72 backdrop-blur">
<nav
aria-label="Primary"
className="mx-auto flex h-16 w-full max-w-6xl items-center justify-between px-6 md:px-8"
>
<a className="text-base font-semibold text-stone-950" href="/">
x402 Directory
</a>
<div className="flex items-center gap-5 text-sm font-medium text-stone-700">
<a className="transition hover:text-stone-950" href="#directory-preview">
Preview
</a>
<a
className="transition hover:text-stone-950"
href="https://github.com/shipyard-projects/x402-directory"
rel="noreferrer"
target="_blank"
>
GitHub
</a>
</div>
</nav>
</header>

<main className="flex-1">{children}</main>

<footer className="bg-stone-950 text-stone-200">
<div className="mx-auto flex w-full max-w-6xl flex-col gap-3 px-6 py-8 text-sm md:flex-row md:items-center md:justify-between md:px-8">
<p>x402 Directory</p>
<p className="text-stone-400">
Built for agent-maintained payment endpoint discovery.
</p>
</div>
</footer>
</div>
);
}
23 changes: 23 additions & 0 deletions data/placeholder-listings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
export const placeholderListings = [
{
name: "Micropay API",
category: "Developer tool",
status: "Live",
description:
"A sample payment-enabled API listing with category metadata and endpoint status.",
},
{
name: "Agent File Store",
category: "Storage",
status: "Live",
description:
"Placeholder listing for an app that accepts x402 payments for file access.",
},
{
name: "Inference Gateway",
category: "AI service",
status: "Checking",
description:
"Example service card for future liveness checks, tags, and verification details.",
},
];
5 changes: 5 additions & 0 deletions next-env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />

// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information.
4 changes: 4 additions & 0 deletions next.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/** @type {import('next').NextConfig} */
const nextConfig = {};

export default nextConfig;
28 changes: 28 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"name": "x402-directory",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"typecheck": "tsc --noEmit",
"lint": "next lint"
},
"dependencies": {
"next": "14.2.35",
"react": "18.3.1",
"react-dom": "18.3.1"
},
"devDependencies": {
"@types/node": "20.19.7",
"@types/react": "18.3.23",
"@types/react-dom": "18.3.7",
"autoprefixer": "10.4.21",
"eslint": "8.57.1",
"eslint-config-next": "14.2.35",
"postcss": "8.5.6",
"tailwindcss": "3.4.17",
"typescript": "5.8.3"
}
}
8 changes: 8 additions & 0 deletions postcss.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
const config = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
};

export default config;
24 changes: 24 additions & 0 deletions tailwind.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import type { Config } from "tailwindcss";

const config: Config = {
content: [
"./app/**/*.{js,ts,jsx,tsx,mdx}",
"./components/**/*.{js,ts,jsx,tsx,mdx}",
"./data/**/*.{js,ts,jsx,tsx,mdx}",
],
theme: {
extend: {
colors: {
stone: {
650: "#57534a",
},
},
fontFamily: {
sans: ["var(--font-inter)", "system-ui", "sans-serif"],
},
},
},
plugins: [],
};

export default config;
28 changes: 28 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": false,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"baseUrl": ".",
"paths": {
"@/*": ["./*"]
},
"plugins": [
{
"name": "next"
}
]
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}