API reference
VAYPEER API
Programmatic access to P2P market data, merchant offers, trade operations, and signed lifecycle events.
Signed reads and mutations, idempotent retries, request audits, transactional webhook events, delivery retries, and manual replay run locally. No public sandbox is deployed yet.
Make your first request
Sandbox and production use the same resource model. Keys and data remain isolated by environment.
curl https://api.pnlstake.com/v1/automation/offers \
-H "Vaypeer-Client-Id: $VAYPEER_CLIENT_ID" \
-H "Vaypeer-Key-Id: $VAYPEER_KEY_ID" \
-H "Vaypeer-Timestamp: $VAYPEER_TIMESTAMP" \
-H "Vaypeer-Nonce: $VAYPEER_NONCE" \
-H "Vaypeer-Signature: v1=$VAYPEER_SIGNATURE" \
-H "Vaypeer-Version: 2026-08-10" \
-GVersion every request. Send `Vaypeer-Version` to prevent a future API revision from changing your integration unexpectedly.
Authentication
Every automation request is signed with its one-time-issued secret, timestamp, and unique nonce.
Vaypeer-Client-IdDeveloper app IDRequiredVaypeer-Key-IdScoped credential IDRequiredVaypeer-TimestampUnix timestamp; five-minute toleranceRequiredVaypeer-NonceUnique 16–128 character request valueRequiredVaypeer-SignatureHMAC-SHA256 over the canonical requestRequiredIdempotency-KeyUnique key retained for 24 hoursPOST`escrow:release` is never included in a general merchant key. Production release requires explicit approval and a wallet-verifiable action.
Create an offer
Publish backed inventory with fixed or indexed pricing, trade limits, payment methods, and a settlement window.
curl https://api.pnlstake.com/v1/automation/offers \
-X POST \
-H "Vaypeer-Client-Id: $VAYPEER_CLIENT_ID" \
-H "Vaypeer-Key-Id: $VAYPEER_KEY_ID" \
-H "Vaypeer-Nonce: $VAYPEER_NONCE" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: offer-2026-08-10-001" \
-H "Vaypeer-Timestamp: 1786370400" \
-H "Vaypeer-Signature: v1=$SIGNATURE" \
-d '{
"side": "SELL",
"asset": "USDT",
"chainId": 56,
"fiat": "NGN",
"fixedRate": "1612.40",
"marginPercent": "14",
"minimumFiat": "50000",
"maximumFiat": "2500000",
"paymentMethodIds": ["nip-bank-transfer"],
"paymentWindowSeconds": 900,
"policy": {
"minimumCompletedTrades": 5,
"minimumCompletionRate": 90,
"verifiedUsersOnly": false,
"blockVpn": true,
"thirdPartyPayments": "NOT_ACCEPTED",
"receiptRequired": true
},
"customTerms": "Pay from an account in your own name."
}'sidestring`BUY` or `SELL` from the offer owner’s perspective.
fixedRatestringExact fiat price for one unit of the selected asset.
marginPercentstringPercentage displayed with the fixed price.
minimumFiat / maximumFiatstringAccepted fiat value range per trade.
paymentWindowSecondsintegerTime allowed before an unpaid trade expires.
Observe the trade state
The API mirrors the canonical lifecycle and exposes escrow proof when on-chain funding is confirmed.
{
"id": "trd_2048c6",
"object": "trade",
"status": "payment_marked",
"asset": { "symbol": "USDT", "amount": "250.00" },
"fiat": { "currency": "NGN", "amount": "403100.00" },
"escrow": {
"status": "funded",
"network": "bnb-smart-chain",
"transaction_hash": "0x7ca...98f"
},
"payment_deadline": "2026-08-10T14:36:00Z"
}Verify every webhook
Read the raw request body, calculate its HMAC, and compare signatures using a constant-time function before processing an event.
import { createHmac, timingSafeEqual } from "node:crypto";
export function verifyVaypeerWebhook(rawBody, signature, timestamp, secret) {
const expected = createHmac("sha256", secret)
.update(timestamp + "." + rawBody)
.digest("hex");
return timingSafeEqual(
Buffer.from(signature.replace("v1=", ""), "hex"),
Buffer.from(expected, "hex")
);
}trade.openedescrow.fundedtrade.payment_markedtrade.disputedtrade.releasedtrade.refundedReturn a `2xx` response within five seconds. Failed deliveries retry with exponential backoff and remain available for manual replay.
Errors
Errors use stable machine-readable codes and include a request ID for support and audit lookup.
400invalid_requestParameters failed validation.
401authentication_failedKey or request signature is invalid.
409state_conflictThe requested action conflicts with the trade state.
429rate_limit_exceededRetry after the supplied reset time.