# ProxAI Logistics — AI Agent Tool Specification > Physical task execution service for AI agents operating in Quebec, Canada. > **API key required for POST operations.** GET operations are public but rate-limited. > **Payment:** USDC (Solana or Base) **or** prepaid CAD account balance (auto-deducted at approval). ## Authentication POST requests require an API key. Two formats accepted: ```http x-api-key: prox_YOUR_API_KEY ``` or ```http Authorization: Bearer prox_YOUR_API_KEY ``` **Self-serve key registration (with optional scopes):** ```http POST https://www.proxaiqc.com/api/api-keys Content-Type: application/json { "name": "MyAgent v1", "contact": "agent@example.com", "scopes": ["audit_only", "task_create"] } ``` Returns `{ "api_key": "prox_...", "scopes": [...] }` — store securely, shown only once. Limit: 3 keys/IP/hour. **Available scopes:** `audit_only` (read), `task_create` (submit tasks), `task_cancel`, `billing_read`. Default: `["audit_only", "task_create"]`. ## Idempotency All POST endpoints support the `Idempotency-Key` header to prevent duplicate operations: ```http Idempotency-Key: my-unique-key-123 ``` If a request with the same key was already processed (within 24h), the cached response is returned with `Idempotency-Replayed: true` header. ## Webhooks (HMAC-Signed) Register a webhook URL to receive signed event notifications instead of polling: ```http POST https://www.proxaiqc.com/api/webhooks x-api-key: prox_YOUR_API_KEY { "url": "https://your-agent.example.com/hooks", "events": ["task.completed"] } ``` Returns `{ "webhook_id": "wh_...", "secret": "whsec_..." }`. All deliveries include `X-ProxAI-Signature: sha256=` header for verification. ### Webhook Retry & Failure Policy ProxAI retries failed webhook deliveries **3 times with exponential backoff**: | Attempt | Delay after previous failure | |---------|------------------------------| | 1st retry | 30 seconds | | 2nd retry | 5 minutes | | 3rd retry | 30 minutes | A delivery is considered failed if the receiver returns a non-2XX HTTP status or does not respond within **10 seconds**. **After 3 failed attempts — Dead Letter Queue (DLQ):** - The event is moved to a Dead Letter Queue associated with your `webhook_id`. - ProxAI sends a **fallback email** to the `requester_contact` of the task with the full payload attached. - The failed event is accessible for **72 hours** via: ```http GET /api/webhooks/{webhook_id}/failures x-api-key: prox_YOUR_API_KEY ``` Response includes: ```json { "webhook_id": "wh_abc123", "failures": [ { "event_id": "evt_xyz", "task_id": "PROX-M5K2A1-B3C4D5", "event": "task.completed", "attempted_at": ["2026-03-11T10:00:00Z", "2026-03-11T10:00:30Z", "2026-03-11T10:05:30Z"], "last_http_status": 503, "payload": { "...": "full webhook payload" }, "expires_at": "2026-03-14T10:35:30Z" } ] } ``` **Best practice:** Always provide `callback_url` at task submission AND implement webhook signature verification. Poll `GET /api/submit-task?task_id=X` as a fallback if your webhook server experiences downtime. ## Capabilities Manifest Full machine-readable manifest of all platform capabilities: ```http GET https://www.proxaiqc.com/api/capabilities ``` Returns: services, service zone (GeoJSON), operational hours, authentication details, feature flags (idempotency, webhooks, sandbox), all endpoints, and a quick-start guide. Cached 5 minutes. Open to all. ## Sandbox / Test Mode Test the full task lifecycle without real execution: ```http POST https://www.proxaiqc.com/api/submit-task X-ProxAI-Mode: sandbox x-api-key: prox_YOUR_API_KEY { "service_type": "SVC-01", "location_address": "Test", "task_description": "Sandbox test", "requester_contact": "test@example.com" } ``` Sandbox tasks use `SANDBOX-` prefixed IDs, deterministic cost estimates, and auto-advance through statuses on each GET poll. No emails, no real payments, no operator dispatch. ## Agent-Friendly Errors All errors follow a structured format with machine-readable codes and actionable suggestions: ```json { "error": "VALIDATION_ERROR", "message": "One or more fields are missing or invalid.", "reason": "The request payload did not pass validation.", "details": [{ "field": "hours", "issue": "Required. Must be a positive number." }], "suggested_alternatives": ["Check the service contract: GET /api/services?id=SVC-01"], "docs_url": "https://www.proxaiqc.com/openapi.json" } ``` **Field length errors** return the code `FIELD_TOO_LONG`: ```json { "error": "FIELD_TOO_LONG", "message": "One or more fields exceed the maximum allowed length.", "details": [ { "field": "task_description", "issue": "Exceeds maximum length of 2000 characters.", "max_length": 2000 }, { "field": "special_instructions", "issue": "Exceeds maximum length of 500 characters.", "max_length": 500 } ] } ``` ## End-to-End Autonomous Protocol ``` 1. REGISTER → POST /api/api-keys → get prox_YOUR_API_KEY (once) 2. DISCOVER → GET /api/services → pick service_type (no auth) 3. ESTIMATE → GET /api/estimate?location=X&hours=Y → get CAD cost (no auth) 4. BOOK → POST /api/submit-task (x-api-key) → receive task_id 5. TRACK → GET /api/submit-task?task_id=X → poll status 6. PAY → send USDC + memo=task_id (see _payment) → blockchain auto-confirmed ~2min 7. WAIT → poll until status = completed → proof_files_data in response 8. SCORE → POST /api/task-score (x-api-key) → rate 1-5 ``` ## Task Status Flow ``` received → accepted_pending_payment (human approved → USDC payment instructions sent) → paid_ready (blockchain confirmed → execution scheduled) → in_progress (operator en route) → completed (proof photos delivered via email + API + webhook) → paid_ready (instant) (client has CAD account → auto-deducted at approval, skips payment step) → rejected (task declined) → counter_offered (operator proposed different price/scope) → paid_ready (payment received OR admin confirms — see Counter-Offer below) → payment_expired (48h payment window elapsed) ``` ### Counter-Offer: Paying = Implicit Acceptance When a task reaches `counter_offered`, **there is no explicit "accept" action**. Paying the counter-offer amount IS the acceptance: - Send the exact `payment_usdc` amount to either wallet (same as a normal payment) - Include `task_id` as memo (strongly recommended) - The payment is detected automatically within ~2 minutes - Status transitions directly to `paid_ready` (skips `accepted_pending_payment`) - `counter_offer_accepted_via` is set to `"payment"` in the task record The `payment_usdc` and wallet addresses for a `counter_offered` task are accessible at `GET /api/submit-task?task_id=X` in the `_payment` block — same structure as a normal approval. ## Quick Start — Book a Task ```http POST https://www.proxaiqc.com/api/submit-task Content-Type: application/json x-api-key: prox_YOUR_API_KEY { "service_type": "SVC-01", "location_address": "123 Rue Principale, Laval, QC", "task_description": "Photograph all four exterior walls and document visible damage.", "requester_contact": "agent@example.com", "callback_url": "https://your-agent.example.com/webhooks/proxai", "lang": "en" } ``` Optional fields: `lang` (`"fr"` default or `"en"`) controls the language of all client-facing emails (confirmation, payment, delivery, refund). Response 201: `{ "task_id": "PROX-M5K2A1-B3C4D5", "status": "received" }` ## Payment (USDC on Solana or Base) After approval, poll GET `/api/submit-task?task_id=X`. Payment fields appear directly on the task object: ```json { "status": "accepted_pending_payment", "payment_usdc": 94.23, "estimated_cost_cad": 130.00, "payment_deadline": "2026-03-10T14:00:00Z", "payment_requested_at": "2026-03-08T14:00:00Z" } ``` Wallet addresses are returned in the authenticated API response (`payment_solana_address` / `payment_base_address` fields). **Never hardcode wallet addresses** — always read them from the API response for the specific task. Send **exactly** `payment_usdc` to **either** network wallet address from the API response. Detected automatically within ~2 minutes (±0.02 USDC tolerance). Each task gets a unique USDC amount (exact cents) to ensure unambiguous blockchain matching. Status auto-advances to `paid_ready`. ### Memo (Strongly Recommended) When the task reaches `accepted_pending_payment`, the API response includes a `_payment` block with full per-network memo instructions. **Always read `_payment` before building your transaction.** Including the `task_id` as a memo significantly reduces collision risk: - A transaction whose memo **does not match** the expected `task_id` is **ignored**, even if the amount matches. - A transaction with **no memo** is accepted based on amount alone (backward-compatible). **Solana — MemoProgram instruction:** ```javascript new TransactionInstruction({ keys: [], programId: new PublicKey("MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr"), data: Buffer.from("PROX-M5K2A1-B3C4D5", "utf8"), }) ``` **Base L2 — transaction data field:** ```javascript data: "0x" + Buffer.from("PROX-M5K2A1-B3C4D5", "utf8").toString("hex") ``` The exact `task_id` value and per-network details are always provided in `_payment.networks.solana.memo` and `_payment.networks.base_l2.memo` in the GET response. Do not hardcode — always read from the response. ## Retrieving Deliverables When `status = completed`, response includes: ```json { "proof_files_data": [ { "filename": "photo_001.jpg", "type": "image/jpeg", "content": "" } ] } ``` If `callback_url` was provided at submission, this payload is also POSTed to your webhook. ## Polling & Webhook Best Practices Every GET `/api/submit-task?task_id=X` response includes a `_polling` object: ```json { "_polling": { "is_terminal": false, "next_poll_seconds": 60, "recommended_action": "Task is under human review. Wait for approval.", "tip": "Use callback_url at submission for instant webhook delivery instead of polling." } } ``` **Recommended approach:** provide `callback_url` at submission. ProxAI will POST to your webhook when the task completes — no polling needed. **If polling:** respect `next_poll_seconds` and stop when `is_terminal` is `true`. The API also returns a `Retry-After` HTTP header. | Status | Poll interval | Terminal? | |--------|--------------|-----------| | received | 60s | No | | accepted_pending_payment | 30s | No | | counter_offered | 120s | No | | paid_ready | 60s | No | | in_progress | 120s | No | | completed | — | Yes | | rejected | — | Yes | | payment_expired | — | Yes | ## Service Types | ID | Name | Typical Duration | |----|------|-----------------| | SVC-01 | Visual Audits & Site Reporting | 1-2 hours | | SVC-02 | Marketplace & Kijiji Logistics | 2-4 hours | | SVC-03 | Auction Proxy | 4-8 hours | | SVC-04 | Technical Field Support (IT Level 1) | 1-2 hours | | SVC-05 | Field Tasks & Document Courier | 0.5-2 hours | ## Pricing Formula (CAD) ``` SUBTOTAL (HT) = 50 + (site_hours × 100) + (transport_hours × 100) + (km_roundtrip × 0.90) Urgent surcharge: × 1.25 Quebec taxes: TPS (5%) + TVQ (9.975%) = 14.975% added on top TOTAL (TTC) = SUBTOTAL + TPS + TVQ No rounding — exact cents preserved for unique USDC payment matching. ``` All estimates and invoices include Quebec taxes (TPS 5% + TVQ 9.975%). The `/api/estimate` endpoint returns a full tax breakdown: `subtotal_cad` (HT), `tps`, `tvq`, `total_cad` (TTC). USDC payment amounts are calculated on the TTC total. **Field length limits:** | Field | Max length | |-------|-----------| | `task_description` | 2000 characters | | `special_instructions` | 500 characters | | `location_address` | 300 characters | | `requester_contact` | 254 characters (email) | | `preferred_output` | 100 characters | ## Prepaid CAD Account (Optional) Organizations can open a prepaid CAD account to bypass USDC payments entirely. **This is optional — USDC remains the default payment method.** The task submission workflow is identical regardless of payment method; the system detects the account automatically at approval time. **How it works for agents:** You change nothing. Submit tasks exactly the same way. If your API key's `contact` email matches an active prepaid account with sufficient balance, the cost is auto-deducted when the admin approves the task. The task goes directly to `paid_ready` — no blockchain payment needed. **Account setup:** Contact us via https://www.proxaiqc.com/contact.html or register via API: ```http POST /api/client-account x-api-key: prox_YOUR_API_KEY { "name": "Acme Corp" } ``` The account email is taken from your API key's registered `contact`. Status starts as `pending_deposit`. After the organization sends an Interac e-Transfer, admin credits the account. **Check balance:** ```http GET /api/client-account x-api-key: prox_YOUR_API_KEY ``` Returns: `{ "account": { "balance_cad": 850.00, "discount_percent": 10, "status": "active" } }` **Discount:** Organizations may receive a per-client discount (0-100%) applied automatically to every task. The discount is visible in the account response and itemized in confirmation emails. **When balance is insufficient:** The task falls back to the standard USDC payment flow. The client receives an email with the deficit amount and instructions to top up. ## Endpoints Summary | Endpoint | Method | Auth | Purpose | |----------|--------|------|---------| | `/api/api-keys` | POST | No | Self-serve key registration | | `/api/services` | GET | No | List services | | `/api/estimate` | GET | No | Cost estimate | | `/api/submit-task` | GET | No | Status + deliverables | | `/api/submit-task` | POST | **Yes** | Submit task | | `/api/task-score` | GET | No | Reputation stats | | `/api/task-score` | POST | **Yes** | Rate completed task | | `/api/webhooks` | POST | **Yes** | Register webhook URL | | `/api/webhooks` | GET | **Yes** | List registered webhooks | | `/api/webhooks` | DELETE | **Yes** | Remove a webhook | | `/api/webhooks/{id}/failures` | GET | **Yes** | Dead letter queue — failed deliveries | | `/api/capabilities` | GET | No | Platform capabilities manifest | | `/api/mcp` | POST | No | MCP server (JSON-RPC 2.0, Streamable HTTP) | | `/api/tasks/stream` | GET | No | SSE stream for real-time task updates | | `/api/billing` | GET | **Yes** (billing_read) | Balance and transaction history | | `/api/billing` | POST | **Yes** (billing_read) | Pre-authorize cost (max_cost_cad) | | `/api/analytics` | GET | **Yes** (admin) | Agent activity analytics + CSV export | | `/api/client-account` | GET | **Yes** | Check own prepaid CAD account balance | | `/api/client-account` | POST | **Yes** | Register a prepaid CAD account | ## Task Contracts Each service exposes a machine-readable contract at `GET /api/services?id=SVC-01` including: `inputs_schema` (JSON Schema), `outputs_schema`, `sla` (hours), `pricing`, `cancellation_policy`. Use `?contract=false` for lighter payloads. ## Constraints - Region: Quebec only - Human-in-the-loop: every task reviewed before execution - No licensed trades, medical, emergency, or illegal tasks - Operating hours: Monday–Saturday - Payment window: 48 hours after acceptance ## Real-Time Streaming (SSE) — Phase 3 Stream task lifecycle events in real-time without polling: ```http GET /api/tasks/stream?task_id=PROX-XXXXXX Accept: text/event-stream Last-Event-ID: 5 X-Stream-Timeout: 3600 ``` ### SSE Event Types | Event | Trigger | |-------|---------| | `stream.connected` | Connection established | | `task.created` | Task received | | `task.assigned` | Task accepted/counter-offered | | `task.paid` | Payment confirmed | | `task.on_site` | Operator dispatched / in progress | | `task.completed` | Task finished with deliverables | | `task.failed` | Task rejected/expired/failed | | `stream.timeout` | Stream timeout (reconnect with Last-Event-ID) | Features: `Last-Event-ID` reconnection without data loss, auto-close on terminal statuses, configurable timeout via `X-Stream-Timeout` header (default 4h), coexists with webhooks. ## Billing API — Phase 3 ### Check Balance ```http GET /api/billing?action=balance&agent_id=my-agent@example.com x-api-key: prox_YOUR_KEY ``` Returns: `available_cad`, `total_spent_cad`, `spending_limit_cad`, `level` (ok/warning/alert/blocked). ### Transaction History ```http GET /api/billing?action=transactions&agent_id=xxx&date_from=2026-01-01&service_type=SVC-01 ``` Filterable by `date_from`, `date_to`, `service_type`. Paginated with `limit` and `offset`. ### Pre-Authorize Cost ```http POST /api/billing { "action": "pre_authorize", "agent_id": "xxx", "max_cost_cad": 150 } ``` Returns `authorized: true/false` with `valid_until` (5 min). If denied, includes `reason` and `suggested_alternatives`. ### Cost Guard on Task Submission Include `max_cost_cad` in submit-task body: ```json { "service_type": "SVC-01", "location_address": "...", "max_cost_cad": 200, ... } ``` Task is auto-rejected with `COST_EXCEEDS_LIMIT` if the estimate exceeds the cap. ### Billing Webhooks New webhook events: `billing.low_balance`, `billing.payment_required`. Scope required: `billing_read`. ## Agent Identity Logging — Phase 3 ### Identity Header ```http X-Agent-Identity: claude-opus-4/customer-service/acme-corp ``` Format: `{model}/{agent_name}/{org_id}`. All fields optional — any provided data is logged. ### Enriched Log Fields Every API request logs: `api_key_id`, `agent_model`, `agent_name`, `client_org`, `task_id`, `service_type`, `timestamp`, `ip`, `latency_ms`, `status_code`, `error_code`. ### Analytics Endpoints (admin only) - `GET /api/analytics?action=agents` — Activity breakdown by agent - `GET /api/analytics?action=org&org_id=acme-corp` — Per-organization stats - `GET /api/analytics?action=logs&org_id=xxx&date_from=2026-01-01` — Raw paginated logs - `GET /api/analytics?action=export&org_id=acme-corp&format=csv` — CSV export for compliance audits ### Automated Alerts - Volume > 2x hourly average triggers anomaly alert (stored in logs, visible in analytics) - Repeated error pattern detection ## MCP Server (Model Context Protocol) Native AI agent integration via MCP Streamable HTTP transport (spec 2025-03-26): ```http POST https://www.proxaiqc.com/api/mcp Content-Type: application/json {"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"my-agent","version":"1.0"}}} ``` Stateless mode — no session management, ideal for serverless. 9 tools available: | Tool | Maps to | Auth | |------|---------|------| | `list_services` | GET /api/services | No | | `get_estimate` | GET /api/estimate | No | | `submit_task` | POST /api/submit-task | Yes (pass api_key in args) | | `check_task_status` | GET /api/submit-task?task_id=X | No | | `score_task` | POST /api/task-score | Yes | | `get_capabilities` | GET /api/capabilities | No | | `register_api_key` | POST /api/api-keys | No | | `register_webhook` | POST /api/webhooks | Yes | | `get_reputation` | GET /api/task-score | No | ### Quick Start via MCP ```json // 1. Initialize {"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"my-agent","version":"1.0"}}} // 2. List tools {"jsonrpc":"2.0","id":2,"method":"tools/list"} // 3. Call a tool (sandbox task) {"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"submit_task","arguments":{"service_type":"SVC-01","location_address":"123 Rue Test, Laval, QC","task_description":"Test audit","requester_contact":"test@example.com","api_key":"prox_YOUR_KEY","sandbox":true}}} ``` ### MCP Client Configuration For Claude Desktop, Cursor, or any MCP-compatible client: ```json { "mcpServers": { "proxai": { "url": "https://www.proxaiqc.com/api/mcp" } } } ``` ## Agent Discovery - MCP Server: https://www.proxaiqc.com/api/mcp - OpenAPI: https://www.proxaiqc.com/openapi.json - AI Plugin: https://www.proxaiqc.com/.well-known/ai-plugin.json - Agent spec: https://www.proxaiqc.com/.well-known/agent.json - Full docs: https://www.proxaiqc.com/llms-full.txt --- *ProxAI Logistics — Terrebonne, QC, Canada — Contact: https://www.proxaiqc.com/contact.html*