| Endpoint | Purpose |
|---|---|
POST /api/v1/webhooks/marketplace/repayment | Repayment events (deducted, failed, reversed) |
POST /api/v1/webhooks/marketplace/settlement | Settlement events (created, transferred) |
| Header | Required | Description |
|---|---|---|
X-Marketplace-Signature | Yes | HMAC-SHA256 signature of the payload |
X-Marketplace-Timestamp | Yes | Unix timestamp (seconds) of when the webhook was sent |
X-Marketplace-Id | Yes | Your marketplace ID |
X-Marketplace-Event-Id | No | Unique idempotency key for the event |
payload = "<timestamp>.<JSON_body>"
signature = "sha256=" + HMAC-SHA256(your_api_secret, payload)| Event | Description |
|---|---|
repayment.deducted | A repayment was successfully deducted from a merchant's sale/settlement |
repayment.failed | A repayment deduction attempt failed |
repayment.reversed | A previously deducted repayment was reversed |
settlement.created | A settlement batch was created containing repayment deductions |
settlement.transferred | A settlement was transferred via bank transfer |
{
"event": "repayment.deducted",
"event_id": "evt_rep_001",
"timestamp": "2026-01-29T10:30:00.000Z",
"marketplace": {
"id": "marketplace_uuid",
"name": "Your Marketplace"
},
"merchant": {
"marketplace_id": "your_internal_merchant_id",
"opensylo_id": "opensylo_merchant_uuid"
},
"loan": {
"opensylo_id": "loan_uuid",
"opensylo_reference": "LOAN-2026-001"
},
"deduction": {
"reference": "deduct_ref_001",
"amount": 5000,
"currency": "NGN",
"deducted_at": "2026-01-29T10:30:00.000Z"
},
"source_transaction": {
"id": "order_123",
"type": "sale",
"gross_amount": 25000,
"timestamp": "2026-01-29T10:25:00.000Z"
},
"loan_balance": {
"total_due": 100000,
"total_paid": 55000,
"outstanding": 45000
}
}{
"event": "repayment.failed",
"event_id": "evt_rep_002",
"timestamp": "2026-01-30T11:00:00.000Z",
"marketplace": {
"id": "marketplace_uuid",
"name": "Your Marketplace"
},
"merchant": {
"marketplace_id": "your_internal_merchant_id",
"opensylo_id": "opensylo_merchant_uuid"
},
"loan": {
"opensylo_id": "loan_uuid",
"opensylo_reference": "LOAN-2026-001"
},
"failure": {
"reference": "fail_ref_001",
"attempted_amount": 5000,
"currency": "NGN",
"reason": "Merchant wallet balance insufficient for deduction",
"code": "INSUFFICIENT_BALANCE",
"attempted_at": "2026-01-30T11:00:00.000Z"
},
"source_transaction": {
"id": "order_456",
"type": "sale",
"gross_amount": 3000,
"timestamp": "2026-01-30T10:55:00.000Z"
},
"loan_balance": {
"total_due": 100000,
"total_paid": 55000,
"outstanding": 45000
}
}{
"event": "repayment.reversed",
"event_id": "evt_rep_003",
"timestamp": "2026-02-01T14:00:00.000Z",
"marketplace": {
"id": "marketplace_uuid",
"name": "Your Marketplace"
},
"merchant": {
"marketplace_id": "your_internal_merchant_id",
"opensylo_id": "opensylo_merchant_uuid"
},
"loan": {
"opensylo_id": "loan_uuid",
"opensylo_reference": "LOAN-2026-001"
},
"reversal": {
"reference": "rev_ref_001",
"original_deduction_reference": "deduct_ref_001",
"amount": 5000,
"currency": "NGN",
"reason": "Original sale was refunded by buyer",
"reversed_at": "2026-02-01T14:00:00.000Z"
},
"loan_balance": {
"total_due": 100000,
"total_paid": 50000,
"outstanding": 50000
}
}{
"event": "settlement.created",
"event_id": "evt_stl_001",
"timestamp": "2026-02-03T00:00:00.000Z",
"marketplace": {
"id": "marketplace_uuid",
"name": "Your Marketplace"
},
"settlement": {
"reference": "stl_2026_w05",
"period_start": "2026-01-27T00:00:00.000Z",
"period_end": "2026-02-02T23:59:59.000Z",
"currency": "NGN",
"created_at": "2026-02-03T00:00:00.000Z"
},
"summary": {
"total_deductions": 12,
"total_amount": 60000,
"merchants_included": 3
},
"loans_included": [
{
"opensylo_id": "loan_uuid_1",
"opensylo_reference": "LOAN-2026-001",
"deduction_count": 8,
"deduction_total": 40000
},
{
"opensylo_id": "loan_uuid_2",
"opensylo_reference": "LOAN-2026-002",
"deduction_count": 4,
"deduction_total": 20000
}
],
"bank_transfer": {
"status": "pending",
"destination_bank": "OpenSylo Collections",
"destination_account": "0123456789"
}
}{
"event": "settlement.transferred",
"event_id": "evt_stl_002",
"timestamp": "2026-02-03T10:30:00.000Z",
"marketplace": {
"id": "marketplace_uuid",
"name": "Your Marketplace"
},
"settlement": {
"reference": "stl_2026_w05",
"currency": "NGN"
},
"transfer": {
"reference": "txn_bank_001",
"amount": 60000,
"bank_name": "OpenSylo Collections",
"account_number": "0123456789",
"transferred_at": "2026-02-03T10:30:00.000Z",
"bank_reference": "NIP/230203/ABCDEF"
}
}{
"status": "received",
"event_id": "evt_rep_001",
"opensylo_reference": "txn_uuid",
"received_at": "2026-01-29T10:30:01.000Z"
}429 Too Many Requests and a Retry-After header indicating how many seconds to wait before retrying.| Header | Description |
|---|---|
X-OpenSylo-Signature | sha256= + HMAC-SHA256 hex digest |
X-OpenSylo-Timestamp | Unix timestamp in seconds |
X-OpenSylo-Event-Id | Unique event ID (e.g., evt_loan_approved_1706529000_a1b2c3d4) |
timingSafeEqual) to prevent timing attacks. Reject any request where the timestamp is more than 5 minutes old.| Event | Description |
|---|---|
loan.approved | A loan has been approved for one of your merchants. Includes loan terms, repayment terms, and optional repayment schedule. |
loan.disbursed | Loan funds have been disbursed to the merchant. Includes disbursement details and repayment start date. Start deducting repayments. |
loan.repayment_updated | Repayment terms have changed (deduction percentage, due date). Update your deduction logic. |
loan.nearly_complete | Loan is close to full repayment (>90% paid). Includes max_deduction_amount -- cap the next deduction to avoid overpayment. |
loan.completed | Loan is fully repaid. Stop all deductions immediately. |
loan.defaulted | Loan has defaulted. Includes collection_instructions with priority level. |
| Event | Description |
|---|---|
merchant.created | A merchant was created via POST /api/v1/marketplace-api/merchants. |
kyc.submitted | The merchant submitted KYC for review (via API or the embedded journey). |
kyc.approved | KYC was approved. Pending funding requests become eligible for fulfillment. |
kyc.rejected | KYC was rejected. Includes rejection_reason -- the merchant can correct and resubmit. |
funding_request.created | A funding request was created (via API or the embedded journey). |
funding_request.fulfilled | The funding request was promoted to a real loan. Includes loan_id -- the standard loan.* events follow. |
funding_request.rejected | Fulfillment was blocked by credit policy. Includes failure_reason. |
{
"event": "loan.approved",
"event_id": "evt_loan_001",
"timestamp": "2026-01-29T14:00:00.000Z",
"loan": {
"id": "loan_uuid",
"reference": "LOAN-2026-001",
"status": "APPROVED"
},
"merchant": {
"opensylo_id": "merchant_uuid",
"marketplace_id": "your_internal_merchant_id"
},
"lender": {
"id": "lender_uuid",
"name": "FinCo Lending"
},
"terms": {
"principal_amount": 500000,
"interest_rate": 5.0,
"tenor_days": 90,
"total_repayment": 525000,
"currency": "NGN"
},
"repayment": {
"method": "sales_deduction",
"deduction_percentage": 10,
"minimum_deduction": 500,
"start_date": "2026-02-01T00:00:00.000Z",
"due_date": "2026-05-01T00:00:00.000Z"
},
"schedule": [
{ "installment": 1, "due_date": "2026-02-01", "amount": 175000 },
{ "installment": 2, "due_date": "2026-03-01", "amount": 175000 },
{ "installment": 3, "due_date": "2026-04-01", "amount": 175000 }
]
}{
"event": "loan.disbursed",
"event_id": "evt_loan_002",
"timestamp": "2026-02-01T09:00:00.000Z",
"loan": {
"id": "loan_uuid",
"reference": "LOAN-2026-001",
"status": "DISBURSED"
},
"merchant": {
"opensylo_id": "merchant_uuid",
"marketplace_id": "your_internal_merchant_id"
},
"disbursement": {
"amount": 500000,
"currency": "NGN",
"method": "bank_transfer",
"bank_name": "Access Bank",
"account_number": "****6789",
"disbursed_at": "2026-02-01T09:00:00.000Z",
"reference": "DSB-2026-001"
},
"repayment_start": {
"effective_date": "2026-02-01T00:00:00.000Z",
"deduction_percentage": 10,
"minimum_deduction": 500
},
"action_required": "start_deductions",
"message": "Loan disbursed. Begin deducting 10% from merchant sales immediately."
}{
"event": "loan.repayment_updated",
"event_id": "evt_loan_003",
"timestamp": "2026-03-01T12:00:00.000Z",
"loan": {
"id": "loan_uuid",
"reference": "LOAN-2026-001",
"status": "ACTIVE"
},
"merchant": {
"opensylo_id": "merchant_uuid",
"marketplace_id": "your_internal_merchant_id"
},
"changes": {
"deduction_percentage": {
"previous": 10,
"new": 15
},
"due_date": {
"previous": "2026-05-01T00:00:00.000Z",
"new": "2026-04-15T00:00:00.000Z"
}
},
"reason": "Repayment schedule adjusted due to missed milestones",
"updated_schedule": [
{ "installment": 2, "due_date": "2026-03-01", "amount": 200000 },
{ "installment": 3, "due_date": "2026-04-01", "amount": 200000 }
],
"action_required": "update_deduction_settings",
"message": "Deduction percentage changed from 10% to 15%. Update your deduction logic."
}{
"event": "loan.nearly_complete",
"event_id": "evt_loan_004",
"timestamp": "2026-04-10T08:00:00.000Z",
"loan": {
"id": "loan_uuid",
"reference": "LOAN-2026-001",
"status": "ACTIVE"
},
"merchant": {
"opensylo_id": "merchant_uuid",
"marketplace_id": "your_internal_merchant_id"
},
"repayment_status": {
"total_due": 525000,
"total_paid": 510000,
"outstanding": 15000,
"percent_complete": 97.14
},
"recommendation": {
"max_deduction_amount": 15000,
"message": "Cap the next deduction at NGN 15,000 to avoid over-collection."
},
"action_required": "cap_deductions",
"message": "Loan is 97.14% repaid. Cap next deduction to NGN 15,000."
}{
"event": "loan.completed",
"event_id": "evt_loan_005",
"timestamp": "2026-04-15T09:00:00.000Z",
"loan": {
"id": "loan_uuid",
"reference": "LOAN-2026-001",
"status": "REPAID"
},
"merchant": {
"opensylo_id": "merchant_uuid",
"marketplace_id": "your_internal_merchant_id"
},
"summary": {
"principal_repaid": 500000,
"interest_repaid": 25000,
"total_repaid": 525000,
"total_deductions": 42,
"first_deduction_at": "2026-02-01T10:00:00.000Z",
"final_deduction_at": "2026-04-15T08:55:00.000Z",
"completed_at": "2026-04-15T09:00:00.000Z"
},
"action_required": "stop_deductions",
"message": "Loan fully repaid. Stop all deductions for this loan immediately."
}{
"event": "loan.defaulted",
"event_id": "evt_loan_006",
"timestamp": "2026-06-01T00:00:00.000Z",
"loan": {
"id": "loan_uuid",
"reference": "LOAN-2026-001",
"status": "DEFAULTED"
},
"merchant": {
"opensylo_id": "merchant_uuid",
"marketplace_id": "your_internal_merchant_id"
},
"default_details": {
"total_due": 525000,
"total_paid": 350000,
"outstanding": 175000,
"days_overdue": 31,
"last_payment_at": "2026-04-30T15:00:00.000Z",
"defaulted_at": "2026-06-01T00:00:00.000Z"
},
"collection_instructions": {
"priority": "HIGH",
"deduction_percentage": 25,
"withhold_settlements": true,
"message": "Increase deduction rate to 25%. Withhold merchant settlements until further notice."
},
"action_required": "escalate_collection",
"message": "Loan has defaulted. Follow collection instructions immediately."
}{
"event": "merchant.created",
"event_id": "evt_merchant.created_a1b2c3d4",
"timestamp": "2026-06-10T10:00:00.123Z",
"merchant": {
"opensylo_id": "merchant_uuid",
"marketplace_id": "marketplace_uuid",
"third_party_customer_id": "mkt_merchant_8421"
},
"business_name": "Mama Cass Foods Ltd"
}third_party_customer_id is the ID you supplied when creating the merchant -- use it to correlate the event with your own records.{
"event": "kyc.submitted",
"event_id": "evt_kyc.submitted_b2c3d4e5",
"timestamp": "2026-06-10T10:05:00.123Z",
"merchant": {
"opensylo_id": "merchant_uuid",
"marketplace_id": "marketplace_uuid",
"third_party_customer_id": "mkt_merchant_8421"
},
"kyc_status": "SUBMITTED",
"rejection_reason": null
}{
"event": "kyc.approved",
"event_id": "evt_kyc.approved_c3d4e5f6",
"timestamp": "2026-06-11T09:00:00.123Z",
"merchant": {
"opensylo_id": "merchant_uuid",
"marketplace_id": "marketplace_uuid",
"third_party_customer_id": "mkt_merchant_8421"
},
"kyc_status": "APPROVED",
"rejection_reason": null
}funding_request.fulfilled or funding_request.rejected event to follow.{
"event": "kyc.rejected",
"event_id": "evt_kyc.rejected_d4e5f6g7",
"timestamp": "2026-06-11T09:00:00.123Z",
"merchant": {
"opensylo_id": "merchant_uuid",
"marketplace_id": "marketplace_uuid",
"third_party_customer_id": "mkt_merchant_8421"
},
"kyc_status": "REJECTED",
"rejection_reason": "CAC certificate expired. Please upload a valid document."
}rejection_reason to the merchant -- they can correct the issue in the embedded journey and resubmit.{
"event": "funding_request.created",
"event_id": "evt_funding_request.created_e5f6g7h8",
"timestamp": "2026-06-10T10:10:00.123Z",
"merchant": {
"opensylo_id": "merchant_uuid",
"marketplace_id": "marketplace_uuid",
"third_party_customer_id": "mkt_merchant_8421"
},
"funding_request": {
"id": "fr_uuid",
"amount_requested": 2000000,
"tenor_days": 90,
"purpose": "Inventory purchase",
"status": "PENDING",
"loan_id": null,
"failure_reason": null
}
}{
"event": "funding_request.fulfilled",
"event_id": "evt_funding_request.fulfilled_f6g7h8i9",
"timestamp": "2026-06-11T09:02:00.123Z",
"merchant": {
"opensylo_id": "merchant_uuid",
"marketplace_id": "marketplace_uuid",
"third_party_customer_id": "mkt_merchant_8421"
},
"funding_request": {
"id": "fr_uuid",
"amount_requested": 2000000,
"tenor_days": 90,
"purpose": "Inventory purchase",
"status": "FULFILLED",
"loan_id": "loan_uuid",
"failure_reason": null
}
}loan_id) and proceeds through the standard lifecycle -- the loan.* events above apply from here on.{
"event": "funding_request.rejected",
"event_id": "evt_funding_request.rejected_g7h8i9j0",
"timestamp": "2026-06-11T09:02:00.123Z",
"merchant": {
"opensylo_id": "merchant_uuid",
"marketplace_id": "marketplace_uuid",
"third_party_customer_id": "mkt_merchant_8421"
},
"funding_request": {
"id": "fr_uuid",
"amount_requested": 2000000,
"tenor_days": 90,
"purpose": "Inventory purchase",
"status": "REJECTED",
"loan_id": null,
"failure_reason": "Requested amount NGN 2,000,000 exceeds lending cap of NGN 1,500,000"
}
}| Attempt | Delay |
|---|---|
| 1 | Immediate |
| 2 | 1 minute |
| 3 | 5 minutes |
| 4 | 30 minutes |
| 5 | 2 hours |
| 6 | 24 hours |
2xx status code to acknowledge receipt.| Header | Direction | Description |
|---|---|---|
X-Marketplace-Signature | Inbound (you to OpenSylo) | sha256= + HMAC-SHA256 hex digest |
X-Marketplace-Timestamp | Inbound (you to OpenSylo) | Unix timestamp in seconds |
X-Marketplace-Id | Inbound (you to OpenSylo) | Your marketplace UUID |
X-Marketplace-Event-Id | Inbound (you to OpenSylo) | Idempotency key (optional) |
X-OpenSylo-Signature | Outbound (OpenSylo to you) | sha256= + HMAC-SHA256 hex digest |
X-OpenSylo-Timestamp | Outbound (OpenSylo to you) | Unix timestamp in seconds |
X-OpenSylo-Event-Id | Outbound (OpenSylo to you) | Unique event ID |
payload = "<unix_timestamp>.<JSON.stringify(body)>"
signature = "sha256=" + HMAC_SHA256(api_secret, payload).hexdigest()