# Portal — Autonomous Service Signup for AI Agents > Portal lets AI agents autonomously sign up for services and retrieve credentials. Pay per signup with USDC on Base via x402 — no human intervention needed. ## Base URL https://getportal.dev ## Quick Start (MCP) ```json { "mcpServers": { "portal": { "command": "npx", "args": ["@getportal/mcp"] } } } ``` Or run directly: `npx @getportal/mcp` --- ## Supported Services | Service | Price (USDC) | Time | Credential Type | |---------|--------------|------|-----------------| | resend | $0.50 | ~20s | API key | | railway | $0.50 | ~25s | API key | | vercel | $1.00 | ~30s | API key | | supabase | $1.00 | ~35s | API key | | cloudflare | $1.00 | ~30s | API key | --- ## API Reference ### POST /signup Create a new signup job. Requires x402 payment. **Request:** ```json { "service": "resend", "email_mode": "portal_managed", "callback_url": "https://your-webhook.com/callback" } ``` **Parameters:** - `service` (required): Service ID from supported list - `email_mode`: "portal_managed" (default) or "agent_provided" - `agent_email`: Required if email_mode is "agent_provided" - `callback_url`: Optional webhook for completion notification - `metadata`: Optional JSON object for your reference **Response (201):** ```json { "job_id": "portal_abc123_xyz789", "status": "pending", "poll_url": "https://getportal.dev/jobs/portal_abc123_xyz789", "estimated_seconds": 20, "expires_at": "2026-02-28T03:45:00.000Z" } ``` **Payment (402 response if missing):** ``` X-PAYMENT: ``` --- ### GET /jobs/:id Check job status. **Response:** ```json { "job_id": "portal_abc123_xyz789", "status": "completed", "service": "resend", "credential_url": "https://getportal.dev/credentials/portal_abc123_xyz789", "credential_expires_at": "2026-02-28T03:50:00.000Z", "completed_at": "2026-02-28T03:45:30.000Z" } ``` **Status values:** - `pending` - Waiting for worker - `claimed` - Worker picked up job - `in_progress` - Signup in progress - `completed` - Credentials ready - `failed` - Signup failed (check `error` field) --- ### GET /credentials/:jobId Retrieve credentials. **ONE-TIME RETRIEVAL** — credentials are deleted immediately after access. **Response:** ```json { "credentials": { "api_key": "re_abc123...", "email": "agent-abc123@portal.getportal.dev", "password_encrypted": "base64...", "account_url": "https://resend.com/api-keys" }, "retrieved_at": "2026-02-28T03:46:00.000Z", "warning": "These credentials have been deleted from Portal and will not be shown again." } ``` **Security:** - Credentials expire 5 minutes after job completion - One-time retrieval — deleted after first access - Encrypted in transit and at rest --- ### GET /signup/services List all supported services with pricing. **Response:** ```json { "services": [ { "id": "resend", "name": "Resend", "price": "0.50", "estimated_seconds": 20 }, { "id": "railway", "name": "Railway", "price": "0.50", "estimated_seconds": 25 }, { "id": "vercel", "name": "Vercel", "price": "1.00", "estimated_seconds": 30 }, { "id": "supabase", "name": "Supabase", "price": "1.00", "estimated_seconds": 35 }, { "id": "cloudflare", "name": "Cloudflare", "price": "1.00", "estimated_seconds": 30 } ] } ``` --- ## Workflow Example ```python # 1. Request signup response = post("https://getportal.dev/signup", { "service": "resend", "email_mode": "portal_managed" }, headers={"X-PAYMENT": x402_payment}) job_id = response["job_id"] # 2. Poll for completion while True: status = get(f"https://getportal.dev/jobs/{job_id}") if status["status"] == "completed": break if status["status"] == "failed": raise Exception(status["error"]) sleep(2) # 3. Retrieve credentials (one-time) creds = get(status["credential_url"]) api_key = creds["credentials"]["api_key"] ``` --- ## Webhook Callback If `callback_url` is provided, Portal will POST on completion: ```json { "job_id": "portal_abc123_xyz789", "status": "completed", "credential_url": "https://getportal.dev/credentials/portal_abc123_xyz789" } ``` Or on failure: ```json { "job_id": "portal_abc123_xyz789", "status": "failed", "error": "CAPTCHA solving failed after 3 attempts" } ``` --- ## x402 Payment Portal uses the x402 protocol for micropayments. **Network:** Base (eip155:8453) **Currency:** USDC **Prices:** $0.50 - $1.00 per signup Payment is verified before job creation. No refunds for failed signups (failures are rare, <2%). --- ## Rate Limits - 10 concurrent jobs per wallet - 100 jobs per hour per wallet - Credentials expire 5 minutes after completion --- ## Error Codes | Code | Meaning | |------|---------| | 400 | Invalid request (missing service, bad email_mode) | | 402 | Payment required | | 404 | Job or credentials not found | | 429 | Rate limit exceeded | | 500 | Internal error | --- ## Contact - GitHub: https://github.com/moltyfromclaw/portal - Website: https://getportal.dev