Skip to main content

Unofficial Python SDK for the Papa John's ordering API

Project description

pajohns — Unofficial Papa John's Python SDK

PyPI version Python 3.12+ License: MIT

An unofficial, strongly-typed Python SDK for the Papa John's ordering API. Built with pydantic and requests, designed after the patterns of Stripe and OpenAI SDKs.

Disclaimer: This is an unofficial SDK and is not affiliated with, maintained, authorized, endorsed, or sponsored by Papa John's International, Inc. or any of its affiliates. Use at your own risk and in compliance with Papa John's Terms of Service.


Features

  • Object-Oriented API — Clean, module-based interface (client.store, client.deals, client.cart, etc.)
  • Strong Typing — Full Pydantic v2 request/response models with IDE auto-completion
  • Session Management — Optional file-based session persistence for local scripts
  • Cookie-Based Auth — Import a live browser session in one line
  • OrderingSkill — High-level conversational ordering interface for AI agents
  • Bilingual Output — English/Chinese display support in OrderingSkill

Installation

pip install pajohns

Requirements: Python 3.12+


Authentication

pajohns authenticates by importing your browser session cookies. No username/password is stored.

How to get your cookie string:

  1. Log in to papajohns.com in Chrome
  2. Open DevTools → ApplicationCookieshttps://www.papajohns.com
  3. Copy all cookies as a header string (or use a browser extension like "Copy Cookies")
from pajohns import PajohnsClient

client = PajohnsClient(session_file="session.json")  # persist session to disk
client.login("pj-session-id=abc123; auth-store=%7B%22state%22...")

After calling login(), the session is saved to session_file and reloaded automatically on future runs.


Quick Start

from pajohns import PajohnsClient

# Initialize (loads existing session from disk if file exists)
client = PajohnsClient(session_file="session.json")

# Search for nearby stores
stores = client.store.search("10001")
for s in stores:
    print(f"#{s.store_id}{s.address.address1}, {s.address.city}")

# Set the store you want to order from
client.session_data["store_id"] = stores[0].store_id

# Browse available deals
deals = client.deals.get_by_store(stores[0].store_id)
for d in deals:
    print(f"[{d.deal_id}] {d.title} — ${d.display_price}")

# Add a deal to cart (uses default configuration)
client.cart.add_deal(deal_id=61891, quantity=1)

# Generate a PayPal payment link to complete the order
url = client.checkout.get_paypal_link()
print(f"Pay here: {url}")

API Reference

PajohnsClient

PajohnsClient(session_file: str | None = None)

The main entry point. Pass session_file to enable automatic session persistence.

Method Description
client.login(cookie_str) Import a browser cookie string and authenticate
client.save_session() Persist current session state to disk

client.store — Store Discovery

# Search by ZIP code (carryout)
stores = client.store.search("90210")

# Search delivery stores by address
result = client.store.get_delivery_stores(
    street="123 Main St", city="Los Angeles", postal_code="90210", state="CA"
)

# Get store details by ID
store = client.store.get_details(store_id=3888)

# Get available order timeslots
slots = client.store.get_timeslots(store_id=3888, fulfillment_type="CARRYOUT")

client.deals — Deals & Specials

# List all deals for a store
deals = client.deals.get_by_store(store_id=3888)

# Get configuration for a specific deal
config = client.deals.get_deal(deal_id=61891)

# Fetch all ordering context in one call (toppings, sauces, crusts, instructions)
ctx = client.deals.get_deal_context(deal_id=61891)
print(ctx.deal_config.title)
print([s.title for s in ctx.sauces])
print(ctx.premium_crusts)

client.cart — Cart Management

# Add a deal with default options
cart = client.cart.add_deal(deal_id=61891)

# Add a deal with custom pizza configuration
cart = client.cart.add_deal(
    deal_id=61891,
    quantity=1,
    options={
        "products": [
            {
                "sku": "PIZZA-1-4-1",
                "productGroupId": "classic-pepperoni",
                "sauceId": 429,
                "sectionWhole": {"toppings": [19, 20]},
                "instructions": [
                    {"groupId": 3, "detailId": 58},  # Normal Bake
                    {"groupId": 4, "detailId": 10},  # Normal Cut
                ],
                "productModificationCodes": [],
                "sides": [],
                "papaSized": False,
                "productConfigurationId": 0,
                "quantity": 1,
            }
        ]
    }
)

# Sync cart state with server
cart = client.cart.refresh()

# Remove an item
client.cart.remove(shopcart_item_id="abc-123")

# Clear cart locally
client.cart.empty()

client.checkout — Payment

# Generate a PayPal checkout link
url = client.checkout.get_paypal_link()

client.catalog — Menu & Ingredients

# Get available toppings for a store
toppings = client.catalog.get_toppings(store_id=3888, topping_ids=[19, 20, 21])

# Get available sauces
sauces = client.catalog.get_sauces(store_id=3888)

# Get premium crust options and flavor upgrades
crust_data = client.catalog.get_crusts(store_id=3888)
print(crust_data.crust_types)   # {size_key: [PremiumCrust, ...]}
print(crust_data.crust_flavors) # {size_key: [CrustFlavor, ...]}

# Get nutritional info for a product group
info = client.catalog.get_nutritional_info(product_group_id="classic-pepperoni")

client.tracking — Order Tracking

status = client.tracking.get_order_status(order_id="PJ-123456")

client.ordering — AI Agent OrderingSkill

OrderingSkill is a high-level interface that wraps the full ordering state machine. All methods return formatted strings suitable for presenting directly to a user or AI agent.

Lifecycle: Authentication → Store → Deals → Pizza Configuration → Cart → Payment

# Phase 0: Auth check (prompts for cookies if not authenticated)
print(client.ordering.get_or_confirm_store())

# Phase 0: Login
print(client.ordering.login("pj-session-id=abc; auth-store=..."))

# Phase 1: Store
print(client.ordering.search_stores("10001"))
print(client.ordering.set_store(store_id=3888, order_type="CARRYOUT"))

# Phase 2: Deals
print(client.ordering.get_all_deals())

# Phase 2: Switch order type
print(client.ordering.set_order_type("DELIVERY"))

# Phase 3: Select a deal and load configuration
print(client.ordering.select_deal(deal_id=61891))

# Phase 4: View pizza configuration options
print(client.ordering.get_pizza_options(pizza_index=0))

# Phase 4: Configure a pizza
print(client.ordering.configure_pizza(
    pizza_index=0,
    config={
        "crust_type_id": 1,         # Original Crust
        "sauce_id": 429,            # Original Pizza Sauce
        "topping_ids": [19, 20],
        "instructions": [
            {"groupId": 3, "detailId": 58},  # Normal Bake
            {"groupId": 4, "detailId": 10},  # Normal Cut
        ],
    }
))

# Phase 4: Look up a specific option
print(client.ordering.explain_option("Thin Crust"))

# Phase 5: Add configured pizzas to cart
print(client.ordering.add_to_cart())

# Phase 6: Generate payment link
print(client.ordering.get_payment_link())

# Utility: Order summary
print(client.ordering.get_order_summary())

Exceptions

All exceptions inherit from PajohnsException.

from pajohns import APIError, AuthError, NetworkError, ValidationError

try:
    client.cart.add_deal(deal_id=99999)
except AuthError:
    print("Session expired — please log in again")
except APIError as e:
    print(f"API error {e.status_code}: {e}")
except NetworkError:
    print("Network request failed")
except ValidationError:
    print("Invalid input data")
Exception When raised
NetworkError Timeout, connection failure
APIError Non-2xx HTTP response or business logic error
AuthError Expired session, missing credentials
ValidationError Client-side validation failure

Session File Format

When session_file is set, the client saves session state as JSON:

{
    "cookies": {"pj-session-id": "...", "auth-store": "..."},
    "store_id": 3888,
    "order_type": "CARRYOUT",
    "customerToken": "...",
    "shopcart_id": "...",
    "cart_state": {...},
    "cart_price": {...}
}

You can pre-populate store_id and order_type in this file to skip interactive setup.


Disclaimer

This SDK is not affiliated with Papa John's International, Inc. It reverse-engineers the public-facing web API for personal and educational use. The API may change at any time without notice, which could break SDK functionality. The author assumes no responsibility for any issues arising from its use.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pajohns-0.1.0.tar.gz (32.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pajohns-0.1.0-py3-none-any.whl (42.6 kB view details)

Uploaded Python 3

File details

Details for the file pajohns-0.1.0.tar.gz.

File metadata

  • Download URL: pajohns-0.1.0.tar.gz
  • Upload date:
  • Size: 32.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.2 {"installer":{"name":"uv","version":"0.10.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for pajohns-0.1.0.tar.gz
Algorithm Hash digest
SHA256 ac876a9ad2778787bd01a7a290e4c4bd0a1f1093ed1b225594ea688eea87d79a
MD5 e1b64e3f9ae72fe25d8e75018a20c072
BLAKE2b-256 1c30e52b6a30035103764acef7b031620dba3ac3fe7340b515fd8f2d9a33d994

See more details on using hashes here.

File details

Details for the file pajohns-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: pajohns-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 42.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.2 {"installer":{"name":"uv","version":"0.10.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for pajohns-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 75aad6bbe123cb0b34b649a55ad5c6ba667083b18e8ec3ed3d32fcf0ee27940f
MD5 f03a5177198a01fdfb483747e5cadd8f
BLAKE2b-256 92d60c70ca4bad87499276b0569b463871d29187de3bbb82bbd7d5eecb2b39fc

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page