Endpoints#
Complete API reference for all PayWatcher endpoints.
Overview#
Base URL#
https://api.masem.atAll endpoints are relative to this base URL (e.g. https://api.masem.at/v1/payments).
Authentication#
Every request requires an API key in the x-api-key header:
curl https://api.masem.at/v1/payments \
-H "x-api-key: mms_paywatcher_YOUR_API_KEY"Response Format#
All responses use an envelope format:
Single object:
{
"data": { ... }
}List with pagination:
{
"data": [ ... ],
"meta": {
"page": 1,
"limit": 25,
"total": 142
}
}Error:
{
"error": {
"code": "UNAUTHORIZED",
"message": "Invalid or missing API key"
}
}Error Codes#
| HTTP Status | Code | Description |
|---|---|---|
| 400 / 422 | VALIDATION_ERROR | Invalid request parameters or body |
| 401 | UNAUTHORIZED | Missing or invalid API key |
| 403 | FORBIDDEN | API key lacks required scope |
| 404 | NOT_FOUND | Resource does not exist |
| 500 | INTERNAL_ERROR | Server error — retry later |
Create Payment#
POST /v1/payments
Create a new payment intent. Returns a payment object with a unique exactAmount and depositAddress for your customer.
Request Body#
| Field | Type | Required | Description |
|---|---|---|---|
amount | string | Yes | Amount in USDC (e.g. "49.00") |
currency | string | Yes | Currency code — only "USDC" supported |
chain | string | Yes | Blockchain network (e.g. "base") — see Supported Networks. Same value as network |
network | string | No | Preferred alias for chain. If both are provided, network takes precedence. Defaults to "base". Supported: base, ethereum, arbitrum, optimism, polygon |
metadata | object | No | Key-value pairs for your reference (max 10 keys) |
expires_in | number | No | Seconds until expiry (default: 3600 = 1 hour) |
webhook_url | string | No | Override the global webhook URL for this payment |
Response#
{
"data": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"amount": "49.00",
"exactAmount": "49.000042",
"status": "pending",
"depositAddress": "0x742d35Cc6634C0532925a3b844Bc9e7595f2bD18",
"currency": "USDC",
"chain": "base",
"network": "base",
"chainId": 8453,
"explorerUrl": null,
"confirmations": 0,
"confirmationsRequired": 6,
"txHash": null,
"metadata": {
"order_id": "ORD-123",
"customer": "john@example.com"
},
"expiresAt": "2026-01-15T11:00:00Z",
"createdAt": "2026-01-15T10:00:00Z",
"updatedAt": "2026-01-15T10:00:00Z"
}
}Example#
curl -X POST https://api.masem.at/v1/payments \
-H "x-api-key: mms_paywatcher_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"amount": "49.00",
"currency": "USDC",
"chain": "base",
"metadata": {
"order_id": "ORD-123",
"customer": "john@example.com"
},
"expires_in": 3600,
"webhook_url": "https://your-app.com/webhook"
}'Get Payment#
GET /v1/payments/:id
Retrieve a single payment by its ID.
Path Parameters#
| Parameter | Type | Description |
|---|---|---|
id | string | Payment UUID |
Response#
{
"data": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"amount": "49.00",
"exactAmount": "49.000042",
"status": "confirmed",
"depositAddress": "0x742d35Cc6634C0532925a3b844Bc9e7595f2bD18",
"currency": "USDC",
"chain": "base",
"network": "base",
"chainId": 8453,
"explorerUrl": "https://basescan.org/tx/0x7a3f9c2e1d4b5a6f8e0c3d2b1a9f8e7d6c5b4a3f2e1d0c9b8a7f6e5d4c3b2a1",
"confirmations": 6,
"confirmationsRequired": 6,
"txHash": "0x7a3f9c2e1d4b5a6f8e0c3d2b1a9f8e7d6c5b4a3f2e1d0c9b8a7f6e5d4c3b2a1",
"metadata": {
"order_id": "ORD-123",
"customer": "john@example.com"
},
"expiresAt": "2026-01-15T11:00:00Z",
"createdAt": "2026-01-15T10:00:00Z",
"updatedAt": "2026-01-15T10:05:00Z"
}
}Response Fields (Multi-Chain)#
| Field | Type | Description |
|---|---|---|
network | string | Blockchain network identifier (e.g. "base", "ethereum", "arbitrum") |
chainId | number | EVM chain ID (e.g. 8453 for Base, 1 for Ethereum) |
explorerUrl | string | null | Direct link to the transaction on the block explorer (null if no transaction yet) |
Example#
curl https://api.masem.at/v1/payments/a1b2c3d4-e5f6-7890-abcd-ef1234567890 \
-H "x-api-key: mms_paywatcher_YOUR_API_KEY"List Payments#
GET /v1/payments
List payments with optional filtering, sorting, and pagination.
Query Parameters#
| Parameter | Type | Default | Description |
|---|---|---|---|
status | string | — | Filter by status (comma-separated, e.g. "pending,confirmed") |
network | string | — | Filter by network (e.g. "base", "ethereum") |
from | string | — | ISO 8601 date — only payments created after this date |
to | string | — | ISO 8601 date — only payments created before this date |
page | number | 1 | Page number |
limit | number | 25 | Items per page (max: 100) |
sort | string | "created_at" | Sort field (only "created_at" supported) |
order | string | "desc" | Sort direction: "asc" or "desc" |
Response#
{
"data": [
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"amount": "49.00",
"exactAmount": "49.000042",
"status": "confirmed",
"depositAddress": "0x742d35Cc6634C0532925a3b844Bc9e7595f2bD18",
"currency": "USDC",
"chain": "base",
"network": "base",
"chainId": 8453,
"explorerUrl": "https://basescan.org/tx/0x7a3f9c2e1d4b5a6f8e0c3d2b1a9f8e7d6c5b4a3f2e1d0c9b8a7f6e5d4c3b2a1",
"confirmations": 6,
"confirmationsRequired": 6,
"txHash": "0x7a3f9c2e1d4b5a6f8e0c3d2b1a9f8e7d6c5b4a3f2e1d0c9b8a7f6e5d4c3b2a1",
"metadata": null,
"expiresAt": "2026-01-15T11:00:00Z",
"createdAt": "2026-01-15T10:00:00Z",
"updatedAt": "2026-01-15T10:05:00Z"
}
],
"meta": {
"page": 1,
"limit": 25,
"total": 142
}
}Example#
curl "https://api.masem.at/v1/payments?status=confirmed&limit=10&order=desc" \
-H "x-api-key: mms_paywatcher_YOUR_API_KEY"Webhook History#
GET /v1/payments/:id/webhooks
Retrieve the webhook delivery history for a specific payment.
This endpoint returns snake_case field names.
Path Parameters#
| Parameter | Type | Description |
|---|---|---|
id | string | Payment UUID |
Response#
{
"data": [
{
"event": "payment.confirmed",
"attempt_number": 1,
"response_code": 200,
"error": null,
"created_at": "2026-01-15T10:05:00Z"
}
]
}Response Fields#
| Field | Type | Description |
|---|---|---|
event | string | Event type (e.g. "payment.confirmed") |
attempt_number | number | Delivery attempt number (starts at 1) |
response_code | number | null | HTTP status code from your server |
error | string | null | Error message if delivery failed |
created_at | string | ISO 8601 timestamp of the delivery attempt |
Example#
curl https://api.masem.at/v1/payments/a1b2c3d4-e5f6-7890-abcd-ef1234567890/webhooks \
-H "x-api-key: mms_paywatcher_YOUR_API_KEY"Read Config#
GET /v1/paywatcher/config
Retrieve the current tenant configuration.
This endpoint returns snake_case field names.
Response#
{
"data": {
"tenant_slug": "acme-corp",
"tenant_name": "Acme Corp",
"contact_email": "dev@acme.com",
"tier": "starter",
"deposit_address": "0x742d35Cc6634C0532925a3b844Bc9e7595f2bD18",
"confirmations": 6,
"confirmation_override": null,
"webhook_url": "https://acme.com/webhook",
"enabled": true,
"created_at": "2026-01-01T00:00:00Z",
"updated_at": "2026-01-15T10:00:00Z"
}
}Response Fields#
| Field | Type | Description |
|---|---|---|
tenant_slug | string | Unique tenant identifier |
tenant_name | string | Display name |
contact_email | string | Contact email address |
tier | string | Subscription tier |
deposit_address | string | Your own wallet address. PayWatcher monitors it but never holds funds. |
confirmations | number | Default confirmation threshold |
confirmation_override | number | null | Custom confirmation threshold (null = use default) |
webhook_url | string | null | Global webhook URL |
enabled | boolean | Whether the tenant is active |
created_at | string | ISO 8601 creation timestamp |
updated_at | string | ISO 8601 last update timestamp |
Example#
curl https://api.masem.at/v1/paywatcher/config \
-H "x-api-key: mms_paywatcher_YOUR_API_KEY"Update Config#
PATCH /v1/paywatcher/config
Update the tenant configuration. Only the fields you include in the request body will be updated.
This endpoint accepts and returns snake_case field names.
Request Body#
| Field | Type | Required | Description |
|---|---|---|---|
webhook_url | string | No | HTTPS URL for webhook deliveries |
confirmation_override | number | null | No | Custom confirmation threshold (2–20), or null to reset to default (6) |
Response#
Returns the full updated tenant config (same schema as Read Config).
{
"data": {
"tenant_slug": "acme-corp",
"tenant_name": "Acme Corp",
"contact_email": "dev@acme.com",
"tier": "starter",
"deposit_address": "0x742d35Cc6634C0532925a3b844Bc9e7595f2bD18",
"confirmations": 6,
"confirmation_override": 12,
"webhook_url": "https://acme.com/webhook",
"enabled": true,
"created_at": "2026-01-01T00:00:00Z",
"updated_at": "2026-01-15T10:30:00Z"
}
}Example#
curl -X PATCH https://api.masem.at/v1/paywatcher/config \
-H "x-api-key: mms_paywatcher_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"webhook_url": "https://your-app.com/webhook",
"confirmation_override": 12
}'Test Webhook#
POST /v1/paywatcher/config/test-webhook
Send a test webhook to your configured webhook URL to verify it's working.
This endpoint returns snake_case field names.
Request Body#
No request body required.
Response#
{
"data": {
"success": true,
"response_code": 200,
"error": null
}
}Response Fields#
| Field | Type | Description |
|---|---|---|
success | boolean | Whether the test webhook was delivered successfully |
response_code | number | null | HTTP status code from your server |
error | string | null | Error message if delivery failed |
Example#
curl -X POST https://api.masem.at/v1/paywatcher/config/test-webhook \
-H "x-api-key: mms_paywatcher_YOUR_API_KEY"View API Key#
GET /v1/paywatcher/config/api-key
Retrieve your masked API key and its scopes.
This endpoint returns snake_case field names. The full API key is never returned — only a masked version.
Response#
{
"data": {
"masked_key": "mms_paywatcher_abc...xyz",
"scopes": ["payments:read", "payments:write"],
"created_at": "2026-01-15T10:00:00Z"
}
}Response Fields#
| Field | Type | Description |
|---|---|---|
masked_key | string | Masked API key (first and last characters visible) |
scopes | string[] | Permissions granted to this key |
created_at | string | ISO 8601 timestamp when the key was created |
Example#
curl https://api.masem.at/v1/paywatcher/config/api-key \
-H "x-api-key: mms_paywatcher_YOUR_API_KEY"Next Steps#
- Quick Start — Get started with your first payment in under 15 minutes
- Webhooks — Webhook events, retry logic, and signature verification
- Examples — Code examples in multiple languages