Recurring payments

Find the transaction that charged one recurring period

For when a charge landed and its response did not: your retry answers ALREADY_CHARGED, which proves the period was collected and names no transaction. P2Flux stores nothing, so the hash lives only in the contract's log - and without it you cannot attribute the payment to an order, audit it, or refund it, because refunds start from the original settlement.

Give it the subscription and the exact period. There is no 'current period' form on purpose: you are reconciling one specific collection, today or in a year, and the answer must not move under you.

The event is the proof. A settlement is returned only when the contract's own SubscriptionCharged log names this subscription AND this period, and only when its payer, recipient and amount match the signed authorization.

found: false is ordinary. There is no catch-up billing, so a period that was never collected is a normal history: a later period having been charged says nothing about an earlier one. Like the one-time recovery, a miss is a statement about one block height and never a permanent verdict.

A hint is an optimisation and nothing else - it narrows where the search starts, can never turn a miss into a hit, and is safe to omit.

post/v1/charges/recover

Request

  • Base URL: https://api.p2flux.com
  • URL: https://api.p2flux.com/v1/charges/recover
  • Auth: none required

Request body

subscriptionstring required

A signed P2Flux capability: payment intent (p2f1.), setup token (p2setup2.), subscription capability (p2s2.), cancel token (p2cancel1.) or refund token (p2refund1.). Opaque to the caller and unforgeable - the signature is what authorises the call. Treat it as a bearer secret: keep it server-side, never in a URL query or a log.

period_indexinteger required

The exact billing period to reconcile, as returned by /v1/charges or /v1/subscriptions/status.

Response

Either the located settlement, or a not-found that names the block it was true at.

foundboolean required
subscription_idstring

A 32-byte hex value, lowercase. Transaction hashes and references.

period_indexinteger
tx_hashstring

A 32-byte hex value, lowercase. Transaction hashes and references.

block_numberstring
payerstring

An EVM address.

recipientstring

An EVM address.

net_unitsstring

An integer count of micro-USDC (6 decimals), as a string. 2500000 is 2.50 USDC. Used wherever a decimal would invite a rounding error - notably refund amounts.

fee_unitsstring

An integer count of micro-USDC (6 decimals), as a string. 2500000 is 2.50 USDC. Used wherever a decimal would invite a rounding error - notably refund amounts.

network_fee_unitsstring

An integer count of micro-USDC (6 decimals), as a string. 2500000 is 2.50 USDC. Used wherever a decimal would invite a rounding error - notably refund amounts.

amount_unitsstring

An integer count of micro-USDC (6 decimals), as a string. 2500000 is 2.50 USDC. Used wherever a decimal would invite a rounding error - notably refund amounts.

code'INVALID_INTENT' | 'INTENT_EXPIRED' | 'INVALID_REFERENCE' | 'INVALID_SETUP_TOKEN' | 'SETUP_TOKEN_EXPIRED' | 'INVALID_CANCEL_TOKEN' | 'CANCEL_TOKEN_EXPIRED' | 'TERMS_MISMATCH' | 'AMOUNT_OUT_OF_BOUNDS' | 'PERIOD_OUT_OF_BOUNDS' | 'PERMISSION_NOT_FOUND' | 'TRANSACTION_NOT_FOUND' | 'PERMISSION_REVOKED' | 'ALREADY_CHARGED' | 'NOT_DUE' | 'SUBSCRIPTION_EXPIRED' | 'INVALID_SIGNATURE' | 'REFUND_CONFIRMING' | 'INVALID_REFUND_TOKEN' | 'REFUND_TOKEN_EXPIRED' | 'REFUND_AMOUNT_INVALID' | 'REFUND_WRONG_MERCHANT' | 'REFUND_TRANSACTION_MISMATCH' | 'REFUND_ORIGINAL_PAYMENT_INVALID' | 'SIGNATURE_VALIDATION_TOO_EXPENSIVE' | 'UNSUPPORTED_SIGNATURE_FORMAT' | 'PAYMENT_ALREADY_PROCESSED' | 'PAYMENT_NOT_FOUND' | 'PAYMENT_RECOVERY_INCONSISTENT' | 'RECOVERY_UNAVAILABLE' | 'WRONG_SPENDER' | 'WRONG_TOKEN' | 'INVALID_EXTRA_DATA' | 'GAS_FEE_TOO_HIGH' | 'INSUFFICIENT_ALLOWANCE' | 'INSUFFICIENT_BALANCE' | 'INVALID_SUBSCRIPTION' | 'RPC_ERROR' | 'RELAYER_ERROR' | 'INTERNAL_ERROR' | 'TRANSACTION_REVERTED' | 'INVALID_REQUEST' | 'RATE_LIMITED' | 'CONCURRENCY_LIMIT' | 'GAS_TOO_HIGH' | 'GAS_QUOTE_UNAVAILABLE' | 'PAYMENT_CONFIRMING' | 'RELAYER_TX_COST_TOO_HIGH' | 'RELAYER_BUDGET_EXCEEDED' | 'RELAYER_NOT_READY' | 'MERCHANT_SPONSORED_LIMIT_EXCEEDED' | 'RPC_BUSY' | 'PAYMENT_TOKEN_GAS_UNSUPPORTED' | 'PAYMENT_TOKEN_GAS_UNAVAILABLE' | 'PAYMENT_TOKEN_GAS_QUOTE_EXPIRED' | 'PAYMENT_TOKEN_GAS_LIMIT_EXCEEDED' | 'INVALID_GAS_QUOTE' | 'INSUFFICIENT_PAYMENT_TOKEN_FOR_GAS' | 'SPONSORED_TRANSACTION_FAILED' | 'SPONSORED_PERMIT_FAILED' | 'SPONSORSHIP_CONFIRMING' | 'INVALID_LINK' | 'LINK_EXPIRED' | 'LINK_UNAVAILABLE' | 'ALREADY_SUBSCRIBED' | 'PAYER_SANCTIONED' | 'RECIPIENT_SANCTIONED'

Every code this API can return. Stable identifiers - branch on these, never on the human-readable text or the HTTP status alone.

as_of_blockstring

Only on a miss. The head this answer was computed at.

Example response

{
  "subscription_id": "0x2d6bbc112885a6976289e599f71003f7d310e7152ebd662c6221dffd3e0da708",
  "tx_hash": "0x2d6bbc112885a6976289e599f71003f7d310e7152ebd662c6221dffd3e0da708",
  "payer": "0xb4e43f3fBa5Add75395adAD366627E7d74141Fa9",
  "recipient": "0xb4e43f3fBa5Add75395adAD366627E7d74141Fa9",
  "net_units": "2500000",
  "fee_units": "2500000",
  "network_fee_units": "2500000",
  "amount_units": "2500000"
}

Changes

No recorded changes to this operation across all 1 revision of this API.