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#
- 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 acheck_key. - Share — Agent A sends the
check_keyto Agent B over any channel (API call, message, QR code). The key is a 64-char hex string — compact and easy to transmit. - Claim — Agent B calls
POST /payment-check/claimwith 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. - 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.
| Operation | From | To | Who Signs | Gas Required |
|---|---|---|---|---|
| Create | Wallet | Ephemeral | Wallet key (TEE keystore) | None |
| Claim | Ephemeral | Claimer wallet | Ephemeral key (from check_key) | None |
| Reclaim | Ephemeral | Creator wallet | Ephemeral 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.
/createCreate a new payment check. Locks tokens from the sender's intents balance into an ephemeral account.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
| token | string | yes | Token contract ID (e.g., USDC contract address) |
| amount | string | yes | Amount in smallest units (e.g., "1000000" = 1 USDC) |
| memo | string | no | Optional memo (max 256 chars), visible to receiver |
| expires_in | number | no | Expiry in seconds from now (e.g., 3600 = 1 hour) |
Response
Returns check_id, check_key, token, amount, memo, created_at, expires_at.
/batch-createCreate multiple checks in a single call (max 10). Each check gets independent key and ephemeral account.
Request body
| Field | Type | Description |
|---|---|---|
| checks | array | Array of create requests (same fields as /create), max 10 |
Response
Returns { checks: [...] } — array of create responses.
/claimClaim funds from a check. Transfers from ephemeral account to the caller's wallet. Supports partial claims.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
| check_key | string | yes | The 64-char hex key received from the sender |
| amount | string | no | Partial claim amount (omit for full claim) |
Response
Returns token, amount_claimed, remaining, memo, claimed_at, intent_hash.
/reclaimReclaim unclaimed funds back to the sender's wallet. Only the original creator can reclaim. Supports partial reclaim.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
| check_id | string | yes | The check ID returned from create |
| amount | string | no | Partial reclaim amount (omit for full reclaim) |
Response
Returns token, amount_reclaimed, remaining, reclaimed_at, intent_hash.
/status?check_id=...Get the current status of a check. Only the creator can query by check_id.
Query parameters
| Param | Description |
|---|---|
| check_id | The 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.
/list?status=...&limit=...&offset=...List all checks created by the authenticated wallet. Supports filtering and pagination.
Query parameters
| Param | Required | Description |
|---|---|---|
| status | no | Filter: unclaimed, claimed, reclaimed, partially_claimed |
| limit | no | Max results (default 50, max 100) |
| offset | no | Pagination offset (default 0) |
Response
Returns { checks: [...] } — array of status responses.
/peekCheck a payment check's balance and status using the check_key. Use this to verify a check before claiming.
Request body
| Field | Type | Description |
|---|---|---|
| check_key | string | The 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 senderExpiry: 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#
| Threat | Mitigation |
|---|---|
| check_key intercepted in transit | Use encrypted channels (HTTPS, E2E encrypted messaging). A leaked key lets anyone with a wallet API key claim the funds. |
| Sender's wallet compromised | Wallet private key never leaves TEE. API key can be revoked. Policy engine limits exposure. |
| Replay of claim/reclaim | Each intent has a unique nonce and 5-minute deadline. Solver relay rejects duplicates. DB tracks claimed amounts atomically. |
| Ephemeral key derivation collision | Monotonic counter per wallet (DB enforced, atomic increment). Same wallet + counter = same key, but counter never reuses. |
| Funds stuck in ephemeral account | Sender 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 Checks | Direct Transfer | Smart Contract Escrow | |
|---|---|---|---|
| Gas required | None | Sender pays | Both parties pay |
| Receiver needs account | Only a wallet API key | On-chain account + gas | On-chain account + gas |
| Partial payment | Built-in | N/A | Custom logic |
| Reclaim | Built-in, gasless | N/A (irreversible) | Custom logic + gas |
| On-chain footprint | Solver relay only | 1 transaction | Contract deployment + calls |
| Setup complexity | One API call | One API call | Contract dev + deployment |