{
  "openapi": "3.1.0",
  "info": {
    "title": "NERO Paymaster JSON-RPC API",
    "version": "1.0.0",
    "summary": "Gas abstraction for NERO Chain via ERC-4337 paymasters.",
    "description": "The NERO Paymaster API is a JSON-RPC 2.0 service that lets dApps sponsor user\ngas fees or let users pay gas in any supported ERC-20 token. It runs on top\nof ERC-4337 and cooperates with the EntryPoint contract deployed at\n`0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789` on NERO Chain.\n\n## Payment types\n\n- **Type 0 — Sponsored**: developer pays gas from their AA Platform balance.\n- **Type 1 — Prepay ERC-20**: user pays in an ERC-20 token up-front, with a\n  refund for any surplus.\n- **Type 2 — Postpay ERC-20**: user pays in an ERC-20 token for the exact\n  gas consumed, settled after execution.\n\n## Authentication\n\nLong-lived API key sent as `X-API-Key` header. Keys are issued through the\n[AA Platform dashboard](https://aa-platform.nerochain.io). Never ship the\nAPI key in client-side code. See the\n[Agent Auth Guide](https://docs.nerochain.io/en/agent-auth) for the full\nprogrammatic flow.\n\n## Rate limits\n\nPer-project limits are configured in the AA Platform dashboard:\n\n| Limit | Default |\n|---|---|\n| Daily gas cap | project sponsorship balance |\n| Transactions per minute per sender | 30 |\n| Concurrent in-flight UserOps | 50 |\n| `maxFeePerGas` ceiling | network-derived |\n\nExceeded limits return JSON-RPC error code `-32504` (throttled). Clients\nshould back off exponentially, starting at 1 second.\n\n## Dispatch\n\nAll methods share one HTTP endpoint: `POST /`. For OpenAPI clarity, this\nspec lists one operation per method (dispatched by the `method` field of\nthe request body). The separate `/rpc/pm_…` paths are documentation\naliases; the real endpoint is the server root.\n",
    "termsOfService": "https://nerochain.io/legal",
    "contact": {
      "name": "NERO Chain",
      "url": "https://nerochain.io",
      "email": "contact@nerochain.io"
    },
    "license": {
      "name": "MIT",
      "identifier": "MIT"
    }
  },
  "externalDocs": {
    "description": "NERO Paymaster API documentation",
    "url": "https://docs.nerochain.io/en/developer-tools/paymaster-api"
  },
  "servers": [
    {
      "url": "https://paymaster-testnet.nerochain.io",
      "description": "NERO testnet"
    },
    {
      "url": "https://paymaster-mainnet.nerochain.io",
      "description": "NERO mainnet"
    }
  ],
  "tags": [
    {
      "name": "paymaster",
      "description": "Paymaster JSON-RPC methods"
    }
  ],
  "security": [
    {
      "apiKeyAuth": []
    }
  ],
  "paths": {
    "/": {
      "post": {
        "operationId": "jsonRpcDispatch",
        "tags": [
          "paymaster"
        ],
        "summary": "JSON-RPC dispatch endpoint (any supported method)",
        "description": "Physical endpoint. Send a JSON-RPC 2.0 request with `method` set to one\nof `pm_supported_tokens`, `pm_sponsor_userop`, `pm_entrypoints`. See\nthe per-method operations below for detailed parameter/response shapes.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/JsonRpcRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "JSON-RPC success or error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JsonRpcResponse"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "4XX": {
            "$ref": "#/components/responses/BadRequest"
          },
          "5XX": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/rpc/pm_supported_tokens": {
      "post": {
        "operationId": "pmSupportedTokens",
        "tags": [
          "paymaster"
        ],
        "summary": "List ERC-20 tokens accepted for gas (pm_supported_tokens)",
        "description": "Retrieves the list of ERC-20 tokens supported by the Paymaster for gas\npayments along with current price ratios relative to the native NERO\ntoken. Also reports whether developer-sponsored gas (Type 0) is\ncurrently enabled.\n\n**Documentation alias** — the real endpoint is `POST /` with\n`\"method\": \"pm_supported_tokens\"`.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SupportedTokensRequest"
              },
              "example": {
                "$ref": "#/components/examples/SupportedTokensRequest/value"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Supported tokens.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SupportedTokensResponse"
                },
                "example": {
                  "$ref": "#/components/examples/SupportedTokensResponse/value"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "4XX": {
            "$ref": "#/components/responses/BadRequest"
          },
          "5XX": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/rpc/pm_sponsor_userop": {
      "post": {
        "operationId": "pmSponsorUserOp",
        "tags": [
          "paymaster"
        ],
        "summary": "Sign a UserOperation with the Paymaster (pm_sponsor_userop)",
        "description": "Signs a UserOperation with the Paymaster, adding the `paymasterAndData`\nfield required for sponsored or token-paid transactions.\n\nThe `context` object selects the payment type: `{\"type\": 0}` for\ndeveloper-sponsored (free) gas, `{\"type\": 1, \"token\": \"0x…\"}` for\nprepay-in-ERC-20 with automatic refund, `{\"type\": 2, \"token\": \"0x…\"}`\nfor postpay-in-ERC-20 settled after execution.\n\n**Documentation alias** — the real endpoint is `POST /` with\n`\"method\": \"pm_sponsor_userop\"`.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SponsorUserOpRequest"
              },
              "example": {
                "$ref": "#/components/examples/SponsorFreeRequest/value"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Signed UserOperation with paymasterAndData populated.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SponsorUserOpResponse"
                },
                "example": {
                  "$ref": "#/components/examples/SponsorResponse/value"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "4XX": {
            "$ref": "#/components/responses/BadRequest"
          },
          "5XX": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/rpc/pm_entrypoints": {
      "post": {
        "operationId": "pmEntrypoints",
        "tags": [
          "paymaster"
        ],
        "summary": "List supported EntryPoint contract addresses (pm_entrypoints)",
        "description": "Returns the EntryPoint contract addresses currently supported by this\nPaymaster. For NERO mainnet and testnet this is\n`0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789`.\n\n**Documentation alias** — the real endpoint is `POST /` with\n`\"method\": \"pm_entrypoints\"`.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EntrypointsRequest"
              },
              "example": {
                "$ref": "#/components/examples/EntrypointsRequest/value"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "List of EntryPoint addresses.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EntrypointsResponse"
                },
                "example": {
                  "$ref": "#/components/examples/EntrypointsResponse/value"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "4XX": {
            "$ref": "#/components/responses/BadRequest"
          },
          "5XX": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "apiKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key",
        "description": "API key issued by the AA Platform dashboard. Some SDK clients pass the\nAPI key as the second JSON-RPC parameter instead of as a header; both\nforms are accepted.\n"
      }
    },
    "schemas": {
      "Hex": {
        "type": "string",
        "pattern": "^0x[0-9a-fA-F]*$",
        "description": "Hex-encoded byte string."
      },
      "Address": {
        "type": "string",
        "pattern": "^0x[0-9a-fA-F]{40}$",
        "description": "Ethereum-format address.",
        "examples": [
          "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789"
        ]
      },
      "UserOperation": {
        "type": "object",
        "description": "ERC-4337 UserOperation.",
        "required": [
          "sender",
          "nonce",
          "initCode",
          "callData",
          "callGasLimit",
          "verificationGasLimit",
          "preVerificationGas",
          "maxFeePerGas",
          "maxPriorityFeePerGas",
          "paymasterAndData",
          "signature"
        ],
        "properties": {
          "sender": {
            "$ref": "#/components/schemas/Address"
          },
          "nonce": {
            "$ref": "#/components/schemas/Hex"
          },
          "initCode": {
            "$ref": "#/components/schemas/Hex"
          },
          "callData": {
            "$ref": "#/components/schemas/Hex"
          },
          "callGasLimit": {
            "$ref": "#/components/schemas/Hex"
          },
          "verificationGasLimit": {
            "$ref": "#/components/schemas/Hex"
          },
          "preVerificationGas": {
            "$ref": "#/components/schemas/Hex"
          },
          "maxFeePerGas": {
            "$ref": "#/components/schemas/Hex"
          },
          "maxPriorityFeePerGas": {
            "$ref": "#/components/schemas/Hex"
          },
          "paymasterAndData": {
            "$ref": "#/components/schemas/Hex"
          },
          "signature": {
            "$ref": "#/components/schemas/Hex"
          }
        }
      },
      "SponsorContext": {
        "type": "object",
        "required": [
          "type"
        ],
        "description": "Payment selector passed as the fourth parameter to pm_sponsor_userop.",
        "properties": {
          "type": {
            "type": "integer",
            "enum": [
              0,
              1,
              2
            ],
            "description": "0 = developer-sponsored (free gas).\n1 = user prepays gas in an ERC-20 token; excess refunded.\n2 = user pays exactly the gas consumed in an ERC-20 token (postpay).\n"
          },
          "token": {
            "$ref": "#/components/schemas/Address",
            "description": "ERC-20 token address. Required for `type=1` and `type=2`."
          }
        }
      },
      "JsonRpcRequest": {
        "type": "object",
        "required": [
          "jsonrpc",
          "id",
          "method",
          "params"
        ],
        "description": "Generic JSON-RPC 2.0 request envelope dispatched by method name.",
        "properties": {
          "jsonrpc": {
            "type": "string",
            "const": "2.0"
          },
          "id": {
            "description": "Client-chosen request identifier echoed back in the response.",
            "oneOf": [
              {
                "type": "integer"
              },
              {
                "type": "string"
              }
            ]
          },
          "method": {
            "type": "string",
            "enum": [
              "pm_supported_tokens",
              "pm_sponsor_userop",
              "pm_entrypoints"
            ]
          },
          "params": {
            "type": "array",
            "items": {},
            "description": "Positional parameters. Shape depends on method; see per-method schemas."
          }
        }
      },
      "SupportedTokensRequest": {
        "type": "object",
        "required": [
          "jsonrpc",
          "id",
          "method",
          "params"
        ],
        "properties": {
          "jsonrpc": {
            "type": "string",
            "const": "2.0"
          },
          "id": {
            "oneOf": [
              {
                "type": "integer"
              },
              {
                "type": "string"
              }
            ]
          },
          "method": {
            "type": "string",
            "const": "pm_supported_tokens"
          },
          "params": {
            "type": "array",
            "items": {},
            "minItems": 3,
            "maxItems": 3,
            "description": "[UserOperation, apiKey, entryPoint]",
            "prefixItems": [
              {
                "$ref": "#/components/schemas/UserOperation"
              },
              {
                "type": "string",
                "description": "API key from AA Platform"
              },
              {
                "$ref": "#/components/schemas/Address",
                "description": "EntryPoint address"
              }
            ]
          }
        }
      },
      "SupportedTokensResult": {
        "type": "object",
        "required": [
          "freeGas",
          "native",
          "tokens"
        ],
        "properties": {
          "freeGas": {
            "type": "boolean",
            "description": "Whether Type 0 sponsorship is currently enabled for this project."
          },
          "native": {
            "type": "object",
            "required": [
              "gas",
              "price",
              "decimals",
              "symbol"
            ],
            "properties": {
              "gas": {
                "$ref": "#/components/schemas/Hex"
              },
              "price": {
                "type": "number"
              },
              "decimals": {
                "type": "integer"
              },
              "symbol": {
                "type": "string"
              }
            }
          },
          "tokens": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "type",
                "token",
                "symbol",
                "decimals",
                "price"
              ],
              "properties": {
                "type": {
                  "type": "string",
                  "enum": [
                    "system",
                    "custom"
                  ]
                },
                "token": {
                  "$ref": "#/components/schemas/Address"
                },
                "symbol": {
                  "type": "string"
                },
                "decimals": {
                  "type": "integer"
                },
                "price": {
                  "type": "number"
                }
              }
            }
          }
        }
      },
      "SupportedTokensResponse": {
        "type": "object",
        "required": [
          "jsonrpc",
          "id"
        ],
        "properties": {
          "jsonrpc": {
            "type": "string",
            "const": "2.0"
          },
          "id": {
            "oneOf": [
              {
                "type": "integer"
              },
              {
                "type": "string"
              }
            ]
          },
          "result": {
            "$ref": "#/components/schemas/SupportedTokensResult"
          },
          "error": {
            "$ref": "#/components/schemas/JsonRpcErrorObject"
          }
        }
      },
      "SponsorUserOpRequest": {
        "type": "object",
        "required": [
          "jsonrpc",
          "id",
          "method",
          "params"
        ],
        "properties": {
          "jsonrpc": {
            "type": "string",
            "const": "2.0"
          },
          "id": {
            "oneOf": [
              {
                "type": "integer"
              },
              {
                "type": "string"
              }
            ]
          },
          "method": {
            "type": "string",
            "const": "pm_sponsor_userop"
          },
          "params": {
            "type": "array",
            "items": {},
            "minItems": 4,
            "maxItems": 4,
            "description": "[UserOperation, apiKey, entryPoint, context]",
            "prefixItems": [
              {
                "$ref": "#/components/schemas/UserOperation"
              },
              {
                "type": "string",
                "description": "API key from AA Platform"
              },
              {
                "$ref": "#/components/schemas/Address",
                "description": "EntryPoint address"
              },
              {
                "$ref": "#/components/schemas/SponsorContext"
              }
            ]
          }
        }
      },
      "SponsorUserOpResponse": {
        "type": "object",
        "required": [
          "jsonrpc",
          "id"
        ],
        "properties": {
          "jsonrpc": {
            "type": "string",
            "const": "2.0"
          },
          "id": {
            "oneOf": [
              {
                "type": "integer"
              },
              {
                "type": "string"
              }
            ]
          },
          "result": {
            "$ref": "#/components/schemas/UserOperation"
          },
          "error": {
            "$ref": "#/components/schemas/JsonRpcErrorObject"
          }
        }
      },
      "EntrypointsRequest": {
        "type": "object",
        "required": [
          "jsonrpc",
          "id",
          "method"
        ],
        "properties": {
          "jsonrpc": {
            "type": "string",
            "const": "2.0"
          },
          "id": {
            "oneOf": [
              {
                "type": "integer"
              },
              {
                "type": "string"
              }
            ]
          },
          "method": {
            "type": "string",
            "const": "pm_entrypoints"
          },
          "params": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Empty array or `[\"entryPoint\"]`."
          }
        }
      },
      "EntrypointsResponse": {
        "type": "object",
        "required": [
          "jsonrpc",
          "id"
        ],
        "properties": {
          "jsonrpc": {
            "type": "string",
            "const": "2.0"
          },
          "id": {
            "oneOf": [
              {
                "type": "integer"
              },
              {
                "type": "string"
              }
            ]
          },
          "result": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Address"
            }
          },
          "error": {
            "$ref": "#/components/schemas/JsonRpcErrorObject"
          }
        }
      },
      "JsonRpcResponse": {
        "type": "object",
        "required": [
          "jsonrpc",
          "id"
        ],
        "properties": {
          "jsonrpc": {
            "type": "string",
            "const": "2.0"
          },
          "id": {
            "oneOf": [
              {
                "type": "integer"
              },
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "result": {},
          "error": {
            "$ref": "#/components/schemas/JsonRpcErrorObject"
          }
        }
      },
      "JsonRpcErrorObject": {
        "type": "object",
        "required": [
          "code",
          "message"
        ],
        "description": "Standard JSON-RPC 2.0 error object with Paymaster-specific codes.",
        "properties": {
          "code": {
            "type": "integer",
            "description": "Paymaster JSON-RPC error codes:\n- -32521: Transaction reverted (or will revert) during execution.\n- -32602: Invalid UserOperation struct/fields.\n- -32500: Rejected by EntryPoint simulateValidation.\n- -32501: Rejected by paymaster validatePaymasterUserOp.\n- -32502: Rejected due to opcode validation.\n- -32503: UserOperation out of time-range.\n- -32504: Paymaster throttled/banned (rate limit).\n- -32505: Paymaster stake/unstake-delay too low.\n- -32506: Unsupported signature aggregator.\n- -32507: Invalid signature check.\n"
          },
          "message": {
            "type": "string"
          },
          "data": {
            "description": "Implementation-specific diagnostic payload."
          }
        }
      },
      "HttpError": {
        "type": "object",
        "description": "Structured error returned for non-2xx HTTP responses.",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "integer"
              },
              "type": {
                "type": "string"
              },
              "message": {
                "type": "string"
              },
              "resolution": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "Ordered list of suggested remediation steps."
              }
            }
          }
        }
      }
    },
    "responses": {
      "RateLimited": {
        "description": "Rate limit exceeded. Back off exponentially starting at 1 second. Also returned as JSON-RPC code -32504.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/HttpError"
            },
            "example": {
              "error": {
                "code": 429,
                "type": "rate_limited",
                "message": "Paymaster throttled. Retry with exponential backoff.",
                "resolution": [
                  "wait 1s",
                  "retry with jittered backoff up to 3 times",
                  "check AA Platform dashboard for daily cap"
                ]
              }
            }
          }
        }
      },
      "BadRequest": {
        "description": "Invalid request (malformed JSON-RPC envelope, invalid params, or missing API key).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/HttpError"
            },
            "example": {
              "error": {
                "code": 400,
                "type": "invalid_request",
                "message": "Missing X-API-Key header.",
                "resolution": [
                  "include X-API-Key header or pass apiKey as the second JSON-RPC param",
                  "rotate key via AA Platform if expired"
                ]
              }
            }
          }
        }
      },
      "ServerError": {
        "description": "Upstream failure.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/HttpError"
            },
            "example": {
              "error": {
                "code": 500,
                "type": "server_error",
                "message": "Internal paymaster failure.",
                "resolution": [
                  "retry with exponential backoff",
                  "check https://docs.nerochain.io/en/status"
                ]
              }
            }
          }
        }
      }
    },
    "examples": {
      "SupportedTokensRequest": {
        "summary": "List supported gas tokens for a sender.",
        "value": {
          "jsonrpc": "2.0",
          "id": 1,
          "method": "pm_supported_tokens",
          "params": [
            {
              "sender": "0xAABbCc00112233445566778899AaBbCcDdEeFf00",
              "nonce": "0x0",
              "initCode": "0x",
              "callData": "0x",
              "callGasLimit": "0x0",
              "verificationGasLimit": "0x0",
              "preVerificationGas": "0x0",
              "maxFeePerGas": "0x0",
              "maxPriorityFeePerGas": "0x0",
              "paymasterAndData": "0x",
              "signature": "0x"
            },
            "YOUR_API_KEY",
            "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789"
          ]
        }
      },
      "SupportedTokensResponse": {
        "summary": "Supported tokens response.",
        "value": {
          "jsonrpc": "2.0",
          "id": 1,
          "result": {
            "freeGas": true,
            "native": {
              "gas": "0x337dc",
              "price": 1,
              "decimals": 18,
              "symbol": "NERO"
            },
            "tokens": [
              {
                "type": "system",
                "token": "0xD5a6dcff7AC339A03f6964c315575bF65c3c6cF6",
                "symbol": "DAI",
                "decimals": 18,
                "price": 2.1
              },
              {
                "type": "custom",
                "token": "0x13DCf97b6B94bDA883492AB46d556E8919445876",
                "symbol": "TestToken",
                "decimals": 18,
                "price": 0.1
              }
            ]
          }
        }
      },
      "SponsorFreeRequest": {
        "summary": "Sponsor a UserOp (Type 0 — free gas).",
        "value": {
          "jsonrpc": "2.0",
          "id": 1,
          "method": "pm_sponsor_userop",
          "params": [
            {
              "sender": "0xAABbCc00112233445566778899AaBbCcDdEeFf00",
              "nonce": "0x0",
              "initCode": "0x",
              "callData": "0xb61d27f6",
              "callGasLimit": "0x88b8",
              "verificationGasLimit": "0x33450",
              "preVerificationGas": "0xc350",
              "maxFeePerGas": "0x9502f900",
              "maxPriorityFeePerGas": "0x9502f900",
              "paymasterAndData": "0x",
              "signature": "0xdeadbeef"
            },
            "YOUR_API_KEY",
            "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789",
            {
              "type": 0
            }
          ]
        }
      },
      "SponsorResponse": {
        "summary": "Signed UserOperation with paymasterAndData populated.",
        "value": {
          "jsonrpc": "2.0",
          "id": 1,
          "result": {
            "sender": "0xAABbCc00112233445566778899AaBbCcDdEeFf00",
            "nonce": "0x0",
            "initCode": "0x",
            "callData": "0xb61d27f6",
            "callGasLimit": "0x88b8",
            "verificationGasLimit": "0x33450",
            "preVerificationGas": "0xc350",
            "maxFeePerGas": "0x9502f900",
            "maxPriorityFeePerGas": "0x9502f900",
            "paymasterAndData": "0xcafebabecafebabecafebabecafebabecafebabe",
            "signature": "0xdeadbeef"
          }
        }
      },
      "EntrypointsRequest": {
        "summary": "List supported EntryPoint addresses.",
        "value": {
          "jsonrpc": "2.0",
          "id": 1,
          "method": "pm_entrypoints",
          "params": [
            "entryPoint"
          ]
        }
      },
      "EntrypointsResponse": {
        "summary": "EntryPoint addresses response.",
        "value": {
          "jsonrpc": "2.0",
          "id": 1,
          "result": [
            "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789"
          ]
        }
      }
    }
  }
}
