Skip to main content
Glama
PulseBet

pulse-verity

Verify a Signed Print

verify_print
Read-onlyIdempotent

Verify signed crypto price prints locally with ECDSA P-256/SHA-256, checking v1 price fields or full v2 records to confirm authenticity and detect alteration.

Instructions

Verify a signed print locally with ECDSA P-256/SHA-256. Legacy valid authenticates only the v1 canonical price fields. Pass the whole print including v2 to authenticate its complete live, archive or daily-close index record; agents using sources, confidence, interval or cadence must require recordValid=true. Live records sign 18 fields; archive records sign 13 without freshness ages, and daily-close records add signed assetId and closeDay. v2.signedFields lists exactly what is authenticated. kind selects the format and is not signed. Added non-null freshness ages invalidate archived verification. verificationScope is full-record only when both signatures and all required fields match, price-only for a valid v1 print without v2, or invalid otherwise. metadataSigned equals recordValid. deltaMs and surrounding metadata remain unsigned. Public keys come from /api/index/v1/pubkey, cached five minutes with refresh at most every 30 seconds. Each supplied kid selects only its exact published key; v1 prints without kid (or with kid null, as some history rows carry) use the bounded ring. No API key is sent to the key endpoint. Invalid verification can mean alteration or a key no longer published. Works without a developer key.

Input Schema

NameRequiredDescriptionDefault
atYesTimestamp from the print, unchanged
v2NoThe unchanged v2 block, which signs price and quality fields together
kidNoSigning key identifier, when provided by the API; null counts as absent
sigNo
kindNoSelects the daily-close record format; this selector is not itself signed
tierNo
gradeYes
priceYes
engineNo
symbolYesCrypto ticker symbol, e.g. BTC, ETH, SOL
assetIdNo
cadenceNo
sourcesNo
closeDayNo
intervalNo
priceTextNoExact signed price text, when provided by the API; preserve unchanged
signatureYesECDSA P-256 signature in base64
confidenceNo
dispersionBpsNo

Output Schema

NameRequiredDescriptionDefault
v2No
errorNo
validNoLegacy price-only signature check. Use recordValid for quality metadata.
checkedNo
keySourceNo
requestIdYesIdentifier for this MCP call; not a signed price field.
recordValidNoBoth signatures and every required v2 field verified. Does not prove freshness or settlement suitability.
metadataSignedNo
verifiedWithKidNo
verificationScopeNo

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed8 schema fields changedv1.3.6
    • addedInput schema / properties / kid / anyOf
      Added value: +[
      +  {
      +    "pattern": "^[A-Za-z0-9._:-]{1,64}$",
      +    "type": "string"
      +  },
      +  {
      +    "type": "null"
      +  }
      +]
    • changedInput schema / properties / kid / description
      Previous value: -"Signing key identifier, when provided by the API"New value: +"Signing key identifier, when provided by the API; null counts as absent"
    • removedInput schema / properties / kid / pattern
      Removed value: -"^[A-Za-z0-9._:-]{1,64}$"
    • removedInput schema / properties / kid / type
      Removed value: -"string"
    • changedInput schema / properties / v2 / properties / kid / $ref
      Previous value: -"#/properties/kid"New value: +"#/properties/kid/anyOf/0"
    • addedOutput schema / properties / error / properties / batchLimit
      Added value: +{
      +  "maximum": 100000,
      +  "minimum": 1,
      +  "type": "integer"
      +}
    • addedOutput schema / properties / error / properties / plan
      Added value: +{
      +  "enum": [
      +    "Developer",
      +    "Basic",
      +    "Builder",
      +    "Commercial",
      +    "Enterprise"
      +  ],
      +  "type": "string"
      +}
    • addedOutput schema / properties / error / properties / requested
      Added value: +{
      +  "maximum": 100000,
      +  "minimum": 1,
      +  "type": "integer"
      +}
  2. Changed6 schema fields changedv1.3.3
    • addedOutput schema / properties / error / properties / capacityAction
      Added value: +{
      +  "enum": [
      +    "review_plans",
      +    "contact_support"
      +  ],
      +  "type": "string"
      +}
    • addedOutput schema / properties / error / properties / getKeyUrl
      Added value: +{
      +  "maxLength": 256,
      +  "pattern": "^https:\\/\\/thepulse\\.markets\\/developers(?:[/?#][^\\s]*)?$",
      +  "type": "string"
      +}
    • addedOutput schema / properties / error / properties / hostedServerUrl
      Added value: +{
      +  "const": "https://mcp.thepulse.markets/api/index/mcp",
      +  "type": "string"
      +}
    • changedOutput schema / properties / error / properties / nextAction / enum
      Previous value: -[
      -  "wait",
      -  "review_access",
      -  "check_limits",
      -  "reconnect",
      -  "check_input",
      -  "choose_another_symbol",
      -  "report_issue"
      -]New value: +[
      +  "wait",
      +  "review_access",
      +  "check_limits",
      +  "reconnect",
      +  "check_input",
      +  "choose_another_symbol",
      +  "report_issue",
      +  "get_key"
      +]
    • addedOutput schema / properties / error / properties / resetAt
      Added value: +{
      +  "pattern": "^\\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\\d|3[01])T([01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d\\.\\d{3}Z$",
      +  "type": "string"
      +}
    • addedOutput schema / properties / error / properties / upgradeUrl
      Added value: +{
      +  "const": "https://thepulse.markets/developers#/portal/pricing",
      +  "type": "string"
      +}
  3. Changed3 schema fields changedv1.3.1
    • addedInput schema / properties / assetId
      Added value: +{
      +  "anyOf": [
      +    {
      +      "maxLength": 160,
      +      "minLength": 1,
      +      "pattern": "^[^\\x00-\\x1f\\x7f\\u0085\\u2028\\u2029]+$",
      +      "type": "string"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ]
      +}
    • addedInput schema / properties / closeDay
      Added value: +{
      +  "anyOf": [
      +    {
      +      "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      +      "type": "string"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ]
      +}
    • addedInput schema / properties / kind
      Added value: +{
      +  "const": "daily-close",
      +  "description": "Selects the daily-close record format; this selector is not itself signed",
      +  "type": "string"
      +}
  4. Changed9 schema fields changedv1.3.0
    • addedInput schema / properties / cadence
      Added value: +{
      +  "anyOf": [
      +    {
      +      "additionalProperties": false,
      +      "properties": {
      +        "band": {
      +          "anyOf": [
      +            {
      +              "maxLength": 40,
      +              "minLength": 1,
      +              "pattern": "^[^\\x00-\\x1f\\x7f\\u0085\\u2028\\u2029]+$",
      +              "type": "string"
      +            },
      +            {
      +              "type": "null"
      +            }
      +          ]
      +        },
      +        "calculatedAgeMs": {
      +          "anyOf": [
      +            {
      +              "type": "number"
      +            },
      +            {
      +              "type": "null"
      +            }
      +          ]
      +        },
      +        "newestSourceAgeMs": {
      +          "anyOf": [
      +            {
      +              "type": "number"
      +            },
      +            {
      +              "type": "null"
      +            }
      +          ]
      +        },
      +        "oldestSourceAgeMs": {
      +          "anyOf": [
      +            {
      +              "type": "number"
      +            },
      +            {
      +              "type": "null"
      +            }
      +          ]
      +        },
      +        "p50UpdateMs": {
      +          "anyOf": [
      +            {
      +              "type": "number"
      +            },
      +            {
      +              "type": "null"
      +            }
      +          ]
      +        },
      +        "p95UpdateMs": {
      +          "anyOf": [
      +            {
      +              "type": "number"
      +            },
      +            {
      +              "type": "null"
      +            }
      +          ]
      +        }
      +      },
      +      "type": "object"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ]
      +}
    • addedInput schema / properties / confidence
      Added value: +{
      +  "anyOf": [
      +    {
      +      "type": "number"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ]
      +}
    • addedInput schema / properties / dispersionBps
      Added value: +{
      +  "anyOf": [
      +    {
      +      "type": "number"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ]
      +}
    • addedInput schema / properties / engine
      Added value: +{
      +  "anyOf": [
      +    {
      +      "maxLength": 64,
      +      "minLength": 1,
      +      "pattern": "^[^\\x00-\\x1f\\x7f\\u0085\\u2028\\u2029]+$",
      +      "type": "string"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ]
      +}
    • addedInput schema / properties / interval
      Added value: +{
      +  "anyOf": [
      +    {
      +      "additionalProperties": false,
      +      "properties": {
      +        "lower": {
      +          "anyOf": [
      +            {
      +              "type": "number"
      +            },
      +            {
      +              "type": "null"
      +            }
      +          ]
      +        },
      +        "upper": {
      +          "anyOf": [
      +            {
      +              "type": "number"
      +            },
      +            {
      +              "type": "null"
      +            }
      +          ]
      +        }
      +      },
      +      "required": [
      +        "lower",
      +        "upper"
      +      ],
      +      "type": "object"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ]
      +}
    • addedInput schema / properties / sources
      Added value: +{
      +  "anyOf": [
      +    {
      +      "minimum": 0,
      +      "type": "integer"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ]
      +}
    • addedInput schema / properties / tier
      Added value: +{
      +  "anyOf": [
      +    {
      +      "maxLength": 20,
      +      "minLength": 1,
      +      "pattern": "^[^\\x00-\\x1f\\x7f\\u0085\\u2028\\u2029]+$",
      +      "type": "string"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ]
      +}
    • addedInput schema / properties / v2
      Added value: +{
      +  "additionalProperties": false,
      +  "description": "The unchanged v2 block, which signs price and quality fields together",
      +  "properties": {
      +    "canonical": {
      +      "description": "The exact signed string from the print, unchanged",
      +      "maxLength": 8192,
      +      "minLength": 1,
      +      "type": "string"
      +    },
      +    "kid": {
      +      "$ref": "#/properties/kid"
      +    },
      +    "sig": {
      +      "const": "pulse-index-v2",
      +      "type": "string"
      +    },
      +    "signature": {
      +      "maxLength": 88,
      +      "minLength": 88,
      +      "pattern": "^[A-Za-z0-9+/]{86}==$",
      +      "type": "string"
      +    }
      +  },
      +  "required": [
      +    "sig",
      +    "canonical",
      +    "signature",
      +    "kid"
      +  ],
      +  "type": "object"
      +}
    • changedOutput schema / (root)
      Previous value: -nullNew value: +{
      +  "$schema": "http://json-schema.org/draft-07/schema#",
      +  "additionalProperties": false,
      +  "properties": {
      +    "checked": {
      +      "maxLength": 512,
      +      "type": "string"
      +    },
      +    "error": {
      +      "additionalProperties": false,
      +      "properties": {
      +        "accountUrl": {
      +          "const": "https://thepulse.markets/developers/access",
      +          "type": "string"
      +        },
      +        "code": {
      +          "pattern": "^[A-Z][A-Z0-9_]{0,79}$",
      +          "type": "string"
      +        },
      +        "nextAction": {
      +          "enum": [
      +            "wait",
      +            "review_access",
      +            "check_limits",
      +            "reconnect",
      +            "check_input",
      +            "choose_another_symbol",
      +            "report_issue"
      +          ],
      +          "type": "string"
      +        },
      +        "retryAfterSeconds": {
      +          "maximum": 86400,
      +          "minimum": 1,
      +          "type": "integer"
      +        },
      +        "retryable": {
      +          "type": "boolean"
      +        }
      +      },
      +      "required": [
      +        "code",
      +        "nextAction"
      +      ],
      +      "type": "object"
      +    },
      +    "keySource": {
      +      "maxLength": 256,
      +      "type": "string"
      +    },
      +    "metadataSigned": {
      +      "type": "boolean"
      +    },
      +    "recordValid": {
      +      "description": "Both signatures and every required v2 field verified. Does not prove freshness or settlement suitability.",
      +      "type": "boolean"
      +    },
      +    "requestId": {
      +      "description": "Identifier for this MCP call; not a signed price field.",
      +      "format": "uuid",
      +      "type": "string"
      +    },
      +    "v2": {
      +      "anyOf": [
      +        {
      +          "additionalProperties": false,
      +          "properties": {
      +            "fieldsMatch": {
      +              "type": "boolean"
      +            },
      +            "mismatches": {
      +              "items": {
      +                "maxLength": 80,
      +                "type": "string"
      +              },
      +              "maxItems": 18,
      +              "type": "array"
      +            },
      +            "signatureValid": {
      +              "type": "boolean"
      +            },
      +            "signedFields": {
      +              "anyOf": [
      +                {
      +                  "additionalProperties": {
      +                    "anyOf": [
      +                      {
      +                        "type": "string"
      +                      },
      +                      {
      +                        "type": "number"
      +                      },
      +                      {
      +                        "type": "boolean"
      +                      },
      +                      {
      +                        "type": "null"
      +                      }
      +                    ]
      +                  },
      +                  "type": "object"
      +                },
      +                {
      +                  "type": "null"
      +                }
      +              ]
      +            },
      +            "valid": {
      +              "type": "boolean"
      +            },
      +            "verifiedWithKid": {
      +              "anyOf": [
      +                {
      +                  "$ref": "#/properties/verifiedWithKid/anyOf/0"
      +                },
      +                {
      +                  "type": "null"
      +                }
      +              ]
      +            }
      +          },
      +          "required": [
      +            "valid",
      +            "signatureValid",
      +            "fieldsMatch",
      +            "mismatches",
      +            "signedFields",
      +            "verifiedWithKid"
      +          ],
      +          "type": "object"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ]
      +    },
      +    "valid": {
      +      "description": "Legacy price-only signature check. Use recordValid for quality metadata.",
      +      "type": "boolean"
      +    },
      +    "verificationScope": {
      +      "enum": [
      +        "full-record",
      +        "price-only",
      +        "invalid"
      +      ],
      +      "type": "string"
      +    },
      +    "verifiedWithKid": {
      +      "anyOf": [
      +        {
      +          "pattern": "^[A-Za-z0-9._:-]{1,64}$",
      +          "type": "string"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ]
      +    }
      +  },
      +  "required": [
      +    "requestId"
      +  ],
      +  "type": "object"
      +}
  5. First observedv1.1.0

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover read-only/idempotent/non-destructive, yet the description adds substantial behavioral context: public keys cached five minutes with refresh at most every 30 seconds, no API key sent to the key endpoint, a bounded key ring for v1 prints lacking kid, added non-null freshness ages invalidating archived verification, and that deltaMs and surrounding metadata remain unsigned. It also explains what an invalid result can mean (alteration or an unpublished key).

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Purpose is front-loaded in sentence one, and nearly every subsequent sentence carries non-obvious operational information (signing scope, key caching, invalidation rules). The prose is dense and clause-heavy, which hurts scannability, but there is little filler to cut.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 19-parameter, nested-schema verification tool, the description covers what the schema cannot: verification modes, signed-field counts per format, key resolution, and the meaning of verificationScope (full-record, price-only, invalid) and metadataSigned. With an output schema present, it does not need to enumerate return values and correctly focuses on call-time semantics.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is only 37% across 19 parameters, so the description must carry weight, and it does: 'kind selects the format and is not signed', 'kid selects only its exact published key; null counts as absent', and it enumerates which fields each record format signs (18 live, 13 archive without freshness ages, daily-close adds assetId and closeDay). Some parameters (tier, engine, dispersionBps, interval internals) still get no explanation, keeping this below a 5.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The first sentence gives a specific verb, resource and mechanism (verify a signed print locally with ECDSA P-256/SHA-256), and the description immediately distinguishes the price-only v1 path from the full-record v2 path. An agent can tell this is a cryptographic verification tool rather than a fetch tool like get_recorded_print or get_settlement_print.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It states the key selection rule clearly: 'Pass the whole print including v2 to authenticate its complete live, archive or daily-close index record', and warns that 'agents using sources, confidence, interval or cadence must require recordValid=true'. It also explains when legacy v1-only verification suffices. It stops short of naming sibling fetch tools as alternatives, so the routing guidance is implied rather than explicit.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.