OutLayer Documentation

Payment Checks

Gasless agent-to-agent payments. Agent A locks tokens into a check and sends a single key to Agent B, who claims the funds — no gas, no on-chain account, no private key exchange. Supports partial claims, expiry, and reclaim.

⛽️

Fully Gasless

Create, claim, and reclaim — all operations work without NEAR for gas. Uses the NEAR Intents solver relay with off-chain NEP-413 signatures. Neither sender nor receiver needs gas tokens.

🔑

Single Key Transfer

The entire check is represented by a single check_key — a 64-character hex string. Send it over any channel (HTTP, message, QR code). Whoever has the key can claim the funds.

🔒

No Private Key Exposure

The sender's wallet key never leaves the TEE. Checks use ephemeral keys derived deterministically inside the enclave — the sender can always reclaim funds without storing anything locally.

📈

Partial Claims & Reclaim

A check can be claimed in parts (e.g., claim 30%, then claim more later). The sender can reclaim unclaimed funds at any time. Supports optional expiry.

How It Works#

🤖
Agent A (Sender)
Has wallet API key
check_key
any channel
🤖
Agent B (Receiver)
Has wallet API key
create check
claim check
TEE (Intel TDX)
Ephemeral Key
Derived per check
HMAC from master secret
NEP-413 Signing
Off-chain intent signatures
No gas required
Reclaim
Re-derives ephemeral key
Sender never stores key
publish_intent (gasless)
Solver Relay
Executes signed transfer intents
No gas from sender or receiver
intents.near
Token balances (multi-token)
Ephemeral accounts as escrow
  1. Create — Agent A calls POST /payment-check/create. The TEE derives a unique ephemeral key, transfers tokens from the wallet to the ephemeral account via solver relay (gasless), and returns a check_key.
  2. Share — Agent A sends the check_key to Agent B over any channel (API call, message, QR code). The key is a 64-char hex string — compact and easy to transmit.
  3. Claim — Agent B calls POST /payment-check/claim with the key. The coordinator signs a transfer intent from the ephemeral account to Agent B's wallet and submits it via solver relay. Agent B receives the tokens gaslessly.
  4. Reclaim (optional) — Agent A can reclaim any unclaimed funds at any time. The TEE re-derives the ephemeral key (no need to store it) and signs a transfer back to Agent A.

Transfer Mechanism#

All payment check operations use the NEAR Intents solver relay — a gasless off-chain transfer protocol. Instead of submitting on-chain transactions (which require NEAR for gas), the coordinator signs NEP-413 messages and submits them to the solver relay, which executes the transfer on intents.near.

OperationFromToWho SignsGas Required
CreateWalletEphemeralWallet key (TEE keystore)None
ClaimEphemeralClaimer walletEphemeral key (from check_key)None
ReclaimEphemeralCreator walletEphemeral key (TEE re-derivation)None

Why ephemeral accounts? Each check gets its own ephemeral account on intents.near — derived from the wallet's master secret + a monotonic counter. This gives each check an isolated balance that can only be moved by whoever holds the check_key (claim) or by the TEE re-deriving the key (reclaim). Think of it as a single-use escrow address.

Key Derivation#

Ephemeral keys are derived deterministically inside the TEE using HMAC-SHA256 from the master secret. The derivation path includes the wallet ID and a monotonic counter, ensuring each check gets a unique, non-reusable key.

Derivation hierarchy:
  wallet:{id}:near                        <- main wallet key
  wallet:{id}:near:check:{counter}        <- ephemeral key per check

The check_key IS the raw ed25519 private key of the ephemeral account.
The ephemeral account ID = hex(public_key) on intents.near.

Because the derivation is deterministic, the sender never needs to store the ephemeral key. For reclaim, the TEE re-derives it from the same path. For claim, the receiver uses the check_key directly to sign the transfer intent.

Use Cases#

Agent-to-Agent Payments

Agent A needs data from Agent B. A creates a check, sends the key as part of the API request. B validates the check (peek), performs the work, claims the payment. If B doesn't deliver, A reclaims.

Bounties & Task Rewards

Create a check with an expiry. Share the check_key with whoever completes the task. Partial claims allow splitting rewards among multiple contributors. Unclaimed funds auto-expire and can be reclaimed.

Escrow-Style Payments

Lock funds in a check. Share the key only when conditions are met (off-chain verification, delivery confirmation). The check acts as a lightweight escrow without a smart contract.

Batch Payouts

Use batch-create to generate up to 10 checks in a single call. Each check gets its own key and can be distributed independently.

Quick Start#

All examples use the OutLayer API at https://api.outlayer.fastnear.com.

1. Create a check

curl -X POST https://api.outlayer.fastnear.com/wallet/v1/payment-check/create \
  -H "Authorization: Bearer wk_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "token": "17208628f84f5d6ad33f0da3bbbeb27ffcb398eac501a31bd6ad2011e36133a1",
    "amount": "1000000",
    "memo": "Payment for data analysis",
    "expires_in": 3600
  }'
{
  "check_id": "a1b2c3d4-...",
  "check_key": "7f3a9b2c...64 hex chars...",
  "token": "17208628f84f5d6ad33f0da3bbbeb27ffcb398eac501a31bd6ad2011e36133a1",
  "amount": "1000000",
  "memo": "Payment for data analysis",
  "created_at": "2026-03-13T10:00:00Z",
  "expires_at": "2026-03-13T11:00:00Z"
}

2. Share the check_key with the receiver

Send check_key to the other agent via any channel. The key is all they need to claim the funds.

3. Receiver claims the check

# Full claim (all funds)
curl -X POST https://api.outlayer.fastnear.com/wallet/v1/payment-check/claim \
  -H "Authorization: Bearer wk_RECEIVER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"check_key": "7f3a9b2c...64 hex chars..."}'

# Partial claim (specific amount)
curl -X POST https://api.outlayer.fastnear.com/wallet/v1/payment-check/claim \
  -H "Authorization: Bearer wk_RECEIVER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"check_key": "7f3a9b2c...", "amount": "500000"}'
{
  "token": "17208628f84f5d6ad33f0da3bbbeb27ffcb398eac501a31bd6ad2011e36133a1",
  "amount_claimed": "500000",
  "remaining": "500000",
  "memo": "Payment for data analysis",
  "claimed_at": "2026-03-13T10:05:00Z",
  "intent_hash": "Bx7k..."
}

4. Sender reclaims unclaimed funds (optional)

curl -X POST https://api.outlayer.fastnear.com/wallet/v1/payment-check/reclaim \
  -H "Authorization: Bearer wk_SENDER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"check_id": "a1b2c3d4-..."}'
{
  "token": "17208628f84f5d6ad33f0da3bbbeb27ffcb398eac501a31bd6ad2011e36133a1",
  "amount_reclaimed": "500000",
  "remaining": "0",
  "reclaimed_at": "2026-03-13T10:10:00Z",
  "intent_hash": "Cx9m..."
}

API Reference#

Base URL: https://api.outlayer.fastnear.com/wallet/v1/payment-check. All endpoints require wallet API key authentication via Authorization: Bearer wk_... header.

POST/create

Create a new payment check. Locks tokens from the sender's intents balance into an ephemeral account.

Request body

FieldTypeRequiredDescription
tokenstringyesToken contract ID (e.g., USDC contract address)
amountstringyesAmount in smallest units (e.g., "1000000" = 1 USDC)
memostringnoOptional memo (max 256 chars), visible to receiver
expires_innumbernoExpiry in seconds from now (e.g., 3600 = 1 hour)

Response

Returns check_id, check_key, token, amount, memo, created_at, expires_at.

POST/batch-create

Create multiple checks in a single call (max 10). Each check gets independent key and ephemeral account.

Request body

FieldTypeDescription
checksarrayArray of create requests (same fields as /create), max 10

Response

Returns { checks: [...] } — array of create responses.

POST/claim

Claim funds from a check. Transfers from ephemeral account to the caller's wallet. Supports partial claims.

Request body

FieldTypeRequiredDescription
check_keystringyesThe 64-char hex key received from the sender
amountstringnoPartial claim amount (omit for full claim)

Response

Returns token, amount_claimed, remaining, memo, claimed_at, intent_hash.

POST/reclaim

Reclaim unclaimed funds back to the sender's wallet. Only the original creator can reclaim. Supports partial reclaim.

Request body

FieldTypeRequiredDescription
check_idstringyesThe check ID returned from create
amountstringnoPartial reclaim amount (omit for full reclaim)

Response

Returns token, amount_reclaimed, remaining, reclaimed_at, intent_hash.

GET/status?check_id=...

Get the current status of a check. Only the creator can query by check_id.

Query parameters

ParamDescription
check_idThe check ID to query

Response

Returns full check details: check_id, token, amount, claimed_amount, reclaimed_amount, status, memo, created_at, expires_at, claimed_at, claimed_by.

GET/list?status=...&limit=...&offset=...

List all checks created by the authenticated wallet. Supports filtering and pagination.

Query parameters

ParamRequiredDescription
statusnoFilter: unclaimed, claimed, reclaimed, partially_claimed
limitnoMax results (default 50, max 100)
offsetnoPagination offset (default 0)

Response

Returns { checks: [...] } — array of status responses.

POST/peek

Check a payment check's balance and status using the check_key. Use this to verify a check before claiming.

Request body

FieldTypeDescription
check_keystringThe 64-char hex check key

Response

Returns token, balance (on-chain), memo, status, expires_at.

Check Lifecycle#

                    create
                      |
                      v
                  [unclaimed]
                   /      \
          claim   /        \  reclaim
                 v          v
       [partially_claimed] [partially_reclaimed]
              |       \         /       |
       claim  |        \       /        | reclaim
              v         v     v         v
          [claimed]   (mixed)    [reclaimed]

Statuses:
  unclaimed           - funds locked, waiting to be claimed
  partially_claimed   - some funds claimed, rest available
  partially_reclaimed - some funds reclaimed by sender
  claimed             - all funds claimed by receiver
  reclaimed           - all funds reclaimed by sender

Expiry: If expires_in is set, the check cannot be claimed after expiry. However, funds remain in the ephemeral account — the sender must explicitly reclaim them. Expiry prevents new claims but does not auto-return funds.

Security Model#

ThreatMitigation
check_key intercepted in transitUse encrypted channels (HTTPS, E2E encrypted messaging). A leaked key lets anyone with a wallet API key claim the funds.
Sender's wallet compromisedWallet private key never leaves TEE. API key can be revoked. Policy engine limits exposure.
Replay of claim/reclaimEach intent has a unique nonce and 5-minute deadline. Solver relay rejects duplicates. DB tracks claimed amounts atomically.
Ephemeral key derivation collisionMonotonic counter per wallet (DB enforced, atomic increment). Same wallet + counter = same key, but counter never reuses.
Funds stuck in ephemeral accountSender can always reclaim — TEE re-derives the ephemeral key from the same deterministic path. No key storage needed.

Key insight: The check_key is the only secret. It never touches the blockchain, it never enters the TEE (for claim — the coordinator signs locally with it). The sender doesn't even need to store it — the TEE can re-derive it for reclaim. This makes the system self-healing: even if the sender loses all local state, their funds are recoverable through the TEE.

Comparison with Alternatives#

Payment ChecksDirect TransferSmart Contract Escrow
Gas requiredNoneSender paysBoth parties pay
Receiver needs accountOnly a wallet API keyOn-chain account + gasOn-chain account + gas
Partial paymentBuilt-inN/ACustom logic
ReclaimBuilt-in, gaslessN/A (irreversible)Custom logic + gas
On-chain footprintSolver relay only1 transactionContract deployment + calls
Setup complexityOne API callOne API callContract dev + deployment