""" Porkbun API client for .ca domain operations. Docs: https://porkbun.com/api/json/v3/documentation All endpoints are POST with JSON body containing apikey + secretapikey. """ import logging import os from typing import Optional import requests LOG = logging.getLogger("tests.porkbun") API_BASE = "https://api.porkbun.com/api/json/v3" class PorkbunClient: def __init__( self, api_key: Optional[str] = None, secret_key: Optional[str] = None, ): self.api_key = api_key or os.environ["PORKBUN_API_KEY"] self.secret_key = secret_key or os.environ["PORKBUN_SECRET_KEY"] self.session = requests.Session() self.session.headers["Content-Type"] = "application/json" def _auth_body(self, **extra) -> dict: return {"apikey": self.api_key, "secretapikey": self.secret_key, **extra} def ping(self) -> bool: """Verify API credentials are valid.""" r = self.session.post(f"{API_BASE}/ping", json=self._auth_body()) data = r.json() if data.get("status") == "SUCCESS": LOG.info("Porkbun API ping OK — IP: %s", data.get("yourIp")) return True LOG.error("Porkbun ping failed: %s", data) return False def check_availability(self, domain: str) -> dict: """Check if a domain is available for registration. Returns: {"available": bool, "price": str, "currency": str} """ r = self.session.post( f"{API_BASE}/domain/checkDomainAvailability/{domain}", json=self._auth_body(), timeout=15, ) data = r.json() avail = data.get("status") == "SUCCESS" and data.get("pricing") price = "" currency = "" if avail and data.get("pricing"): # Pricing is keyed by TLD tld = domain.split(".", 1)[1] if "." in domain else "" tld_pricing = data["pricing"].get(tld, {}) price = tld_pricing.get("registration", "") currency = tld_pricing.get("currency", "USD") return { "available": avail, "domain": domain, "price": price, "currency": currency, "raw": data, } def register_domain( self, domain: str, years: int = 1, nameservers: Optional[list[str]] = None, ) -> dict: """Register a domain. Returns registration details.""" body = self._auth_body(domain=domain, years=years) if nameservers: body["ns"] = nameservers r = self.session.post( f"{API_BASE}/domain/register/{domain}", json=body, timeout=30, ) data = r.json() success = data.get("status") == "SUCCESS" LOG.info("Porkbun register %s: %s", domain, "OK" if success else data.get("message")) return {"success": success, "domain": domain, "raw": data} def get_dns_records(self, domain: str) -> list[dict]: """List DNS records for a domain.""" r = self.session.post( f"{API_BASE}/dns/retrieve/{domain}", json=self._auth_body(), timeout=10, ) data = r.json() return data.get("records", []) def add_dns_record( self, domain: str, record_type: str, name: str, content: str, ttl: int = 300 ) -> dict: """Add a DNS record.""" r = self.session.post( f"{API_BASE}/dns/create/{domain}", json=self._auth_body( type=record_type, name=name, content=content, ttl=str(ttl) ), timeout=10, ) return r.json() def delete_domain(self, domain: str) -> dict: """Delete/cancel a domain (for test cleanup).""" r = self.session.post( f"{API_BASE}/domain/delete/{domain}", json=self._auth_body(), timeout=10, ) return r.json()