contract-withdrawals

Stable. Describes behaviour that is built and covered by tests in this repository.

API reference

GET /v1/contract-withdrawals #

Withdrawal requests, newest first (at most 200)

Parameters

NameInTypeDescription
customer_external_idquerystring
statusqueryreceived | accepted | rejected | refunded

Responses

StatusMeaningBody
200OKListContractWithdrawalsResponse
400Error envelopeError
Example response
{
  "withdrawals": [
    {
      "id": "0192f0b4-6f6e-7c3a-9a3e-6a1f2b3c4d5e",
      "customer_id": "0192f0b4-6f6e-7c3a-9a3e-6a1f2b3c4d5e",
      "customer_external_id": "string",
      "subscription_id": "string",
      "invoice_id": "string",
      "statement": "string",
      "source": "api",
      "status": "received",
      "receive_time": "2026-11-03T10:15:00Z",
      "decide_time": "2026-11-03T10:15:00Z",
      "decided_by": "string",
      "decision_note": "string",
      "credit_note_id": "string",
      "refund_state": "none",
      "refund_note": "string",
      "refund_time": "2026-11-03T10:15:00Z"
    }
  ]
}
curl
curl -X GET https://YOUR-API-ADDRESS/v1/contract-withdrawals \
  -H "Authorization: Bearer $PAYRUDDER_API_KEY"

PUT /v1/contract-withdrawals/{id}/status #

Decide a withdrawal request, or mark an accepted one refunded

received becomes accepted or rejected, once; accepted becomes refunded (plans.contract.withdrawal_decided otherwise). Sends the webhook event contract.withdrawal_decided. Accepting a withdrawal that names an invoice also asks billing for the refund when the settings say withdrawal_refund: full (the default): a credit note that returns the amount to the card, for refund_amount_minor or whatever is left of the invoice. The decision is recorded first; what happened to the refund is on the returned withdrawal (refund_state, credit_note_id, refund_note) and never makes this call fail. An invoice paid by bank transfer or cash cannot go back through Payrudder: refund_state is outside and the seller refunds it by hand, then marks the withdrawal refunded. Needs customers:write. A key that does not also hold invoices:write cannot accept a withdrawal while the settings say withdrawal_refund: full (403 gateway.auth.permission_denied, nothing is decided): the refund is a credit note, and creating one needs invoices:write everywhere. Rejecting, or accepting while the setting is none, needs customers:write only.

Parameters

NameInTypeDescription
id requiredpathstring · uuid

Request body

FieldTypeDescription
status requiredaccepted | rejected | refunded
notestring
refund_amount_minorstring · int64Accepting only: the amount to refund when the settings ask for a refund, in minor units; 0 or absent is whatever is left of the invoice.
Example
{
  "status": "accepted"
}

Responses

StatusMeaningBody
200OKContractWithdrawal
404Error envelopeError
409Error envelopeError
Example response
{
  "id": "0192f0b4-6f6e-7c3a-9a3e-6a1f2b3c4d5e",
  "customer_id": "0192f0b4-6f6e-7c3a-9a3e-6a1f2b3c4d5e",
  "customer_external_id": "string",
  "subscription_id": "string",
  "invoice_id": "string",
  "statement": "string",
  "source": "api",
  "status": "received",
  "receive_time": "2026-11-03T10:15:00Z",
  "decide_time": "2026-11-03T10:15:00Z",
  "decided_by": "string",
  "decision_note": "string",
  "credit_note_id": "string",
  "refund_state": "none",
  "refund_note": "string",
  "refund_time": "2026-11-03T10:15:00Z"
}
curl
curl -X PUT https://YOUR-API-ADDRESS/v1/contract-withdrawals/<id>/status \
  -H "Authorization: Bearer $PAYRUDDER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"status":"accepted"}'

POST /v1/contract-withdrawals/{id}/refund #

Ask for the refund of an accepted withdrawal

For a withdrawal whose settings say withdrawal_refund: none, or whose first request failed. Only an accepted withdrawal that names an invoice, once: a request under way or made already answers plans.contract.refund_not_possible. The refund is a credit note with refund_to_card for amount_minor (0 is whatever is left of the invoice), made by billing under its own rules (a paid invoice, never more than what is left of it, only a payment a provider can return). The answer is the withdrawal with its refund_state. Needs invoices:write, not only customers:write: it returns money to a card.

Parameters

NameInTypeDescription
id requiredpathstring · uuid

Request body

FieldTypeDescription
amount_minorstring · int64In minor units; 0 or absent is whatever is left of the invoice.
Example
{}

Responses

StatusMeaningBody
200OKContractWithdrawal
404Error envelopeError
409Error envelopeError
Example response
{
  "id": "0192f0b4-6f6e-7c3a-9a3e-6a1f2b3c4d5e",
  "customer_id": "0192f0b4-6f6e-7c3a-9a3e-6a1f2b3c4d5e",
  "customer_external_id": "string",
  "subscription_id": "string",
  "invoice_id": "string",
  "statement": "string",
  "source": "api",
  "status": "received",
  "receive_time": "2026-11-03T10:15:00Z",
  "decide_time": "2026-11-03T10:15:00Z",
  "decided_by": "string",
  "decision_note": "string",
  "credit_note_id": "string",
  "refund_state": "none",
  "refund_note": "string",
  "refund_time": "2026-11-03T10:15:00Z"
}
curl
curl -X POST https://YOUR-API-ADDRESS/v1/contract-withdrawals/<id>/refund \
  -H "Authorization: Bearer $PAYRUDDER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'

Models

ContractWithdrawal

FieldTypeDescription
id requiredstring · uuid
customer_id requiredstring · uuid
customer_external_id requiredstring
subscription_id requiredstring
invoice_id requiredstring
statement requiredstring
source requiredapi | console | hosted
status requiredreceived | accepted | rejected | refunded
receive_time requiredstring · date-time
decide_time requiredstring · date-time
decided_by requiredstring
decision_note requiredstring
credit_note_id requiredstringThe credit note billing made to refund the invoice, once one was requested (GET /v1/credit-notes/{id} says how the refund went).
refund_state requirednone | requesting | requested | refunded | refund_failed | outside | failednone: nothing asked of billing; requesting: being asked; requested: a credit note exists and the provider has not answered; refunded: the provider returned the money; refund_failed: the credit note exists and the provider did not return the money, retry the credit note's refund (a second credit note would credit the invoice twice), refund_note says why; outside: the money cannot go back through Payrudder (a bank transfer, cash), refund it by hand; failed: billing refused or did not answer, ask again with POST /v1/contract-withdrawals/{id}/refund. refunded and refund_failed are copied from the credit note's own result (credit_note.refunded, credit_note.refund_failed). The withdrawal's status stays the seller's to set.
refund_note requiredstring
refund_time requiredstring · date-time

Error

FieldTypeDescription
error requiredobject

ListContractWithdrawalsResponse

FieldTypeDescription
withdrawals requiredarray of ContractWithdrawal

RequestContractWithdrawalRefundRequest

FieldTypeDescription
amount_minorstring · int64In minor units; 0 or absent is whatever is left of the invoice.

SetContractWithdrawalStatusRequest

FieldTypeDescription
status requiredaccepted | rejected | refunded
notestring
refund_amount_minorstring · int64Accepting only: the amount to refund when the settings ask for a refund, in minor units; 0 or absent is whatever is left of the invoice.