charge AI agents per API call

Jul 27, 2026

Share

Category /

other

11 min read

GOAT Network

How to Charge AI Agents Per API Call with x402

Charge AI agents per API call with an exact x402 price, settle only accepted work, and make paid retries replay the same stored result.

scroll

Table of contents

To charge AI agents per API call, define one bounded API operation as a fixed-price product, protect it with an x402 exact payment requirement, and connect the resource server to payment verification and settlement. The agent requests the endpoint, receives 402 Payment Required, authorizes the price under its wallet policy, retries with signed payment evidence, and receives the result after the server accepts the payment.

The implementation is only correct when the same paid retry maps to the same execution. A network timeout must not cause a second charge or repeat an expensive operation. The API also needs a precise definition of success: payment can authorize a call, but the application decides whether the call produced the billable result.

The working contract is:

one price
+ one endpoint version
+ one bounded input
+ one payment authorization
+ one idempotent execution
= one billable API call
one price
+ one endpoint version
+ one bounded input
+ one payment authorization
+ one idempotent execution
= one billable API call
one price
+ one endpoint version
+ one bounded input
+ one payment authorization
+ one idempotent execution
= one billable API call

Define One Billable Call Before Adding Middleware

An HTTP request is not automatically a good billing unit. A fixed per-call price works when requests to the endpoint are economically similar and return a recognizable unit of value.

A normalized company record, one address-risk score, one cached market snapshot, or one bounded translation can be priced per call. An open-ended research request that may invoke several models and thousands of tokens is not one predictable product merely because it enters through one route.

Write the call contract before implementation:

Contract field

Example

resource

company-normalization

version

v2

method and route

POST /v2/normalize-company

fixed price

$0.02

maximum input

one company name, 200 characters

output

one structured company record

success condition

validated result returned or stored

idempotency window

24 hours

retry behavior

replay the stored result

paid failure remedy

retry same execution, service credit, or refund under policy

Versioning matters because a route can change while the URL remains stable. A new data source, output schema, model, or service-level target may change both cost and value. Bind the payment terms to the resource version that the agent is buying.

The price should cover expected provider cost, infrastructure overhead, failure allowance, payment operations, and margin. Do not use a low headline price while allowing unbounded batch sizes or compute. The call must remain bounded in practice, not only in marketing copy.

Bound Cost Before Publishing A Fixed Price

Per-call pricing transfers cost variability to the provider. Keep that variability within a range the fixed price can support.

Apply limits before issuing a payment challenge:

  • maximum request body size;

  • required fields and schema version;

  • maximum records per call;

  • accepted file type and file size;

  • model or data-source tier;

  • execution timeout;

  • concurrency limit;

  • geographic or licensing restrictions;

  • cache and freshness policy.

Use a cheap preflight validation that can reject malformed or unsupported requests before asking the agent to pay. The server should not charge for a missing required field it could detect immediately.

Do not perform the expensive work during preflight. The preflight establishes that the request is eligible for the advertised product. The paid handler performs the actual service.

If one endpoint contains several cost classes, split it into products. For example:

POST /v1/lookup             $0.01  one record
POST /v1/lookup-premium     $0.05  fresh premium sources
POST /v1/lookup-batch       quoted by declared batch tier
POST /v1/lookup             $0.01  one record
POST /v1/lookup-premium     $0.05  fresh premium sources
POST /v1/lookup-batch       quoted by declared batch tier
POST /v1/lookup             $0.01  one record
POST /v1/lookup-premium     $0.05  fresh premium sources
POST /v1/lookup-batch       quoted by declared batch tier

That is easier for an agent policy engine to evaluate than a single route whose cost changes after payment. If usage truly cannot be known in advance, use maximum authorization and metering instead of pretending every request has the same price.

Configure An Exact x402 API Route

The x402 exact scheme is the simplest fit for a known per-call price. The route advertises the amount, network, recipient, scheme, description, and response type. The resource server verifies payment evidence locally or through a facilitator and handles the configured settlement path.

For a current Next.js implementation, create the payment server once:

// lib/x402-server.ts
import {
  HTTPFacilitatorClient,
  x402ResourceServer,
} from "@x402/core/server";
import { ExactEvmScheme } from "@x402/evm/exact/server";

const facilitator = new HTTPFacilitatorClient({
  url: process.env.X402_FACILITATOR_URL!,
});

export const paymentServer = new x402ResourceServer(facilitator);

paymentServer.register(
  "eip155:*",
  new ExactEvmScheme(),
);
// lib/x402-server.ts
import {
  HTTPFacilitatorClient,
  x402ResourceServer,
} from "@x402/core/server";
import { ExactEvmScheme } from "@x402/evm/exact/server";

const facilitator = new HTTPFacilitatorClient({
  url: process.env.X402_FACILITATOR_URL!,
});

export const paymentServer = new x402ResourceServer(facilitator);

paymentServer.register(
  "eip155:*",
  new ExactEvmScheme(),
);
// lib/x402-server.ts
import {
  HTTPFacilitatorClient,
  x402ResourceServer,
} from "@x402/core/server";
import { ExactEvmScheme } from "@x402/evm/exact/server";

const facilitator = new HTTPFacilitatorClient({
  url: process.env.X402_FACILITATOR_URL!,
});

export const paymentServer = new x402ResourceServer(facilitator);

paymentServer.register(
  "eip155:*",
  new ExactEvmScheme(),
);

Then wrap one API handler:

// app/api/v2/normalize-company/route.ts
import { NextRequest, NextResponse } from "next/server";
import { withX402 } from "@x402/next";
import { paymentServer } from "@/lib/x402-server";
import { normalizeCompanyRequest } from "@/lib/normalize-company";

const handler = async (request: NextRequest) => {
  const payload = await request.json();
  const result = await normalizeCompanyRequest(payload, {
    clientRequestId: request.headers.get("x-client-request-id"),
  });

  if (!result.ok) {
    return NextResponse.json(
      {
        error: result.code,
        retryable: result.retryable,
      },
      { status: result.httpStatus },
    );
  }

  return NextResponse.json({
    requestId: result.requestId,
    data: result.data,
  });
};

export const POST = withX402(
  handler,
  {
    accepts: [
      {
        scheme: "exact",
        price: "$0.02",
        network: "eip155:84532",
        payTo: process.env.MERCHANT_ADDRESS!,
      },
    ],
    description: "Normalize one company name",
    mimeType: "application/json",
  },
  paymentServer,
);
// app/api/v2/normalize-company/route.ts
import { NextRequest, NextResponse } from "next/server";
import { withX402 } from "@x402/next";
import { paymentServer } from "@/lib/x402-server";
import { normalizeCompanyRequest } from "@/lib/normalize-company";

const handler = async (request: NextRequest) => {
  const payload = await request.json();
  const result = await normalizeCompanyRequest(payload, {
    clientRequestId: request.headers.get("x-client-request-id"),
  });

  if (!result.ok) {
    return NextResponse.json(
      {
        error: result.code,
        retryable: result.retryable,
      },
      { status: result.httpStatus },
    );
  }

  return NextResponse.json({
    requestId: result.requestId,
    data: result.data,
  });
};

export const POST = withX402(
  handler,
  {
    accepts: [
      {
        scheme: "exact",
        price: "$0.02",
        network: "eip155:84532",
        payTo: process.env.MERCHANT_ADDRESS!,
      },
    ],
    description: "Normalize one company name",
    mimeType: "application/json",
  },
  paymentServer,
);
// app/api/v2/normalize-company/route.ts
import { NextRequest, NextResponse } from "next/server";
import { withX402 } from "@x402/next";
import { paymentServer } from "@/lib/x402-server";
import { normalizeCompanyRequest } from "@/lib/normalize-company";

const handler = async (request: NextRequest) => {
  const payload = await request.json();
  const result = await normalizeCompanyRequest(payload, {
    clientRequestId: request.headers.get("x-client-request-id"),
  });

  if (!result.ok) {
    return NextResponse.json(
      {
        error: result.code,
        retryable: result.retryable,
      },
      { status: result.httpStatus },
    );
  }

  return NextResponse.json({
    requestId: result.requestId,
    data: result.data,
  });
};

export const POST = withX402(
  handler,
  {
    accepts: [
      {
        scheme: "exact",
        price: "$0.02",
        network: "eip155:84532",
        payTo: process.env.MERCHANT_ADDRESS!,
      },
    ],
    description: "Normalize one company name",
    mimeType: "application/json",
  },
  paymentServer,
);

This follows the official server shape while leaving business logic in an application service. Use a test network and test assets during development. Confirm current package versions, scheme support, facilitator configuration, production network, asset, and recipient before launch.

The current official Next.js guidance recommends withX402 for individual API routes because it settles after the handler returns a successful HTTP response, defined there as a status below 400. That is useful for per-call charging: the handler can return an error before settlement when the service did not accept the work.

However, status <400 is only a transport rule. A 200 response containing { "success": false } may still trigger settlement. Make business failures return an appropriate error status before the response leaves the handler.

Follow The Two-Request Agent Flow

The agent normally reaches the resource twice.

First Request: Discover The Price

The agent calls the protected route without payment evidence. The server returns 402 Payment Required and a PAYMENT-REQUIRED header containing encoded requirements.

The requirements should identify:

  • the fixed amount;

  • accepted payment scheme;

  • network;

  • asset or payment option;

  • recipient;

  • resource description;

  • any expiration or extension data.

This response is an offer, not a generic error. The agent's x402 client parses it and presents it to a wallet or payment policy.

Policy Decision: Approve Or Refuse

The agent should check:

  • whether the endpoint and seller are allowed;

  • whether $0.02 is within the per-call limit;

  • whether cumulative task and daily budgets remain available;

  • whether the network and asset are approved;

  • whether the destination matches the expected seller;

  • whether the same request has already been paid;

  • whether human approval is required.

Programmatic payment handling does not mean unrestricted payment. The agent should have narrowly scoped authority and a way to stop.

Second Request: Present Payment Evidence

If approved, the client creates the signed payment payload and retries the same API request with PAYMENT-SIGNATURE. The resource server checks that the payload satisfies the advertised requirements. A facilitator can perform verification and settlement for supported configurations.

On success, the response includes the API result and a PAYMENT-RESPONSE carrying settlement information. The application should also return its own stable request or result ID so the agent can recover the business output independently of transport details.

The seller must test this flow with a real compatible client. A correct 402 response is not enough if the target agent runtime cannot parse the requirements, support the selected network, or sign under the expected scheme.

Bind The Paid Retry To One Execution

The first request and paid retry have the same business purpose, but networks and clients can create more attempts. The agent may retry because it did not receive the response, not because it wants to buy again.

Require a client request ID:

X-Client-Request-Id: req_01K
X-Client-Request-Id: req_01K
X-Client-Request-Id: req_01K

Canonicalize the input and derive a seller key:

execution_key =
  hash(
    merchant_scope
    + endpoint_version
    + client_request_id
    + normalized_request_body
    + payer_or_payment_scope
  )
execution_key =
  hash(
    merchant_scope
    + endpoint_version
    + client_request_id
    + normalized_request_body
    + payer_or_payment_scope
  )
execution_key =
  hash(
    merchant_scope
    + endpoint_version
    + client_request_id
    + normalized_request_body
    + payer_or_payment_scope
  )

Store:

{
  "requestId": "req_01K...",
  "endpoint": "normalize-company:v2",
  "inputHash": "sha256:...",
  "paymentReference": "pay_...",
  "executionState": "succeeded",
  "resultReference": "result_...",
  "settlementState": "settled"
}
{
  "requestId": "req_01K...",
  "endpoint": "normalize-company:v2",
  "inputHash": "sha256:...",
  "paymentReference": "pay_...",
  "executionState": "succeeded",
  "resultReference": "result_...",
  "settlementState": "settled"
}
{
  "requestId": "req_01K...",
  "endpoint": "normalize-company:v2",
  "inputHash": "sha256:...",
  "paymentReference": "pay_...",
  "executionState": "succeeded",
  "resultReference": "result_...",
  "settlementState": "settled"
}

The exact way to extract a payment reference depends on the SDK and integration hooks. Keep that package-specific adapter at the payment boundary. The application service should receive normalized identifiers, not parse raw payment headers throughout the codebase.

Enforce three rules:

  1. The same request ID and same normalized input return the existing execution or stored result.

  2. The same request ID with different input is rejected as a conflict.

  3. Payment evidence already bound to one request cannot unlock another billable call.

Persist the result before sending the response. If the handler finishes but the connection drops, the next retry can replay the stored result.

For side-effecting calls, idempotency is mandatory. A paid endpoint that sends a message, creates an account, purchases an asset, or submits a transaction must not repeat the action because the response was lost.

Decide What Counts As Billable Success

The API needs one authoritative success event. It should not be inferred later from payment alone.

For a synchronous data endpoint, billable success may mean:

input accepted
+ paid request verified
+ dependency response validated
+ result persisted
+ handler returns 2xx
input accepted
+ paid request verified
+ dependency response validated
+ result persisted
+ handler returns 2xx
input accepted
+ paid request verified
+ dependency response validated
+ result persisted
+ handler returns 2xx

For a long-running operation, the call may buy job admission:

input accepted
+ payment verified
+ unique job reserved
+ durable receipt returned
input accepted
+ payment verified
+ unique job reserved
+ durable receipt returned
input accepted
+ payment verified
+ unique job reserved
+ durable receipt returned

In the second model, payment does not promise immediate completion. The product terms must state whether the fee covers admission, consumed work, or a successful final result.

Avoid ambiguous partial responses. If an endpoint returns ten requested records but only six are available, decide before launch whether that is:

  • a successful fixed-price response;

  • a lower-priced tier;

  • a retryable error;

  • a partial delivery requiring a credit.

Make the handler's HTTP status match the decision. Middleware cannot infer product semantics from response JSON.

Also decide how redirects, cached responses, 204 No Content, and partial-content responses are treated. Status-based settlement behavior is useful only when the application uses statuses consistently.

Handle Failures By Stage

Per-call billing needs a response for every failure boundary.

Failure stage

Was work admitted?

Seller action

Agent action

invalid input before challenge

no

return validation error

fix request

agent rejects price

no

no execution

choose another service or stop

payment evidence invalid

no

return payment error or fresh requirements

reauthorize if appropriate

facilitator unavailable before acceptance

no

fail closed and expose retryable state

retry later without assuming payment

settlement result unknown

hold

persist reference and reconcile

query status; do not blindly pay again

handler returns business error

depends on integration

avoid settlement where supported; record failure

correct input or retry under policy

execution succeeds, response lost

yes

replay stored result

retry with same request ID

settlement succeeds, delivery fails

yes

redeliver, rerun, credit, or refund under policy

query result or remedy state

duplicate paid retry

already admitted

return existing execution

accept replayed result

Unknown is a real state. A timeout does not prove that payment failed. Before issuing a new charge, query settlement or order status using the stored reference.

The facilitator simplifies verification and settlement, but it does not decide whether the API output was correct or delivered. The seller retains that obligation.

Use machine-readable error codes such as:

INVALID_INPUT
PAYMENT_REQUIRED
PAYMENT_INVALID
PAYMENT_STATUS_UNKNOWN
REQUEST_ID_CONFLICT
EXECUTION_FAILED
RESULT_PENDING
REMEDY_PENDING
INVALID_INPUT
PAYMENT_REQUIRED
PAYMENT_INVALID
PAYMENT_STATUS_UNKNOWN
REQUEST_ID_CONFLICT
EXECUTION_FAILED
RESULT_PENDING
REMEDY_PENDING
INVALID_INPUT
PAYMENT_REQUIRED
PAYMENT_INVALID
PAYMENT_STATUS_UNKNOWN
REQUEST_ID_CONFLICT
EXECUTION_FAILED
RESULT_PENDING
REMEDY_PENDING

An agent can act safely only when it can distinguish "pay now," "retry without paying," "wait," and "stop."

Store A Receipt That Joins Payment And Delivery

The protocol settlement response and the API result answer different questions. Store both under the same seller request ID.

The receipt should retain:

  • request and endpoint version;

  • normalized input hash;

  • offered fixed price;

  • scheme, network, asset, and recipient;

  • payment and settlement references;

  • facilitator or verifier observation;

  • execution start and completion time;

  • result reference and delivery state;

  • retry count;

  • remedy state.

Do not put sensitive API arguments into public transaction metadata or payment descriptions. The hash can establish application correlation without exposing the raw input.

Reconciliation should scan for mismatched states:

settled payment + no execution
successful execution + no settlement closure
stored result + delivery interrupted
duplicate payment + one execution
one payment + multiple executions
unknown settlement older than threshold
settled payment + no execution
successful execution + no settlement closure
stored result + delivery interrupted
duplicate payment + one execution
one payment + multiple executions
unknown settlement older than threshold
settled payment + no execution
successful execution + no settlement closure
stored result + delivery interrupted
duplicate payment + one execution
one payment + multiple executions
unknown settlement older than threshold

This record also supports pricing analysis. The provider can compare fixed revenue per call with actual compute, data, and support cost without charging the buyer by those internal units.

Use GOAT Where The Per-Call Flow Needs More State

GOAT Network is relevant as one infrastructure context for x402-based agent payments, particularly when the API provider needs durable orders, status, proof, merchant operations, and AgentKit integration around the request.

GOAT's current developer path distinguishes DIRECT mode for payment-gated API responses and other offchain delivery from DELEGATE mode for payment-triggered contract execution. A fixed-price data or model endpoint normally aligns with the DIRECT concept: payment gates delivery, while the API remains responsible for producing the response.

The documented GOAT flow can create an order, expose payment requirements, query order status, and retrieve settlement proof. Those records can be joined to the API's request and result IDs. AgentKit separately provides payer-side actions and merchant-side operations, which can help when both machine customers and seller administration need tooling.

This is an implementation option, not a protocol requirement. x402 is not exclusive to GOAT Network, and the API still needs its own input validation, idempotency, execution, result storage, and remedy logic. Developers should verify current environments, credentials, supported assets, payment modes, API status semantics, and production availability before integrating.

For a basic per-call API, avoid adding payment-triggered contract execution unless the product genuinely needs it. More callback and onchain logic creates more failure states than a straightforward payment-gated response.

Test One Call Under Adverse Conditions

Start on a supported test network with one endpoint, one asset, one fixed price, and one facilitator.

The test suite should prove:

  1. Invalid input is rejected before a payment challenge.

  2. A valid unpaid request receives the expected price and resource terms.

  3. The agent policy rejects a price over its configured limit.

  4. An approved agent signs and retries successfully.

  5. Invalid, expired, or mismatched payment evidence never reaches execution.

  6. The handler returns an error status when the business result fails.

  7. One paid request creates exactly one execution record.

  8. Retrying after a dropped response replays the stored result.

  9. Reusing a request ID with different input returns a conflict.

  10. Reusing payment evidence for another call does not unlock execution.

  11. Facilitator timeout produces an unknown or retryable state, not a second charge.

  12. A settled-but-undelivered call enters the remedy path.

  13. Payment, settlement, execution, and result records reconcile.

Inject failures rather than waiting for them. Terminate the handler after persistence but before response, drop the connection, delay the facilitator, return malformed dependency data, and run two retries concurrently.

Monitor challenge volume, paid conversion, verification latency, handler success, payment-to-result latency, duplicate attempts, paid execution failures, unknown settlement age, and remedies. A transaction count alone cannot show whether customers received their calls.

Know When Per-Call Pricing Stops Fitting

Keep fixed per-call charging when:

  • the endpoint has a clear and bounded output;

  • cost variation is narrow;

  • agents can understand the price before payment;

  • retries can replay one result;

  • the call is a useful product unit.

Change the model when:

  • input size varies by orders of magnitude;

  • model tokens or compute dominate cost;

  • one request orchestrates many unpredictable tools;

  • the buyer wants a long-lived data stream;

  • high-frequency calls make per-request settlement inefficient;

  • value depends on task completion or outcome rather than invocation.

Alternatives include fixed tiers, prepaid credits, maximum authorization with usage settlement, batch settlement, task pricing, or entitlements. Do not retain per-call pricing only because it is easy to configure in middleware.

FAQ

Can x402 charge a different price for every API endpoint?

Yes. Seller route configuration can attach different payment requirements to different protected resources. Keep each endpoint's resource version, input limits, output, and success rule explicit.

Should the API charge again when an AI agent retries?

Not when the retry represents the same paid business request. Use a client request ID, normalized input hash, payment reference, and stored result so the retry replays the original execution.

Does payment verification mean the API call succeeded?

No. Verification establishes that the payment evidence satisfies the requirements. The API must separately execute the operation, validate and store the result, and track delivery.

What x402 scheme is best for a fixed API price?

The exact scheme is the direct fit for a known fixed amount. When actual cost depends on tokens, compute, or bytes served, maximum authorization and metering may be more appropriate.

Can AI agents approve x402 calls automatically?

They can process compatible payment requirements programmatically, but the wallet should enforce per-call and cumulative budgets, approved sellers, networks, assets, and human-approval thresholds.

How can GOAT Network support per-call x402 APIs?

GOAT documents x402 order creation, payment requirements, status, settlement proof, merchant operations, and AgentKit payer tooling. Its DIRECT flow is relevant to payment-gated API delivery, while the provider still owns endpoint execution and result handling.

Make The API Call A Product, Not Just A Request

x402 can carry a fixed price through the same HTTP flow an AI agent already uses. The seller declares an exact requirement, the agent evaluates and signs it, the resource server verifies the paid retry, and the handler returns the protected result under the configured settlement rule.

Reliable per-call charging depends on the application contract around that flow. Bound the input, version the offer, define billable success, bind payment to one idempotent execution, persist the result, and make retries replay rather than repurchase.

When those rules are explicit, an API call becomes a machine-readable product unit. Without them, a working 402 handshake can still produce duplicate work, uncertain charges, and paid requests with no recoverable result.

[01]

AI Knowledge base

More Articles

More Articles

More Articles