Skip to main content
Glama
README.md
<p align="center">
  <img src="./.github/assets/banner.gif" alt="Rift" width="100%">
</p>

# Rift

**Deep links for humans and agents.** — [riftl.ink](https://riftl.ink)

Rift is a deep linking platform that creates smart, cross-platform links with structured context for AI agents. One link works across iOS, Android, and web — with built-in click tracking, attribution, webhooks, and machine-readable metadata.

## Why Rift

- **Cross-platform deep links** — one URL routes to the right destination on iOS, Android, or web
- **Agent-readable** — structured `agent_context` and JSON-LD so AI agents understand what a link does and can act on it ([`/llms.txt`](https://api.riftl.ink/llms.txt) for machine-readable API reference)
- **Real-time webhooks** — get notified on clicks, attributions, and conversions with HMAC-signed payloads
- **Conversion tracking** — attribute post-install events (signups, purchases, deposits) back to the link that drove them via backend webhooks
- **Smart landing pages** — split layout showing both a human CTA and machine-readable data panel
- **Deferred deep linking** — user clicks a link, installs the app, and lands on the right content
- **Custom domains** — use your own brand: `go.yourcompany.com/summer-sale`
- **x402 payments** — accept crypto payments for API access via the x402 protocol

## Architecture

```
server/          Rust + Axum API server (MongoDB, Sentry)
client/mobile/   Swift/Kotlin mobile SDK via UniFFI
sdk/web/         TypeScript web SDK (ESM/CJS/IIFE)
marketing/       Next.js documentation and marketing site
```

The server separates **domain logic** (`services/`) from **transport layers** (`api/` for HTTP, `mcp/` for MCP protocol). Both transports share the same services, repos, and models. `AppState` lives in `app.rs`.

## Quick Start

### Prerequisites

- Rust 1.75+
- Node.js 20+ (for web SDK builds)
- MongoDB (local or Atlas)
- Optional: Custom domain with DNS access (any provider)

### Pick a setup path

#### CLI path

Best if you want the guided onboarding flow.

```sh
curl -fsSL https://raw.githubusercontent.com/saltyskip/rift/main/client/cli/install.sh | sh
rift init
rift domains setup
rift doctor
```

The CLI handles account setup, stores your secret key locally, helps you verify your primary
and alternate domains, and tests connectivity.

#### Manual path

Best if you want to drive the API and DNS steps yourself.

### Setup

```sh
# Enable shared git hooks (auto-builds web SDK, checks mobile SDK)
git config core.hooksPath .githooks
```

### Run the server

```sh
cd server
cp ../.env.example .env
# Edit .env with your MongoDB URI

cargo run
```

The server starts on `http://localhost:3000`. MongoDB is optional — the server boots without it (auth, links, and webhooks will be disabled).

### Get an API key

```sh
curl -X POST http://localhost:3000/v1/auth/signup \
  -H "Content-Type: application/json" \
  -d '{"email": "you@example.com"}'
```

### Set up a custom domain

Follow the custom domain guide in `marketing/src/app/docs/domains/page.tsx` or the hosted docs at
`https://riftl.ink/docs/domains`. You will:

- create a primary branded domain
- add a CNAME pointing to the Rift server
- verify ownership with a TXT record
- optionally add an alternate domain for more reliable Open in App behavior

### Create a publishable key

After verifying your email and setting up a custom domain, create a publishable key for SDK use:

```sh
curl -X POST http://localhost:3000/v1/auth/publishable-keys \
  -H "Authorization: Bearer rl_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"domain": "go.yourcompany.com"}'
```

### Create a link

```sh
curl -X POST http://localhost:3000/v1/links \
  -H "Authorization: Bearer rl_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "web_url": "https://example.com",
    "ios_deep_link": "myapp://product/123",
    "agent_context": {
      "action": "purchase",
      "cta": "Buy Now",
      "description": "Premium widget, 50% off today"
    }
  }'
```

### Resolve a link (agent)

```sh
curl http://localhost:3000/r/LINK_ID \
  -H "Accept: application/json"
```

Response:

```json
{
  "link_id": "LINK_ID",
  "ios_deep_link": "myapp://product/123",
  "web_url": "https://example.com",
  "metadata": null,
  "agent_context": {
    "action": "purchase",
    "cta": "Buy Now",
    "description": "Premium widget, 50% off today"
  },
  "_rift_meta": {
    "context": "This is a Rift deep link...",
    "source": "tenant_asserted",
    "status": "active",
    "tenant_domain": "go.yourcompany.com",
    "tenant_verified": true
  }
}
```

## MCP Server (for Claude Code, Cursor, etc.)

Rift exposes an [MCP](https://modelcontextprotocol.io/) endpoint at `/mcp` using streamable HTTP transport. This lets AI coding tools manage deep links directly.

### Setup with Claude Code

Add a `.mcp.json` to your project root:

```json
{
  "mcpServers": {
    "rift": {
      "type": "http",
      "url": "http://localhost:3000/mcp",
      "headers": {
        "x-api-key": "rl_live_YOUR_API_KEY_HERE"
      }
    }
  }
}
```

Claude will then have access to these tools: `links.create`, `links.bulk_create`, `links.get`, `links.list`, `links.update`, `links.delete`, `sources.create`, `sources.list`.

### Setup with other MCP clients

Any MCP client that supports streamable HTTP transport can connect to `http://localhost:3000/mcp`. Pass your API key via the `x-api-key` HTTP header or the `_meta.api_key` field during initialization.

## CI Checks

```sh
cd server
cargo fmt -- --check
cargo clippy -- -D warnings
cargo test
```

## Environment Variables

| Variable | Required | Purpose |
|----------|----------|---------|
| `HOST` / `PORT` | No | Server bind address and port (default `0.0.0.0:3000`) |
| `MONGO_URI` / `MONGO_DB` | No | MongoDB connection (server boots without it) |
| `SENTRY_DSN` | No | Error tracking |
| `RESEND_API_KEY` | No | Email verification via Resend |
| `RESEND_FROM_EMAIL` | No | Sender address for verification emails (default `Rift <noreply@updates.riftl.ink>`) |
| `PUBLIC_URL` | No | Base URL for links and verification emails |
| `FREE_DAILY_LIMIT` | No | Anonymous requests per IP per day (default 5) |
| `X402_ENABLED` | No | Enable x402 crypto payments (`true`/`false`) |
| `X402_RECIPIENT` | No | USDC recipient wallet address |
| `X402_PRICE` | No | Price per request in USDC (default `0.01`) |
| `X402_DESCRIPTION` | No | Resource description shown to payers |
| `X402_FACILITATOR_URL` | No | x402 facilitator URL (default `https://facilitator.x402.org`) |
| `CDP_API_KEY_ID` / `CDP_API_KEY_SECRET` | No | Coinbase Developer Platform keys for x402 |
| `PRIMARY_DOMAIN` | No | Primary domain for link resolution (default `riftl.ink`) |

See `.env.example` for the full list.

## License

The server (`server/`) is licensed under the [Business Source License 1.1](LICENSE). You can use, modify, and self-host it freely — you just can't use it to run a competing commercial deep linking service. The license converts to Apache 2.0 on 2030-03-25.

The SDKs (`sdk/`) are licensed under [Apache 2.0](sdk/LICENSE) — use them freely in your apps with no restrictions.