Webhooks
Webhooks let your server react to events in CreditCore: a new customer, a successful or failed charge, a refund, a cancellation.
Events
Section titled “Events”| Event | Sent when |
|---|---|
CONVERSION |
A checkout completes and a customer is created. |
TRANSACTION |
A charge is attempted: first payment, capture or renewal, whether it succeeded or failed. |
REFUND |
A transaction is refunded. |
CANCELLATION |
A customer is unsubscribed. |
-
Expose an HTTPS endpoint on your server that accepts
POSTrequests with a JSON body. -
Register the URL and the events you want to receive in the platform, under Management → Webhook Config (see Webhooks in the platform). Each account has one webhook endpoint.
-
Return a
2xxstatus as fast as possible. Do any heavy processing asynchronously.
Delivery
Section titled “Delivery”| Property | Value |
|---|---|
| Method | POST |
| Headers | Content-Type: application/json |
| Timeout | 5 s to connect, 10 s to respond |
| Success | Any 2xx status |
| Retries | None. Failed deliveries are not retried. |
| Order | Not guaranteed. TRANSACTION and CONVERSION for the same checkout may arrive in any order. |
Verifying events
Section titled “Verifying events”Webhooks are not signed. Before granting access or moving money based on a webhook, confirm it with an authenticated API call:
TRANSACTION/REFUND: fetchGET /api/transaction/{transaction_id}and checksuccess,amountandtype.CONVERSION/CANCELLATION: fetchGET /api/customer/{customer_id}and checkstatus.
Also restrict your endpoint to HTTPS and use a long, unguessable path.
Example receiver
Section titled “Example receiver”import express from 'express';
const app = express();app.use(express.json());
const api = (path) => fetch(`https://api.creditcore.io${path}`, { headers: { Authorization: `Bearer ${process.env.CREDITCORE_API_TOKEN}` }, }).then((r) => r.json());
app.post('/webhooks/creditcore/transaction', async (req, res) => { res.sendStatus(200); // acknowledge immediately
const event = req.body; const tx = await api(`/api/transaction/${event.transaction_id}`); // verify if (tx.success) { await grantAccess(event.customer_id, event.product_id); } else { await notifyPaymentFailed(event.email, event.attempts); }});
app.listen(3000);@RestController@RequestMapping("/webhooks/creditcore")class CreditCoreWebhookController {
@PostMapping("/transaction") ResponseEntity<Void> transaction(@RequestBody Map<String, Object> event) { webhookQueue.enqueue(event); // process async, verify via API return ResponseEntity.ok().build(); }}Idempotency
Section titled “Idempotency”The same event may occasionally be delivered more than once. Deduplicate with:
TRANSACTION/REFUND:transaction_idCONVERSION:customer_id+subscription_timestampCANCELLATION:customer_id+unsubscription_timestamp