{
  "openapi": "3.1.0",
  "info": {
    "title": "Meridian Protocol API",
    "description": "API for x402 payments",
    "license": {
      "name": "MIT"
    },
    "version": "1.0.0"
  },
  "servers": [
    {
      "url": "https://api.mrdn.finance",
      "description": "Production server"
    }
  ],
  "security": [
    {
      "cookieAuth": []
    },
    {
      "apiKeyAuth": []
    }
  ],
  "paths": {
    "/v1/settle": {
      "post": {
        "summary": "Settle x402 payment",
        "description": "Settle an x402 payment with organization-specific authentication. This endpoint supports standard exact EIP-3009 EVM payloads, Circle Gateway batched payloads, and the Permit2 payload used on non-EIP-3009 EVM networks.",
        "security": [
          {
            "apiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "paymentPayload": {
                    "$ref": "#/components/schemas/SettlePaymentPayload"
                  },
                  "paymentRequirements": {
                    "$ref": "#/components/schemas/PaymentRequirements"
                  }
                },
                "required": [
                  "paymentPayload",
                  "paymentRequirements"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Payment settlement result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SettleResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid payment data"
          },
          "401": {
            "description": "Invalid API key"
          }
        }
      }
    },
    "/v1/verify": {
      "post": {
        "summary": "Verify x402 payment (deprecated)",
        "description": "Deprecated legacy endpoint for verifying an x402 payment with organization-specific authentication",
        "deprecated": true,
        "security": [
          {
            "apiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "paymentPayload": {
                    "$ref": "#/components/schemas/PaymentPayload"
                  },
                  "paymentRequirements": {
                    "$ref": "#/components/schemas/PaymentRequirements"
                  }
                },
                "required": [
                  "paymentPayload",
                  "paymentRequirements"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Legacy payment verification result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VerifyResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid payment data"
          },
          "401": {
            "description": "Invalid API key"
          }
        }
      }
    },
    "/v1/supported": {
      "get": {
        "summary": "Get supported payment kinds",
        "description": "Get list of supported payment types and networks",
        "responses": {
          "200": {
            "description": "Supported payment kinds",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SupportedResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/batched-sample": {
      "get": {
        "summary": "Get Nanopayments Gateway status",
        "description": "Returns Circle Gateway client status, the per-network enablement map, and the upstream `getSupported()` payload from Circle. Useful to confirm Gateway connectivity from your environment.",
        "security": [
          {
            "apiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Gateway status",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BatchedSampleResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key"
          },
          "500": {
            "description": "Internal server error"
          }
        }
      }
    },
    "/v1/permit": {
      "post": {
        "summary": "Execute ERC-20 Permit",
        "description": "Submit a signed EIP-2612 permit and have the facilitator's signer execute `transferWithPermit` on the Meridian Proxy Facilitator contract. The user signs the permit off-chain; the facilitator pays the gas to apply the permit and transfer `value` tokens from `owner` to `recipient`.",
        "security": [
          {
            "apiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PermitRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Permit transaction submitted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PermitResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request, unsupported network, network not configured, or invalid signature",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PermitResponse"
                }
              }
            }
          },
          "500": {
            "description": "Permit execution failed (on-chain submission threw)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PermitResponse"
                }
              }
            }
          }
        }
      },
      "get": {
        "summary": "Describe /v1/permit",
        "description": "Returns a static, self-describing JSON document for `POST /v1/permit` (endpoint, request body fields, and response fields).",
        "responses": {
          "200": {
            "description": "Endpoint description",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PermitDescribeResponse"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "apiKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "Authorization"
      },
      "cookieAuth": {
        "type": "apiKey",
        "in": "cookie",
        "name": "siwe-session"
      }
    },
    "schemas": {
      "SettlePaymentPayload": {
        "description": "Payload accepted by `POST /v1/settle`. Permit2 is currently settle-only; the deprecated `POST /v1/verify` endpoint still uses the legacy `PaymentPayload` schema.",
        "oneOf": [
          {
            "$ref": "#/components/schemas/ExactEvmPaymentPayload"
          },
          {
            "$ref": "#/components/schemas/Permit2PaymentPayload"
          }
        ]
      },
      "PaymentPayload": {
        "description": "Legacy x402 payment payload used by `POST /v1/verify` and by standard EIP-3009 EVM settlement.",
        "oneOf": [
          {
            "$ref": "#/components/schemas/ExactEvmPaymentPayload"
          }
        ]
      },
      "ExactEvmPaymentPayload": {
        "type": "object",
        "required": [
          "x402Version",
          "scheme",
          "network",
          "payload"
        ],
        "properties": {
          "x402Version": {
            "type": "integer",
            "enum": [
              1
            ],
            "example": 1
          },
          "scheme": {
            "type": "string",
            "enum": [
              "exact"
            ],
            "example": "exact"
          },
          "network": {
            "type": "string",
            "example": "base-sepolia"
          },
          "payload": {
            "$ref": "#/components/schemas/ExactEvmPayload"
          }
        }
      },
      "ExactEvmPayload": {
        "type": "object",
        "required": [
          "signature",
          "authorization"
        ],
        "properties": {
          "signature": {
            "type": "string",
            "pattern": "^0x[a-fA-F0-9]+$"
          },
          "authorization": {
            "$ref": "#/components/schemas/ExactEvmAuthorization"
          }
        }
      },
      "ExactEvmAuthorization": {
        "type": "object",
        "required": [
          "from",
          "to",
          "value",
          "validAfter",
          "validBefore",
          "nonce"
        ],
        "properties": {
          "from": {
            "type": "string",
            "pattern": "^0x[a-fA-F0-9]{40}$"
          },
          "to": {
            "type": "string",
            "pattern": "^0x[a-fA-F0-9]{40}$"
          },
          "value": {
            "type": "string",
            "pattern": "^\\d+$"
          },
          "validAfter": {
            "type": "string",
            "pattern": "^\\d+$"
          },
          "validBefore": {
            "type": "string",
            "pattern": "^\\d+$"
          },
          "nonce": {
            "type": "string",
            "pattern": "^0x[a-fA-F0-9]{64}$"
          }
        }
      },
      "Permit2PaymentPayload": {
        "type": "object",
        "description": "Permit2 payload accepted by `POST /v1/settle` for non-EIP-3009 EVM payment tokens.",
        "required": [
          "x402Version",
          "scheme",
          "network",
          "payload"
        ],
        "properties": {
          "x402Version": {
            "type": "integer",
            "enum": [
              1
            ],
            "example": 1
          },
          "scheme": {
            "type": "string",
            "enum": [
              "exact"
            ]
          },
          "network": {
            "type": "string",
            "enum": [
              "megaeth",
              "bot-chain-testnet",
              "bot-chain",
              "bsc"
            ]
          },
          "payload": {
            "$ref": "#/components/schemas/Permit2Payload"
          }
        }
      },
      "Permit2Payload": {
        "type": "object",
        "required": [
          "signature",
          "owner",
          "permit",
          "witness"
        ],
        "properties": {
          "signature": {
            "type": "string",
            "pattern": "^0x[a-fA-F0-9]+$",
            "description": "Permit2 witness signature from the token owner."
          },
          "owner": {
            "type": "string",
            "pattern": "^0x[a-fA-F0-9]{40}$",
            "description": "Token owner address."
          },
          "permit": {
            "$ref": "#/components/schemas/Permit2Transfer"
          },
          "witness": {
            "$ref": "#/components/schemas/Permit2Witness"
          },
          "permit2612": {
            "$ref": "#/components/schemas/Permit2612"
          }
        }
      },
      "Permit2Transfer": {
        "type": "object",
        "required": [
          "permitted",
          "nonce",
          "deadline"
        ],
        "properties": {
          "permitted": {
            "$ref": "#/components/schemas/Permit2TokenPermissions"
          },
          "nonce": {
            "type": "string",
            "pattern": "^\\d+$"
          },
          "deadline": {
            "type": "string",
            "pattern": "^\\d+$"
          }
        }
      },
      "Permit2TokenPermissions": {
        "type": "object",
        "required": [
          "token",
          "amount"
        ],
        "properties": {
          "token": {
            "type": "string",
            "pattern": "^0x[a-fA-F0-9]{40}$"
          },
          "amount": {
            "type": "string",
            "pattern": "^\\d+$"
          }
        }
      },
      "Permit2Witness": {
        "type": "object",
        "required": [
          "to",
          "validAfter"
        ],
        "properties": {
          "to": {
            "type": "string",
            "pattern": "^0x[a-fA-F0-9]{40}$",
            "description": "Meridian facilitator address."
          },
          "validAfter": {
            "type": "string",
            "pattern": "^\\d+$"
          }
        }
      },
      "Permit2612": {
        "type": "object",
        "description": "Optional ERC-2612 permit used to approve Permit2 during first-payment flows.",
        "required": [
          "value",
          "deadline",
          "r",
          "s",
          "v"
        ],
        "properties": {
          "value": {
            "type": "string",
            "pattern": "^\\d+$"
          },
          "deadline": {
            "type": "string",
            "pattern": "^\\d+$"
          },
          "r": {
            "type": "string",
            "pattern": "^0x[a-fA-F0-9]{64}$"
          },
          "s": {
            "type": "string",
            "pattern": "^0x[a-fA-F0-9]{64}$"
          },
          "v": {
            "type": "integer",
            "minimum": 0,
            "maximum": 255
          }
        }
      },
      "PaymentRequirements": {
        "type": "object",
        "required": [
          "scheme",
          "network",
          "maxAmountRequired",
          "resource",
          "description",
          "mimeType",
          "payTo",
          "maxTimeoutSeconds",
          "asset"
        ],
        "properties": {
          "scheme": {
            "type": "string",
            "enum": [
              "exact"
            ]
          },
          "network": {
            "type": "string",
            "description": "Network identifier"
          },
          "maxAmountRequired": {
            "type": "string",
            "pattern": "^\\d+$",
            "description": "Maximum amount required in the token's smallest unit."
          },
          "resource": {
            "type": "string",
            "format": "uri"
          },
          "description": {
            "type": "string",
            "description": "Payment description"
          },
          "mimeType": {
            "type": "string",
            "description": "Content MIME type"
          },
          "payTo": {
            "type": "string",
            "description": "Facilitator or recipient address required by the selected payment type."
          },
          "maxTimeoutSeconds": {
            "type": "integer",
            "description": "Maximum validity window in seconds."
          },
          "asset": {
            "type": "string",
            "description": "Payment asset contract address or chain-specific asset identifier."
          },
          "extra": {
            "type": "object",
            "additionalProperties": true
          }
        }
      },
      "SettleResponse": {
        "type": "object",
        "required": [
          "success",
          "transaction",
          "network"
        ],
        "properties": {
          "success": {
            "type": "boolean"
          },
          "transaction": {
            "type": "string",
            "description": "Transaction hash on success. Empty string on failure."
          },
          "network": {
            "type": "string"
          },
          "payer": {
            "type": "string"
          },
          "errorReason": {
            "type": "string"
          },
          "authContext": {
            "type": "object",
            "additionalProperties": true
          }
        }
      },
      "VerifyResponse": {
        "type": "object",
        "properties": {
          "isValid": {
            "type": "boolean",
            "description": "Whether payment is valid"
          },
          "invalidReason": {
            "type": "string",
            "description": "Reason if payment is invalid"
          },
          "payer": {
            "type": "string",
            "description": "Payment sender address"
          },
          "authContext": {
            "type": "object",
            "properties": {
              "organizationId": {
                "type": "string"
              },
              "authMethod": {
                "type": "string"
              },
              "timestamp": {
                "type": "string"
              }
            }
          }
        }
      },
      "AuthResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "data": {
            "type": "object",
            "properties": {
              "user": {
                "$ref": "#/components/schemas/User"
              },
              "token": {
                "type": "string"
              },
              "expiresAt": {
                "type": "string"
              }
            }
          }
        }
      },
      "UserResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "data": {
            "type": "object",
            "properties": {
              "user": {
                "$ref": "#/components/schemas/User"
              }
            }
          }
        }
      },
      "NonceResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "data": {
            "type": "object",
            "properties": {
              "nonce": {
                "type": "string"
              },
              "message": {
                "type": "string"
              }
            }
          }
        }
      },
      "SupportedResponse": {
        "type": "object",
        "required": [
          "kinds"
        ],
        "properties": {
          "kinds": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "x402Version",
                "scheme",
                "network"
              ],
              "properties": {
                "x402Version": {
                  "type": "integer",
                  "enum": [
                    1
                  ]
                },
                "scheme": {
                  "type": "string",
                  "enum": [
                    "exact"
                  ]
                },
                "network": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "User": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "address": {
            "type": "string"
          },
          "organization": {
            "type": "string"
          },
          "createdAt": {
            "type": "string"
          },
          "updatedAt": {
            "type": "string"
          }
        }
      },
      "PermitRequest": {
        "type": "object",
        "required": [
          "network",
          "owner",
          "spender",
          "value",
          "deadline",
          "recipient"
        ],
        "properties": {
          "network": {
            "type": "string",
            "description": "EVM network identifier. Must be one of the facilitator's configured EVM networks (e.g. `base`, `arbitrum`, `bsc`, `bot-chain`, `base-sepolia`, `bot-chain-testnet`, `optimism`, `optimism-sepolia`, `polygon`, `unichain`, `ink`, `tempo`, `monad`, `robinhood`, `worldchain`, `hyperevm`, `megaeth`, `fluent-testnet`, etc.).",
            "example": "base-sepolia"
          },
          "tokenAddress": {
            "type": "string",
            "pattern": "^0x[a-fA-F0-9]{40}$",
            "description": "ERC-20 token address. Documented as optional with a fallback to the network's USDC, but the actual `transferWithPermit` call uses this value directly. Provide it explicitly to avoid `permit_execution_failed`.",
            "example": "0x036CbD53842c5426634e7929541eC2318f3dCF7e"
          },
          "owner": {
            "type": "string",
            "pattern": "^0x[a-fA-F0-9]{40}$",
            "description": "Token owner address (the signer of the EIP-2612 permit). Tokens are pulled from this address.",
            "example": "0x742d35Cc6634C0532925a3b8D0c4E5e6C2aE7A3e"
          },
          "spender": {
            "type": "string",
            "pattern": "^0x[a-fA-F0-9]{40}$",
            "description": "Spender address authorized by the permit signature. Required by the request schema. The on-chain `transferWithPermit` call uses the facilitator contract as the spender; this field is forwarded for signing-side compatibility.",
            "example": "0x8e633dBf31adCc7D41BE3e95B7c8DD3526B5235A"
          },
          "value": {
            "type": "string",
            "pattern": "^\\d+$",
            "description": "uint256 token amount as a decimal string in the token's smallest unit (e.g. `1000000` = 1 USDC at 6 decimals). Numbers and bigints are accepted and coerced to a decimal string.",
            "example": "1000000"
          },
          "deadline": {
            "type": "string",
            "pattern": "^\\d+$",
            "description": "uint256 permit deadline as a decimal Unix timestamp string. Numbers and bigints are accepted and coerced to a decimal string.",
            "example": "1893456000"
          },
          "signature": {
            "type": "string",
            "pattern": "^0x[a-fA-F0-9]+$",
            "description": "Optional 65-byte EIP-2612 permit signature, hex-encoded. Schema accepts `^0x[a-fA-F0-9]+$`. WARNING: this field is broken at runtime in the current handler (viem returns `r`/`s` as `0x`-prefixed and the assembler re-wraps them, producing malformed bytes); use the split `(v, r, s)` form instead. Provide this OR (`v`, `r`, `s`), but not both.",
            "example": "0x..."
          },
          "v": {
            "type": "integer",
            "minimum": 0,
            "maximum": 255,
            "description": "Optional `v` byte of the signature. The exclusivity check uses `Boolean(data.v)`, so `v = 0` is treated as missing; use 27 or 28."
          },
          "r": {
            "type": "string",
            "description": "Optional `r` component. The schema accepts any string (no regex). In practice, send a 32-byte hex value (with or without leading `0x`); only the first occurrence of `0x` is stripped when assembling the final signature."
          },
          "s": {
            "type": "string",
            "description": "Optional `s` component. The schema accepts any string (no regex). In practice, send a 32-byte hex value (with or without leading `0x`); only the first occurrence of `0x` is stripped when assembling the final signature."
          },
          "recipient": {
            "type": "string",
            "pattern": "^0x[a-fA-F0-9]{40}$",
            "description": "Address that receives the transferred tokens after the permit is applied.",
            "example": "0x742d35Cc6634C0532925a3b8D0c4E5e6C2aE7A3e"
          }
        }
      },
      "PermitResponse": {
        "type": "object",
        "required": [
          "success",
          "transaction",
          "network"
        ],
        "properties": {
          "success": {
            "type": "boolean",
            "description": "`true` only when the on-chain transaction was submitted successfully."
          },
          "transaction": {
            "type": "string",
            "description": "Transaction hash on success. Empty string (`\"\"`) on every error response."
          },
          "network": {
            "type": "string",
            "description": "Echoes the network from the request (or `\"\"` if the request body could not be parsed)."
          },
          "errorReason": {
            "type": "string",
            "description": "Present on error responses only.",
            "enum": [
              "invalid_request",
              "unsupported_network",
              "network_not_configured",
              "invalid_signature",
              "permit_execution_failed"
            ]
          }
        }
      },
      "PermitDescribeResponse": {
        "type": "object",
        "properties": {
          "endpoint": {
            "type": "string",
            "example": "POST /v1/permit"
          },
          "description": {
            "type": "string",
            "example": "Execute an ERC20 permit transaction using the facilitator signer"
          },
          "authentication": {
            "type": "string",
            "example": "Requires valid API key if enabled"
          },
          "requestBody": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "response": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          }
        }
      },
      "BatchedSampleResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "example": true
          },
          "data": {
            "type": "object",
            "properties": {
              "message": {
                "type": "string",
                "example": "Circle Gateway batched nanopayments integration"
              },
              "organization": {
                "type": "string"
              },
              "organizationId": {
                "type": "string"
              },
              "gatewayMainnetEnabled": {
                "type": "boolean",
                "example": true
              },
              "networkStatus": {
                "type": "object",
                "additionalProperties": {
                  "type": "boolean"
                },
                "description": "Map of internal network name to whether Gateway batching is enabled.",
                "example": {
                  "base-sepolia": true,
                  "optimism-sepolia": true,
                  "base": true,
                  "optimism": true,
                  "polygon": true,
                  "unichain": true,
                  "ink": true,
                  "hyperevm": true,
                  "megaeth": true
                }
              },
              "gatewaySupported": {
                "type": "object",
                "description": "Pass-through `/supported` payload from the Circle Gateway API."
              },
              "endpoints": {
                "type": "object",
                "description": "Static labels returned verbatim by the facilitator. Note: the strings reference `/v1/batched-verify` and `/v1/batched-settle`, but those URLs do not exist as distinct routes; batched routing happens on the regular `/v1/verify` and `/v1/settle` endpoints.",
                "properties": {
                  "batchedVerify": {
                    "type": "string",
                    "example": "POST /v1/batched-verify"
                  },
                  "batchedSettle": {
                    "type": "string",
                    "example": "POST /v1/batched-settle"
                  },
                  "batchedSample": {
                    "type": "string",
                    "example": "GET /v1/batched-sample"
                  }
                }
              },
              "usage": {
                "type": "object",
                "properties": {
                  "description": {
                    "type": "string"
                  },
                  "note": {
                    "type": "string"
                  }
                }
              },
              "timestamp": {
                "type": "string",
                "format": "date-time"
              }
            }
          }
        }
      }
    }
  }
}