WalletWallet API
Get API Key Docs Log in

API Documentation

Complete reference for the WalletWallet API. Generate signed Apple Wallet passes with a single HTTP request.

Base URL: https://api.walletwallet.dev

Overview

The WalletWallet API lets you generate signed Apple Wallet (.pkpass) files programmatically. Send a POST request with your pass data and receive a ready-to-distribute pass file.

All requests use JSON bodies and return JSON responses, except the pass creation endpoint which returns a binary .pkpass file on success.

Quick start

  1. Get your API key (instant, no credit card)
  2. Make a POST request to /api/pkpass
  3. Save the response as a .pkpass file
  4. Distribute to your users via email, web, or AirDrop

Authentication

All API requests require a valid API key. Include it in the Authorization header using the Bearer scheme:

Header
Authorization: Bearer ww_live_<your_key>

API keys follow the format ww_live_ followed by 32 hexadecimal characters. You can get one instantly from the signup page.

GET

/api/auth/usage

Returns your current monthly usage statistics. Requires authentication.

Headers

Header Value
Authorization Bearer ww_live_<your_key>

Response

200
{
  "count": 150,
  "limit": 1000,
  "remaining": 850,
  "resetDate": "2026-03-01",
  "plan": "free"
}
401 Invalid or missing API key
cURL
curl https://api.walletwallet.dev/api/auth/usage \
  -H "Authorization: Bearer ww_live_<your_key>"
POST

/api/pkpass

Generates a signed Apple Wallet pass (.pkpass file). This is the primary endpoint. Requires authentication.

Headers

Header Value
Content-Type application/json
Authorization Bearer ww_live_<your_key>

Request Body

Field Type Required Description
barcodeValue string Yes Data encoded in the barcode. Max 512 characters.
barcodeFormat string Yes QR PDF417 Aztec Code128
title string Yes Pass title shown on the card. Max 64 characters.
label string No Label text above the value field. Must be provided together with value.
value string No Value text below the label. Must be provided together with label.
colorPreset string No Color theme: dark blue green red purple orange. Defaults to dark.
expirationDays number No Pass expires after this many days: 30, 90, or 365
color Pro string No Custom hex background color, e.g. #1e40af. Overrides colorPreset.
logoURL Pro string No Custom logo image. Must use HTTPS — HTTP URLs are rejected. Also accepts PNG data URIs (data:image/png;base64,...). Private/internal addresses are not allowed.

Response

200 Returns binary application/vnd.apple.pkpass file. Save as .pkpass.
400 Validation error — missing or invalid fields
401 Invalid or missing API key
429 Monthly rate limit exceeded
cURL — minimal
curl -X POST https://api.walletwallet.dev/api/pkpass \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer ww_live_<your_key>" \
  -d '{
    "barcodeValue": "MEMBER-12345",
    "barcodeFormat": "QR",
    "title": "Membership Card"
  }' \
  -o membership.pkpass
cURL — all options
curl -X POST https://api.walletwallet.dev/api/pkpass \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer ww_live_<your_key>" \
  -d '{
    "barcodeValue": "LOYALTY-98765",
    "barcodeFormat": "QR",
    "title": "Coffee Rewards",
    "label": "Member",
    "value": "Gold Status",
    "colorPreset": "green",
    "expirationDays": 365
  }' \
  -o rewards.pkpass
cURL — Pro features (custom color + logo)
curl -X POST https://api.walletwallet.dev/api/pkpass \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer ww_live_<your_key>" \
  -d '{
    "barcodeValue": "VIP-001",
    "barcodeFormat": "QR",
    "title": "VIP Access",
    "color": "#8B4513",
    "logoURL": "https://example.com/logo.png"
  }' \
  -o vip.pkpass

Barcode Formats

Format Type Best For
QR 2D square General purpose, high data capacity, most common
PDF417 2D stacked Boarding passes, ID cards, government documents
Aztec 2D square Transit tickets, compact spaces, no quiet zone needed
Code128 1D linear Retail, inventory, shipping labels

Color Presets

Available on all plans. Use the colorPreset field.

dark (default)
blue
green
red
purple
orange

Pro plan: Use the color field with any hex value (e.g. #1e40af) to set a fully custom background color.

Rate Limits

Plan Passes / Month Custom Color Custom Logo Price
Free 1,000 No No $0
Pro 100,000 Yes Yes $19/mo

Usage resets on the 1st of each month (UTC). You can check your current usage at any time via the /api/auth/usage endpoint.

When you exceed your limit, the API returns a 429 response with the reset date:

{
  "error": "Rate limit exceeded",
  "resetDate": "2026-03-01",
  "message": "Monthly limit reached. Resets on 2026-03-01"
}

Errors

All error responses return JSON with an error field:

{
  "error": "Error message describing the issue"
}

HTTP Status Codes

Code Description
200 Success
400 Bad request — invalid input, malformed JSON, or validation failure
401 Unauthorized — missing or invalid API key
404 Not found — endpoint does not exist
405 Method not allowed — wrong HTTP method
429 Rate limit exceeded — monthly quota used up
500 Internal server error

Common Validation Errors

Cause Error Message
Missing required field barcodeValue is required
Invalid barcode format barcodeFormat must be one of: QR, PDF417, Aztec, Code128
Title too long title must be 64 characters or less
Label without value label and value must both be provided together
Custom color on free plan color is only available on the Pro plan
Invalid expiration expirationDays must be 30, 90, or 365

Code Examples

JavaScript / Node.js
const response = await fetch('https://api.walletwallet.dev/api/pkpass', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer ww_live_<your_key>'
  },
  body: JSON.stringify({
    barcodeValue: 'TICKET-789',
    barcodeFormat: 'QR',
    title: 'Event Ticket',
    label: 'Seat',
    value: 'A-23'
  })
});

if (!response.ok) {
  const error = await response.json();
  throw new Error(error.error);
}

// Browser: trigger download
const blob = await response.blob();
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'ticket.pkpass';
a.click();

// Node.js: save to file
// const fs = require('fs');
// const buffer = Buffer.from(await response.arrayBuffer());
// fs.writeFileSync('ticket.pkpass', buffer);
Python
import requests

response = requests.post(
    'https://api.walletwallet.dev/api/pkpass',
    headers={
        'Content-Type': 'application/json',
        'Authorization': 'Bearer ww_live_<your_key>'
    },
    json={
        'barcodeValue': 'ORDER-456',
        'barcodeFormat': 'Code128',
        'title': 'Order Pickup',
        'label': 'Order #',
        'value': '456'
    }
)

response.raise_for_status()

with open('order.pkpass', 'wb') as f:
    f.write(response.content)
Ruby
require 'net/http'
require 'json'
require 'uri'

uri = URI('https://api.walletwallet.dev/api/pkpass')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request['Content-Type'] = 'application/json'
request['Authorization'] = 'Bearer ww_live_<your_key>'
request.body = {
  barcodeValue: 'MEMBER-001',
  barcodeFormat: 'QR',
  title: 'Gym Membership',
  label: 'Member',
  value: 'Premium'
}.to_json

response = http.request(request)
File.binwrite('membership.pkpass', response.body)
PHP
$ch = curl_init('https://api.walletwallet.dev/api/pkpass');

curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Content-Type: application/json',
        'Authorization: Bearer ww_live_<your_key>'
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'barcodeValue' => 'COUPON-50OFF',
        'barcodeFormat' => 'QR',
        'title' => 'Discount Coupon',
        'label' => 'Discount',
        'value' => '50% Off'
    ])
]);

$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if ($httpCode === 200) {
    file_put_contents('coupon.pkpass', $response);
}
Go
package main

import (
    "bytes"
    "encoding/json"
    "io"
    "net/http"
    "os"
)

func main() {
    body, _ := json.Marshal(map[string]interface{}{
        "barcodeValue":  "PASS-999",
        "barcodeFormat": "QR",
        "title":         "Access Pass",
    })

    req, _ := http.NewRequest("POST", "https://api.walletwallet.dev/api/pkpass", bytes.NewBuffer(body))
    req.Header.Set("Content-Type", "application/json")
    req.Header.Set("Authorization", "Bearer ww_live_<your_key>")

    resp, _ := http.DefaultClient.Do(req)
    defer resp.Body.Close()

    out, _ := os.Create("access.pkpass")
    defer out.Close()
    io.Copy(out, resp.Body)
}

Testing Your Pass

  1. Save the API response to a .pkpass file
  2. macOS: Double-click the file to preview in Finder
  3. iOS: AirDrop or email the file to your device
  4. The pass will prompt to add to Apple Wallet

Tip: Passes are signed with Apple certificates, so they work immediately on any iOS device — no additional configuration needed.

Get Your API Key

Free plan includes 1,000 passes/month