mppx

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 29, 2026 License: MIT Imports: 12 Imported by: 0

README

mppx

mppx-go

Go SDK for the Machine Payment Protocol (MPP): the server returns 402 Payment Required with a challenge, and the client can automatically pay and retry the request.

Installation

go get github.com/cp0x-org/mppx

Requirement: Go 1.25+ (see go.mod).

What Is Included

  • github.com/cp0x-org/mppx - core protocol types:
    • Challenge, Credential, Receipt
    • header serialization/deserialization
    • PaymentError + RFC 9457 ProblemDetails
    • Expires.*, ComputeDigest, VerifyDigest
  • github.com/cp0x-org/mppx/server - server-side 402/200 flow (Handle, Compose, Middleware, HandlerFunc)
  • github.com/cp0x-org/mppx/client - automatic 402 handling and retry with Authorization: Payment ...
  • github.com/cp0x-org/mppx/middleware/gin - Gin middleware
  • github.com/cp0x-org/mppx/middleware/fiber - Fiber middleware
  • github.com/cp0x-org/mppx/tempo - Tempo payment method (charge and session)
  • github.com/cp0x-org/mppx/stripe - Stripe payment method (charge)

Quick Start

# PowerShell
$env:MPP_SECRET_KEY="demo-secret-key-change-in-production"
go run ./examples/basic/server

In another terminal:

go run ./examples/basic/client

Payment Flow

  1. Client sends a regular HTTP request.
  2. Server responds with 402, adds WWW-Authenticate: Payment ..., and returns application/problem+json.
  3. Client parses the challenge, creates a credential, and retries with Authorization: Payment ....
  4. Server verifies the credential and returns 200 + Payment-Receipt.

Errors and Status Codes

If a method returns *mppx.PaymentError from Verify(), the server serializes it as RFC 9457 application/problem+json (usually with a new challenge).

Main SDK errors:

Constructor HTTP Problem Type
ErrMalformedCredential 402 .../malformed-credential
ErrInvalidChallenge 402 .../invalid-challenge
ErrVerificationFailed 402 .../verification-failed
ErrPaymentRequired 402 .../payment-required
ErrPaymentExpired 402 .../payment-expired
ErrInvalidPayload 402 .../invalid-payload
ErrPaymentInsufficient 402 .../payment-insufficient
ErrInsufficientBalance 402 .../session/insufficient-balance
ErrInvalidSignature 402 .../session/invalid-signature
ErrBadRequest 400 .../bad-request
ErrMethodUnsupported 400 .../method-unsupported
ErrChannelNotFound 410 .../session/channel-not-found
ErrChannelClosed 410 .../session/channel-finalized

Useful helpers:

  • mppx.IsPaymentError(err) / mppx.AsPaymentError(err) for checking/unwrapping payment errors.
  • Any non-PaymentError returned from Verify() is automatically wrapped as ErrVerificationFailed(...).

Headers and Data Format

  • Server challenge: WWW-Authenticate: Payment id="...", realm="...", method="...", intent="...", request="..."
  • Client credential: Authorization: Payment <base64url-json>
  • Server receipt: Payment-Receipt: <base64url-json>
  • Error body: Content-Type: application/problem+json (RFC 9457)

Challenge fields:

  • realm, method, intent, request are required for payment routing.
  • expires is supported and validated via mppx.IsExpired.
  • description is set via server.WithDescription.
  • opaque is set via server.WithMeta.

Key Server API Elements

  • server.New(server.Config{SecretKey, Realm, DefaultExpiry})
  • srv.Handle(r, method, req, opts...)
  • srv.Compose(entries...) - multiple payment methods for one endpoint
  • srv.Middleware(...) / srv.HandlerFunc(...)
  • server.WithDescription(...), server.WithExpires(...), server.WithMeta(...)

Validations inside Handle:

  • challenge signature (SecretKey + HMAC),
  • method/intent/realm match,
  • key request field match: amount, currency, recipient,
  • expires check.

Key Client API Elements

  • client.New(client.Config{Methods, HTTPClient, OnChallenge})
  • c.Do(req), c.Get(ctx, url), c.Post(...)
  • client.GetReceipt(resp)

Do behavior:

  • validates URL (http/https),
  • on 402, parses challenge,
  • finds registered method by method/intent,
  • creates credential and retries the request.

Middleware (Gin/Fiber)

Detailed documentation:

In short:

  • Payment(...) - one payment method per route.
  • Compose(...) - multiple payment methods.
  • GetReceipt(c) - extracts mppx.Receipt in the handler.

Repository Examples

  • go run ./examples/basic/server - basic net/http + Gin
  • go run ./examples/fiber/server - Fiber middleware
  • go run ./examples/http-middleware/server - HTTP middleware patterns
  • go run ./examples/multi-method/server - multi-method (server.Compose)
  • go run ./examples/session/server - session flow (tempo/session-like)
  • go run ./examples/stripe/server - Stripe flow (STRIPE_SECRET_KEY=sk_test_...)
  • go run ./examples/tempo/charge/server - Tempo one-time charge (TIP-20 transfer)
  • go run ./examples/tempo/session/server - Tempo payment channel (open/voucher/close)

Clients are in matching examples/*/client folders.

How to run the Tempo charge example (server + client), configure .env files, and see real output: docs/tempo-charge-example.md.

Minimal Example: Paid Server Endpoint

package main

import (
	"context"
	"encoding/json"
	"net/http"
	"os"

	mppx "github.com/cp0x-org/mppx"
	"github.com/cp0x-org/mppx/server"
)

type DemoMethod struct{}

func (m *DemoMethod) Name() string   { return "demo" }
func (m *DemoMethod) Intent() string { return "charge" }
func (m *DemoMethod) DefaultRequest() map[string]any {
	return map[string]any{"currency": "USDC", "recipient": "0xabc"}
}
func (m *DemoMethod) Verify(_ context.Context, cred mppx.Credential, _ map[string]any) (mppx.Receipt, error) {
	payload, ok := cred.Payload.(map[string]any)
	if !ok {
		return mppx.Receipt{}, mppx.ErrInvalidPayload("expected object payload")
	}
	txHash, _ := payload["txHash"].(string)
	if txHash == "" {
		return mppx.Receipt{}, mppx.ErrInvalidPayload("missing txHash")
	}
	return mppx.NewReceipt(mppx.ReceiptParams{Method: "demo", Reference: txHash}), nil
}

func main() {
	srv := server.New(server.Config{SecretKey: os.Getenv("MPP_SECRET_KEY"), Realm: "localhost"})
	method := &DemoMethod{}

	http.HandleFunc("/premium", func(w http.ResponseWriter, r *http.Request) {
		result := srv.Handle(r, method, map[string]any{"amount": "1000000"}, server.WithDescription("Premium API"))
		if result.Status == http.StatusPaymentRequired {
			result.Write(w) // 402 + WWW-Authenticate + Problem Details
			return
		}
		result.SetReceiptHeader(w) // Payment-Receipt
		_ = json.NewEncoder(w).Encode(map[string]any{"ok": true})
	})

	_ = http.ListenAndServe(":8080", nil)
}

Minimal Example: Client Request and Handling

package main

import (
	"context"
	"net/http"

	mppx "github.com/cp0x-org/mppx"
	"github.com/cp0x-org/mppx/client"
)

type DemoClientMethod struct{}

func (m *DemoClientMethod) Name() string   { return "demo" }
func (m *DemoClientMethod) Intent() string { return "charge" }
func (m *DemoClientMethod) CreateCredential(_ context.Context, ch mppx.Challenge) (string, error) {
	cred := mppx.Credential{
		Challenge: ch,
		Payload:   map[string]any{"txHash": "0xdeadbeef"},
		Source:    "did:pkh:eip155:1:0xDemo",
	}
	return mppx.SerializeCredential(cred), nil
}

func main() {
	c := client.New(client.Config{
		Methods:    []mppx.ClientMethod{&DemoClientMethod{}},
		HTTPClient: http.DefaultClient,
	})

	resp, err := c.Get(context.Background(), "http://localhost:8080/premium")
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()

	receipt, err := client.GetReceipt(resp) // Payment-Receipt -> mppx.Receipt
	if err != nil {
		panic(err)
	}
	_ = receipt // use receipt.Method / receipt.Reference / receipt.Timestamp
}

Development

go build ./...
go test ./...

Contributing

Documentation

Index

Constants

View Source
const (
	// HTTP header names.
	AuthorizationHeader   = "Authorization"
	WWWAuthenticateHeader = "WWW-Authenticate"
	PaymentReceiptHeader  = "Payment-Receipt"
	ContentTypeHeader     = "Content-Type"
	CacheControlHeader    = "Cache-Control"
	XForwardedHostHeader  = "X-Forwarded-Host"
	IdempotencyKeyHeader  = "Idempotency-Key"
)
View Source
const (
	// Shared HTTP header values and auth scheme fragments.
	AuthSchemePayment       = "Payment"
	AuthSchemePaymentPrefix = AuthSchemePayment + " "
	CacheControlNoStore     = "no-store"
	ReceiptStatusSuccess    = "success"
)
View Source
const (
	// Common media types.
	MediaTypeJSON            = "application/json"
	MediaTypeProblemJSON     = "application/problem+json"
	MediaTypeFormURLEncoded  = "application/x-www-form-urlencoded"
	HeaderValueBooleanTrue   = "true"
	HeaderIdempotentReplayed = "idempotent-replayed"
)

Variables

View Source
var Expires = expiresHelper{}

Expires provides convenience functions for generating ISO 8601 expiration timestamps. Pass the result as the Expires field in ChallengeParams.

Example:

challenge, _ := mppx.NewChallenge(mppx.ChallengeParams{
    SecretKey: secretKey,
    Realm:     "api.example.com",
    Expires:   mppx.Minutes(5),
    // ...
})

Functions

func ComputeDigest

func ComputeDigest(data any) (string, error)

ComputeDigest computes a SHA-256 digest of the given data. The returned string is in the format "sha-256=<base64>", suitable for the digest field in a Challenge.

data may be a []byte, string, or a JSON-serializable value.

func DeserializePaymentRequest

func DeserializePaymentRequest(encoded string) (map[string]any, error)

DeserializePaymentRequest decodes a base64url-encoded payment request string into a map.

func IsExpired

func IsExpired(expires string) bool

IsExpired reports whether an ISO 8601 expiration timestamp has passed. Returns false if the timestamp is empty (no expiration).

func IsPaymentError

func IsPaymentError(err error) bool

IsPaymentError reports whether err is or wraps a *PaymentError.

func MarkUsed

func MarkUsed(ctx context.Context, store Store, key string) (bool, error)

MarkUsed marks a key as used in the store (for replay detection). Returns (true, nil) if the key was newly marked, (false, nil) if already used.

func MergeRequest

func MergeRequest(method ServerMethod, callSiteRequest map[string]any) map[string]any

MergeRequest merges method defaults with call-site request parameters. Call-site values take precedence over defaults.

func MethodKey

func MethodKey(m ServerMethod) string

MethodKey returns the canonical "name/intent" key for a ServerMethod.

func SerializeChallenge

func SerializeChallenge(c Challenge) string

SerializeChallenge serializes a Challenge to the WWW-Authenticate header value format.

Format: Payment id="...", realm="...", method="...", intent="...", request="<base64url>"[, ...]

func SerializeCredential

func SerializeCredential(cred Credential) string

SerializeCredential serializes a Credential to the Authorization header value format.

Format: Payment <base64url(JSON)>

func SerializePaymentRequest

func SerializePaymentRequest(req map[string]any) string

SerializePaymentRequest serializes a payment request map to a base64url-encoded canonical JSON string. Go's encoding/json sorts map keys, producing deterministic output suitable for HMAC computation.

func SerializeReceipt

func SerializeReceipt(r Receipt) string

SerializeReceipt serializes a Receipt to a base64url-encoded JSON string suitable for the Payment-Receipt response header.

func VerifyChallenge

func VerifyChallenge(c Challenge, secretKey string) bool

VerifyChallenge verifies that a challenge's ID matches the expected HMAC-SHA256. Uses constant-time comparison to prevent timing attacks.

func VerifyDigest

func VerifyDigest(digest string, data any) (bool, error)

VerifyDigest verifies that a digest string matches the given data. digest must be in the format "sha-256=<base64>".

Types

type Challenge

type Challenge struct {
	// ID is the challenge identifier. When created with SecretKey it is HMAC-bound to its contents.
	ID string `json:"id"`
	// Realm identifies the server (e.g. hostname).
	Realm string `json:"realm"`
	// Method is the payment method name (e.g. "tempo", "stripe").
	Method string `json:"method"`
	// Intent is the intent type (e.g. "charge", "session").
	Intent string `json:"intent"`
	// Request contains method-specific payment parameters.
	Request map[string]any `json:"request"`
	// Digest is an optional SHA-256 digest of the HTTP request body ("sha-256=<base64>").
	Digest string `json:"digest,omitempty"`
	// Expires is an optional ISO 8601 expiration timestamp.
	Expires string `json:"expires,omitempty"`
	// Opaque contains optional server-defined correlation data. Clients MUST NOT modify this.
	Opaque map[string]string `json:"opaque,omitempty"`
	// Description is an optional human-readable payment description.
	Description string `json:"description,omitempty"`
}

Challenge is a payment challenge issued by a server in a WWW-Authenticate header.

func DeserializeChallenge

func DeserializeChallenge(header string) (Challenge, error)

DeserializeChallenge parses the first Payment challenge from a WWW-Authenticate header value.

func DeserializeChallenges

func DeserializeChallenges(header string) ([]Challenge, error)

DeserializeChallenges parses all Payment challenges from a WWW-Authenticate header value that may contain multiple comma-separated challenges.

func NewChallenge

func NewChallenge(p ChallengeParams) (Challenge, error)

NewChallenge creates a Challenge. Either ID or SecretKey must be set in params.

type ChallengeParams

type ChallengeParams struct {
	// ID is an explicit challenge identifier.
	ID string
	// SecretKey causes the ID to be computed as HMAC-SHA256 over the challenge parameters.
	// Use this instead of ID for stateless server-side verification.
	SecretKey string
	// Realm identifies the server.
	Realm string
	// Method is the payment method name.
	Method string
	// Intent is the intent type.
	Intent string
	// Request contains method-specific payment parameters.
	Request map[string]any
	// Digest is an optional body digest.
	Digest string
	// Expires is an optional ISO 8601 expiration timestamp.
	Expires string
	// Opaque contains optional server-defined correlation data.
	Opaque map[string]string
	// Description is an optional human-readable description.
	Description string
}

ChallengeParams holds parameters for creating a new Challenge. Either ID or SecretKey must be provided.

type ClientMethod

type ClientMethod interface {
	// Name returns the payment method identifier.
	Name() string
	// Intent returns the intent type.
	Intent() string
	// CreateCredential creates a payment credential from a challenge.
	// Returns the serialized credential string suitable for an Authorization header.
	CreateCredential(ctx context.Context, challenge Challenge) (string, error)
}

ClientMethod is a payment method that creates credentials on the client side. Implement this interface to add a custom payment method to your client.

type Credential

type Credential struct {
	// Challenge is the challenge this credential responds to.
	Challenge Challenge `json:"challenge"`
	// Payload contains method-specific payment proof (e.g. transaction hash, signature).
	// The concrete type depends on the payment method.
	Payload any `json:"payload"`
	// Source is an optional payer identifier as a DID (e.g. "did:pkh:eip155:1:0x...").
	Source string `json:"source,omitempty"`
}

Credential is a payment credential sent by a client in an Authorization header.

func DeserializeCredential

func DeserializeCredential(header string) (Credential, error)

DeserializeCredential parses an Authorization header value into a Credential.

func ExtractCredential

func ExtractCredential(r *http.Request) (Credential, bool, error)

ExtractCredential extracts a Credential from an HTTP request's Authorization header. Returns (cred, true, nil) if a valid Payment credential is present. Returns (Credential{}, false, nil) if no Payment scheme is present. Returns (Credential{}, true, err) if a Payment scheme is present but malformed.

type MemoryStore

type MemoryStore struct {
	// contains filtered or unexported fields
}

MemoryStore is a thread-safe in-memory Store implementation. Suitable for development and testing; does not persist across restarts.

func NewMemoryStore

func NewMemoryStore() *MemoryStore

NewMemoryStore creates a new in-memory store.

func (*MemoryStore) Delete

func (s *MemoryStore) Delete(_ context.Context, key string) error

func (*MemoryStore) Get

func (s *MemoryStore) Get(_ context.Context, key string) (value string, found bool, err error)

func (*MemoryStore) Put

func (s *MemoryStore) Put(_ context.Context, key, value string) error

type PaymentError

type PaymentError struct {
	// ErrorType is the RFC 9457 problem type URI.
	ErrorType string
	// Title is a human-readable summary.
	Title string
	// HTTPStatus is the HTTP status code (default 402).
	HTTPStatus int
	// Detail is a human-readable explanation.
	Detail string
}

PaymentError is the base type for all payment-related errors. It implements the error interface and serializes to RFC 9457 Problem Details.

func AsPaymentError

func AsPaymentError(err error) (*PaymentError, bool)

AsPaymentError returns the *PaymentError within err, or (nil, false).

func ErrBadRequest

func ErrBadRequest(reason string) *PaymentError

ErrBadRequest creates a "bad request" error (400).

func ErrChannelClosed

func ErrChannelClosed(reason string) *PaymentError

ErrChannelClosed creates a "channel closed" error (410).

func ErrChannelNotFound

func ErrChannelNotFound(reason string) *PaymentError

ErrChannelNotFound creates a "channel not found" error (410).

func ErrInsufficientBalance

func ErrInsufficientBalance(reason string) *PaymentError

ErrInsufficientBalance creates an "insufficient balance" error (402) for streaming sessions.

func ErrInvalidChallenge

func ErrInvalidChallenge(id, reason string) *PaymentError

ErrInvalidChallenge creates an "invalid challenge" error (402).

func ErrInvalidPayload

func ErrInvalidPayload(reason string) *PaymentError

ErrInvalidPayload creates an "invalid payload" error (402).

func ErrInvalidSignature

func ErrInvalidSignature(reason string) *PaymentError

ErrInvalidSignature creates an "invalid signature" error (402) for session vouchers.

func ErrMalformedCredential

func ErrMalformedCredential(reason string) *PaymentError

ErrMalformedCredential creates a "malformed credential" error (402).

func ErrMethodUnsupported

func ErrMethodUnsupported(method string) *PaymentError

ErrMethodUnsupported creates a "method unsupported" error (400).

func ErrPaymentExpired

func ErrPaymentExpired(expires string) *PaymentError

ErrPaymentExpired creates a "payment expired" error (402).

func ErrPaymentInsufficient

func ErrPaymentInsufficient(reason string) *PaymentError

ErrPaymentInsufficient creates a "payment insufficient" error (402).

func ErrPaymentRequired

func ErrPaymentRequired(description string) *PaymentError

ErrPaymentRequired creates a "payment required" error (402).

func ErrVerificationFailed

func ErrVerificationFailed(reason string) *PaymentError

ErrVerificationFailed creates a "verification failed" error (402).

func (*PaymentError) Error

func (e *PaymentError) Error() string

func (*PaymentError) Status

func (e *PaymentError) Status() int

Status returns the HTTP status code for this error (defaults to 402).

func (*PaymentError) ToProblemDetails

func (e *PaymentError) ToProblemDetails(challengeID string) ProblemDetails

ToProblemDetails converts the error to RFC 9457 Problem Details format.

type ProblemDetails

type ProblemDetails struct {
	Type        string `json:"type"`
	Title       string `json:"title"`
	Status      int    `json:"status"`
	Detail      string `json:"detail"`
	ChallengeID string `json:"challengeId,omitempty"`
}

ProblemDetails is an RFC 9457 Problem Details object returned in 402 response bodies.

type Receipt

type Receipt struct {
	// Method is the payment method used (e.g. "tempo", "stripe").
	Method string `json:"method"`
	// Reference is a method-specific payment reference (e.g. transaction hash).
	Reference string `json:"reference"`
	// Status is always "success". Failures use HTTP 402 + Problem Details.
	Status string `json:"status"`
	// Timestamp is the RFC 3339 settlement timestamp.
	Timestamp string `json:"timestamp"`
	// ExternalID is an optional external reference ID echoed from the credential payload.
	ExternalID string `json:"externalId,omitempty"`
}

Receipt is a payment receipt returned by a server after successful payment verification.

func DeserializeReceipt

func DeserializeReceipt(encoded string) (Receipt, error)

DeserializeReceipt decodes a base64url-encoded Payment-Receipt header value.

func ExtractReceipt

func ExtractReceipt(resp *http.Response) (Receipt, error)

ExtractReceipt extracts the Receipt from an HTTP response's Payment-Receipt header.

func NewReceipt

func NewReceipt(p ReceiptParams) Receipt

NewReceipt creates a Receipt. Status is always set to "success".

type ReceiptParams

type ReceiptParams struct {
	Method     string
	Reference  string
	Timestamp  time.Time // defaults to time.Now() if zero
	ExternalID string
}

ReceiptParams holds parameters for creating a Receipt.

type ServerMethod

type ServerMethod interface {
	// Name returns the payment method identifier (e.g. "tempo", "stripe").
	Name() string
	// Intent returns the intent type (e.g. "charge", "session").
	Intent() string
	// DefaultRequest returns default request parameters merged with call-site options.
	// Return nil if no defaults.
	DefaultRequest() map[string]any
	// Verify verifies a payment credential and returns a Receipt.
	// Return a *PaymentError for payment-specific failures (will be serialized to RFC 9457).
	// Return any other error for internal failures (wrapped in VerificationFailedError).
	Verify(ctx context.Context, cred Credential, req map[string]any) (Receipt, error)
}

ServerMethod is a payment method that verifies credentials on the server side. Implement this interface to add a custom payment method to your server.

Example usage:

type MyChargeMethod struct {
    recipient string
    currency  string
}

func (m *MyChargeMethod) Name() string   { return "mymethod" }
func (m *MyChargeMethod) Intent() string { return "charge" }
func (m *MyChargeMethod) DefaultRequest() map[string]any {
    return map[string]any{"currency": m.currency, "recipient": m.recipient}
}
func (m *MyChargeMethod) Verify(ctx context.Context, cred Credential, req map[string]any) (Receipt, error) {
    // verify payment on-chain, via API, etc.
    return NewReceipt(ReceiptParams{Method: m.Name(), Reference: txHash}), nil
}

type Store

type Store interface {
	// Get retrieves a value by key. Returns ("", false, nil) if not found.
	Get(ctx context.Context, key string) (string, bool, error)
	// Put stores a value by key.
	Put(ctx context.Context, key, value string) error
	// Delete removes a value by key.
	Delete(ctx context.Context, key string) error
}

Store is a generic key-value store interface for tracking used credentials, session state, and other payment-related state.

Implement this interface to use Redis, Postgres, Cloudflare KV, etc.

Directories

Path Synopsis
Package client implements the Machine Payment Protocol client-side handler.
Package client implements the Machine Payment Protocol client-side handler.
examples
basic/client command
Example MPP client that automatically handles 402 Payment Required responses.
Example MPP client that automatically handles 402 Payment Required responses.
basic/server command
Example MPP server using net/http and Gin.
Example MPP server using net/http and Gin.
fiber/client command
Fiber MPP client — exercises the Fiber server example.
Fiber MPP client — exercises the Fiber server example.
fiber/server command
Fiber MPP server — payment-gated photo and generation API.
Fiber MPP server — payment-gated photo and generation API.
gin-tempo/client command
Gin + Tempo MPP client example.
Gin + Tempo MPP client example.
gin-tempo/server command
Gin + Tempo MPP server example.
Gin + Tempo MPP server example.
http-middleware/client command
net/http middleware patterns client — exercises all four server patterns.
net/http middleware patterns client — exercises all four server patterns.
http-middleware/server command
net/http middleware patterns server — four ways to gate routes with MPP payments.
net/http middleware patterns server — four ways to gate routes with MPP payments.
multi-method/client command
Multi-method MPP client — demonstrates client-side method selection with server.Compose.
Multi-method MPP client — demonstrates client-side method selection with server.Compose.
multi-method/server command
Multi-method MPP server — accepts two payment methods on the same route.
Multi-method MPP server — accepts two payment methods on the same route.
session/client command
Session MPP client example.
Session MPP client example.
session/server command
Session MPP server example.
Session MPP server example.
stripe/client command
Stripe MPP client — demonstrates the full 402 → SPT → payment flow.
Stripe MPP client — demonstrates the full 402 → SPT → payment flow.
stripe/server command
Stripe MPP server — fortune cookie API gated behind a $1.00 Stripe payment.
Stripe MPP server — fortune cookie API gated behind a $1.00 Stripe payment.
tempo/charge/client command
Tempo charge client example.
Tempo charge client example.
tempo/charge/server command
Tempo charge server example.
Tempo charge server example.
tempo/session/client command
Tempo session client example.
Tempo session client example.
tempo/session/server command
Tempo session server example.
Tempo session server example.
middleware
fiber
Package fibermpp provides Fiber middleware for the Machine Payment Protocol.
Package fibermpp provides Fiber middleware for the Machine Payment Protocol.
gin
Package ginmpp provides Gin middleware for the Machine Payment Protocol.
Package ginmpp provides Gin middleware for the Machine Payment Protocol.
Package server implements the Machine Payment Protocol server-side handler.
Package server implements the Machine Payment Protocol server-side handler.
Package stripe implements the Stripe payment method for the Machine Payment Protocol.
Package stripe implements the Stripe payment method for the Machine Payment Protocol.
Package tempo implements Tempo payment methods for the Machine Payment Protocol.
Package tempo implements Tempo payment methods for the Machine Payment Protocol.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL