Skip to main content
Glama

get_payment

Retrieve payment details including amount, status, payment method, and customer information using a payment ID.

Instructions

Get details of a single payment by ID.

Returns amount, status, payment method, customer info, and more.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
payment_idYes

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault

No arguments

Implementation Reference

  • The get_payment tool handler - decorated with @mcp.tool and implements the logic to retrieve a single payment by ID using the Stream API client
    @mcp.tool
    async def get_payment(
        payment_id: str,
        ctx: Context = None,  # type: ignore[assignment]
    ) -> dict[str, Any]:
        """Get details of a single payment by ID.
    
        Returns amount, status, payment method, customer info, and more.
        """
        client = await get_client(ctx)
        try:
            return await client.get(f"{_BASE}/{payment_id}")
        except StreamAPIError as exc:
            return _err(exc)
  • The register function that registers all payment tools including get_payment, which is called by register_all_tools during server initialization
    def register(mcp: FastMCP) -> None:
        """Register all payment tools on *mcp*."""
    
        @mcp.tool
        async def list_payments(
            page: int = 1,
            limit: int = 20,
            statuses: list[str] | None = None,
            invoice_id: str | None = None,
            search_term: str | None = None,
            from_date: str | None = None,
            to_date: str | None = None,
            ctx: Context = None,  # type: ignore[assignment]
        ) -> dict[str, Any]:
            """List payments with optional filters.
    
            Filter by *statuses* (PENDING, PROCESSING, SUCCEEDED, FAILED, CANCELED,
            UNDER_REVIEW, EXPIRED, SETTLED, REFUNDED), *invoice_id*, *search_term*,
            or a date range (*from_date* / *to_date* in ISO-8601).
            """
            params: dict[str, Any] = {"page": page, "limit": limit}
            if statuses:
                params["statuses"] = statuses
            if invoice_id:
                params["invoice_id"] = invoice_id
            if search_term:
                params["search_term"] = search_term
            if from_date:
                params["from_date"] = from_date
            if to_date:
                params["to_date"] = to_date
            client = await get_client(ctx)
            try:
                return await client.get(_BASE, params=params)
            except StreamAPIError as exc:
                return _err(exc)
    
        @mcp.tool
        async def get_payment(
            payment_id: str,
            ctx: Context = None,  # type: ignore[assignment]
        ) -> dict[str, Any]:
            """Get details of a single payment by ID.
    
            Returns amount, status, payment method, customer info, and more.
            """
            client = await get_client(ctx)
            try:
                return await client.get(f"{_BASE}/{payment_id}")
            except StreamAPIError as exc:
                return _err(exc)
    
        @mcp.tool
        async def mark_payment_as_paid(
            payment_id: str,
            payment_method: str = "CASH",
            note: str | None = None,
            ctx: Context = None,  # type: ignore[assignment]
        ) -> dict[str, Any]:
            """Manually mark a payment as paid.
    
            Record a payment received through manual methods.
            *payment_method* must be one of: CASH, BANK_TRANSFER, CARD, or QURRAH.
            """
            body = MarkPaymentPaidRequest(
                payment_method=payment_method,
                note=note,
            )
            client = await get_client(ctx)
            try:
                return await client.post(
                    f"{_BASE}/{payment_id}/mark-paid",
                    body.model_dump(exclude_none=True),
                )
            except StreamAPIError as exc:
                return _err(exc)
    
        @mcp.tool
        async def refund_payment(
            payment_id: str,
            refund_reason: str = "REQUESTED_BY_CUSTOMER",
            refund_note: str | None = None,
            allow_refund_multiple_related_payments: bool = False,
            ctx: Context = None,  # type: ignore[assignment]
        ) -> dict[str, Any]:
            """Issue a refund on a completed payment.
    
            *refund_reason* must be one of: REQUESTED_BY_CUSTOMER, DUPLICATE, FRAUDULENT, OTHER.
            """
            body = RefundPaymentRequest(
                refund_reason=refund_reason,
                refund_note=refund_note,
                allow_refund_multiple_related_payments=allow_refund_multiple_related_payments,
            )
            client = await get_client(ctx)
            try:
                return await client.post(
                    f"{_BASE}/{payment_id}/refund",
                    body.model_dump(exclude_none=True),
                )
            except StreamAPIError as exc:
                return _err(exc)
  • PaymentResponse Pydantic model defining the schema/structure of payment data returned by the get_payment tool
    class PaymentResponse(BaseModel):
        """Subset of fields returned by the Stream API for a payment."""
    
        id: str
        amount: float | None = None
        currency: str | None = None
        status: str | None = None
        customer_id: str | None = None
        payment_method: str | None = None
        created_at: str | None = None
    
        model_config = {"extra": "allow"}
  • get_client helper function used by the get_payment handler to retrieve the appropriate Stream API client (shared in local mode, per-user in remote mode)
    async def get_client(ctx: "Context") -> StreamClient:
        """Return a :class:`StreamClient` for the current request.
    
        Resolution order:
    
        1. **Lifespan client** — used in local / stdio mode where a single
           ``STREAM_API_KEY`` is set as an environment variable.
        2. **Per-user client** — used in remote mode where each user passes
           their own API key as a Bearer token and (optionally) a custom
           base URL via the ``X-Stream-Base-URL`` header.
        """
        # ── 1. Local mode: shared client from server lifespan ─────────────
        shared_client = ctx.lifespan_context.get("client")
        if shared_client is not None:
            return shared_client
    
        # ── 2. Remote mode: per-user client from Bearer token ─────────────
        api_key = current_api_key.get()
        if not api_key:
            raise StreamError(
                "No Stream API key found. "
                "In local mode, set the STREAM_API_KEY env var. "
                "In remote mode, pass your key as a Bearer token in the Authorization header."
            )
    
        base_url = current_base_url.get() or settings.stream_base_url
        cache_key = f"{api_key}::{base_url}"
    
        if cache_key not in _client_cache:
            client = StreamClient(
                api_key=api_key,
                base_url=base_url,
                timeout=settings.stream_timeout,
                max_retries=settings.stream_max_retries,
            )
            await client.__aenter__()
            _client_cache[cache_key] = client
            logger.info(
                "Created cached StreamClient for remote user (key=…%s, base=%s)",
                api_key[-4:], base_url,
            )
    
        return _client_cache[cache_key]
  • register_all_tools function that imports and calls payments.register(mcp) to register the get_payment tool during server startup
    def register_all_tools(mcp: FastMCP) -> None:
        """Import every tool / resource module and call its ``register(mcp)``."""
        from stream_mcp.tools import (
            coupons,
            customers,
            docs,
            invoices,
            payment_links,
            payments,
            products,
        )
    
        payment_links.register(mcp)
        customers.register(mcp)
        products.register(mcp)
        payments.register(mcp)
        coupons.register(mcp)
        invoices.register(mcp)
        docs.register(mcp)
Behavior3/5

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

No annotations are provided, so the description carries full burden. It indicates a read operation ('Get details') and specifies return fields ('amount, status, payment method, customer info, and more'), which adds useful context beyond the input schema. However, it lacks details on permissions, error handling, rate limits, or whether it's idempotent, which are important for a tool with no annotation coverage.

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

Conciseness5/5

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

The description is front-loaded with the core purpose in the first sentence and adds return details in the second. Both sentences earn their place by providing essential information without redundancy. It's appropriately sized for a simple retrieval tool, with no wasted words or unnecessary elaboration.

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

Completeness4/5

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

Given the tool's low complexity (1 parameter), no annotations, and the presence of an output schema (which handles return values), the description is reasonably complete. It covers purpose, parameter intent, and return fields. However, it could improve by addressing behavioral aspects like error cases or idempotency, especially since annotations are absent.

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 description coverage is 0%, so the description must compensate. It clarifies that 'payment_id' is required to retrieve a single payment, adding meaning beyond the schema's basic type and requirement. However, it doesn't specify format constraints (e.g., string length or pattern) or provide examples, leaving some semantic gaps. With 0 parameters documented in the schema, the description does a good but not complete job.

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

Purpose4/5

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

The description clearly states the tool's purpose: 'Get details of a single payment by ID' specifies the verb ('Get'), resource ('payment'), and scope ('single payment by ID'). It distinguishes from sibling 'list_payments' by focusing on individual retrieval rather than listing multiple payments. However, it doesn't explicitly differentiate from other get_* tools like 'get_invoice' or 'get_customer' beyond the resource type.

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

Usage Guidelines3/5

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

The description implies usage context through 'by ID,' suggesting it's for retrieving specific known payments. It doesn't provide explicit guidance on when to use this versus alternatives like 'list_payments' for browsing or other get_* tools for different resources. No exclusions or prerequisites are mentioned, leaving usage context somewhat inferred rather than clearly defined.

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

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/streampayments/stream'

If you have feedback or need assistance with the MCP directory API, please join our Discord server