Free trial
One free score to get started. Inspect the API shape with no payment, no headers and no rail to choose. Every other match is pay-per-view.
curl https://www.payforgoals.com/api/v1/scores/trial
Matchday · On demand
Every iconic result, ready to relive in a single request. PayForGoals.com returns the scoreline - the comeback, the collapse, the impossible final - straight to your terminal.
Same scores, two ways to pay: on-chain over Tempo, or by card over Stripe. Your agent picks whichever rail it can pay.
One detail. We return the score, and only the score. Team names are a premium feature, coming soon.
How it works
Agentic commerce, made concrete: a software agent pays per request over the Machine
Payments Protocol. Free to browse, then pick how your agent pays. One endpoint,
/api/v1/scores/match/{id}, offers Stripe
and Tempo together. Its 402 carries one challenge for each method; the agent pays one
and retries the same URL. No signup, no checkout page.
The OpenAPI document lists the paid endpoints, prices and available methods before
an agent makes a request. It is the useful advance scouting report; the actual
WWW-Authenticate: Payment challenges
returned by the endpoint remain authoritative.
curl https://www.payforgoals.com/openapi.json
{
"paths": {
"/api/v1/scores/match/{id}": {
"get": {
"x-payment-info": {
"offers": [
{ "method": "stripe", "intent": "charge", "amount": "100", "currency": "usd" },
{ "method": "tempo", "intent": "charge", "amount": "1000000", "currency": "0x20c0000000000000000000000000000000000000" }
]
}
}
}
}
}
One free score to get started. Inspect the API shape with no payment, no headers and no rail to choose. Every other match is pay-per-view.
curl https://www.payforgoals.com/api/v1/scores/trial
One result by id from the shared endpoint, settled on-chain as 1.00 pathUSD.
npx mppx https://www.payforgoals.com/api/v1/scores/match/1 \
-H 'Accept-Payment: tempo/charge' \
--network testnet
One payment of 3.00 USD unlocks the 80s, 90s and 00s - three calls on a reusable session.
npx mppx https://www.payforgoals.com/api/v1/scores/classics/80s \
-H 'Accept-Payment: tempo/charge' \
--network testnet
The same result and price, paid with a Stripe Shared Payment Token.
link-cli mpp pay https://www.payforgoals.com/api/v1/scores/match/1 \
--context "Purchase scoreline #1 from PayForGoals for $1.00 USD because the user asked the agent to retrieve this specific football result from the demo API." \
--test
One payment of $3.00 USD unlocks all three decades - same metered session, settled on a PaymentIntent.
link-cli mpp pay https://www.payforgoals.com/api/v1/scores/classics/80s \
--context "Purchase a three-use Decade Pass from PayForGoals for $3.00 USD because the user asked the agent to retrieve classic football results." \
--test
The first paid request returns a 402. After the client settles and retries, the API serves the scoreline with a payment receipt.
{
"tier": "pay-per-view",
"scoreline": {
"id": 1,
"home_score": 7,
"away_score": 1,
"year": 2014,
"teams": null
}
}
Levelling with you
Yes, in the way a score API without teams can be real. PayForGoals.com is a working demo of the Machine Payments Protocol (MPP), built by Square1 on our open-source package square1/laravel-mpp.
MPP lets a server charge for a request using nothing but HTTP. There's no signup, no checkout page, no stored card. The buyer is usually a software agent, and it pays per request, in the moment, then moves on. This is what agentic commerce looks like in practice: machine payments settled inline, with no human at a checkout.
Those paid PayForGoals.com endpoints above are gated by exactly this package. The same 402 loop runs on two rails: a pathUSD transfer on Tempo's test network, or a Stripe PaymentIntent confirmed from a Shared Payment Token.
The unpaid request comes back with a signed challenge: amount, method, scope and expiry.
The agent settles on its rail, then retries the same request with a payment credential.
The server verifies settlement, serves the data, and returns a receipt with the settlement reference.
Getting started
Call one endpoint and choose a settlement method. Tempo runs end to end with
npx mppx; Stripe uses a Shared Payment Token
from Link or a test buyer account.
With no hint, the server offers both methods. A client can ask for one method, or rank
several with quality values. The returned WWW-Authenticate
challenges are always authoritative.
curl -i https://www.payforgoals.com/api/v1/scores/match/1
HTTP/1.1 402 Payment Required
Content-Type: application/problem+json
Cache-Control: no-store, private
WWW-Authenticate: Payment … method="stripe" …,
Payment … method="tempo" …
curl -i https://www.payforgoals.com/api/v1/scores/match/1 \
-H 'Accept-Payment: tempo/charge'
HTTP/1.1 402 Payment Required
Content-Type: application/problem+json
Cache-Control: no-store, private
WWW-Authenticate: Payment … method="tempo" …
curl -i https://www.payforgoals.com/api/v1/scores/match/1 \
-H 'Accept-Payment: stripe/charge'
HTTP/1.1 402 Payment Required
Content-Type: application/problem+json
Cache-Control: no-store, private
WWW-Authenticate: Payment … method="stripe" …
A throwaway wallet, funded with test pathUSD. No real money touches this.
npx mppx account create
npx mppx account fund --network testnet
mppx fetches the 402, signs the transfer, and retries - all in one command.
npx mppx https://www.payforgoals.com/api/v1/scores/match/1 \
-H 'Accept-Payment: tempo/charge' \
--network testnet --account main
HTTP/1.1 402 Payment Required
Content-Type: application/problem+json
Cache-Control: no-store, private
WWW-Authenticate: Payment id="LRt7…w7k",
realm="www.payforgoals.com", method="stripe",
intent="charge", request="<base64url>", …,
Payment id="Kf9c…x2m", realm="…", method="tempo",
intent="charge", request="<base64url>", …
{
"type": "https://paymentauth.org/problems/payment-required",
"title": "Payment Required",
"status": 402,
"detail": "Payment is required.",
"challengeId": "LRt7…w7k"
}
one 402, one challenge per rail. mppx picks Tempo. Its request decodes to →
{"amount":"1000000","currency":"0x20c00000…","methodDetails":{"chainId":42431,"memo":"0x…","supportedModes":["pull"]},"recipient":"0x0dcd39…"}
1000000 = 1.00 pathUSD at 6 decimals.
HTTP/1.1 200 OK
Payment-Receipt: <base64url-json>
# decoded receipt:
{
"method": "tempo",
"status": "success",
"timestamp": "2026-06-23T12:51:42.163Z",
"reference": "0x3da1…913b",
"challengeId": "Kf9c…x2m",
"amount": "1000000",
"currency": "0x20c00000…"
}
reference is the settled transaction hash. The funds - 1.00 pathUSD - land at the recipient on Tempo testnet. View the recipient wallet.
A metered endpoint charges once and hands back a Payment-Session
with credits. Present that session for the same endpoint's other decades and they're served with no
new payment, until the credits run out.
# 1 · pay once - issues a 3-credit session
npx mppx https://www.payforgoals.com/api/v1/scores/classics/80s \
-H 'Accept-Payment: tempo/charge' \
--network testnet --account main -i
→ Payment-Session: id="sess_…EP",
remaining="2", scope="classics"
# 2 · reuse it - no charge, credits decrement
curl https://www.payforgoals.com/api/v1/scores/classics/90s \
-H 'Authorization: Payment session="sess_…EP"'
→ 200 OK · Payment-Session remaining="1"
curl https://www.payforgoals.com/api/v1/scores/classics/00s \
-H 'Authorization: Payment session="sess_…EP"'
→ 200 OK · Payment-Session remaining="0"
The same /api/v1/scores/match/{id}
402 carries a method="stripe" challenge
alongside Tempo. Pay it with Stripe Link, or mint a test Shared Payment Token yourself.
This plain curl only inspects the challenge. The Stripe challenge's
request carries the amount in minor units
and the seller's network profile; a payment client handles the credential and retry.
curl -i https://www.payforgoals.com/api/v1/scores/match/1 \
-H 'Accept-Payment: stripe/charge'
HTTP/1.1 402 Payment Required
Content-Type: application/problem+json
Cache-Control: no-store, private
WWW-Authenticate: Payment id="…", realm="…", method="stripe",
intent="charge", request="<base64url>", expires="…", opaque="…"
the stripe request decodes to → {"amount":"100","currency":"usd","methodDetails":{"networkId":"profile_…","paymentMethodTypes":["card"]}}
Link is the buyer wallet for Stripe SPTs and currently requires a US Link account. This command reads the challenge, requests approval, presents a test token and retries.
link-cli auth login
link-cli mpp pay https://www.payforgoals.com/api/v1/scores/match/1 \
--context "Purchase scoreline #1 from PayForGoals for $1.00 USD because the user asked the agent to retrieve this specific football result from the demo API." \
--test
For a quick test, mint an SPT from a buyer Stripe test account, then let an MPP client replay the request. The credential contains the echoed challenge and token as base64url JSON.
curl -s -u "sk_test_buyer_...:" \
-H "Stripe-Version: 2026-05-27.preview" \
-X POST https://api.stripe.com/v1/test_helpers/shared_payment/granted_tokens \
-d payment_method=pm_card_visa \
-d "usage_limits[currency]=usd" \
-d "usage_limits[max_amount]=100" \
-d "seller_details[network_id]=profile_..."
# seller_details is optional for this test helper. When present, use the
# networkId decoded from the Stripe challenge to scope the SPT to this seller.
curl -i https://www.payforgoals.com/api/v1/scores/match/1 \
-H 'Authorization: Payment <base64url {challenge, payload, source}>'
HTTP/1.1 200 OK
Payment-Receipt: <base64url-json>
# decoded receipt:
{
"status": "success",
"method": "stripe",
"timestamp": "…",
"reference": "pi_3Q…",
"challengeId": "LRt7…w7k",
"amount": "1.00",
"currency": "USD"
}
The shared /api/v1/scores/classics/{80s|90s|00s} endpoint
settles a single $3.00 USD PaymentIntent and issues a 3-credit
Payment-Session - the same metered session as Tempo, paid by card instead of on-chain.
# 1 · pay the first decade with an SPT - issues a 3-credit session
curl -i https://www.payforgoals.com/api/v1/scores/classics/80s \
-H 'Authorization: Payment <base64url … + SPT>'
→ Payment-Session: id="sess_...",
remaining="2", scope="classics"
# 2 · reuse it on the other decades - no charge, credits decrement
curl https://www.payforgoals.com/api/v1/scores/classics/90s \
-H 'Authorization: Payment session="sess_..."'
→ 200 OK · Payment-Session remaining="1"
curl https://www.payforgoals.com/api/v1/scores/classics/00s \
-H 'Authorization: Payment session="sess_..."'
→ 200 OK · Payment-Session remaining="0"
FAQ
The short version of what this demo is and how an agent pays for a request.
Agentic commerce is buying and selling where the customer is a software agent rather than a person clicking through a checkout. The agent discovers a price, pays for exactly what it needs, and moves on. PayForGoals.com is a small working example: an agent pays per request for a single football scoreline.
The Machine Payments Protocol (MPP) is an open way for a server to charge for an HTTP request and for a client to pay it using standard web mechanics. An unpaid request returns an HTTP 402 Payment Required challenge; the client settles it and retries, and the server returns the resource plus a receipt. It is the rail-agnostic plumbing underneath this demo.
Machine payments happen inline, per request. There is no account, no checkout page and no stored card. The agent reads the 402 challenge, settles it on one of two rails, then replays the request with an Authorization: Payment header. Settlement is verified before the resource is served.
Two. Stripe Shared Payment Tokens (SPTs), settled inline as a PaymentIntent, and Tempo pathUSD, an on-chain stablecoin transfer on the Tempo testnet. One unpaid request offers both methods, and the agent chooses one.
No. That is the point of agentic commerce: the buyer pays for one request in the moment, then leaves. Nothing is stored and there is no signup. You can inspect the API shape for free with a single trial score before paying for anything.
The demo is real and the payments settle for real (Stripe in test mode, Tempo on testnet). The gating is provided by Square1's open-source package square1/laravel-mpp, which drops into any Laravel app. Stripe live acceptance is currently US-gated; Tempo runs on testnet.