Integrate PayMeCheck payment links, webhooks, and on-chain settlements into your product.
Non-custodial on-chain settlement
HMAC-signed webhooks with retries
Multi-chain USDC & USDT support
Dedicated contract per merchant
Introduction
The PayMeCheck REST API lets you programmatically create payment links, query payment status, and receive real-time notifications via webhooks. All payments settle on-chain through dedicated smart contracts — PayMeCheck never holds or custodies funds.
Each merchant account has a unique API key and dedicated proxy contracts on Ethereum, Polygon, Base, Arbitrum, BNB Chain, and Optimism. When a customer pays, the smart contract atomically splits USDC/USDT between the merchant wallet and the platform treasury.
Authentication
All API requests require a merchant API key sent as a Bearer token. Keys are issued when your merchant account is activated and can be found in the merchant dashboard (contact admin if you need a key rotated).
Header
Authorization: Bearer pmck_your_api_key
Only merchants with status active can use the API. Requests with invalid or missing keys return 401 Unauthorized.
Rate limits
API endpoints are rate-limited per IP address to protect the platform.
60 requests per minute per IP for write operations (POST).
When exceeded, the API returns 429 Too Many Requests. Implement exponential backoff in your integration.
Errors
Errors use conventional HTTP status codes and a JSON body with an error field.
Error response
{ "error": "Invalid input" }
Common error codes
HTTP
Meaning
400
Invalid input or business rule violation
401
Missing or invalid API key
404
Resource not found
429
Rate limit exceeded
Payment links
Payment links are shareable URLs that direct customers to the hosted checkout at /pay/{linkId}. Each link is bound to a unique paymentId (bytes32) used on-chain.
GET/api/v1/payment-links
List payment links
Returns payment links for the authenticated merchant, sorted by creation date (newest first). Omit query parameters to list all links, or pass external_order_id to find links for a specific store order.
Query parameters
Field
Type
Required
Description
external_order_id
string
No
Filter by external_order_id. Returns matching links for your merchant only (newest first).
Creates a new active payment link. Links expire after 1 hour by default. The merchant must have contracts deployed on all requested chains. Optionally set redirect_url_ok and redirect_url_error to send customers back to your site after checkout.
Request body
Field
Type
Required
Description
amount
string
Yes
Integer amount in cents with two implied decimals (no decimal point). Examples: "100" = 1.00 USDC, "150" = 1.50, "15000" = 150.00. Used in API requests only.
token
USDC | USDT | BOTH
Yes
Stablecoin: USDC, USDT, or BOTH (payer chooses USDC or USDT at checkout when BOTH).
chains
string[]
Yes
Array of chains where this link can be paid: ethereum, polygon, base, arbitrum, bsc, optimism.
description
string
No
Optional human-readable description shown in dashboard.
metadata
object
No
Optional key-value object for your internal reference (e.g. extra custom fields).
external_order_id
string
No
Optional string (max 256 chars). Your store or ERP order reference (e.g. WooCommerce order ID). Included in webhooks and searchable via GET /api/v1/payment-links?external_order_id=…
expiresAt
string
No
Optional ISO 8601 expiry, capped at 1 hour from creation. Default: now + 1 hour. Expired active links trigger payment.expired.
redirect_url_ok
string
No
Optional absolute URL (http or https). After a successful payment, the hosted checkout redirects the customer here after a short confirmation screen.
redirect_url_error
string
No
Optional absolute URL (http or https). After a failed payment, link expiry, or cancellation, the hosted checkout redirects the customer here after a brief error message.
Current link status: active, paid, expired, or cancelled.
data.external_order_id
string | null
No
Optional string (max 256 chars). Your store or ERP order reference (e.g. WooCommerce order ID). Included in webhooks and searchable via GET /api/v1/payment-links?external_order_id=…
Payments are indexed from on-chain PaymentProcessed events. They appear after block confirmation via the platform indexer. Amount fields in API responses use decimal strings (e.g. "150.00").
GET/api/v1/payments
List payments
Returns all indexed payments for the authenticated merchant, sorted by creation date (newest first).
Response
Field
Type
Required
Description
data[].paymentId
string
No
Unique bytes32 payment ID bound to this link.
data[].chain
string
No
Blockchain network where payment was confirmed.
data[].txHash
string
No
On-chain transaction hash.
data[].payerAddress
string
No
Wallet address that initiated the payment.
data[].amount
string
No
Integer amount in cents with two implied decimals (no decimal point). Examples: "100" = 1.00 USDC, "150" = 1.50, "15000" = 150.00. Used in API requests only.
data[].fee
string
No
Platform fee amount (token units, string).
data[].merchantAmount
string
No
Amount sent to merchant wallet (token units, string).
data[].status
string
No
in-progress | completed | failed
Webhooks
Configure your webhook endpoint in the merchant dashboard. PayMeCheck sends HTTP POST requests with JSON payloads when events occur.
Enable webhooks in Dashboard → Webhook. Set your HTTPS endpoint URL and toggle webhooks on. The signing secret (whsec_…) is generated automatically when you first enable webhooks — copy it once; it is not shown again in full.
Regenerate the secret from the same page if you lose it. Updating the secret invalidates HMAC verification until your server uses the new value.
Every delivery includes Content-Type: application/json, X-PayMeCheck-Signature (sha256={hex}), and X-PayMeCheck-Delivery-Id (MongoDB delivery ID for idempotency and support).
Webhook amounts use human-readable decimal strings (e.g. "150.00" USDC). The REST API uses integer cents in requests (e.g. "15000" = 150.00) — do not mix the two formats.
Use Send test event in Dashboard → Webhook to receive a full payment.completed payload (same shape as a real payment). Test deliveries include test: true in data. Use webhook.site or ngrok if you do not have an endpoint yet.
Dashboard → Webhook Monitor shows delivery stats, filters, full payload/attempt history, and manual retry for failed deliveries.
Failed deliveries are retried automatically up to 3 times (1 min, 5 min, 30 min). Monitor status and retry manually in Webhook Monitor.
Event types
payment.completed
Fired when an on-chain payment is indexed and confirmed. data includes top-level fields for quick parsing plus nested payment (full indexed record) and paymentLink (link snapshot: amount, metadata, external_order_id, description, redirect URLs, contract addresses, payUrl, explorer URLs).
payment.expired
Fired when an active link expires without payment (default max 1 hour after creation). data contains linkId, paymentId, amount (decimal string), and token — not the full link object.
Redirect the customer to https://paymecheck.com/pay/{linkId}.
3
Customer completes payment on the hosted checkout (connect wallet, confirm USDC or USDT).
4
PayMeCheck confirms the payment on-chain and marks the link as paid.
5
Webhook payment.completed is dispatched to your endpoint with the full payment and link payload.
6
If redirect_url_ok or redirect_url_error were set on the link, the hosted checkout redirects the customer to your URL after success (~2.5 s) or after payment failure, expiry, or cancellation (~2 s).
Redirect customers to the pay URL — checkout is fully hosted. You receive payment.completed via webhook when settlement is confirmed. Post-checkout redirects are optional and configured per link.
Statuses
Payment link statuses
activeAwaiting payment
paidPayment confirmed on-chain
expiredUnpaid after expiry (default max 1 hour from creation)