---
name: xagent-core
version: "0.5.0"
description: XAgent Pay Core — HTTP REST API for x402 gasless payments, NUPS multi-merchant escrow, and ERC-8183 Agentic Commerce jobs
protocol: NUPS/1.5 + x402 + ERC-8183
category: finance.payment
currencies: [USDG, USDT]
chain_id: 196
payment_methods: [DIRECT_TRANSFER, ESCROW_CONTRACT, ACP_JOB]
---

# XAgent Pay Core — HTTP REST API

**Pay for merchant orders in a single aggregated transaction via HTTP.** No MCP client required — all functionality is available as standard REST endpoints.

> For MCP tool definitions and connection config, see [skill.md](https://api.xagentgo.com/skill.md).

**Base URL:** `https://api.xagentgo.com`

## Step 1 — Orchestrate Payment

Submit all merchant quotes + user wallet to create a payment group.

```bash
curl -X POST https://api.xagentgo.com/api/orchestrate \
  -H "Content-Type: application/json" \
  -d '{
    "quotes": [
      {
        "merchant_did": "did:xagent:196:demo_flight",
        "merchant_order_ref": "FLT-001",
        "amount": "100000",
        "currency": "USDG",
        "chain_id": 196,
        "expiry": 9999999999,
        "context": {"summary": "Flight SFO-LAX", "line_items": []},
        "signature": "0x..."
      }
    ],
    "payer_wallet": "0xYourWalletAddress"
  }'
```

### How to extract quotes from merchant responses

The quote you need is at:
`response.ucp.payment_handlers["urn:ucp:payment:xagent_v1"][0].config`

Required fields: `merchant_did`, `merchant_order_ref`, `amount`, `currency`, `chain_id`, `expiry`, `context`, `signature`.

### Response (HTTP 402)

The response body always wraps a single `instruction` object, but the **shape of `instruction` depends on `instruction.payment_method`**. XAgent Pay Core auto-selects the method:

- **Single-merchant** group → `DIRECT_TRANSFER` (x402 gasless; relayer pays gas)
- **Multi-merchant** group → `ESCROW_CONTRACT` (NUPS; user pays gas)
- **Merchant enrolled in ERC-8183 or quote sets `payment_method: "ACP_JOB"`** → `ACP_JOB`

**Common top-level fields:**

| Field | Description |
|-------|-------------|
| `http_status` | HTTP status code mirrored in response body (e.g. `402`). Present in **all** JSON responses. |
| `checkout_url` | Token-protected URL (valid 1 hour). Open in a browser for interactive MetaMask checkout. |
| `instruction.payment_method` | `"DIRECT_TRANSFER"` \| `"ESCROW_CONTRACT"` \| `"ACP_JOB"` — branch on this. |
| `instruction.chain_id` / `chain_name` / `rpc_url` / `token_address` / `total_amount_*` | Always present. |

#### Shape A — `DIRECT_TRANSFER` (x402 gasless)

```json
{
  "instruction": {
    "payment_method": "DIRECT_TRANSFER",
    "token_address": "0x4ae46a509f6b1d9056937ba4500cb143933d2dc8",
    "token_symbol": "USDG",
    "token_decimals": 6,
    "total_amount_uint256": "1200000",
    "pay_to": "0xMerchantAddress",
    "payments": [{ "xagent_payment_id": "PAY-...", "merchant_did": "did:xagent:...", "amount_uint256": "1200000", "summary": "..." }],
    "eip3009": {
      "domain": { "name": "Global Dollar", "version": "1", "chainId": 196, "verifyingContract": "0x4ae4..." },
      "message": { "from": "0xPayer", "to": "0xMerchant", "value": "1200000", "valid_after": "0", "valid_before": "<unix+1800>", "nonce": "0x..." }
    },
    "user_action": "SIGN_EIP3009",
    "gas_paid_by": "RELAYER"
  }
}
```

> **EIP-712 domain name is `"Global Dollar"` for USDG and `"USD₮0"` for USDT.** Use `token_symbol` + `eip3009.domain.name` from the instruction verbatim; signing with any other string will revert on-chain with an invalid-signature error.

#### Shape B — `ESCROW_CONTRACT` (NUPS multi-merchant)

```json
{
  "instruction": {
    "payment_method": "ESCROW_CONTRACT",
    "escrow_contract": "0x959028964e8a4e52d6AC716E621B68b3fa579A25",
    "token_address": "0x4ae46a509f6b1d9056937ba4500cb143933d2dc8",
    "total_amount_uint256": "100000",
    "payments": [
      {
        "xagent_payment_id": "PAY-...",
        "merchant_did": "did:xagent:196:demo_flight",
        "merchant_order_ref": "FLT-001",
        "merchant_address": "0x...",
        "amount_uint256": "100000",
        "payment_id_bytes32": "0x...",
        "order_ref_bytes32": "0x...",
        "merchant_did_bytes32": "0x...",
        "context_hash": "0x..."
      }
    ],
    "approve_tx": { "to": "0x4ae4...", "abi": "function approve(address,uint256)", "value": "0", "gas_limit": "100000" },
    "deposit_tx": { "to": "0x9590...", "abi": "function batchDepositApprove(...)", "value": "0", "gas_limit": "350000" },
    "user_action": "SIGN_AND_SEND",
    "gas_paid_by": "USER",
    "xagent_group_sig": "0x...EIP-712 signature...",
    "core_operator_address": "0x..."
  },
  "xagent_group_sig": "0x...EIP-712 signature...",
  "core_operator_address": "0x..."
}
```

> **Two transactions required:** first `approve_tx` (USDG → escrow allowance), then `deposit_tx` (`batchDepositApprove`). The legacy `batchDepositWithAuthorization` ABI is also available but not the default — `batchDepositApprove` works with both USDG and USDT on XLayer.

#### Shape C — `ACP_JOB` (ERC-8183 Agentic Commerce)

```json
{
  "instruction": {
    "payment_method": "ACP_JOB",
    "acp_contract": "0xACP_CONTRACT_ADDR",
    "token_address": "0x4ae46a509f6b1d9056937ba4500cb143933d2dc8",
    "total_amount_uint256": "1200000",
    "approve_tx": { "to": "0x4ae4...", "abi": "function approve(address,uint256)", "value": "0", "gas_limit": "100000" },
    "jobs": [
      {
        "xagent_payment_id": "PAY-...",
        "merchant_did": "did:xagent:196:demo_flight",
        "provider_address": "0xMerchant",
        "evaluator_address": "0xAutoEvaluator",
        "amount_uint256": "1200000",
        "expired_at": 9999999999,
        "description_json": "{\"merchant_did\":\"...\",\"order_ref\":\"...\",\"summary\":\"...\"}"
      }
    ],
    "user_action": "SIGN_AND_SEND",
    "gas_paid_by": "USER"
  }
}
```

> **N+1 transactions:** first `approve_tx`, then one `createAndFund(...)` per job on the ACP contract. After funding, the merchant submits a `deliverable` → the Evaluator auto-completes and releases funds.

**ESCROW_CONTRACT-only fields:**

| Field | Description |
|-------|-------------|
| `instruction.payments[].payment_id_bytes32` | Precomputed `keccak256(xagent_payment_id)` for on-chain `BatchEntry` |
| `instruction.payments[].context_hash` | Precomputed `keccak256(JSON.stringify(context))` — matches on-chain exactly |
| `instruction.xagent_group_sig` | EIP-712 signature over `(groupId, entriesHash, totalAmount)` by XAgent Pay Core operator |
| `instruction.core_operator_address` | Address of the signing operator — verify before submitting |

## Step 2 — Pay

The 402 response provides **two ways to execute the instruction**:

**Path A — Checkout URL (recommended for human users):**
Direct the user to open `checkout_url` in their browser. The checkout page auto-detects the `payment_method`, handles MetaMask wallet connection, chain switching, EIP-712 / EIP-3009 signing, and transaction submission.

**Path B — Programmatic (for capable agents):**
Branch on `instruction.payment_method`:

- **`DIRECT_TRANSFER`** — sign `instruction.eip3009` via `eth_signTypedData_v4`, POST the signature to `/api/checkout/:token/confirm-x402`. Relayer settles on-chain.
- **`ESCROW_CONTRACT`** — verify `xagent_group_sig`/`core_operator_address`, then submit `approve_tx` followed by `deposit_tx`. Both paid by the user.
- **`ACP_JOB`** — submit `approve_tx`, then one `createAndFund(...)` tx per entry in `instruction.jobs[]`. Capture each `jobId` from the `JobCreated` event, POST `{job_ids, tx_hashes}` to `/api/checkout/:token/confirm-acp`.

## Step 3 — Confirm Transaction

| Route | Confirmation endpoint | Body |
|-------|----------------------|------|
| `DIRECT_TRANSFER` | `POST /api/checkout/:token/confirm-x402` | `{ "signature": "0x..." }` |
| `ESCROW_CONTRACT` | `POST /api/checkout/:token/confirm` | `{ "tx_hash": "0x..." }` |
| `ACP_JOB` | `POST /api/checkout/:token/confirm-acp` | `{ "job_ids": ["1","2",...], "tx_hashes": ["0x...","0x..."] }` |

```bash
# ESCROW_CONTRACT example
curl -X POST https://api.xagentgo.com/api/checkout/tok_.../confirm \
  -H "Content-Type: application/json" \
  -d '{"tx_hash": "0x..."}'
```

## Step 4 — Track Status

```bash
curl "https://api.xagentgo.com/api/payments?group_id=grp_..."
```

Status lifecycle depends on `payment_method`:

| Route | Lifecycle |
|-------|-----------|
| `DIRECT_TRANSFER` | `CREATED → X402_SIGNED → SETTLED → COMPLETED` |
| `ESCROW_CONTRACT` | `CREATED → ESCROWED → SETTLED → COMPLETED` |
| `ACP_JOB` | `CREATED → JOB_FUNDED → JOB_SUBMITTED → JOB_COMPLETED` |

## API Reference

| Endpoint | Method | Description |
|----------|--------|-------------|
| `/api/orchestrate` | POST | Create payment group (returns HTTP 402) |
| `/api/checkout/:token` | GET | Get payment group details |
| `/api/checkout/:token/confirm` | POST | Confirm on-chain transaction |
| `/api/payments/:id` | GET | Payment status by XAgent Pay payment ID |
| `/api/payments?group_id=...` | GET | Payment status by group ID |
| `/api/payments?merchant_order_ref=...` | GET | Payment status by merchant order ref |
| `/api/agents` | GET | Discover merchant agents |
| `/api/agents?query=...&category=...` | GET | Search agents by keyword/category |
| `/api/agents/:did/skill` | GET | Fetch agent's skill.md content |
| `/checkout/:token` | GET | Browser checkout page (MetaMask) |
| `/health` | GET | Health check |
| `/api/health` | GET | Detailed health (relayer balance, services) |

### `GET /api/checkout/:token` — Payment Group Details

Retrieve group, payments, and instruction for a checkout token. The `:token` can be a `tok_...` token (from `checkout_url`) or a direct `grp_...` / `GRP-...` group ID.

```bash
curl https://api.xagentgo.com/api/checkout/tok_abc123...
```

### `GET /checkout/:token` — Browser Checkout Page

Open in browser for MetaMask-powered interactive checkout. The checkout page handles wallet connection, chain switching, EIP-3009 signing, and transaction submission.

```
https://api.xagentgo.com/checkout/tok_abc123...
```

> **Note:** Checkout URLs expire after 1 hour. If expired, the user must re-orchestrate to get a new URL.

### `GET /api/payments/:id` — Payment Status

Query payment status by XAgent Pay payment ID:

```bash
curl https://api.xagentgo.com/api/payments/PAY-xxx
```

Response (HTTP 200):
```json
{
  "http_status": 200,
  "payment": {
    "xagent_payment_id": "PAY-xxx",
    "status": "ESCROWED",
    "amount_display": "0.10",
    "currency": "USDG",
    "merchant_did": "did:xagent:...",
    "merchant_order_ref": "FLT-123",
    "tx_hash": "0x..."
  },
  "group": {
    "group_id": "grp_xxx",
    "status": "GROUP_ESCROWED",
    "total_amount_display": "0.10",
    "payment_count": 1
  },
  "group_payments": [
    { "xagent_payment_id": "PAY-xxx", "status": "ESCROWED", "amount_display": "0.10" }
  ]
}
```

### `GET /api/agents` — Discover Merchant Agents

Search and discover merchant agents. No authentication required.

```bash
curl "https://api.xagentgo.com/api/agents"
curl "https://api.xagentgo.com/api/agents?query=flight&category=travel&limit=10"
```

Response (HTTP 200):
```json
{
  "http_status": 200,
  "agents": [
    {
      "merchant_did": "did:xagent:196:demo_flight",
      "name": "Demo Flight Agent",
      "description": "Book flights with USDG",
      "category": "travel.flights",
      "mcp_endpoint": "https://xagentgo.com/flight/mcp",
      "skill_md_url": "https://xagentgo.com/flight/skill.md",
      "currencies": ["USDG", "USDT"],
      "health_status": "ONLINE",
      "stars": 5,
      "tools": [{ "name": "xagent_generate_quote", "role": "quote" }]
    }
  ],
  "total": 1,
  "limit": 20
}
```

### `GET /api/agents/:did/skill` — Agent Skill File

Fetch the full skill.md content for a specific merchant agent. Returns `text/markdown`.

```bash
curl https://api.xagentgo.com/api/agents/did:xagent:196:demo_flight/skill
```

### Rate Limits

All HTTP endpoints are rate-limited per IP address (30 requests/minute burst, ~0.5/sec sustained). Rate limit headers are included in every response:

```
X-RateLimit-Limit: 30
X-RateLimit-Remaining: 28
X-RateLimit-Reset: 1709712460
```

## Security

### Group Signature (`xagent_group_sig`)

Every `BatchDepositInstruction` includes an EIP-712 signature from the XAgent Pay Core operator over `XAgent PayGroupApproval(groupId, entriesHash, totalAmount)`. This prevents MITM tampering of the payments array (merchant addresses and amounts). Clients should verify `xagent_group_sig` and `core_operator_address` before submitting transactions.

### Precomputed Hashes

All `bytes32` fields in `GroupPaymentDetail` (`payment_id_bytes32`, `order_ref_bytes32`, `merchant_did_bytes32`, `context_hash`) are precomputed on the server using `keccak256`. Clients use these directly when building on-chain calldata, eliminating hash mismatch bugs between server and client.

### Token-Protected Checkout URLs

Checkout URLs use short-lived tokens (`tok_...`) instead of raw group IDs. Tokens expire after 1 hour and are single-use. Direct `grp_` / `GRP-` IDs are still accepted as fallback.

## Contracts

- **NexusPay Escrow Proxy (UUPS):** `0x959028964e8a4e52d6AC716E621B68b3fa579A25` — `ESCROW_CONTRACT` route, `batchDepositApprove`.
- **USDG (Global Dollar):** `0x4ae46a509f6b1d9056937ba4500cb143933d2dc8` — `name() = "Global Dollar"`, `version() = "1"`. **EIP-712 domain `name` must be `"Global Dollar"`** or EIP-3009 signatures will revert with an invalid-signature error.
- **USDT (USD₮0):** also supported as a secondary payment asset. The EIP-712 domain name is `"USD₮0"`.
- **AgenticCommerce / AutoEvaluator:** environment-injected for the `ACP_JOB` route; see `instruction.acp_contract`.
- **Chain:** XLayer Mainnet (chainId `196`)
- **RPC:** `https://rpc.xlayer.tech`
- **Explorer:** `https://www.oklink.com/xlayer`

> The `DIRECT_TRANSFER` path has no XAgent contract — settlement happens directly on the USDG (or USDT) contract via `transferWithAuthorization`, with the relayer paying gas.
