Open Collections

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

Bash
GET /v1/open-collections/endpoints
JSON
{
  "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

Bash
PUT /v1/open-collections/endpoints/{id}
Content-Type: application/json

{
  "url": "https://your-server.com/v2/harpoon/payments",
  "is_active": true
}
FieldTypeDescription
urlstringNew URL (HTTPS)
descriptionstringLabel
is_activebooleanfalse 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

Bash
POST /v1/open-collections/endpoints/{id}/test

Sends 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.

Bash
POST /v1/open-collections/endpoints/{id}/secret
Authorization: Bearer <dashboard-jwt>
Content-Type: application/json

{ "password": "your-account-password" }

Rotate the signing secret

Bash
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

Bash
GET /v1/open-collections/deliveries?endpoint_id={id}&status=failed&limit=50
JSON
{
  "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

Bash
POST /v1/open-collections/deliveries/{id}/redeliver

Queues 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:

Bash
POST /v1/payment-methods/{id}/claim-unplaced
JSON
{ "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:

Bash
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"
}
JSON
{ "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

Bash
DELETE /v1/open-collections/endpoints/{id}
JSON
{ "success": true, "deleted": true }

Creating it again generates a new signing secret.