Use when working with the Heropayments crypto gateway (api.heropayments.io) — the Heropayment driver, HeropaymentClient/HeropaymentProvider/HeropaymentAdapter/HeropaymentQuoteService, Heropayment callbacks and webhooks, or Heropayment crypto deposits, invoices, rate and minimum-amount quotes, withdrawals and balances. Covers both the V2 and Custody API flows.
php artisan boost:add-skill asciisd/cashier-core
Save this content to: .claude/skills/heropayments/SKILL.md
# Heropayments
Heropayments publishes no OpenAPI spec, no changelog and no API versioning —
only a Postman documenter page. This skill vendors the collection so the
contract is available offline and upstream changes show up as diffs.
## References
Read the one you need; they are large.
- `references/quirks.md` — **start here.** Where the live API departs from its
own docs, and where the docs are silent. Fourteen entries, each citing the
code in this package that handles it. Seven are marked **Unverified**: they may
be live defects.
- `references/overview.md` — auth, HMAC-SHA512 request signing with worked
samples in five languages, both integration flows, the two status
vocabularies, multiple-deposit and mistaken-deposit processing, static
deposit addresses.
- `references/callbacks.md` — callback mechanics and the three annotated
payloads. The file to open for webhook work.
- `references/v2.md` — the 12 V2 requests. This is the flow the driver uses.
- `references/custody.md` — the 8 Custody requests. Nothing here calls them.
- `references/errors.md` — both error-code tables, V2 and Custody.
- `references/SOURCES.md` — source URLs, fetch date, and the commands to
regenerate and verify the mirrors.
## Before you change anything
Five things that will otherwise cost time:
1. **A saved deposit address keeps working forever.** Addresses are static per
`customerId` — we pass the MT5 login — and a repeat send raises a new payment
with the **same `externalOrderId`** and a new `sequence`. We resolve
transactions by `externalOrderId` alone and never read `sequence`, so the
second deposit lands on the first one's transaction. `quirks.md` entry 1.
2. **The field is `paidAmount`, not `actuallyPaid`.** The adapter reads a name
that appears nowhere in the contract. `quirks.md` entry 2.
3. **Sign the body exactly as Node's `JSON.stringify` would emit it.** PHP's
default `json_encode` escapes slashes and unicode; both yield
`401 Invalid signature`. `quirks.md` entry 4.
4. **The id in the create-invoice response is not the id in the callback.** One
is an invoice, the other a payment. Correlate on `externalOrderId`.
`quirks.md` entry 6.
5. **V2 and Custody have disjoint status vocabularies.** `waiting`/`confirming`/
`exchanging`/`sending` against `new`/`pending`/`processing`. Our status map
knows only the V2 half. `quirks.md` entry 10.
## The code
- `src/Drivers/Heropayment/HeropaymentClient.php` — HTTP surface, signing,
signature verification
- `src/Drivers/Heropayment/HeropaymentProvider.php` — charge, retrieve,
webhook correlation
- `src/Drivers/Heropayment/HeropaymentAdapter.php` — response/callback →
cashier-core objects, status mapping
- `src/Drivers/Heropayment/HeropaymentQuoteService.php` — pre-redirect rate,
network fee and minimum lookups, with caching
- `src/Drivers/Heropayment/HeropaymentQuote.php` — the quote value object
- `src/Http/Controllers/Webhooks/HeropaymentWebhookController.php` — callback
entry point, signature check, replay guard
- `src/Drivers/Heropayment/HeropaymentPayoutService.php` — V2 withdrawals:
balance preflight, send, lookup; fail-closed behind `withdrawals_enabled`
- `src/Jobs/ProcessPayoutWebhook.php` — withdrawal callbacks (routed by
`transactionType`), applied through `WithdrawalWorkflow::applyPayoutUpdate()`
Payouts are supported through `SendsPayouts` (V2 only). Refunds, capture,
authorize and void all throw: Heropayments has no merchant-initiated refund.
## Refreshing
Follow `## Regenerating` in `references/SOURCES.md`, then read `git diff` — that
diff is the changelog Heropayments does not publish. `quirks.md` is hand-written
and is not regenerated; check whether any entry the diff touches still holds.
Heropayments publishes no OpenAPI spec, no changelog and no API versioning — only a Postman documenter page. This skill vendors the collection so the contract is available offline and upstream changes show up as diffs.
Read the one you need; they are large.
references/quirks.md — start here. Where the live API departs from its
own docs, and where the docs are silent. Fourteen entries, each citing the
code in this package that handles it. Seven are marked Unverified: they may
be live defects.references/overview.md — auth, HMAC-SHA512 request signing with worked
samples in five languages, both integration flows, the two status
vocabularies, multiple-deposit and mistaken-deposit processing, static
deposit addresses.references/callbacks.md — callback mechanics and the three annotated
payloads. The file to open for webhook work.references/v2.md — the 12 V2 requests. This is the flow the driver uses.references/custody.md — the 8 Custody requests. Nothing here calls them.references/errors.md — both error-code tables, V2 and Custody.references/SOURCES.md — source URLs, fetch date, and the commands to
regenerate and verify the mirrors.Five things that will otherwise cost time:
customerId — we pass the MT5 login — and a repeat send raises a new payment
with the same externalOrderId and a new sequence. We resolve
transactions by externalOrderId alone and never read sequence, so the
second deposit lands on the first one's transaction. quirks.md entry 1.paidAmount, not actuallyPaid. The adapter reads a name
that appears nowhere in the contract. quirks.md entry 2.JSON.stringify would emit it. PHP's
default json_encode escapes slashes and unicode; both yield
401 Invalid signature. quirks.md entry 4.externalOrderId.
quirks.md entry 6.waiting/confirming/
exchanging/sending against new/pending/processing. Our status map
knows only the V2 half. quirks.md entry 10.src/Drivers/Heropayment/HeropaymentClient.php — HTTP surface, signing,
signature verificationsrc/Drivers/Heropayment/HeropaymentProvider.php — charge, retrieve,
webhook correlationsrc/Drivers/Heropayment/HeropaymentAdapter.php — response/callback →
cashier-core objects, status mappingsrc/Drivers/Heropayment/HeropaymentQuoteService.php — pre-redirect rate,
network fee and minimum lookups, with cachingsrc/Drivers/Heropayment/HeropaymentQuote.php — the quote value objectsrc/Http/Controllers/Webhooks/HeropaymentWebhookController.php — callback
entry point, signature check, replay guardsrc/Drivers/Heropayment/HeropaymentPayoutService.php — V2 withdrawals:
balance preflight, send, lookup; fail-closed behind withdrawals_enabledsrc/Jobs/ProcessPayoutWebhook.php — withdrawal callbacks (routed by
transactionType), applied through WithdrawalWorkflow::applyPayoutUpdate()Payouts are supported through SendsPayouts (V2 only). Refunds, capture,
authorize and void all throw: Heropayments has no merchant-initiated refund.
Follow ## Regenerating in references/SOURCES.md, then read git diff — that
diff is the changelog Heropayments does not publish. quirks.md is hand-written
and is not regenerated; check whether any entry the diff touches still holds.
How can I help you explore Laravel packages today?