Payments API Reference
Query payment transactions, deposits, installment logs, and refund status for payments managed by Hermon.
Date & Timezone Handling: All timestamps in responses are UTC, formatted as ISO 8601 (2026-01-15T10:30:00.000Z). Date-range filters accept either date-only YYYY-MM-DD (which expands to UTC day boundaries) or full ISO 8601 timestamps.
Amounts: All monetary values are in major currency units (e.g. 997.50 for $997.50). The currency field is returned as an ISO 4217 code (e.g. USD, EUR).
VAT Calculation: VAT details are computed based on provider-reported data and org configuration. vat_exempt indicates whether the payment was exempted from VAT.
Amounts: All monetary values are in major currency units (e.g. 997.50 for $997.50). The currency field is returned as an ISO 4217 code (e.g. USD, EUR).
VAT Calculation: VAT details are computed based on provider-reported data and org configuration. vat_exempt indicates whether the payment was exempted from VAT.
List Payments
Retrieve a paginated list of payments. Results can be filtered by status, lead, contract, and assigned setter, closer, or triager.
GET/api/external/payments
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| page | integer | Optional | Page number for pagination. Default: 1 |
| limit | integer | Optional | Number of items per page. Default: 10, Max: 100 |
| status | string | Optional | Filter by payment status. See Payment Status Values. |
| lead_id | string (UUID) | Optional | UUID of the lead to filter payments by. |
| contract_id | string (UUID) | Optional | UUID of the contract to filter payments by. |
| setter | string | Optional | Email address of the setter to filter by. |
| triager | string | Optional | Email address of the triager to filter by. |
| closer | string | Optional | Email address of the closer to filter by. |
| due_date_from | string | Optional | Lower bound for due_date. Accepts YYYY-MM-DD or ISO 8601. |
| due_date_to | string | Optional | Upper bound for due_date. Accepts YYYY-MM-DD or ISO 8601. |
| paid_date_from | string | Optional | Lower bound for paid_at. Same format rules as due_date_from. |
| paid_date_to | string | Optional | Upper bound for paid_at. Same format rules as due_date_to. |
| created_from | string | Optional | Lower bound for created_at. |
| created_to | string | Optional | Upper bound for created_at. |
Totals Information:
- totals aggregates net amounts across all pages matching filters.
- totals_page aggregates net amounts for the current page only.
- If payments span multiple currencies, the root amount defaults to null and aggregates are listed in a by_currency array.
Code Examples
curl -X GET "https://api.hermon.io/api/external/payments?page=1&limit=10&status=REFUNDED&setter=sales-setter@mailinator.com&closer=hermon@mailinator.com&triager=triager@mailinator.com&lead_id=e799c30f-9da7-4fd7-9552-83b96a9bfac2&contract_id=d5e0fb5d-5b14-45cf-81d8-2a0eb7a49224" \
-H "Content-Type: application/json" \
-H "x-api-key: sk_live_your_key_here"Response Example
json
{
"success": true,
"message": "Payments fetched successfully",
"data": [
{
"id": "pay_d4e5f6a7-b8c9-0123-defg-234567890123",
"lead": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"first_name": "John",
"last_name": "Doe",
"email": "john.doe@example.com",
"billing_details": {
"id": "bill_xyz123",
"business_name": "Doe Coaching LLC",
"address": "123 Main St",
"city": "San Francisco",
"zipcode": "94105",
"province": "CA",
"country": "US",
"vat_number": null,
"vat_exempt": false,
"created_at": "2026-02-08T10:00:00.000Z",
"updated_at": "2026-02-08T10:00:00.000Z"
}
},
"is_mandate_payment": false,
"amount": 997.0,
"vat_rate": 0.21,
"vat_amount": 209.37,
"gross_amount": 1206.37,
"vat_exempt": false,
"currency": "USD",
"due_date": "2026-02-10T00:00:00.000Z",
"status": "PAID",
"payment_provider": "STRIPE",
"type": "DEPOSIT",
"paid_at": "2026-02-10T14:30:00.000Z",
"created_at": "2026-02-08T10:00:00.000Z"
}
],
"pagination": {
"page": 1,
"limit": 20,
"total": 1,
"totalPages": 1,
"hasNext": false,
"hasPrev": false
}
}Get Payment Details
Fetch detailed information for a single payment transaction by its unique UUID.
GET/api/external/payments/:id
Path Parameters
:idRequired. The unique payment UUID.
Payment Object Fields
| Field | Type | Description |
|---|---|---|
| id | string (UUID) | Unique identifier for the payment. |
| lead | object | Lead linked to this payment (id, first_name, last_name, email, billing_details). See Payment Lead Object. |
| first_source | object | null | Lead's first attribution source [Details API Only]. |
| last_source | object | null | Lead's last attribution source [Details API Only]. |
| custom_fields | array | Custom field values [Details API Only]. |
| is_mandate_payment | boolean | Whether the payment was charged automatically via a mandate. |
| payment_proofs | array | List of uploaded payment proofs. See Payment Proof Object [Details API Only]. |
| amount | number | Amount in major currency units. |
| vat_rate | number | VAT rate applied (e.g. 0.21 for 21%). |
| vat_amount | number | VAT portion of the payment in major currency units. |
| gross_amount | number | Total payment including VAT (amount + vat_amount). |
| vat_exempt | boolean | Whether this payment is VAT exempt. |
| processor_fee_amount | number | null | Payment processor fee in major units of processor fee currency [Details API Only]. |
| cycle_gross_amount | number | null | Per-cycle gross amount [Details API Only]. |
| pause_credit_applied | number | null | Amount of pause credit applied to this payment [Details API Only]. |
| pause_credit_for_id | string | null | UUID of the payment that generated the pause credit [Details API Only]. |
| is_pause_credit | boolean | Whether this payment represents a pause credit adjustment [Details API Only]. |
| contract | object | null | Contract linked to this payment. See Payment Contract Object [Details API Only]. |
| currency | string | ISO 4217 currency code (e.g. USD, EUR). |
| due_date | string (ISO 8601) | Due date of the payment. |
| status | string (enum) | Current status (DRAFT, PENDING, PAID, FAILED, LOST, REFUNDED). |
| payment_provider | string (enum) | Payment gateway (STRIPE, WHOP, MOLLIE, MANUAL). |
| type | string (enum) | Payment type (DEPOSIT, FIRST_PAYMENT, INSTALMENT, SUBSCRIPTION_CYCLE). |
| paid_at | string (ISO 8601) | null | UTC timestamp when successfully paid. null if unpaid. |
| created_at | string (ISO 8601) | UTC timestamp when the payment was created. |
| failure_reason | string | null | Detailed reason if the payment failed [Details API Only]. |
| card_last4 | string | null | Last 4 digits of the payment card (Stripe/Whop only) [Details API Only]. |
| card_brand | string | null | Brand of the payment card (e.g. visa, mastercard) [Details API Only]. |
| customer_email | string | null | Customer email registered with the payment provider [Details API Only]. |
| processor_fee_currency | string | null | Currency of the processor fee [Details API Only]. |
| refunds | array | List of refunds processed against this payment. See Payment Refund Object [Details API Only]. |
| payment_links | array | Stripe/Mollie payment links generated for this invoice. See Payment Link Object [Details API Only]. |
| unmatched_payment | object | null | Unmatched transaction details if manually reconciled [Details API Only]. |
Code Examples
curl -X GET "https://api.hermon.io/api/external/payments/0174f917-e7c2-4a27-9aca-2626724c04d5" \
-H "Content-Type: application/json" \
-H "x-api-key: sk_live_your_key_here"Response Example
json
{
"success": true,
"message": "Payment fetched successfully",
"data": {
"id": "pay_d4e5f6a7-b8c9-0123-defg-234567890123",
"lead": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"first_name": "John",
"last_name": "Doe",
"email": "john.doe@example.com",
"sales_status": {
"id": "status_xyz789",
"name": "Closed Won",
"text_color": "#14532D",
"bg_color": "#DCFCE7"
},
"billing_details": {
"id": "bill_xyz123",
"business_name": "Doe Coaching LLC",
"address": "123 Main St",
"city": "San Francisco",
"zipcode": "94105",
"province": "CA",
"country": "US",
"vat_number": null,
"vat_exempt": false,
"created_at": "2026-02-08T10:00:00.000Z",
"updated_at": "2026-02-08T10:00:00.000Z"
}
},
"first_source": {
"id": "src_abc",
"name": "Facebook Ad"
},
"last_source": {
"id": "src_def",
"name": "Referral"
},
"custom_fields": [],
"is_mandate_payment": false,
"payment_proofs": [],
"amount": 997.0,
"vat_rate": 0.21,
"vat_amount": 209.37,
"gross_amount": 1206.37,
"vat_exempt": false,
"processor_fee_amount": 30.5,
"cycle_gross_amount": null,
"pause_credit_applied": null,
"pause_credit_for_id": null,
"is_pause_credit": false,
"contract": {
"id": "c3d4e5f6-a7b8-9012-cdef-123456789012",
"status": "SIGNED",
"type": "PP",
"program": {
"name": "12-Week Coaching Program"
},
"payment_mandate": {
"status": "VALID",
"payment_provider": "STRIPE"
},
"subscription": null
},
"currency": "USD",
"due_date": "2026-02-10T00:00:00.000Z",
"status": "PAID",
"payment_provider": "STRIPE",
"type": "DEPOSIT",
"paid_at": "2026-02-10T14:30:00.000Z",
"created_at": "2026-02-08T10:00:00.000Z",
"failure_reason": null,
"card_last4": "4242",
"card_brand": "visa",
"customer_email": "john.doe@example.com",
"processor_fee_currency": "USD",
"refunds": [],
"payment_links": [
{
"id": "link_abc123",
"note": null,
"status": "USED",
"url": "https://pay.stripe.com/xyz",
"provider_link_id": "pi_abc123",
"created_at": "2026-02-08T10:00:00.000Z"
}
],
"unmatched_payment": null
}
}Update Payment Status
Mark an existing payment as paid or refunded. The required fields depend on the payment method and provider (see below). The updated payment is immediately reflected on GET /api/external/payments/:id.
PATCH/api/external/payments/:id/status
Path Parameters
:idRequired. The unique payment UUID.
Headers
Content-Type:multipart/form-data
Encoding: This endpoint accepts multipart/form-data (not JSON) so an optional proof-of-payment file can be uploaded. Send all fields as form fields.
Behaviour by payment method:
- Mark paid · manual: supply proof_of_payment when the org requires it. Only DRAFT/PENDING payments qualify.
- Mark paid · provider (Whop / Stripe / Mollie): provider_payment_id is required and verified at the provider. Only PENDING payments qualify; a non-manual subscription first payment must settle at the provider and cannot be marked paid here.
- Refund · manual: only reason is required; the payment flips to REFUNDED immediately.
- Refund · provider · refund_mode=provider: a refund is initiated at the provider. The payment stays PAID and only becomes REFUNDED once the provider confirms via webhook.
- Refund · provider · refund_mode=record_only: the payment is marked REFUNDED immediately and provider_refund_id is stored if supplied.
Request Body Fields
| Field | Type | Required | Description |
|---|---|---|---|
| status | string | Required | Target status. One of "paid" or "refunded" (case-insensitive). |
| paid_at | string (ISO 8601) | Optional | Only for status=paid. Payment date; defaults to now. Must be after the payment’s creation date and not in the future. |
| proof_of_payment | file | Optional | Only for status=paid on a manual payment. Required when the organization’s "proof of payment required" setting is enabled. Max 5 MB; allowed types: image/jpeg, image/png, image/webp, application/pdf. |
| provider_payment_id | string | Optional | Required for status=paid on a non-manual payment (Whop / Stripe / Mollie). The provider’s own payment id; verified at the provider (must exist, be settled, and match this payment’s amount and currency). |
| reason | string | Required | Required for status=refunded (manual, provider, and record_only). Reason for the refund. |
| refund_mode | string | Optional | Required for status=refunded on a non-manual payment. "provider" initiates the refund at the provider (async). "record_only" records a refund already settled outside Hermon. |
| provider_refund_id | string | Optional | Only for status=refunded with refund_mode=record_only. The provider’s refund id, when known. |
Code Examples
# Manual payment — mark paid with proof of payment
curl -X PATCH "https://api.hermon.io/api/external/payments/0174f917-e7c2-4a27-9aca-2626724c04d5/status" \
-H "x-api-key: sk_live_your_key_here" \
-F "status=paid" \
-F "paid_at=2026-02-10T14:30:00.000Z" \
-F "proof_of_payment=@/path/to/receipt.pdf"
# Provider payment (Whop / Stripe / Mollie) — mark paid
curl -X PATCH "https://api.hermon.io/api/external/payments/0174f917-e7c2-4a27-9aca-2626724c04d5/status" \
-H "x-api-key: sk_live_your_key_here" \
-F "status=paid" \
-F "provider_payment_id=pay_WhopABC123"
# Provider payment — initiate a refund at the provider (settles async via webhook)
curl -X PATCH "https://api.hermon.io/api/external/payments/0174f917-e7c2-4a27-9aca-2626724c04d5/status" \
-H "x-api-key: sk_live_your_key_here" \
-F "status=refunded" \
-F "refund_mode=provider" \
-F "reason=Customer requested cancellation"
# Provider payment — record a refund already settled outside Hermon
curl -X PATCH "https://api.hermon.io/api/external/payments/0174f917-e7c2-4a27-9aca-2626724c04d5/status" \
-H "x-api-key: sk_live_your_key_here" \
-F "status=refunded" \
-F "refund_mode=record_only" \
-F "reason=Refunded via provider dashboard" \
-F "provider_refund_id=re_ABC123"Response Example
On success the endpoint returns only a confirmation — no payment body. Fetch GET /api/external/payments/:id to read the updated payment.
json
{
"success": true,
"message": "Payment status updated successfully"
}Values Reference
Payment Status Values
| Value | Description |
|---|---|
| DRAFT | Created but not yet sent/due |
| PENDING | Awaiting payment from client |
| PAID | Successfully paid |
| FAILED | Payment attempt failed |
| LOST | Payment deemed uncollectable |
| REFUNDED | Payment refunded to client |
Payment Type Values
| Value | Description |
|---|---|
| FIRST_PAYMENT | Initial payment (often used with subscriptions) |
| DEPOSIT | Deposit/down payment |
| INSTALMENT | Payment plan instalment |
| SUBSCRIPTION_CYCLE | Recurring subscription charge |
Payment Provider Values
| Value | Description |
|---|---|
| STRIPE | Stripe |
| WHOP | Whop |
| MOLLIE | Mollie |
| MANUAL | Manual / offline payment |
Nested Objects Reference
Payment Lead Object (List API)
| Field | Type | Description |
|---|---|---|
| id | string | Lead ID |
| first_name | string | First name |
| last_name | string | Last name |
| string | Email address | |
| billing_details | object | null | Lead's billing details for invoicing (business name, full address incl. city, VAT number). Same shape as the Billing Details Object in the Leads API; null when none are set. |
Payment Lead Object (Detail API)
| Field | Type | Description |
|---|---|---|
| id | string | Lead ID |
| first_name | string | First name |
| last_name | string | Last name |
| string | Email address | |
| sales_status | object | Current lead status with id, name, text_color, bg_color |
| billing_details | object | null | Lead's billing details for invoicing (business name, full address incl. city, VAT number). Same shape as the Billing Details Object in the Leads API; null when none are set. |
User Details Object
| Field | Type | Description |
|---|---|---|
| first_name | string | First name |
| last_name | string | Last name |
| profile_image_url | string | Profile image URL (null if none) |
| id | string | Clerk user ID |
| role | string | Organization role |
Payment Contract Object
| Field | Type | Description |
|---|---|---|
| id | string | Contract ID |
| status | string | Contract status |
| type | string | Contract type enum |
| program | object | Program with name |
| payment_mandate | object | Mandate info with status and payment_provider (null if no mandate) |
| subscription | object | Subscription info (null for non-subscription contracts) |
Refund Object
| Field | Type | Description |
|---|---|---|
| id | string | Refund ID |
| amount | number | Refund amount in major units |
| reason | string | Reason for refund |
| status | string (enum) | Refund status (INITIATED, SUCCEEDED, FAILED) |
| currency | string | Currency code |
| refunded_at | string (ISO 8601) | When refund was processed |
| failure_reason | string | Failure reason (if status is FAILED) |
| created_at | string (ISO 8601) | When refund was initiated |
Payment Link Object
| Field | Type | Description |
|---|---|---|
| id | string | Link ID |
| note | string | Optional note about the link |
| status | string (enum) | Link status (ACTIVE, USED, INVALID) |
| url | string | Payment link URL |
| provider_link_id | string | Provider's link identifier |
| created_at | string (ISO 8601) | When the link was created |
Payment Proof Object
| Field | Type | Description |
|---|---|---|
| id | string | Proof ID |
| file_name | string | Original file name |
| mime_type | string | MIME type (e.g. "image/jpeg") |
| file_size_bytes | integer | File size in bytes |
| uploaded_by | string | Clerk user ID who uploaded |
| created_at | string (ISO 8601) | When uploaded |
| url | string | Pre-signed download URL (expires in 1 hour) |
Error Responses
401Missing or invalid API key
json
{
"status": "error",
"message": "Invalid or revoked API key"
}404Resource not found
json
{
"status": "error",
"message": "Resource not found"
}429Rate limit exceeded
json
{
"status": "error",
"message": "Rate limit exceeded for this organization. Retry after the number of seconds in the Retry-After header."
}