@t402/tezos
Tezos blockchain implementation for T402 payments using FA2 (TZIP-12) tokens.
Installation
pnpm add @t402/tezosOverview
The @t402/tezos package enables T402 payments on Tezos using the FA2 token standard (TZIP-12). It uses the exact-direct scheme — the client executes the transfer entrypoint directly on the FA2 contract.
Key features:
- FA2 standard (TZIP-12) — multi-asset token contracts
- Token IDs — FA2 contracts can hold multiple token types
- TzKT indexer — transaction verification via indexer API
Network IDs
| Network | CAIP-2 ID | RPC Endpoint |
|---|---|---|
| Mainnet | tezos:NetXdQprcVkpaWU | https://mainnet.api.tez.ie |
| Ghostnet (Testnet) | tezos:NetXnHfVqm9iesp | https://ghostnet.tezos.marigold.dev |
Tezos CAIP-2 identifiers use the network’s genesis block hash prefix.
Client Usage
import { ExactDirectTezosClient } from '@t402/tezos/exact-direct/client'
const client = new ExactDirectTezosClient({
address: 'tz1YourAddress...',
signAndSendOperation: async (params) => {
// Use your Tezos wallet (Temple, Kukai, etc.)
const result = await wallet.sendOperation(params)
return result.opHash
}
})
const payload = await client.createPaymentPayload(2, requirements)Server Usage
import { ExactDirectTezosServer } from '@t402/tezos/exact-direct/server'
const server = new ExactDirectTezosServer({
rpcUrl: 'https://mainnet.api.tez.ie'
})
const enhanced = await server.enhancePaymentRequirements(baseRequirements)Facilitator Usage
import { ExactDirectTezosFacilitator } from '@t402/tezos/exact-direct/facilitator'
const facilitator = new ExactDirectTezosFacilitator({
rpcUrl: 'https://mainnet.api.tez.ie',
indexerUrl: 'https://api.tzkt.io' // TzKT indexer for verification
})
const result = await facilitator.verify(payload, requirements)
const settled = await facilitator.settle(payload, requirements)PaymentRequirements
const requirements = {
scheme: 'exact-direct',
network: 'tezos:NetXdQprcVkpaWU',
amount: '1000000', // 1 USDT (6 decimals)
asset: 'KT1XnTn74bUtxHfDtBmm2bGZAQfhPbvKWR8o', // FA2 contract
payTo: 'tz1MerchantAddress...',
maxTimeoutSeconds: 300,
extra: {
tokenId: 0 // Token ID within the FA2 contract
}
}Payment Flow
- Client calls the FA2
transferentrypoint on the token contract - Operation is injected into the Tezos network
- Client returns the
opHash(operation hash) as proof - Facilitator verifies via TzKT indexer or RPC
- Operation is confirmed after 1+ block confirmations
Token Addresses
| Token | Network | FA2 Contract | Token ID | Decimals |
|---|---|---|---|---|
| USDt | Mainnet | KT1XnTn74bUtxHfDtBmm2bGZAQfhPbvKWR8o | 0 | 6 |
⚠️
FA2 contracts can hold multiple tokens. Always specify the tokenId in the extra field
of PaymentRequirements. USDT on Tezos uses token ID 0.
Payload Structure
interface ExactDirectTezosPayload {
opHash: string; // operation hash (o prefix, base58)
from: string; // sender address (tz1/tz2/tz3 prefix)
to: string; // recipient address
amount: string; // amount in smallest units
contractAddress: string; // FA2 contract address (KT1 prefix)
tokenId: number; // token ID within contract
}FA2 Transfer Entrypoint
The FA2 transfer entrypoint accepts:
transfer: list(
pair(
address, // from
list(pair(address, pair(nat, nat))) // [(to, (token_id, amount))]
)
)Address Formats
| Prefix | Type |
|---|---|
tz1 | Ed25519 implicit account |
tz2 | Secp256k1 implicit account |
tz3 | P-256 implicit account |
KT1 | Originated contract |
Error Codes
| Code | Description |
|---|---|
invalid_payload_structure | Missing opHash, from, to, or amount |
network_mismatch | Operation network doesn’t match |
amount_mismatch | Transferred amount less than required |
recipient_mismatch | Transfer recipient doesn’t match payTo |
contract_mismatch | FA2 contract doesn’t match asset |
token_id_mismatch | Token ID doesn’t match requirements |
operation_not_found | Operation hash not found |
operation_failed | Operation exists but failed |
Example: Full Integration
import { t402Client } from '@t402/fetch'
import { registerExactDirectTezosClient } from '@t402/tezos/exact-direct/client'
const client = new t402Client()
registerExactDirectTezosClient(client, {
address: wallet.address,
signAndSendOperation: wallet.sendOperation
})
const response = await client.fetch('https://api.example.com/premium')Go SDK
import "github.com/t402-io/t402/sdks/go/mechanisms/tezos"
// Client
client := tezos.NewExactDirectTezosScheme(signer, &tezos.Config{})
payload, err := client.CreatePaymentPayload(ctx, requirements)
// Facilitator
facilitator := tezos.NewExactDirectTezosFacilitator(rpcURL, indexerURL)
result, err := facilitator.Verify(ctx, payload, requirements)