{
  "openapi": "3.1.0",
  "info": {
    "title": "Tokenistry Transaction Engine",
    "description": "Executes signed ERC-2771 forward requests. This service pays gas and nothing else: it holds no role on any contract, and a request it has not been given a valid authority signature for is worthless to it.",
    "license": {
      "name": "LicenseRef-Tokenistry-Commercial",
      "identifier": "LicenseRef-Tokenistry-Commercial"
    },
    "version": "1.0.0"
  },
  "paths": {
    "/health": {
      "get": {
        "tags": [
          "system"
        ],
        "summary": "Liveness. Answers as long as the process is up.",
        "operationId": "health",
        "responses": {
          "200": {
            "description": "The process is running"
          }
        }
      }
    },
    "/ready": {
      "get": {
        "tags": [
          "system"
        ],
        "summary": "Readiness. Fails while the database is unreachable.",
        "operationId": "ready",
        "responses": {
          "200": {
            "description": "Database reachable"
          },
          "500": {
            "description": "Database unreachable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/funding": {
      "get": {
        "tags": [
          "system"
        ],
        "summary": "The root wallet, the funding policy, and recent top-ups.",
        "operationId": "funding",
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FundingDto"
                }
              }
            }
          }
        }
      }
    },
    "/v1/gas-payers": {
      "get": {
        "tags": [
          "system"
        ],
        "summary": "Relayers: nonce, balance and funding state.",
        "description": "Each address is an independent nonce line, so this is also the parallelism\navailable. The balance matters for the same reason: a relayer with no ether\nstops broadcasting without erroring, and that nonce line quietly disappears.",
        "operationId": "gas_payers",
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/GasPayerDto"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/metrics": {
      "get": {
        "tags": [
          "system"
        ],
        "summary": "Queue state and the confirmer's view of the chain.",
        "operationId": "metrics",
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MetricsDto"
                }
              }
            }
          }
        }
      }
    },
    "/v1/transactions": {
      "get": {
        "tags": [
          "transactions"
        ],
        "summary": "A page of transactions, newest first.",
        "description": "Paged by cursor rather than offset: rows change status while a caller reads\nthem, and an offset would silently skip or repeat transactions.",
        "operationId": "list",
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/TxStatus"
            }
          },
          {
            "name": "gas_payer",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "ordering_key",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "Opaque cursor from a previous page's `next_cursor`.",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListResponse"
                }
              }
            }
          },
          "400": {
            "description": "Malformed cursor",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBody"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "transactions"
        ],
        "summary": "Queue a signed forward request.",
        "description": "Returns as soon as the row is durable, before anything is signed or\nbroadcast, so callers poll rather than hold a connection open. Idempotent on\n`idempotency_key`: a repeat returns the original transaction.",
        "operationId": "submit",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SubmitRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "The idempotency key already existed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SubmitResponse"
                }
              }
            }
          },
          "202": {
            "description": "Queued",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SubmitResponse"
                }
              }
            }
          },
          "400": {
            "description": "Malformed request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBody"
                }
              }
            }
          },
          "409": {
            "description": "Key reused with a different payload",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBody"
                }
              }
            }
          },
          "503": {
            "description": "No gas payer for this chain",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/transactions/by-key/{key}": {
      "get": {
        "tags": [
          "transactions"
        ],
        "summary": "The same detail, looked up by the caller's own idempotency key.",
        "operationId": "by_key",
        "parameters": [
          {
            "name": "key",
            "in": "path",
            "description": "Idempotency key",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TransactionDetail"
                }
              }
            }
          },
          "404": {
            "description": "Unknown key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/transactions/{id}": {
      "get": {
        "tags": [
          "transactions"
        ],
        "summary": "One transaction, with every broadcast attempt and its receipt.",
        "operationId": "by_id",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Transaction id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TransactionDetail"
                }
              }
            }
          },
          "404": {
            "description": "Unknown transaction",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBody"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "ApiErrorBody": {
        "type": "object",
        "description": "The body every failed request returns.",
        "required": [
          "error",
          "message"
        ],
        "properties": {
          "error": {
            "type": "string",
            "description": "Stable machine-readable code, e.g. `invalid_request`.",
            "example": "invalid_request"
          },
          "message": {
            "type": "string"
          }
        }
      },
      "AttemptDto": {
        "type": "object",
        "required": [
          "attempt_number",
          "nonce",
          "tx_hash",
          "max_fee_per_gas",
          "max_priority_fee_per_gas",
          "gas_limit",
          "status"
        ],
        "properties": {
          "attempt_number": {
            "type": "integer",
            "format": "int32",
            "minimum": 0
          },
          "broadcast_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "gas_limit": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "max_fee_per_gas": {
            "type": "string"
          },
          "max_priority_fee_per_gas": {
            "type": "string"
          },
          "nonce": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "status": {
            "$ref": "#/components/schemas/AttemptStatus"
          },
          "tx_hash": {
            "type": "string"
          }
        }
      },
      "AttemptStatus": {
        "type": "string",
        "description": "Lifecycle of one signed outer transaction.",
        "enum": [
          "PENDING",
          "BROADCAST",
          "MINED",
          "REPLACED",
          "DROPPED"
        ]
      },
      "ForwardRequest": {
        "type": "object",
        "description": "An ERC-2771 forward request, exactly as `ERC2771Forwarder.execute` expects it.\n\nThe engine treats this as opaque, signed payload. It is never re-encoded,\nre-ordered or otherwise modified: doing so would invalidate the authority's\nsignature, which is precisely the property that keeps this service powerless.",
        "required": [
          "from",
          "to",
          "gas",
          "deadline",
          "data",
          "signature"
        ],
        "properties": {
          "data": {
            "type": "string",
            "description": "ABI-encoded inner calldata.",
            "example": "0x40c10f19…"
          },
          "deadline": {
            "type": "integer",
            "format": "int64",
            "description": "Unix seconds; `uint48` on chain.",
            "minimum": 0
          },
          "from": {
            "type": "string",
            "description": "The authority that signed the request. Not this service.",
            "example": "0x70997970C51812dc3A010C7d01b50e0d17dc79C8"
          },
          "gas": {
            "type": "integer",
            "format": "int64",
            "description": "Inner call gas, as signed by the authority.",
            "minimum": 0
          },
          "signature": {
            "type": "string",
            "description": "EIP-712 signature over the request, 65 bytes."
          },
          "to": {
            "type": "string",
            "description": "The RWA contract the forwarder will call."
          },
          "value": {
            "type": "string",
            "example": "0x0"
          }
        }
      },
      "ForwardRequestDto": {
        "type": "object",
        "description": "The signed ERC-2771 request, transported verbatim.",
        "required": [
          "from",
          "to",
          "gas",
          "deadline",
          "data",
          "signature"
        ],
        "properties": {
          "data": {
            "type": "string",
            "example": "0x40c10f19…"
          },
          "deadline": {
            "type": "integer",
            "format": "int64",
            "description": "Unix seconds. A request past its deadline can never execute.",
            "minimum": 0
          },
          "from": {
            "type": "string",
            "example": "0x70997970C51812dc3A010C7d01b50e0d17dc79C8"
          },
          "gas": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "signature": {
            "type": "string"
          },
          "to": {
            "type": "string"
          },
          "value": {
            "type": "string",
            "description": "Always zero in practice: a gas payer is never asked to fund value.",
            "example": "0x0"
          }
        }
      },
      "FundingDto": {
        "type": "object",
        "description": "The root wallet and the top-ups it has made.",
        "required": [
          "enabled",
          "relayer_backend",
          "min_balance_wei",
          "target_balance_wei",
          "transfers"
        ],
        "properties": {
          "enabled": {
            "type": "boolean",
            "description": "False when no root wallet is configured. Balances are still reported;\nnothing refills a relayer that runs dry."
          },
          "min_balance_wei": {
            "type": "string",
            "description": "A relayer at or below this is topped up. Wei, decimal string."
          },
          "relayer_backend": {
            "type": "string",
            "description": "Custody behind the relayer keys: `mnemonic`, `private_key` or `aws_kms`."
          },
          "root": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/RootWalletDto"
              }
            ]
          },
          "target_balance_wei": {
            "type": "string",
            "description": "Where a top-up refills to."
          },
          "transfers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FundingTransferDto"
            }
          }
        }
      },
      "FundingStatus": {
        "type": "string",
        "description": "Lifecycle of one top-up from the root wallet to a relayer.",
        "enum": [
          "PENDING",
          "CONFIRMED",
          "FAILED"
        ]
      },
      "FundingTransferDto": {
        "type": "object",
        "required": [
          "gas_payer",
          "amount_wei",
          "tx_hash",
          "status",
          "created_at"
        ],
        "properties": {
          "amount_wei": {
            "type": "string"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "error": {
            "type": [
              "string",
              "null"
            ]
          },
          "gas_payer": {
            "type": "string"
          },
          "settled_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "status": {
            "$ref": "#/components/schemas/FundingStatus"
          },
          "tx_hash": {
            "type": "string"
          }
        }
      },
      "GasPayerDto": {
        "type": "object",
        "required": [
          "address",
          "next_nonce",
          "below_threshold",
          "funding_pending",
          "queued",
          "submitted"
        ],
        "properties": {
          "address": {
            "type": "string"
          },
          "balance_checked_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "balance_wei": {
            "type": [
              "string",
              "null"
            ],
            "description": "Wei, as a decimal string: a balance exceeds what a JS number holds\nexactly, and a rounded balance is the wrong number to make a funding\ndecision on. `null` until the first funding sweep has read it."
          },
          "below_threshold": {
            "type": "boolean",
            "description": "True when the last reading was at or below the funding threshold. Says\nnothing about whether a top-up is possible - that needs a root wallet."
          },
          "funding_pending": {
            "type": "boolean",
            "description": "A top-up is on the wire. The balance above has not moved yet."
          },
          "last_funded_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "next_nonce": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "queued": {
            "type": "integer",
            "format": "int64",
            "description": "Work this relayer is carrying: `queued` is waiting for a dispatcher,\n`submitted` is on the wire. New work goes to whichever relayer carries\nthe least, so these two are the scheduler's own view of the pool.",
            "minimum": 0
          },
          "submitted": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          }
        }
      },
      "ListResponse": {
        "type": "object",
        "required": [
          "transactions"
        ],
        "properties": {
          "next_cursor": {
            "type": [
              "string",
              "null"
            ],
            "description": "Pass back as `cursor` for the next page. Absent when the list is complete."
          },
          "transactions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/QueuedTransactionSummary"
            }
          }
        }
      },
      "MetricsDto": {
        "type": "object",
        "description": "Queue state and the worker's view of the chain.",
        "required": [
          "queued",
          "submitted",
          "mined",
          "confirmed",
          "reverted",
          "failed",
          "total",
          "attempts",
          "ready_now",
          "head_block",
          "chain_id",
          "gas_payers"
        ],
        "properties": {
          "attempts": {
            "type": "integer",
            "format": "int64",
            "description": "Broadcast attempts across every transaction. Meaningfully above `total`\nmeans fees are being bumped often.",
            "minimum": 0
          },
          "chain_id": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "confirmed": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "failed": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "gas_payers": {
            "type": "integer",
            "minimum": 0
          },
          "head_block": {
            "type": "integer",
            "format": "int64",
            "description": "0 until the confirmer has seen a block.",
            "minimum": 0
          },
          "mined": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "oldest_in_flight_secs": {
            "type": [
              "number",
              "null"
            ],
            "format": "double"
          },
          "queued": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "ready_now": {
            "type": "integer",
            "format": "int64",
            "description": "In-flight transactions whose backoff has elapsed. Persistently non-zero\nmeans the dispatchers are not keeping up.",
            "minimum": 0
          },
          "reverted": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "submitted": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "total": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          }
        }
      },
      "Priority": {
        "type": "string",
        "description": "Execution urgency.\n\nPriority governs two things: which queued transaction a worker picks up\nfirst, and how aggressively its fees are set. It deliberately does *not*\nreorder work that shares an `ordering_key` - see [`QueuedTransaction`].",
        "enum": [
          "LOW",
          "NORMAL",
          "HIGH",
          "CRITICAL"
        ]
      },
      "QueuedTransactionSummary": {
        "type": "object",
        "description": "Serialisable projection of a transaction, shared by the API and the client.",
        "required": [
          "id",
          "idempotency_key",
          "status",
          "priority",
          "chain_id",
          "gas_payer",
          "target",
          "calldata",
          "attempts_count",
          "confirmations_required",
          "created_at",
          "updated_at"
        ],
        "properties": {
          "attempts_count": {
            "type": "integer",
            "format": "int32",
            "minimum": 0
          },
          "block_number": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64",
            "minimum": 0
          },
          "calldata": {
            "type": "string",
            "description": "The inner calldata, so a console can decode arguments without fetching\nevery transaction individually. Still just bytes to this service."
          },
          "chain_id": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "confirmations_required": {
            "type": "integer",
            "format": "int32",
            "minimum": 0
          },
          "confirmations_seen": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64",
            "minimum": 0
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "gas_payer": {
            "type": "string",
            "example": "0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC"
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "idempotency_key": {
            "type": "string"
          },
          "last_error": {
            "type": [
              "string",
              "null"
            ]
          },
          "ordering_key": {
            "type": [
              "string",
              "null"
            ]
          },
          "priority": {
            "$ref": "#/components/schemas/Priority"
          },
          "revert_reason": {
            "type": [
              "string",
              "null"
            ]
          },
          "selector": {
            "type": [
              "string",
              "null"
            ],
            "description": "The inner call's 4-byte selector, and the contract it is aimed at.\n\nThis service does not know what the selector means and never dispatches\non it - it carries whatever it was handed. Both are here so an operator\nconsole can name the call without having to open every transaction, and\nwithout this service growing an opinion about the contracts it serves."
          },
          "status": {
            "$ref": "#/components/schemas/TxStatus"
          },
          "target": {
            "type": "string"
          },
          "transaction_hash": {
            "type": [
              "string",
              "null"
            ]
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "RootWalletDto": {
        "type": "object",
        "required": [
          "address",
          "backend",
          "reserve_wei"
        ],
        "properties": {
          "address": {
            "type": "string"
          },
          "backend": {
            "type": "string"
          },
          "balance_checked_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "balance_wei": {
            "type": [
              "string",
              "null"
            ]
          },
          "reserve_wei": {
            "type": "string",
            "description": "Never spent, so the root can always pay for its own gas."
          }
        }
      },
      "SubmitRequest": {
        "type": "object",
        "description": "Serializable in both directions so a typed client (the Tokenization\nEngine's) can share this exact shape instead of restating it.",
        "required": [
          "idempotency_key",
          "request"
        ],
        "properties": {
          "chain_id": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64",
            "minimum": 0
          },
          "confirmations": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int32",
            "minimum": 0
          },
          "forwarder": {
            "type": [
              "string",
              "null"
            ]
          },
          "gas_limit": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64",
            "minimum": 0
          },
          "idempotency_key": {
            "type": "string",
            "description": "Caller-owned key. Re-submitting the same key returns the original\ntransaction instead of creating a second one."
          },
          "max_attempts": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int32",
            "minimum": 0
          },
          "ordering_key": {
            "type": [
              "string",
              "null"
            ],
            "description": "Requests sharing a key execute in submission order on one gas payer.\nThe Tokenization Engine sets this to its authority address, because the\nforwarder's nonces for that signer are strictly sequential."
          },
          "priority": {
            "$ref": "#/components/schemas/Priority"
          },
          "request": {
            "$ref": "#/components/schemas/ForwardRequestDto"
          }
        }
      },
      "SubmitResponse": {
        "allOf": [
          {
            "$ref": "#/components/schemas/QueuedTransactionSummary"
          },
          {
            "type": "object",
            "required": [
              "created"
            ],
            "properties": {
              "created": {
                "type": "boolean",
                "description": "False when this call matched an existing idempotency key."
              }
            }
          }
        ]
      },
      "TransactionDetail": {
        "allOf": [
          {
            "$ref": "#/components/schemas/QueuedTransactionSummary"
          },
          {
            "type": "object",
            "required": [
              "forwarder",
              "request",
              "attempts"
            ],
            "properties": {
              "attempts": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/AttemptDto"
                }
              },
              "forwarder": {
                "type": "string"
              },
              "request": {
                "$ref": "#/components/schemas/ForwardRequest"
              }
            }
          }
        ]
      },
      "TxStatus": {
        "type": "string",
        "description": "Lifecycle of a submitted transaction.",
        "enum": [
          "QUEUED",
          "SUBMITTED",
          "MINED",
          "CONFIRMED",
          "REVERTED",
          "FAILED"
        ]
      }
    }
  },
  "tags": [
    {
      "name": "transactions",
      "description": "Queueing signed requests and following their execution"
    },
    {
      "name": "system",
      "description": "Health, relayer wallets, funding and queue metrics"
    }
  ]
}
