Skip to main content
Glama
benswel

QR for Agent

by benswel
README.md
# QR for Agent

[![benswel/qr-for-agent-api MCP server](https://glama.ai/mcp/servers/benswel/qr-for-agent-api/badges/score.svg)](https://glama.ai/mcp/servers/benswel/qr-for-agent-api)

QR-as-a-Service API built for AI agents. Create, update, and track dynamic QR codes programmatically via REST API or MCP (37 tools).

QR codes point to short URLs (`/r/:shortId`) that you can retarget at any time — the QR image never changes, but scanning it goes to the new destination. Multi-tenant by design, with full scan analytics.

**Live API:** [api.qrforagent.com](https://api.qrforagent.com)  |  **Site:** [qrforagent.com](https://qrforagent.com)  |  **MCP:** [`qr-for-agent`](https://www.npmjs.com/package/qr-for-agent)

## Features

- **Dynamic QR codes** — change the destination URL without regenerating the image
- **11 QR types** — URL, vCard, WiFi, Email, SMS, Phone, Event, Text, Location, Social, App Store
- **Custom styling** — dot shapes (square, rounded, dots, classy-rounded), corner styles, colors, gradients, logo embedding, frames with CTA text
- **SVG & PNG** — vector and bitmap output
- **Enriched analytics** — device type, browser, OS, country, city, referrer, scans-by-day
- **Real-time webhooks** — HMAC-SHA256 signed payloads with delivery logging
- **UTM tracking** — auto-append UTM parameters to redirect URLs
- **GTM support** — intermediate page with Google Tag Manager snippets
- **Conditional redirects** — route by device, OS, country, language, time range, or A/B split
- **Custom domains** — Pro users brand short URLs with their own domain (`qr.yourbrand.com/r/abc123`)
- **Expiration & scheduling** — auto-expire QR codes or schedule URL swaps
- **Conversion tracking** — tracking pixel + API for post-scan events (purchases, signups) with ROI analytics
- **Frames & templates** — decorative frames around QR codes (banner_top, banner_bottom, rounded) with CTA text
- **Bulk operations** — create, update, or delete up to 50 QR codes per request, or up to 500 via CSV upload (Pro)
- **Multi-tenant** — each API key sees only its own data
- **MCP server** — [`qr-for-agent`](https://www.npmjs.com/package/qr-for-agent) with 37 tools for Claude Desktop, Cursor, etc.
- **Plan-based quotas** — Free (10 QR, 1K scans/month) and Pro ($19/month, unlimited)
- **Self-service registration** — `POST /api/register` with email, no credit card
- **Stripe integration** — checkout, billing portal, webhook-driven plan management
- **OpenAPI docs** — Swagger UI at `/documentation`
- **AI-discoverable** — `/.well-known/ai-plugin.json` and `/.well-known/mcp.json`
- **Open source** — MIT license, self-hostable via Docker

## Quick Start

```bash
git clone https://github.com/benswel/qr-for-agent-api.git
cd qr-for-agent-api
npm install
npm run dev
```

On first startup, an API key is auto-generated and printed to the console.

```bash
curl -X POST http://localhost:3100/api/qr \
  -H "Content-Type: application/json" \
  -H "X-API-Key: qr_YOUR_KEY_HERE" \
  -d '{"target_url": "https://example.com", "label": "My first QR"}'
```

## API Endpoints

### QR Code Management (`X-API-Key` required)

| Method | Path | Description |
|--------|------|-------------|
| `POST` | `/api/qr` | Create a QR code (11 types, custom styling) |
| `GET` | `/api/qr` | List all QR codes (paginated) |
| `GET` | `/api/qr/:shortId` | Get QR code details |
| `PATCH` | `/api/qr/:shortId` | Update target URL, label, UTM, GTM, redirect rules |
| `DELETE` | `/api/qr/:shortId` | Delete QR code and its analytics |
| `GET` | `/api/qr/:shortId/image` | Download QR image (regenerated with stored style) |
| `POST` | `/api/qr/bulk` | Create up to 50 QR codes (all-or-nothing) |
| `PATCH` | `/api/qr/bulk` | Update up to 50 QR codes (partial success) |
| `DELETE` | `/api/qr/bulk` | Delete up to 50 QR codes (partial success) |
| `POST` | `/api/qr/bulk/csv` | Create up to 500 QR codes from CSV (Pro only) |

### Analytics (`X-API-Key` required)

| Method | Path | Description |
|--------|------|-------------|
| `GET` | `/api/analytics/:shortId` | Scan stats with device, browser, OS, country, city breakdowns + conversions |

### Conversions (`X-API-Key` required)

| Method | Path | Description |
|--------|------|-------------|
| `POST` | `/api/conversions` | Record a conversion event for a QR code you own |
| `GET` | `/api/conversions/:shortId` | Get conversion stats (totals, by_event, by_day, recent) |

### Webhooks (`X-API-Key` required)

| Method | Path | Description |
|--------|------|-------------|
| `POST` | `/api/webhooks` | Register webhook endpoint (returns HMAC secret) |
| `GET` | `/api/webhooks` | List all webhooks |
| `DELETE` | `/api/webhooks/:id` | Delete a webhook |

### Custom Domain (`X-API-Key` required, Pro only)

| Method | Path | Description |
|--------|------|-------------|
| `GET` | `/api/domain` | Get current custom domain and DNS status |
| `PUT` | `/api/domain` | Set custom domain |
| `DELETE` | `/api/domain` | Remove custom domain |

### Account (`X-API-Key` required)

| Method | Path | Description |
|--------|------|-------------|
| `GET` | `/api/usage` | Current usage and quota |
| `POST` | `/api/stripe/checkout` | Create Stripe Checkout session (upgrade to Pro) |
| `POST` | `/api/stripe/portal` | Open Stripe billing portal |

### Public (no auth)

| Method | Path | Description |
|--------|------|-------------|
| `POST` | `/api/register` | Self-service API key registration (rate-limited) |
| `GET` | `/r/:shortId` | Redirect to target URL (records scan) |
| `GET` | `/t/:shortId` | Conversion tracking pixel (returns 1×1 GIF) |
| `GET` | `/i/:shortId` | Serve QR image (cacheable) |
| `GET` | `/health` | Health check |
| `GET` | `/documentation` | Swagger UI |
| `GET` | `/.well-known/ai-plugin.json` | AI plugin manifest |
| `GET` | `/.well-known/mcp.json` | MCP discovery manifest |

### Admin (`X-Admin-Secret` header required)

| Method | Path | Description |
|--------|------|-------------|
| `GET` | `/api/admin/keys` | List all registered API keys |
| `GET` | `/api/admin/stats` | Dashboard metrics |

## Authentication

All `/api/*` endpoints require an `X-API-Key` header.

- **Format**: `qr_` + 32-character random string
- **Auto-generated**: on first startup if no keys exist
- **Multi-tenant**: each key only sees its own QR codes
- **Create a key**: `npm run key:create "my-label"`
- **List keys**: `npm run key:list`

Public endpoints (`/r/*`, `/i/*`, `/health`, `/documentation`, `/.well-known/*`) don't require auth.

## MCP Server

Published as [`qr-for-agent`](https://www.npmjs.com/package/qr-for-agent) on npm. 37 tools for AI agents to manage QR codes natively.

```bash
npx qr-for-agent
```

### Claude Desktop / Cursor

Add to your MCP config (`claude_desktop_config.json` or `.cursor/mcp.json`):

```json
{
  "mcpServers": {
    "qr-for-agent": {
      "command": "npx",
      "args": ["-y", "qr-for-agent"],
      "env": {
        "API_KEY": "your-api-key",
        "BASE_URL": "https://api.qrforagent.com"
      }
    }
  }
}
```

### Available Tools (37)

| Tool | Description |
|------|-------------|
| `create_qr_code` | Create a URL QR code with optional custom styling |
| `get_qr_code` | Get QR code details by short ID |
| `update_qr_destination` | Change where a QR code redirects |
| `list_qr_codes` | List all QR codes with pagination |
| `delete_qr_code` | Delete a QR code and its analytics |
| `get_qr_analytics` | Get scan stats and breakdowns |
| `bulk_create_qr_codes` | Create up to 50 QR codes at once |
| `bulk_update_qr_codes` | Update up to 50 QR codes at once |
| `bulk_delete_qr_codes` | Delete up to 50 QR codes at once |
| `create_vcard_qr` | Create a vCard contact QR code |
| `create_wifi_qr` | Create a WiFi credentials QR code |
| `create_email_qr` | Create an email (mailto:) QR code |
| `create_sms_qr` | Create an SMS QR code |
| `create_phone_qr` | Create a phone call QR code |
| `create_event_qr` | Create a calendar event QR code |
| `create_text_qr` | Create a plain text QR code |
| `create_location_qr` | Create a geo-location QR code |
| `create_social_qr` | Create a social media links QR code |
| `create_app_store_qr` | Create a smart app store redirect QR code |
| `update_vcard_qr` | Update a vCard QR code |
| `update_wifi_qr` | Update a WiFi QR code |
| `update_social_qr` | Update a social media QR code |
| `update_app_store_qr` | Update an app store QR code |
| `create_webhook` | Register a webhook endpoint |
| `list_webhooks` | List all registered webhooks |
| `delete_webhook` | Delete a webhook |
| `register` | Register for an API key |
| `get_usage` | Get current usage and quota |
| `upgrade_to_pro` | Create a Stripe Checkout session |
| `manage_billing` | Open Stripe billing portal |
| `set_utm_params` | Set UTM tracking parameters on a QR code |
| `set_redirect_rules` | Set conditional redirect rules on a QR code |
| `set_custom_domain` | Set or remove custom domain (Pro) |
| `get_custom_domain` | Get current custom domain and DNS status |
| `bulk_create_from_csv` | Create up to 500 QR codes from CSV data (Pro) |
| `record_conversion` | Record a post-scan conversion event |
| `get_conversions` | Get conversion stats for a QR code |

## Configuration

Copy `.env.example` to `.env` and edit:

| Variable | Default | Description |
|----------|---------|-------------|
| `PORT` | `3100` | HTTP port |
| `HOST` | `0.0.0.0` | Bind address |
| `BASE_URL` | `http://localhost:3100` | Public URL (used in short URLs) |
| `DATABASE_URL` | `./data/qr-agent.db` | SQLite file path |
| `SHORT_ID_LENGTH` | `8` | Length of generated short IDs |
| `ADMIN_SECRET` | *(none)* | Secret for admin endpoints (`X-Admin-Secret` header) |
| `STRIPE_SECRET_KEY` | *(none)* | Stripe API secret key |
| `STRIPE_WEBHOOK_SECRET` | *(none)* | Stripe webhook signing secret |
| `STRIPE_PRICE_ID` | *(none)* | Stripe Price ID for Pro plan |

## Database

SQLite with [Drizzle ORM](https://orm.drizzle.team/). Six tables:

- **`api_keys`** — key storage with label, email, plan (free/pro), Stripe IDs, custom domain
- **`qr_codes`** — QR metadata, target URLs, type/type_data, style options, UTM, GTM, redirect rules, expiration/scheduling
- **`scan_events`** — scan tracking: timestamp, user-agent, referer, IP, device, browser, OS, country, city
- **`webhooks`** — webhook endpoints per API key, HMAC secret, subscribed events
- **`webhook_deliveries`** — delivery log: status, response code, error messages
- **`conversion_events`** — conversion tracking: event name, value, metadata, referer, IP, timestamp

```bash
npm run db:generate   # Generate migration from schema changes
npm run db:migrate    # Apply pending migrations
npm run db:studio     # Open Drizzle Studio (web UI)
```

Migrations run automatically on server startup.

## Deployment

### Docker

```bash
docker compose up -d
```

The database is persisted in a Docker volume.

### Railway

The project includes `railway.toml` and a multi-stage `Dockerfile`. Connect your GitHub repo to Railway — it builds and deploys automatically with health checks on `/health`.

## Tests

195 integration tests covering all endpoints, auth, multi-tenant isolation, QR types, webhooks, bulk operations, custom domains, frames, conversions, CSV upload, and analytics.

```bash
npm test           # Run all tests
npm run test:watch # Watch mode
```

## Scripts

| Script | Description |
|--------|-------------|
| `npm run dev` | Start dev server with auto-reload |
| `npm run build` | Compile TypeScript |
| `npm start` | Run production server |
| `npm test` | Run test suite |
| `npm run test:watch` | Tests in watch mode |
| `npm run key:create` | Create API key |
| `npm run key:list` | List API keys |
| `npm run db:generate` | Generate migration |
| `npm run db:migrate` | Run migrations |
| `npm run db:studio` | Open Drizzle Studio |

## License

MIT

TDQS

A3.9/5.0

Scored across 37 tools

Disambiguation5/5

Each tool has a clearly distinct purpose, from creating specific QR code types (email, event, location, etc.) to bulk operations, analytics, and account management. No two tools appear to do the same thing, and descriptions clearly differentiate them.

Naming Consistency5/5

All tool names follow a consistent verb_noun pattern in snake_case (e.g., create_qr_code, get_qr_analytics, update_qr_destination). There are no deviations or mixed conventions, making the set predictable and easy to navigate.

Tool Count4/5

With 37 tools, the count is high but justified by the breadth of functionality: multiple QR types (10+), bulk operations, analytics, webhooks, billing, and customization. While slightly bloated, each tool serves a specific need in QR code management.

Completeness5/5

The tool surface covers the full lifecycle: create (single, bulk, specialized types), read (list, get details, analytics), update (destination, styling, dynamic rules), delete, plus extras like webhooks, billing, custom domains, and conversion tracking. No obvious gaps for a QR code service.

Maintenance

ActivityInactive
ResponsivenessUnresponsive