PayProTec API Reference
The PayProTec REST API lets you access your partner data programmatically — merchants, tickets, and your profile. Use it to build integrations, automate workflows, or sync data with your own tools.
Base URL: https://portal.mypayprotec.com/api/v1
success boolean. On success, data lives under the data key. On failure, the error is under the error key.Authentication
Every request must include your API key in the Authorization header. Generate keys from your Partner Portal under Settings → API Keys.
Authorization: Bearer pk_live_your_api_key_here
Rate Limits
Rate limits are enforced per API key. Every response includes headers showing your current usage.
| Tier | Requests / Minute | Requests / Day | How to Upgrade |
|---|---|---|---|
| Free | 10 | 500 | Default for all partners |
| Standard | 60 | 5,000 | Contact support |
| Enterprise | 300 | 50,000 | Contact your account manager |
Rate Limit Headers
| Header | Description |
|---|---|
| X-RateLimit-Limit | Max requests per minute for your tier |
| X-RateLimit-Remaining | Requests left in the current minute |
| X-RateLimit-Daily-Limit | Max requests per day |
| X-RateLimit-Daily-Remaining | Requests left today |
| X-RateLimit-Reset | ISO timestamp when the current window resets |
| Retry-After | Seconds to wait before retrying (only on 429) |
Errors
All errors follow the same shape. HTTP status codes indicate the category of error.
{
"success": false,
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Rate limit exceeded. Max 10 requests/minute on the free tier.",
"retry_after": 42
}
}
| HTTP Status | Code | Meaning |
|---|---|---|
401 | MISSING_KEY | No Authorization header provided |
401 | INVALID_KEY | Key not found in the system |
401 | KEY_REVOKED | Key exists but has been revoked |
400 | MISSING_PARAM | A required parameter is missing |
400 | INVALID_PARAM | A parameter has an invalid value |
403 | FORBIDDEN | Resource exists but belongs to another account |
404 | NOT_FOUND | Resource does not exist |
405 | METHOD_NOT_ALLOWED | Wrong HTTP method for this endpoint |
429 | RATE_LIMIT_EXCEEDED | Per-minute limit hit |
429 | DAILY_LIMIT_EXCEEDED | Daily limit hit — resets at midnight UTC |
500 | DB_ERROR | Unexpected server error |
Profile
curl https://portal.mypayprotec.com/api/v1/profile \
-H "Authorization: Bearer pk_live_your_key"
{
"success": true,
"data": {
"id": "uuid",
"full_name": "Jane Smith",
"email": "jane@example.com",
"phone_number": "+1 555 000 0000",
"enrolled_at": "2024-01-15T00:00:00Z",
"companies": ["Smith Payments LLC"],
"stats": {
"total_merchants": 42,
"open_tickets": 3
}
}
}
Merchants
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| page | integer | Optional | Page number, 0-indexed. Default: 0 |
| limit | integer | Optional | Results per page. Default: 25, Max: 100 |
| search | string | Optional | Filter by merchant DBA name (partial match) |
| status | string | Optional | Approved, Pending, Closed |
curl "https://portal.mypayprotec.com/api/v1/merchants?page=0&limit=25&status=Approved" \
-H "Authorization: Bearer pk_live_your_key"
{
"success": true,
"data": [
{
"id": "uuid",
"merchant_id": "123456789",
"dba_name": "Acme Coffee Co.",
"account_status": "Approved",
"enrollment_date": "2024-03-01T00:00:00Z",
"volume_mtd": 12480.50,
"volume_30_day": 11200.00,
"volume_90_day": 34100.00,
"merchant_city": "Austin",
"merchant_state": "TX"
}
],
"meta": {
"page": 0,
"limit": 25,
"total": 42,
"has_more": true
}
}
:id accepts either the merchant UUID or the merchant_id string (e.g. 123456789).
curl "https://portal.mypayprotec.com/api/v1/merchants/123456789" \
-H "Authorization: Bearer pk_live_your_key"
{
"success": true,
"data": {
"id": "uuid",
"merchant_id": "123456789",
"dba_name": "Acme Coffee Co.",
"account_status": "Approved",
"merchant_address": "123 Main St",
"merchant_city": "Austin",
"merchant_state": "TX",
"email": "owner@acmecoffee.com",
"volume_mtd": 12480.50,
"equipment": [
{ "serial_number": "SN-001", "terminal_type": "Clover Mini", "status": "deployed" }
],
"recent_notes": [],
"recent_tickets": []
}
}
Tickets
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| page | integer | Optional | Page number, 0-indexed. Default: 0 |
| limit | integer | Optional | Results per page. Default: 25, Max: 100 |
| status | string | Optional | open, in_progress, resolved, closed |
| type | string | Optional | general, equipment, billing, rma, deployment |
curl "https://portal.mypayprotec.com/api/v1/tickets?status=open" \
-H "Authorization: Bearer pk_live_your_key"
:id accepts either the numeric ticket ID or the ticket number string (e.g. TKT-202405-00123).
curl "https://portal.mypayprotec.com/api/v1/tickets/TKT-202405-00123" \
-H "Authorization: Bearer pk_live_your_key"
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| subject | string | Required | Short summary of the issue |
| description | string | Required | Full details of the issue |
| type | string | Optional | general · equipment · billing · rma · deployment · other. Default: general |
| category | string | Optional | Freeform category label. Default: other |
| priority | string | Optional | low · medium · high · urgent. Default: medium |
| merchant_id | string | Optional | Link the ticket to a merchant (UUID or merchant_id string) |
curl -X POST https://portal.mypayprotec.com/api/v1/tickets \ -H "Authorization: Bearer pk_live_your_key" \ -H "Content-Type: application/json" \ -d '{ "subject": "Terminal not printing receipts", "description": "The Clover Mini at Acme Coffee stopped printing since yesterday.", "type": "equipment", "priority": "high", "merchant_id": "123456789" }'
201 Created{
"success": true,
"data": {
"id": 9,
"ticket_number": "TKT-202405-00042",
"subject": "Terminal not printing receipts",
"type": "equipment",
"priority": "high",
"status": "open",
"created_at": "2026-05-14T18:32:00Z"
}
}
Reports
Returns a single aggregated summary of your entire portfolio. Useful for dashboards, automated reports, and health checks. No parameters required.
curl https://portal.mypayprotec.com/api/v1/reports/summary \
-H "Authorization: Bearer pk_live_your_key"
{
"success": true,
"data": {
"merchants": {
"total": 42,
"approved": 38,
"pending": 3,
"closed": 1,
"at_risk": 4 // MTD volume >5% below 90-day baseline
},
"volume": {
"mtd": 187420.50,
"last_30_days": 187420.50,
"last_90_days": 541200.00
},
"tickets": {
"open": 3,
"in_progress": 1,
"resolved": 2
},
"generated_at": "2026-05-14T18:32:00Z"
}
}
Field Notes
| Field | Description |
|---|---|
| merchants.at_risk | Approved merchants whose MTD volume is more than 5% below their 90-day monthly average — may need attention |
| volume.mtd | Total processing volume across all approved merchants month-to-date |
| volume.last_90_days | Cumulative volume over the trailing 90 days |
| tickets.open | Tickets in open status only — does not include closed tickets |
Webhooks
Instead of polling the API, webhooks push data to your server in real-time when events happen in your account. Configure up to 5 active webhook endpoints from your partner settings.
List Webhooks + Delivery Log
Returns all your webhook endpoints and the last 20 delivery attempts across all endpoints.
{
"success": true,
"data": {
"endpoints": [
{
"id": "wh_abc123",
"label": "My CRM",
"url": "https://yourapp.com/webhooks/paypro",
"events": ["ticket.created", "ticket.updated"],
"is_active": true,
"last_triggered_at": "2026-05-14T10:30:00Z",
"last_status": 200,
"created_at": "2026-05-01T09:00:00Z"
}
],
"deliveries": [
{
"id": 1042,
"webhook_id": "wh_abc123",
"event": "ticket.created",
"status_code": 200,
"success": true,
"attempts": 1,
"created_at": "2026-05-14T10:30:01Z"
}
]
}
}
Manage Webhooks
Create, update, delete, or rotate the signing secret for a webhook endpoint.
| action | Required fields | Description |
|---|---|---|
create | url, events | Register a new endpoint. Returns the signing secret (shown once). |
update | webhook_id | Change the label, url, or subscribed events. |
delete | webhook_id | Remove the endpoint permanently. |
rotate_secret | webhook_id | Generate a new signing secret. Old secret stops working immediately. |
POST /api/v1/webhooks
Authorization: Bearer pk_live_...
{
"action": "create",
"label": "My CRM",
"url": "https://yourapp.com/webhooks/paypro",
"events": ["ticket.created", "ticket.updated", "merchant.status_changed"]
}
// Response (201)
{
"success": true,
"data": {
"id": "wh_abc123",
"secret": "a1b2c3d4...", // shown ONCE — store securely
"secret_note": "Store this secret securely. It will not be shown again."
}
}
Event Types
Subscribe to one or more of these events when creating a webhook:
| Event | Fires when… |
|---|---|
ticket.created | A new support ticket is opened (via portal or API) |
ticket.updated | A ticket's status or priority changes |
ticket.comment_added | Staff or partner posts a reply on a ticket |
merchant.status_changed | A merchant's approval status changes |
Each delivery sends a POST with these headers:
| Header | Value |
|---|---|
X-PayProTec-Event | The event name (e.g. ticket.created) |
X-PayProTec-Signature | HMAC-SHA256 signature (see below) |
X-PayProTec-Timestamp | ISO 8601 UTC timestamp |
User-Agent | PayProTec-Webhooks/1.0 |
Delivery is retried up to 3 times (at 2s and 5s intervals) if your server returns a non-2xx status or times out. Your endpoint should respond within 10 seconds.
Verifying Signatures
Each request includes an X-PayProTec-Signature header so you can confirm the payload came from PayProTec and wasn't tampered with.
The signature is sha256= followed by the HMAC-SHA256 hex digest of the raw request body, signed with your endpoint's secret.
import crypto from 'crypto';
function verifyWebhook(rawBody, signature, secret) {
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(rawBody)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(signature)
);
}
// Express example
app.post('/webhooks/paypro', express.raw({ type: 'application/json' }), (req, res) => {
const sig = req.headers['x-paypro-signature'];
if (!verifyWebhook(req.body, sig, process.env.WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature');
}
const event = JSON.parse(req.body);
console.log('Event:', req.headers['x-paypro-event'], event);
res.sendStatus(200);
});
import hmac, hashlib
def verify_webhook(raw_body: bytes, signature: str, secret: str) -> bool:
expected = 'sha256=' + hmac.new(
secret.encode(), raw_body, hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected, signature)
# Flask example
@app.route('/webhooks/paypro', methods=['POST'])
def webhook():
sig = request.headers.get('X-PayProTec-Signature', '')
if not verify_webhook(request.data, sig, WEBHOOK_SECRET):
return 'Invalid signature', 401
event = request.get_json()
print('Event:', request.headers.get('X-PayProTec-Event'), event)
return '', 200
Use Cases
Real examples of what partners have built or can build using this API.
Build your own internal dashboard that shows all your merchants, their volume trends, and at-risk accounts — refreshed automatically without logging into the portal. Use GET /merchants on a schedule to keep it current.
Use Google Apps Script to call GET /merchants every morning and populate a spreadsheet with your full merchant list, statuses, and volume numbers. Share it with your team without giving them portal access.
Poll GET /tickets?status=open every hour and post a summary to your team's Slack or Teams channel. Catch new support issues without anyone having to remember to check the portal.
Sync your merchant data into HubSpot, Salesforce, or any CRM using GET /merchants. Keep your sales pipeline and merchant portfolio in one place so your team has full context when talking to a merchant.
Integrate POST /tickets into your own merchant-facing tools. When a merchant reports an issue through your system, automatically open a support ticket on their behalf — already linked to their merchant record.
Build a lightweight mobile app for your sales reps using GET /merchants/:id. Before a site visit, they can pull up the merchant's current status, volume, equipment, and open tickets — all from their phone.
Automate your monthly business review. Pull merchant counts, volume totals, and ticket stats via the API and generate a formatted PDF or email report — no manual data collection required.
Poll GET /reports/summary daily and alert your team when merchants.at_risk increases. Catch declining merchants before they churn — no manual review required.
Connect the API to Zapier or Make (formerly Integromat) using their HTTP module. Trigger workflows when you detect new merchants, ticket updates, or volume changes — no code required.
Changelog
v1.1 — May 2026
Added webhook management endpoints: create, update, delete, rotate_secret. Added event delivery log. Added HMAC-SHA256 signature verification on all deliveries.
v1.0 — May 2026
Initial release. Endpoints: profile, merchants (list + detail), tickets (list + detail + create), reports summary.