MyTPE is getting a fresh new look! A simpler, faster platform is on the way. Learn more →
MyTPEMyTPE Pay
Webhooks

Security & Signatures

How MyTPE Pay secures webhook deliveries using HMAC-SHA256 signatures, timestamps, and delivery IDs.

Webhook Security

Every webhook sent by MyTPE Pay is cryptographically signed using the same pattern as Stripe, PayPal, and GitHub. This ensures:

  1. Authenticity — The webhook was sent by MyTPE Pay, not an attacker
  2. Integrity — The payload was not modified in transit
  3. Replay Protection — Old webhooks cannot be replayed

Signing Model

Signature = HMAC-SHA256(timestamp + "." + payload, webhook_secret)

Each webhook request includes these headers:

HeaderDescriptionExample
X-MytpePay-SignatureHMAC-SHA256 signaturesha256=a1b2c3d4...
X-MytpePay-TimestampUnix epoch seconds when sent1712678400
X-MytpePay-EventEvent typetransaction.completed
X-MytpePay-Delivery-IdUnique delivery UUIDf47ac10b-58cc-...
Content-TypeAlways JSONapplication/json
User-AgentIdentifies the senderMytpePay-Webhook/1.0

How Signing Works

  1. MyTPE Pay captures the current Unix timestamp
  2. The JSON payload is serialized
  3. They are joined with a dot: timestamp.payload
  4. An HMAC-SHA256 hash is computed using your webhook secret
  5. The result is sent as sha256={hash} in the X-MytpePay-Signature header

Your Webhook Secret

When you configure a webhook URL, MyTPE Pay automatically generates a secret key:

whsec_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6
  • Prefixed with whsec_ for easy identification
  • 48 hex characters of cryptographic randomness
  • Unique per instance
  • Can be regenerated at any time (invalidates the old one)

Keep Your Secret Safe

Store your webhook secret in environment variables. Never expose it in client-side code, logs, or version control.

Replay Protection

To prevent attackers from capturing and resending old webhook requests:

  1. Check the X-MytpePay-Timestamp header
  2. Reject requests older than 5 minutes
  3. The timestamp is part of the signature, so it cannot be modified
$timestamp = $_SERVER['HTTP_X_MYTPEPAY_TIMESTAMP'];

if (abs(time() - (int)$timestamp) > 300) {
    http_response_code(403);
    exit('Timestamp too old — possible replay attack');
}

Idempotency

Each webhook delivery includes a unique X-MytpePay-Delivery-Id (UUID v4). Use this to:

  • Detect duplicates — If you receive the same delivery ID twice, skip processing
  • Log deliveries — Track which webhooks you've processed
  • Debug issues — Reference specific deliveries in support requests

Retry Policy

If your endpoint returns a non-2xx status code or times out (10 second limit):

AttemptDelayTotal Time
1st retry1 minute~1 min after failure
2nd retry5 minutes~6 min after failure
3rd retry15 minutes~21 min after failure

After 3 failed attempts, the webhook is marked as permanently failed and logged.

Best Practice

Always return a 200 OK response quickly — process the webhook data asynchronously (e.g., via a queue) to avoid timeouts.

On this page