KiraPay Public API
Public APIs secured via x-api-key. No JWT required.
Base URLs
- Production:
https://kirapay.focalfossa.site/api
Authentication
Include your API key in every request header:
x-api-key: YOUR_API_KEY
Endpoints
POST Generate Payment Link
Create a new payment link your customers can pay to.
Headers:
x-api-key: YOUR_API_KEY
Content-Type: application/json
Request Body:
{
"currency": "USDC",
"receiver": "0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6",
"price": 100.5,
"name": "Order #A1209",
"redirectUrl": "https://merchant.example.com/thank-you"
}
Request Body Fields:
Field | Type | Required | Description |
---|---|---|---|
currency |
string (enum) | Yes | Currency type for the payment. Supported values: USDC |
receiver |
string | Yes | Ethereum wallet address (42 characters starting with 0x) where payments will be sent |
price |
number | Yes | Payment amount in the specified currency (must be ≥ 0) |
name |
string | Yes | Display name for the payment link (e.g., "Order #A1209", "Product Purchase") |
redirectUrl |
string (URL) | No | URL to redirect users after successful payment completion |
cURL:
curl -X POST "https://kirapay.focalfossa.site/api/link/generate" \
-H "x-api-key: <YOUR_API_KEY>" \
-H "Content-Type: application/json" \
-d '{
"currency": "USDC",
"receiver": "0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6",
"price": 100.5,
"name": "Order #A1209",
"redirectUrl": "https://merchant.example.com/thank-you"
}'
Success (201):
{
"message": "success",
"data": {
"url": "https://kirapay.focalfossa.site/abc123def4"
},
"code": 201
}
Response Fields:
Field | Type | Description |
---|---|---|
message |
string | Response status message, always "success" for successful requests |
data.url |
string (URL) | Complete payment link URL that customers can use to make payments |
code |
number | HTTP status code (201 for successful creation) |
Errors:
{"statusCode": 400, "message": "INVALID_ETHEREUM_ADDRESS"}
{"statusCode": 400, "message": "ADDRESS_REQUIRED"}
{"statusCode": 400, "message": "NAME_MUST_BE_STRING"}
{"statusCode": 401, "message": "API_KEY_INVALID"}
{"statusCode": 500, "message": "Internal server error"}
GET Get User Links
Retrieve a paginated list of payment links created by the authenticated user.
Headers:
x-api-key: YOUR_API_KEY
Query Parameters:
{
"page": 1, // Optional: Page number (default: 1)
"limit": 10 // Optional: Items per page (default: 10)
}
Query Parameters Fields:
Field | Type | Required | Description |
---|---|---|---|
page |
number | No | Page number for pagination (starts from 1, default: 1) |
limit |
number | No | Number of items per page (default: 10, max: 100) |
cURL:
curl -X GET "https://kirapay.focalfossa.site/api/link?page=1&limit=10" \
-H "x-api-key: <YOUR_API_KEY>"
Success (200):
{
"message": "success",
"data": {
"links": [
{
"_id": "67a1b3f2c4d5e6f7g8h9i0j1",
"code": "abc123def4",
"price": 100.5,
"tokenOut": {
"symbol": "USDC",
"address": "0xA0b86a33E6441b8c4C8C0C8C0C8C0C8C0C8C0C8C",
"decimals": 6,
"chain": "ethereum"
},
"receiver": "0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6",
"user": "507f1f77bcf86cd799439011",
"key": "api_key_123",
"name": "Order #A1209",
"redirectUrl": "https://merchant.example.com/thank-you",
"createdAt": "2025-01-25T10:00:00.000Z",
"updatedAt": "2025-01-25T10:00:00.000Z"
}
],
"total": 1,
"page": 1,
"totalPages": 1
},
"code": 200
}
Response Fields:
Field | Type | Description |
---|---|---|
message |
string | Response status message, always "success" for successful requests |
data.links |
array | Array of payment link objects |
data.links[]._id |
string (MongoDB ObjectId) | Unique identifier for the payment link |
data.links[].code |
string | Short code used in the payment URL (e.g., "abc123def4") |
data.links[].price |
number | Payment amount in the specified currency |
data.links[].tokenOut |
object | Token configuration object |
data.links[].tokenOut.symbol |
string | Token symbol (e.g., "USDC") |
data.links[].tokenOut.address |
string | Smart contract address of the token |
data.links[].tokenOut.decimals |
number | Number of decimal places for the token (usually 6 for USDC) |
data.links[].tokenOut.chain |
string | Blockchain network (e.g., "ethereum", "polygon") |
data.links[].receiver |
string | Ethereum wallet address where payments will be sent |
data.links[].user |
string (MongoDB ObjectId) | ID of the user who created the link |
data.links[].key |
string | API key used to create the link |
data.links[].name |
string | Display name for the payment link |
data.links[].redirectUrl |
string (URL) | URL to redirect users after payment completion |
data.links[].createdAt |
string (ISO 8601) | Timestamp when the link was created |
data.links[].updatedAt |
string (ISO 8601) | Timestamp when the link was last updated |
data.total |
number | Total number of links matching the query |
data.page |
number | Current page number |
data.totalPages |
number | Total number of pages available |
code |
number | HTTP status code (200 for successful requests) |
Errors:
{"statusCode": 401, "message": "API_KEY_INVALID"}
GET Get Link by Code
Retrieve the details of a payment link by its code. This is a public endpoint that doesn't require authentication.
cURL:
curl -X GET "https://kirapay.focalfossa.site/api/link/abc123def4"
Success (200):
{
"message": "success",
"data": {
"_id": "67a1b3f2c4d5e6f7g8h9i0j1",
"code": "abc123def4",
"price": 100.5,
"tokenOut": {
"symbol": "USDC",
"address": "0xA0b86a33E6441b8c4C8C0C8C0C8C0C8C0C8C0C8C",
"decimals": 6,
"chain": "ethereum"
},
"receiver": "0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6",
"user": {
"_id": "507f1f77bcf86cd799439011",
"username": "merchant_user",
"address": "0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6",
"isVerified": true
},
"name": "Order #A1209",
"redirectUrl": "https://merchant.example.com/thank-you",
"createdAt": "2025-01-25T10:00:00.000Z",
"updatedAt": "2025-01-25T10:00:00.000Z",
"url": "https://kirapay.focalfossa.site/abc123def4"
},
"code": 200
}
Response Fields:
Field | Type | Description |
---|---|---|
message |
string | Response status message, always "success" for successful requests |
data._id |
string (MongoDB ObjectId) | Unique identifier for the payment link |
data.code |
string | Short code used in the payment URL (e.g., "abc123def4") |
data.price |
number | Payment amount in the specified currency |
data.tokenOut |
object | Token configuration object |
data.tokenOut.symbol |
string | Token symbol (e.g., "USDC") |
data.tokenOut.address |
string | Smart contract address of the token |
data.tokenOut.decimals |
number | Number of decimal places for the token (usually 6 for USDC) |
data.tokenOut.chain |
string | Blockchain network (e.g., "ethereum", "polygon") |
data.receiver |
string | Ethereum wallet address where payments will be sent |
data.user |
object | User information object (populated from database) |
data.user._id |
string (MongoDB ObjectId) | Unique identifier of the user who created the link |
data.user.username |
string | Username of the link creator |
data.user.address |
string | Ethereum wallet address of the user |
data.user.isVerified |
boolean | Whether the user account is verified |
data.name |
string | Display name for the payment link |
data.redirectUrl |
string (URL) | URL to redirect users after payment completion |
data.createdAt |
string (ISO 8601) | Timestamp when the link was created |
data.updatedAt |
string (ISO 8601) | Timestamp when the link was last updated |
data.url |
string (URL) | Complete payment link URL that customers can use to make payments |
code |
number | HTTP status code (200 for successful requests) |
Errors:
{"statusCode": 404, "message": "Link not found"}
GET Get Wallet Transactions
Retrieve a paginated list of wallet transactions for the authenticated user.
Headers:
x-api-key: YOUR_API_KEY
Query Parameters:
{
"status": "PENDING", // Optional: Filter by status (PENDING, COMPLETED, FAILED, CANCELLED)
"transaction_hash": "0x1234567890", // Optional: Filter by transaction hash
"from_date": "2025-01-01T00:00:00.000Z", // Optional: Filter from date
"to_date": "2025-01-31T23:59:59.999Z", // Optional: Filter to date
"page": 1, // Optional: Page number (default: 1)
"limit": 10 // Optional: Items per page (default: 10)
}
Query Parameters Fields:
Field | Type | Required | Description |
---|---|---|---|
status |
string (enum) | No | Filter by transaction status. Values: PENDING , COMPLETED , FAILED , CANCELLED |
transaction_hash |
string | No | Filter by specific blockchain transaction hash |
from_date |
string (ISO 8601) | No | Filter transactions from this date onwards (inclusive) |
to_date |
string (ISO 8601) | No | Filter transactions up to this date (inclusive) |
page |
number | No | Page number for pagination (starts from 1, default: 1) |
limit |
number | No | Number of items per page (default: 10, max: 100) |
cURL:
curl -X GET "https://kirapay.focalfossa.site/api/wallet/transactions?page=1&limit=10&status=PENDING" \
-H "x-api-key: <YOUR_API_KEY>"
Success (200):
{
"message": "success",
"data": {
"transactions": [
{
"_id": "689324309eb9e6e8e0f842cd",
"price": 0.015,
"hash": "0xb6accc136297ad17ab831028f967cbf2bdd9ff67b8fab5d4e8e4f34f8681eb59",
"status": "Success",
"type": "Contract",
"user": {
"_id": "688c82d81c6a157748c5ca7b",
"username": "john_doe"
},
"link": "6891c0896aad1cd3bf2f3490",
"source": "7",
"createdAt": "2025-08-06T09:45:20.374Z",
"updatedAt": "2025-08-06T09:45:50.365Z",
"__v": 0,
"payload": {
"eventNonce": "0x9bd7d21d481bd64a3f046b6c9e930b5843a0c36f8832a1c8e8e2319c16da6f28",
"attestation": "0x8730053fe55a898df9f81f4c45364ef1ad7541125e20656278ec9749d92ec7bb3bd5b5c81703be23d9013e03db36f2b57e8074032f68e1b9dea26570c254c0b41c2bb48dbabb202780d06305148f768bc8af82b92632fddffa88e54950deadf5774fea1bd99f721c08e88d72e15f674200438b25256c88919a6ddf29fee5df91c91c",
"cctpVersion": 2,
"sender": "0x28b5a0e9c621a5badaa536219b3a228c8168cf5d",
"recipient": "0x28b5a0e9c621a5badaa536219b3a228c8168cf5d",
"mintRecipient": "0x4b6aee828992738f64b1e908f082aa9f2cc6936a",
"messageSender": "0x4b6aee828992738f64b1e908f082aa9f2cc6936a",
"amount": "15000",
"maxFee": 2,
"feeExecuted": 0,
"sourceDomain": 7,
"destinationDomain": 6,
"status": "complete"
}
}
],
"total": 1,
"page": 1,
"totalPages": 1
},
"code": 200
}
Response Fields:
Field | Type | Description |
---|---|---|
message |
string | Response status message, always "success" for successful requests |
data.transactions |
array | Array of transaction objects |
data.transactions[]._id |
string (MongoDB ObjectId) | Unique identifier for the transaction |
data.transactions[].price |
number | Transaction amount in the specified currency |
data.transactions[].hash |
string | Blockchain transaction hash (66 characters starting with 0x) |
data.transactions[].status |
string | Transaction status (e.g., "Success", "Pending", "Cancel") |
data.transactions[].type |
string | Transaction type (e.g., "Contract", "Transfer", "Refund") |
data.transactions[].user |
object | User information object (populated from database) |
data.transactions[].user._id |
string (MongoDB ObjectId) | Unique identifier of the user |
data.transactions[].user.username |
string | Username of the user |
data.transactions[].link |
string (MongoDB ObjectId) | ID of the payment link associated with this transaction |
data.transactions[].source |
string | Source domain identifier for cross-chain transactions |
data.transactions[].createdAt |
string (ISO 8601) | Timestamp when the transaction was created |
data.transactions[].updatedAt |
string (ISO 8601) | Timestamp when the transaction was last updated |
data.transactions[].__v |
number | MongoDB version key (internal field) |
data.transactions[].payload |
object | CCTP (Cross-Chain Transfer Protocol) transaction payload |
data.transactions[].payload.eventNonce |
string | Unique event nonce for the cross-chain transaction |
data.transactions[].payload.attestation |
string | Attestation signature for cross-chain verification |
data.transactions[].payload.cctpVersion |
number | Version of the CCTP protocol used |
data.transactions[].payload.sender |
string | Original sender's wallet address |
data.transactions[].payload.recipient |
string | Recipient's wallet address |
data.transactions[].payload.mintRecipient |
string | Address where tokens will be minted on destination chain |
data.transactions[].payload.messageSender |
string | Address that initiated the cross-chain message |
data.transactions[].payload.amount |
string | Transaction amount as string (in smallest token unit) |
data.transactions[].payload.maxFee |
number | Maximum fee allowed for the transaction |
data.transactions[].payload.feeExecuted |
number | Actual fee executed for the transaction |
data.transactions[].payload.sourceDomain |
number | Source blockchain domain identifier |
data.transactions[].payload.destinationDomain |
number | Destination blockchain domain identifier |
data.transactions[].payload.status |
string | CCTP transaction status (e.g., "complete", "pending") |
data.total |
number | Total number of transactions matching the query |
data.page |
number | Current page number |
data.totalPages |
number | Total number of pages available |
code |
number | HTTP status code (200 for successful requests) |
Errors:
{"statusCode": 401, "message": "API_KEY_INVALID"}
{"statusCode": 400, "message": "INVALID_STATUS"}
{"statusCode": 400, "message": "Invalid date format"}
Webhooks
KiraPay can send webhook notifications to your server when important events occur. This allows you to react to events in real-time without polling our API.
How Webhooks Work
- You register a webhook endpoint URL with KiraPay
- When an event occurs, KiraPay sends a POST request to your endpoint
- Your server processes the webhook and returns a 200 status code
- If your server doesn't respond with 200, KiraPay will retry the delivery
Webhook Events
KiraPay currently supports the following webhook events:
transaction.created
- A new transaction has been createdtransaction.succeeded
- A transaction has completed successfullytransaction.failed
- A transaction has failed
Webhook Payload Structure
All webhook payloads follow this structure:
{
"id": "evt_1704067200000_abc123",
"type": "transaction.succeeded",
"createdAt": "2025-01-25T10:00:00.000Z",
"data": {
// Event-specific data (see examples below)
}
}
Webhook Headers
KiraPay includes the following headers with each webhook request:
Header | Description |
---|---|
Content-Type |
Always application/json |
X-KiraPay-Event |
The event type (e.g., transaction.succeeded ) |
X-KiraPay-Id |
Unique event ID (e.g., evt_1704067200000_abc123 ) |
X-KiraPay-Timestamp |
Unix timestamp when the event was created |
X-KiraPay-Signature |
HMAC-SHA256 signature for webhook verification |
Webhook Verification
To verify that webhooks are coming from KiraPay, you should verify the signature:
const crypto = require('crypto');
function verifyWebhook(payload, signature, secret, timestamp) {
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(`${timestamp}.${payload}`)
.digest('base64');
const expectedHeader = `sha256=${expectedSignature}`;
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedHeader)
);
}
// Usage
const isValid = verifyWebhook(
request.body,
request.headers['x-kirapay-signature'],
'your_webhook_secret',
request.headers['x-kirapay-timestamp']
);
Event Examples
transaction.created
Sent when a new transaction is created:
{
"id": "evt_1704067200000_abc123",
"type": "transaction.created",
"createdAt": "2025-01-25T10:00:00.000Z",
"data": {
"_id": "689324309eb9e6e8e0f842cd",
"price": 0.015,
"hash": "0xb6accc136297ad17ab831028f967cbf2bdd9ff67b8fab5d4e8e4f34f8681eb59",
"status": "Pending",
"type": "Contract",
"user": {
"_id": "688c82d81c6a157748c5ca7b",
"username": "john_doe"
},
"link": "6891c0896aad1cd3bf2f3490",
"source": "7",
"createdAt": "2025-01-25T10:00:00.000Z",
"updatedAt": "2025-01-25T10:00:00.000Z"
}
}
transaction.succeeded
Sent when a transaction completes successfully:
{
"id": "evt_1704067260000_def456",
"type": "transaction.succeeded",
"createdAt": "2025-01-25T10:01:00.000Z",
"data": {
"_id": "689324309eb9e6e8e0f842cd",
"price": 0.015,
"hash": "0xb6accc136297ad17ab831028f967cbf2bdd9ff67b8fab5d4e8e4f34f8681eb59",
"status": "Success",
"type": "Contract",
"user": {
"_id": "688c82d81c6a157748c5ca7b",
"username": "john_doe"
},
"link": "6891c0896aad1cd3bf2f3490",
"source": "7",
"createdAt": "2025-01-25T10:00:00.000Z",
"updatedAt": "2025-01-25T10:01:00.000Z",
"payload": {
"eventNonce": "0x9bd7d21d481bd64a3f046b6c9e930b5843a0c36f8832a1c8e8e2319c16da6f28",
"attestation": "0x8730053fe55a898df9f81f4c45364ef1ad7541125e20656278ec9749d92ec7bb3bd5b5c81703be23d9013e03db36f2b57e8074032f68e1b9dea26570c254c0b41c2bb48dbabb202780d06305148f768bc8af82b92632fddffa88e54950deadf5774fea1bd99f721c08e88d72e15f674200438b25256c88919a6ddf29fee5df91c91c",
"cctpVersion": 2,
"sender": "0x28b5a0e9c621a5badaa536219b3a228c8168cf5d",
"recipient": "0x28b5a0e9c621a5badaa536219b3a228c8168cf5d",
"mintRecipient": "0x4b6aee828992738f64b1e908f082aa9f2cc6936a",
"messageSender": "0x4b6aee828992738f64b1e908f082aa9f2cc6936a",
"amount": "15000",
"maxFee": 2,
"feeExecuted": 0,
"sourceDomain": 7,
"destinationDomain": 6,
"status": "complete"
}
}
}
transaction.failed
Sent when a transaction fails:
{
"id": "evt_1704067320000_ghi789",
"type": "transaction.failed",
"createdAt": "2025-01-25T10:02:00.000Z",
"data": {
"_id": "689324309eb9e6e8e0f842cd",
"price": 0.015,
"hash": "0xb6accc136297ad17ab831028f967cbf2bdd9ff67b8fab5d4e8e4f34f8681eb59",
"status": "Failed",
"type": "Contract",
"user": {
"_id": "688c82d81c6a157748c5ca7b",
"username": "john_doe"
},
"link": "6891c0896aad1cd3bf2f3490",
"source": "7",
"createdAt": "2025-01-25T10:00:00.000Z",
"updatedAt": "2025-01-25T10:02:00.000Z",
"error": "Transaction reverted due to insufficient gas"
}
}
Webhook Endpoint Management
Webhook endpoints are managed through the admin API. You need to be authenticated with an admin API key to manage webhooks.
Create Webhook Endpoint
curl -X POST "https://kirapay.focalfossa.site/api/admin/webhooks/endpoints" \
-H "x-api-key: YOUR_ADMIN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-app.com/webhooks/kirapay",
"secret": "whsec_your_webhook_secret"
}'
List Webhook Endpoints
curl -X GET "https://kirapay.focalfossa.site/api/admin/webhooks/endpoints" \
-H "x-api-key: YOUR_ADMIN_API_KEY"
Update Webhook Endpoint
curl -X PATCH "https://kirapay.focalfossa.site/api/admin/webhooks/endpoints/ENDPOINT_ID" \
-H "x-api-key: YOUR_ADMIN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-new-app.com/webhooks/kirapay",
"secret": "whsec_new_webhook_secret"
}'
View Webhook Deliveries
curl -X GET "https://kirapay.focalfossa.site/api/admin/webhooks/deliveries?endpointId=ENDPOINT_ID&status=success" \
-H "x-api-key: YOUR_ADMIN_API_KEY"
Best Practices
- Always verify webhook signatures to ensure requests are from KiraPay
- Return 200 status codes quickly to acknowledge receipt
- Handle duplicate events by checking the event ID
- Use HTTPS endpoints for security
- Implement idempotency in your webhook handlers
- Log webhook events for debugging and auditing
Retry Logic
If your webhook endpoint doesn't return a 200 status code, KiraPay will retry the delivery:
- Initial delivery attempt
- Retry after 1 minute if failed
- Additional retries with exponential backoff
- Maximum retry attempts: 3
Error Handling
Error Response Format
All error responses follow the same structure:
{
"statusCode": 400,
"message": "ERROR_CODE",
"timestamp": "2025-01-25T10:00:00.000Z",
"path": "/request/path"
}
Common HTTP Status Codes
200
: OK201
: Created400
: Bad Request401
: Unauthorized (missing/invalid x-api-key)404
: Not Found429
: Too Many Requests500
: Internal Server Error