Agent Pay for developers
PayFar exposes agent payments as an MCP server at https://mcp.payfar.org/mcp. A host connects with an API key or over OAuth 2.1, and every tool call is decided by the owner's policy before any money or card detail moves.
Connect
Two ways in. Either the owner mints a key in the PayFar app (Agents → your agent → Keys) and the host sends it as a bearer token, or the host registers itself and runs the OAuth 2.1 authorization code flow with PKCE.
Dynamic client registration (RFC 7591) is open. Protected-resource metadata (RFC 9728) is served from the MCP host, and authorization-server metadata (RFC 8414) from the API. Resource indicators (RFC 8707) are required: a token is bound to this server and is refused anywhere else.
- Streamable HTTP: https://mcp.payfar.org/mcp
- stdio: npx @payfar/mcp, with PAYFAR_AGENT_KEY in the environment
- Scopes: payments:read, payments:create, credentials:read, threeds:read, services:read, topup:request
The payment loop
Check first, then create. `check_payment` runs the same policy engine as the real call and answers with the decision it would make, so an agent can tell the user what will happen before committing to anything.
`create_payment` returns approved, held or declined. A held payment is not a failure, it is waiting for the owner, and `wait_for_payment` long-polls until they answer. Only once it is approved does `get_payment_credentials` release the card, inside a bounded window with a bounded number of reveals.
When the charge is done, report it. `report_payment_outcome` is what closes the intent and lets settlement pair it with the real transaction; an agent that skips it leaves the owner's budget reserved.
Errors are instructions
Every failure carries a stable code, a message for the log and a hint written for the agent to act on. The codes that matter most:
- intent.pending_approval, the owner has not answered yet; wait, do not retry.
- policy.declined, a rule refused it; the rule id says which. Do not retry the same payment.
- intent.window_closed / intent.reveals_exhausted, the credential window is over. Start a new intent.
- pin.required, a human has to confirm in the app. Nothing the agent can do.
- card.unlock_failed, transient; retry in a minute.
The skill
There is an Agent Skill that teaches a host the whole flow, when to check before creating, how to read a decision, what to do with a hold, and what never to do with card details. Install it alongside the MCP server rather than writing the loop by hand.
It is bundled with the server: `npx @payfar/mcp skill install`, or read it as the `payfar://skill` resource.
What the server will not do
The MCP server is a translator, not an authority. It stores nothing, decides nothing, and forwards the caller's credential to PayFar untouched: the backend is the single place any credential is verified and any policy is applied.
Card details are returned only to the call that asks for them, and never appear in logs, events, notifications or error bodies. If you find one anywhere else, that is a bug worth reporting.