Management
Inspect, update, test, replay, or remove an endpoint.
Everything here takes a secret API key (hpn_live_sk_*) with the webhooks:manage scope, or a dashboard session. Revealing and rotating a secret are dashboard-only.
List endpoints
GET /v1/open-collections/endpoints{
"success": true,
"data": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"url": "https://your-server.com/harpoon/payments",
"description": "Shop orders",
"is_active": true,
"is_sandbox": false,
"auto_paused_at": null,
"last_success_at": "2026-09-04T13:00:00Z",
"last_failure_at": null,
"consecutive_failures": 0,
"created_at": "2026-09-04T12:00:00Z",
"updated_at": "2026-09-04T12:00:00Z"
}
]
}Signing secrets are never returned here. GET /v1/open-collections/endpoints/{id} returns one endpoint.
Update
PUT /v1/open-collections/endpoints/{id}
Content-Type: application/json
{
"url": "https://your-server.com/v2/harpoon/payments",
"is_active": true
}| Field | Type | Description |
|---|---|---|
url | string | New URL (HTTPS) |
description | string | Label |
is_active | boolean | false pauses delivery |
When we stop an endpoint
After 20 consecutive failures we stop and set auto_paused_at. Queued deliveries wait, so is_active: true sends them. You get an email when it happens.
Test
POST /v1/open-collections/endpoints/{id}/testSends a transaction.forwarded payload with "test": true, and returns what your endpoint replied.
Reveal the signing secret
Dashboard only, with your password. 5 attempts per 15 minutes.
POST /v1/open-collections/endpoints/{id}/secret
Authorization: Bearer <dashboard-jwt>
Content-Type: application/json
{ "password": "your-account-password" }Rotate the signing secret
POST /v1/open-collections/endpoints/{id}/rotate-secret
Authorization: Bearer <dashboard-jwt>
Content-Type: application/json
{ "password": "your-account-password" }Returns the new secret once. For 24 hours deliveries also carry X-Harpoon-Signature-Previous, signed with the old one, so you can change over without dropping one.
Delivery log
GET /v1/open-collections/deliveries?endpoint_id={id}&status=failed&limit=50{
"success": true,
"data": [
{
"id": "1c1f5d6e-1ea6-4c0a-9f3a-2f2f4d1c2b3a",
"webhook_id": "ocl_a1b2c3d4e5f6g7h8i9j0k1l2",
"endpoint_id": "550e8400-e29b-41d4-a716-446655440000",
"transaction_id": "9d8c7b6a-5432-4321-8765-0f0e0d0c0b0a",
"status": "failed",
"attempt_count": 8,
"response_status_code": 500,
"response_body": "Internal Server Error",
"created_at": "2026-09-04T12:05:32Z",
"delivered_at": null,
"failed_at": "2026-09-05T12:05:32Z"
}
]
}status is pending, retrying, delivered or failed. limit defaults to 50, caps at 200; page with offset.
Send one again
POST /v1/open-collections/deliveries/{id}/redeliverQueues a finished delivery again. Only delivered and failed qualify, and it does not count as another verified transaction.
Match payments to a number after the fact
Payments that arrived while a SIM had no number, or the wrong one, went to your catch-all. Once the SIM is right, claim them:
POST /v1/payment-methods/{id}/claim-unplaced{ "success": true, "claimed": 12 }Covers the last 30 days on that number’s own SIM and network. Payments already matched to a number are left alone.
Then replay that window to the endpoint that should have had them.
Send past payments
For an endpoint added after the fact:
POST /v1/open-collections/replay
Content-Type: application/json
{
"endpoint_id": "550e8400-e29b-41d4-a716-446655440000",
"from": "2026-08-01T00:00:00Z",
"to": "2026-08-31T23:59:59Z"
}{ "success": true, "enqueued": 42 }Up to 31 days and 1000 payments per call. Sends only what this endpoint’s rules claim, skips what it already has, and counts against nothing.
Delete
DELETE /v1/open-collections/endpoints/{id}{ "success": true, "deleted": true }Creating it again generates a new signing secret.