customers
Stable. Describes behaviour that is built and covered by tests in this repository.
API reference
GET /v1/customers #
List customers (ordered by external_id)
Parameters
| Name | In | Type | Description |
|---|
page_size | query | integer | |
page_token | query | string | |
Responses
Example response
{
"customers": [
{
"id": "0192f0b4-6f6e-7c3a-9a3e-6a1f2b3c4d5e",
"external_id": "string",
"name": "string",
"email": "string",
"payment_method": "string",
"create_time": "2026-11-03T10:15:00Z",
"country": "string",
"billing_currency": "string",
"address": {
"line1": "string",
"line2": "string",
"city": "string",
"region": "string",
"postal_code": "string",
"country": "string"
},
"tax_id": "string",
"tax_office": "string",
"e_invoice_registered": false,
"locale": "string",
"customer_type": "string",
"block_reason": "string",
"block_category": "string",
"service_suspended": false,
"phone": "string",
"tax_id_warning": "string"
}
],
"next_page_token": "string"
}
curl
curl -X GET https://YOUR-API-ADDRESS/v1/customers \
-H "Authorization: Bearer $PAYRUDDER_API_KEY"
POST /v1/customers #
Create a customer
Request body
| Field | Type | Description |
|---|
external_id required | string | |
name required | string | |
email required | string · email | |
payment_method | string | |
country | string | ISO 3166-1 alpha-2 |
billing_currency | string | ISO 4217; default is the tenant's currency |
address | AddressInput | A postal address as printed on an invoice. Every part is optional. |
locale | en | tr | de | fr | es | ar | The language of the customer's mails, receipts and payment pages |
customer_type | individual | business | A person or a taxpayer |
phone | string | The customer's mobile number in international form, e.g. +90 532 123 45 67 or 0090 532 123 45 67; stored as E.164 (+905321234567). A number without the + or 00 prefix is refused: it cannot be read without a country. |
referral_code | string | The code of the partner whose link or code brought this customer (phase 47). A code that cannot attribute does not fail the creation. |
referral_touch_time | string · date-time | When the visitor followed that link; default now |
Example
{
"external_id": "string",
"name": "string",
"email": "string"
}
Responses
Example response
{
"id": "0192f0b4-6f6e-7c3a-9a3e-6a1f2b3c4d5e",
"external_id": "string",
"name": "string",
"email": "string",
"payment_method": "string",
"create_time": "2026-11-03T10:15:00Z",
"country": "string",
"billing_currency": "string",
"address": {
"line1": "string",
"line2": "string",
"city": "string",
"region": "string",
"postal_code": "string",
"country": "string"
},
"tax_id": "string",
"tax_office": "string",
"e_invoice_registered": false,
"locale": "string",
"customer_type": "string",
"block_reason": "string",
"block_category": "string",
"service_suspended": false,
"phone": "string",
"tax_id_warning": "string"
}
curl
curl -X POST https://YOUR-API-ADDRESS/v1/customers \
-H "Authorization: Bearer $PAYRUDDER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"external_id":"string","name":"string","email":"string"}'
GET /v1/customers/{external_id} #
Get a customer by external id
Parameters
| Name | In | Type | Description |
|---|
external_id required | path | string | |
Responses
Example response
{
"id": "0192f0b4-6f6e-7c3a-9a3e-6a1f2b3c4d5e",
"external_id": "string",
"name": "string",
"email": "string",
"payment_method": "string",
"create_time": "2026-11-03T10:15:00Z",
"country": "string",
"billing_currency": "string",
"address": {
"line1": "string",
"line2": "string",
"city": "string",
"region": "string",
"postal_code": "string",
"country": "string"
},
"tax_id": "string",
"tax_office": "string",
"e_invoice_registered": false,
"locale": "string",
"customer_type": "string",
"block_reason": "string",
"block_category": "string",
"service_suspended": false,
"phone": "string",
"tax_id_warning": "string"
}
curl
curl -X GET https://YOUR-API-ADDRESS/v1/customers/<external_id> \
-H "Authorization: Bearer $PAYRUDDER_API_KEY"
PUT /v1/customers/{external_id}/payment-method #
Set the customer's PSP token (sandbox accepts only pm_sandbox_* tokens)
Parameters
| Name | In | Type | Description |
|---|
external_id required | path | string | |
Request body
| Field | Type | Description |
|---|
payment_method required | string | |
Example
{
"payment_method": "string"
}
Responses
Example response
{
"id": "0192f0b4-6f6e-7c3a-9a3e-6a1f2b3c4d5e",
"external_id": "string",
"name": "string",
"email": "string",
"payment_method": "string",
"create_time": "2026-11-03T10:15:00Z",
"country": "string",
"billing_currency": "string",
"address": {
"line1": "string",
"line2": "string",
"city": "string",
"region": "string",
"postal_code": "string",
"country": "string"
},
"tax_id": "string",
"tax_office": "string",
"e_invoice_registered": false,
"locale": "string",
"customer_type": "string",
"block_reason": "string",
"block_category": "string",
"service_suspended": false,
"phone": "string",
"tax_id_warning": "string"
}
curl
curl -X PUT https://YOUR-API-ADDRESS/v1/customers/<external_id>/payment-method \
-H "Authorization: Bearer $PAYRUDDER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"payment_method":"string"}'
POST /v1/customers/{external_id}/payment-method-setup #
Make the link to the provider's page where the customer saves a card for later charges
For a provider that has the customer save a payment method on its own page (Stripe: Checkout in setup mode). The answer is the address of that page; you send it to the customer. Nothing is charged. When the customer has saved the card, the provider tells Payrudder and the method becomes the customer's payment method (the string a charge takes, cus_...:pm_... at Stripe), which later invoices are charged with: there is nothing to call afterwards. The customer is made at the provider once and remembered, so asking again for the same customer reuses it. Payrudder collects and keeps no consent in this flow. The provider's guide asks you to collect the customer's explicit consent to be charged without them present (the amount and timing, how the amount is decided, how to cancel) and to keep a record of it: send the link together with your terms and keep the agreement yourself. The page is made in the environment of the key (a sk_test_ Stripe account for a sandbox key). return_url must be https. 404 payments.customer.not_ready for a customer that does not exist, 501 for a provider that cannot do this, and the provider's own refusal when the environment has no account for it.
Parameters
| Name | In | Type | Description |
|---|
external_id required | path | string | |
Request body
| Field | Type | Description |
|---|
provider | stripe | The provider whose page it is; only Stripe has one |
return_url required | string · uri | Where the provider sends the customer after the page. `https` only |
Example
{
"return_url": "string"
}
Responses
Example response
{
"url": "string",
"ref": "string"
}
curl
curl -X POST https://YOUR-API-ADDRESS/v1/customers/<external_id>/payment-method-setup \
-H "Authorization: Bearer $PAYRUDDER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"return_url":"string"}'
GET /v1/customers/{external_id}/cards #
The cards the payment provider holds for the customer
The cards of the provider's card storage (iyzico) under the user key the customer's payment method names, never a number: the bank, the first digits (BIN), the last four, the expiry. The card the customer's invoices are charged with is in_use. A customer with no stored card has an empty list and no provider. Payrudder cannot put a card in storage (it holds no card numbers): whoever holds the number puts it there and sets the payment method with PUT /v1/customers/{external_id}/payment-method. The sandbox has none.
Parameters
| Name | In | Type | Description |
|---|
external_id required | path | string | |
Responses
Example response
{
"provider": "string",
"cards": [
{
"token": "string",
"alias": "string",
"bin": "string",
"last4": "string",
"type": "string",
"association": "string",
"family": "string",
"bank": "string",
"expire_month": "string",
"expire_year": "string",
"in_use": false
}
]
}
curl
curl -X GET https://YOUR-API-ADDRESS/v1/customers/<external_id>/cards \
-H "Authorization: Bearer $PAYRUDDER_API_KEY"
DELETE /v1/customers/{external_id}/cards/{token} #
Delete one of the customer's stored cards at the provider
The card must be one of the customer's own (a token of another customer is 404 payments.card.not_found, and nothing is sent to the provider). The customer's payment method is not changed: when the card was in_use the answer says so, and the next charge fails until a new payment method is set.
Parameters
| Name | In | Type | Description |
|---|
external_id required | path | string | |
token required | path | string | |
Responses
Example response
{
"provider": "string",
"deleted": false,
"was_in_use": false
}
curl
curl -X DELETE https://YOUR-API-ADDRESS/v1/customers/<external_id>/cards/<token> \
-H "Authorization: Bearer $PAYRUDDER_API_KEY"
PUT /v1/customers/{external_id}/address #
Replace the customer's billing address
The address is printed on the customer's invoices (PDF and hosted page). Its country becomes the customer's country, which provider routing and tax read. An empty object clears the address and keeps the country.
Parameters
| Name | In | Type | Description |
|---|
external_id required | path | string | |
Request body
| Field | Type | Description |
|---|
line1 | string | |
line2 | string | |
city | string | |
region | string | State, province or county |
postal_code | string | |
country | string | ISO 3166-1 alpha-2 |
Example
{}
Responses
Example response
{
"id": "0192f0b4-6f6e-7c3a-9a3e-6a1f2b3c4d5e",
"external_id": "string",
"name": "string",
"email": "string",
"payment_method": "string",
"create_time": "2026-11-03T10:15:00Z",
"country": "string",
"billing_currency": "string",
"address": {
"line1": "string",
"line2": "string",
"city": "string",
"region": "string",
"postal_code": "string",
"country": "string"
},
"tax_id": "string",
"tax_office": "string",
"e_invoice_registered": false,
"locale": "string",
"customer_type": "string",
"block_reason": "string",
"block_category": "string",
"service_suspended": false,
"phone": "string",
"tax_id_warning": "string"
}
curl
curl -X PUT https://YOUR-API-ADDRESS/v1/customers/<external_id>/address \
-H "Authorization: Bearer $PAYRUDDER_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'
POST /v1/customers/{external_id}/block #
Block a customer from new purchases
A blocked customer cannot get a new subscription or plan change (error key plans.customer.blocked), buy through a payment link or the portal, or have a
payment link made for them (billing.customer.blocked); what exists runs on until you end it, and an invoice that was issued before stays payable, except after
a fraud or chargeback block. A price change you schedule skips them (customer_blocked). Blocking again keeps the block that is in force. The note is
yours, up to 500 characters; category says why; blocked_until ends the block by itself (it must be in the future, and every check reads it, so the block
stops holding at that time). Every block and lift is kept in the customer's history and sent as the customer.blocked / customer.unblocked webhook events
(the end of a block by itself sends none). Usage ingestion is not affected, and entitlements are unless you set suspend_service: then every entitlement
check of this customer answers allowed: false and suspended: true (the limits and the counted usage are untouched, and the events you send are still
accepted and counted) until you lift the block or it ends by itself. The service is suspended only when the block is new: a block already in force is kept
as it is, so lift it first to change it.
Parameters
| Name | In | Type | Description |
|---|
external_id required | path | string | |
Request body
| Field | Type | Description |
|---|
reason | string | Your note on why; never shown to the customer. |
category | CustomerBlockCategory | Why the customer is blocked. fraud and chargeback also refuse paying an invoice that is open. |
blocked_until | string · date-time | When the block ends by itself; must be in the future. Absent: until you lift it. |
suspend_service | boolean | Also suspend the customer's service: every entitlement check answers allowed false (suspended true) until the block is lifted or ends. Usage is still accepted and counted. Default false. |
Example
{}
Responses
Example response
{
"id": "0192f0b4-6f6e-7c3a-9a3e-6a1f2b3c4d5e",
"external_id": "string",
"name": "string",
"email": "string",
"payment_method": "string",
"create_time": "2026-11-03T10:15:00Z",
"country": "string",
"billing_currency": "string",
"address": {
"line1": "string",
"line2": "string",
"city": "string",
"region": "string",
"postal_code": "string",
"country": "string"
},
"tax_id": "string",
"tax_office": "string",
"e_invoice_registered": false,
"locale": "string",
"customer_type": "string",
"block_reason": "string",
"block_category": "string",
"service_suspended": false,
"phone": "string",
"tax_id_warning": "string"
}
curl
curl -X POST https://YOUR-API-ADDRESS/v1/customers/<external_id>/block \
-H "Authorization: Bearer $PAYRUDDER_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'
POST /v1/customers/{external_id}/unblock #
Lift a customer's block
Also clears a block that has ended by itself. A customer who was not blocked is returned as it is.
Parameters
| Name | In | Type | Description |
|---|
external_id required | path | string | |
Responses
Example response
{
"id": "0192f0b4-6f6e-7c3a-9a3e-6a1f2b3c4d5e",
"external_id": "string",
"name": "string",
"email": "string",
"payment_method": "string",
"create_time": "2026-11-03T10:15:00Z",
"country": "string",
"billing_currency": "string",
"address": {
"line1": "string",
"line2": "string",
"city": "string",
"region": "string",
"postal_code": "string",
"country": "string"
},
"tax_id": "string",
"tax_office": "string",
"e_invoice_registered": false,
"locale": "string",
"customer_type": "string",
"block_reason": "string",
"block_category": "string",
"service_suspended": false,
"phone": "string",
"tax_id_warning": "string"
}
curl
curl -X POST https://YOUR-API-ADDRESS/v1/customers/<external_id>/unblock \
-H "Authorization: Bearer $PAYRUDDER_API_KEY"
GET /v1/customers/{external_id}/block-events #
A customer's blocks and lifts, newest first
Who blocked or lifted, when, and why (the latest 100). Never changed or deleted.
Parameters
| Name | In | Type | Description |
|---|
external_id required | path | string | |
Responses
Example response
{
"events": [
{
"id": "0192f0b4-6f6e-7c3a-9a3e-6a1f2b3c4d5e",
"action": "blocked",
"category": "string",
"reason": "string",
"suspend_service": false,
"actor": "string",
"create_time": "2026-11-03T10:15:00Z"
}
]
}
curl
curl -X GET https://YOUR-API-ADDRESS/v1/customers/<external_id>/block-events \
-H "Authorization: Bearer $PAYRUDDER_API_KEY"
GET /v1/customers/{external_id}/appeals #
A blocked customer's appeals, newest first
The statements your customer sent from their portal link against a block (the latest 20), each with its status (open, accepted, rejected, or closed when the block was lifted some other way while it was open) and your answer. The statement is the customer's own words: treat it as untrusted text, never as markup. The category and the note of your block are never part of an appeal. Needs customers:read.
Parameters
| Name | In | Type | Description |
|---|
external_id required | path | string | |
Responses
Example response
{
"appeals": [
{
"id": "0192f0b4-6f6e-7c3a-9a3e-6a1f2b3c4d5e",
"status": "open",
"statement": "string",
"answer": "string",
"decided_by": "string",
"create_time": "2026-11-03T10:15:00Z"
}
]
}
curl
curl -X GET https://YOUR-API-ADDRESS/v1/customers/<external_id>/appeals \
-H "Authorization: Bearer $PAYRUDDER_API_KEY"
POST /v1/customers/{external_id}/appeals/{id}/decision #
Accept or reject a blocked customer's appeal
accepted lifts the block exactly as POST /v1/customers/{external_id}/unblock does (the history row, the customer.unblocked webhook event and, when you have the mail on, the customer's notice) and records your decision in the same step. rejected needs an answer (up to 1000 characters); the block stays and the customer sees your answer on their portal and may send another appeal. An appeal that was decided or closed is refused with plans.customer_appeal.not_open. Both decisions are audit entries (customer_block.appeal_decided); no webhook event is sent for a submitted appeal or a rejection. Needs customers:write.
Parameters
| Name | In | Type | Description |
|---|
external_id required | path | string | |
id required | path | string · uuid | |
Request body
| Field | Type | Description |
|---|
decision required | accepted | rejected | |
answer | string | Required to reject |
Example
{
"decision": "accepted"
}
Responses
Example response
{
"id": "0192f0b4-6f6e-7c3a-9a3e-6a1f2b3c4d5e",
"status": "open",
"statement": "string",
"answer": "string",
"decided_by": "string",
"create_time": "2026-11-03T10:15:00Z"
}
curl
curl -X POST https://YOUR-API-ADDRESS/v1/customers/<external_id>/appeals/<id>/decision \
-H "Authorization: Bearer $PAYRUDDER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"decision":"accepted"}'
PUT /v1/customers/{external_id}/tax #
Replace the customer's tax data used on e-invoices
Tax id (VKN/TCKN in Turkey, VAT id in the EU), tax office (Turkey) and whether the customer is registered for e-fatura. Empty values clear them. An id that does not look right for the customer's country and kind is stored all the same: the customer comes back with tax_id_warning set, and tax_id_validated_at is set only for an id that passes the local checksum or shape check. Error key plans.customer.tax_invalid (only for an id that is not 5 to 20 letters and digits, or a tax office that is not one line).
Parameters
| Name | In | Type | Description |
|---|
external_id required | path | string | |
Request body
| Field | Type | Description |
|---|
tax_id | string | VKN/TCKN (Turkey) or VAT id (EU) |
tax_office | string | Vergi dairesi (Turkey) |
e_invoice_registered | boolean | The customer is registered for e-fatura |
Example
{}
Responses
Example response
{
"id": "0192f0b4-6f6e-7c3a-9a3e-6a1f2b3c4d5e",
"external_id": "string",
"name": "string",
"email": "string",
"payment_method": "string",
"create_time": "2026-11-03T10:15:00Z",
"country": "string",
"billing_currency": "string",
"address": {
"line1": "string",
"line2": "string",
"city": "string",
"region": "string",
"postal_code": "string",
"country": "string"
},
"tax_id": "string",
"tax_office": "string",
"e_invoice_registered": false,
"locale": "string",
"customer_type": "string",
"block_reason": "string",
"block_category": "string",
"service_suspended": false,
"phone": "string",
"tax_id_warning": "string"
}
curl
curl -X PUT https://YOUR-API-ADDRESS/v1/customers/<external_id>/tax \
-H "Authorization: Bearer $PAYRUDDER_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'
GET /v1/customers/{external_id}/contract-requirements #
What the customer must accept before a subscription starts, with the text to show
For an embedded checkout. customer_type overrides the customer's own (a business customer gets the business texts; an unknown type is treated as a consumer). The order fills the variables of the texts.
Parameters
| Name | In | Type | Description |
|---|
external_id required | path | string | |
locale | query | string | |
customer_type | query | individual | business | |
order_description | query | string | |
order_total | query | string | |
order_currency | query | string | |
Responses
Example response
{
"enforced": false,
"requirements": [
{
"kind": "distance_sales",
"version_id": "0192f0b4-6f6e-7c3a-9a3e-6a1f2b3c4d5e",
"version_number": 1,
"audience": "consumer",
"locale": "string",
"body_html": "string",
"body_sha256": "string",
"accepted": false,
"accept_time": "2026-11-03T10:15:00Z",
"has_template_notice": false
}
],
"satisfied": false,
"immediate_start": false,
"missing_kinds": [
"distance_sales"
],
"audience": "consumer"
}
curl
curl -X GET https://YOUR-API-ADDRESS/v1/customers/<external_id>/contract-requirements \
-H "Authorization: Bearer $PAYRUDDER_API_KEY"
GET /v1/customers/{external_id}/contract-acceptances #
What the customer accepted, newest first
The customer's acceptance log, a page at a time (page_size, default 100, at most 200; the next page is next_page_token, empty on the last). The filters narrow it and combine: kind, source (api, hosted), version_id (one version of a text) and the time the customer accepted, from (inclusive) to to (exclusive), as RFC 3339 times.
Parameters
| Name | In | Type | Description |
|---|
external_id required | path | string | |
kind | query | distance_sales | pre_info | tos | privacy | |
source | query | api | hosted | |
version_id | query | string · uuid | |
from | query | string · date-time | Accepted at or after this time |
to | query | string · date-time | Accepted before this time |
page_size | query | integer | |
page_token | query | string | |
Responses
Example response
{
"acceptances": [
{
"id": "0192f0b4-6f6e-7c3a-9a3e-6a1f2b3c4d5e",
"group_id": "0192f0b4-6f6e-7c3a-9a3e-6a1f2b3c4d5e",
"customer_id": "string",
"version_id": "0192f0b4-6f6e-7c3a-9a3e-6a1f2b3c4d5e",
"kind": "distance_sales",
"audience": "consumer",
"version_number": 1,
"version_sha256": "string",
"locale_requested": "string",
"locale_served": "string",
"body_sha256": "string",
"context_kind": "hosted_invoice",
"context_ref": "string",
"source": "hosted",
"observed": {},
"checkbox_text": "string",
"immediate_start_consent": false,
"immediate_start_text": "string",
"withdrawal_waiver_acknowledged": false,
"withdrawal_waiver_text": "string",
"variables": {},
"snapshot_sha256": "string",
"ip": "string",
"user_agent": "string",
"accept_time": "2026-11-03T10:15:00Z",
"customer_external_id": "string"
}
],
"next_page_token": "string"
}
curl
curl -X GET https://YOUR-API-ADDRESS/v1/customers/<external_id>/contract-acceptances \
-H "Authorization: Bearer $PAYRUDDER_API_KEY"
POST /v1/customers/{external_id}/contract-acceptances #
Record that the customer accepted the current versions (an embedded checkout)
The evidence of one checkout moment: one row for each version, all in one group. Every version must be the current one of its series (plans.contract.version_stale otherwise) and checkbox_text is the words next to the box as the customer saw them. What you report about the customer's IP address, browser and time is your claim, and the record says so (observed is false for those fields); Payrudder's own payment pages record what they observed. Acceptances are append-only. The customer is mailed the page they accepted, in their language. Needs customers:write.
Parameters
| Name | In | Type | Description |
|---|
external_id required | path | string | |
Request body
| Field | Type | Description |
|---|
locale | string | The language the page was shown in. |
context_ref | string | Your reference for the checkout (an order id). |
items required | array of ContractAcceptanceItem | |
immediate_start_consent | boolean | |
immediate_start_text | string | |
withdrawal_waiver_acknowledged | boolean | |
withdrawal_waiver_text | string | |
ip | string | Your claim about the customer's address. |
user_agent | string | Your claim about the customer's browser. |
accept_time | string · date-time | When the customer accepted; empty is now. |
customer_type | individual | business | |
order | ContractOrder | |
Example
{
"items": [
{
"version_id": "0192f0b4-6f6e-7c3a-9a3e-6a1f2b3c4d5e",
"checkbox_text": "string"
}
]
}
Responses
Example response
{
"group_id": "0192f0b4-6f6e-7c3a-9a3e-6a1f2b3c4d5e",
"acceptances": [
{
"id": "0192f0b4-6f6e-7c3a-9a3e-6a1f2b3c4d5e",
"group_id": "0192f0b4-6f6e-7c3a-9a3e-6a1f2b3c4d5e",
"customer_id": "string",
"version_id": "0192f0b4-6f6e-7c3a-9a3e-6a1f2b3c4d5e",
"kind": "distance_sales",
"audience": "consumer",
"version_number": 1,
"version_sha256": "string",
"locale_requested": "string",
"locale_served": "string",
"body_sha256": "string",
"context_kind": "hosted_invoice",
"context_ref": "string",
"source": "hosted",
"observed": {},
"checkbox_text": "string",
"immediate_start_consent": false,
"immediate_start_text": "string",
"withdrawal_waiver_acknowledged": false,
"withdrawal_waiver_text": "string",
"variables": {},
"snapshot_sha256": "string",
"ip": "string",
"user_agent": "string",
"accept_time": "2026-11-03T10:15:00Z",
"customer_external_id": "string"
}
]
}
curl
curl -X POST https://YOUR-API-ADDRESS/v1/customers/<external_id>/contract-acceptances \
-H "Authorization: Bearer $PAYRUDDER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"items":[{"version_id":"0192f0b4-6f6e-7c3a-9a3e-6a1f2b3c4d5e","checkbox_text":"string"}]}'
POST /v1/customers/{external_id}/contract-withdrawals #
Record that the customer withdrew from a contract
The seller decides and refunds; this keeps the statement, when it arrived and who decided what. Sends the webhook event contract.withdrawal_requested. The refund follows the seller's decision, never the statement: see setContractWithdrawalStatus and requestContractWithdrawalRefund. Needs customers:write.
Parameters
| Name | In | Type | Description |
|---|
external_id required | path | string | |
Request body
| Field | Type | Description |
|---|
subscription_id | string · uuid | |
invoice_id | string · uuid | |
statement | string | |
receive_time | string · date-time | When the statement reached you; empty is now. |
source | api | console | |
Example
{}
Responses
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/customers/<external_id>/contract-withdrawals \
-H "Authorization: Bearer $PAYRUDDER_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'
GET /v1/customers/{external_id}/usage #
On-time usage of a customer in a period, per meter
Quantities are exact decimals with the meter's scale. Usage that arrived after the period's cutoff is not
included here: it is billed on a later invoice as late usage. period defaults to the current period in the
tenant's time zone.
Parameters
| Name | In | Type | Description |
|---|
external_id required | path | string | |
period | query | string | |
Responses
Example response
{
"customer_external_id": "string",
"period_id": "string",
"usage": [
{
"meter_code": "string",
"quantity": "1500.250",
"event_count": "string"
}
]
}
curl
curl -X GET https://YOUR-API-ADDRESS/v1/customers/<external_id>/usage \
-H "Authorization: Bearer $PAYRUDDER_API_KEY"
GET /v1/customers/{external_id}/upcoming-invoice #
What the customer's next invoice would be if it were drafted now
An estimate of the regular invoice of the period that is still open (or, while a closed period's grace period runs, of that period): the usage and late usage so far, rated by
the plan version in force, the fixed fee, tax at the tenant's rate for the customer's country and the credit balance the invoice would use. It is computed by the same code
that drafts the real invoice, from the same inputs, and nothing is stored. It moves with every event until the period closes, and a change of plan, a coupon or a tax rate
made later can move it too: estimate is always true, and the response has no id and no number. A fixed fee invoiced in advance is its own invoice and is not in it.
A customer with nothing to bill in the period gets has_invoice: false and no lines.
Parameters
| Name | In | Type | Description |
|---|
external_id required | path | string | |
Responses
Example response
{
"estimate": false,
"customer_external_id": "string",
"period_id": "2026-11",
"period_start": "2026-11-03T10:15:00Z",
"period_end": "2026-11-03T10:15:00Z",
"currency": "string",
"lines": [
{
"line_no": 1,
"kind": "BASE_FEE",
"meter_code": "string",
"origin_period_id": "string",
"quantity": "1.250",
"amount_minor": "string",
"description": "string",
"service_from": "2026-11-03T10:15:00Z",
"service_to": "2026-11-03T10:15:00Z"
}
],
"subtotal_minor": "string",
"tax_minor": "string",
"credit_minor": "string",
"total_minor": "string",
"credit_surplus_minor": "string",
"as_of": "2026-11-03T10:15:00Z",
"has_invoice": false
}
curl
curl -X GET https://YOUR-API-ADDRESS/v1/customers/<external_id>/upcoming-invoice \
-H "Authorization: Bearer $PAYRUDDER_API_KEY"
GET /v1/customers/{external_id}/entitlements #
Usage against the limits of every meter the customer has an entitlement on
See getEntitlement for the semantics of each item. Not paged: the response is the complete list.
Parameters
| Name | In | Type | Description |
|---|
external_id required | path | string | |
period | query | string | |
Responses
Example response
{
"items": [
{
"customer_external_id": "string",
"meter_code": "string",
"period_id": "2026-11",
"used": "string",
"limit": null,
"unlimited": false,
"allowed": false,
"as_of": null,
"window": "hour",
"window_id": "2026-11-05",
"resets_at": null,
"mode": "hard",
"over_limit": false,
"overridden": false,
"suspended": false
}
]
}
curl
curl -X GET https://YOUR-API-ADDRESS/v1/customers/<external_id>/entitlements \
-H "Authorization: Bearer $PAYRUDDER_API_KEY"
GET /v1/customers/{external_id}/entitlements/{meter} #
Usage of one meter against the customer's limit
Answered from near-real-time counters. They are eventually consistent (typically well under 2 s behind ingest):
as_of is the ingest time of the newest event reflected in used. Payrudder never blocks ingest on a limit; call
this before serving your customer and decide what to do. A customer without an entitlement on the meter is
unlimited. period defaults to the current period in the tenant's time zone.
A limit counts over its window: the billing month, or an hour, a day, an ISO week, a calendar year or the customer's
whole lifetime, in the tenant's time zone. period picks the month of a monthly limit; every other window always
reports its current one (window_id, ending at resets_at, which a lifetime window does not have). allowed follows
the limit's mode: a hard limit stops allowing at the limit, a soft or notify one keeps allowing and says
over_limit. Every window's counter is reconciled against the aggregator every few minutes, so an event delivered
twice stops counting twice within one cycle.
Parameters
| Name | In | Type | Description |
|---|
external_id required | path | string | |
meter required | path | string | |
period | query | string | |
Responses
Example response
{
"customer_external_id": "string",
"meter_code": "string",
"period_id": "2026-11",
"used": "string",
"limit": null,
"unlimited": false,
"allowed": false,
"as_of": null,
"window": "hour",
"window_id": "2026-11-05",
"resets_at": null,
"mode": "hard",
"over_limit": false,
"overridden": false,
"suspended": false
}
curl
curl -X GET https://YOUR-API-ADDRESS/v1/customers/<external_id>/entitlements/<meter> \
-H "Authorization: Bearer $PAYRUDDER_API_KEY"
GET /v1/customers/{external_id}/entitlement-overrides #
The customer's own limits, which replace its package's on their meters
Not paged: the response is the complete list.
Parameters
| Name | In | Type | Description |
|---|
external_id required | path | string | |
Responses
Example response
{
"overrides": [
{
"customer_external_id": "string",
"meter_code": "string",
"create_time": "2026-11-03T10:15:00Z",
"update_time": "2026-11-03T10:15:00Z",
"limit": "string",
"alert_thresholds_pct": [
50,
80,
100
],
"window": "QUOTA_WINDOW_UNSPECIFIED",
"mode": "QUOTA_MODE_UNSPECIFIED"
}
]
}
curl
curl -X GET https://YOUR-API-ADDRESS/v1/customers/<external_id>/entitlement-overrides \
-H "Authorization: Bearer $PAYRUDDER_API_KEY"
PUT /v1/customers/{external_id}/entitlement-overrides/{meter} #
Give the customer its own limit on a meter
Replaces the entitlement the customer's package gives on the meter, or adds one on a meter the package does not limit, for every
subscription of the customer until the override is deleted. limits-svc applies it within seconds. QUOTA_MODE_SOFT needs every
current package of the customer to price the meter (the usage over the limit is billed at that price).
Parameters
| Name | In | Type | Description |
|---|
external_id required | path | string | |
meter required | path | string | |
Request body
| Field | Type | Description |
|---|
limit required | string | Decimal in meter units; "0" = unlimited |
alert_thresholds_pct | array of integer | Strictly ascending percentages of the limit at which an alert fires; empty = 80 and 100 |
window | QuotaWindow | What a limit counts over, in the tenant's time zone. Unspecified is the month (the billing period). A year is the calendar year (twelve billing periods); a lifetime limit never starts again. |
mode | QuotaMode | What reaching the limit means for `allowed` (Payrudder never refuses usage events). HARD (also unspecified): allowed turns false at the
limit. SOFT: allowed stays true and the usage over the limit is billed at the meter's price, which the package must have. NOTIFY: allowed
stays true; only the alerts are sent.
|
Example
{
"limit": "string"
}
Responses
Example response
{
"customer_external_id": "string",
"meter_code": "string",
"create_time": "2026-11-03T10:15:00Z",
"update_time": "2026-11-03T10:15:00Z",
"limit": "string",
"alert_thresholds_pct": [
50,
80,
100
],
"window": "QUOTA_WINDOW_UNSPECIFIED",
"mode": "QUOTA_MODE_UNSPECIFIED"
}
curl
curl -X PUT https://YOUR-API-ADDRESS/v1/customers/<external_id>/entitlement-overrides/<meter> \
-H "Authorization: Bearer $PAYRUDDER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"limit":"string"}'
DELETE /v1/customers/{external_id}/entitlement-overrides/{meter} #
Return the customer to its package's limit on the meter
Parameters
| Name | In | Type | Description |
|---|
external_id required | path | string | |
meter required | path | string | |
Responses
| Status | Meaning | Body |
|---|
204 | Deleted | |
404 | Error envelope | Error |
curl
curl -X DELETE https://YOUR-API-ADDRESS/v1/customers/<external_id>/entitlement-overrides/<meter> \
-H "Authorization: Bearer $PAYRUDDER_API_KEY"
GET /v1/customers/{external_id}/credits #
What a customer can spend now
The balance leaves out credits whose time has passed. lots shows where it comes from, the credits that expire first at the top.
Parameters
| Name | In | Type | Description |
|---|
external_id required | path | string | |
Responses
Example response
{
"balance": "string",
"next_expire_time": "2026-11-03T10:15:00Z",
"lots": [
{
"id": "0192f0b4-6f6e-7c3a-9a3e-6a1f2b3c4d5e",
"granted": "string",
"remaining": "string",
"source": "purchase",
"expire_time": "2026-11-03T10:15:00Z",
"create_time": "2026-11-03T10:15:00Z"
}
]
}
curl
curl -X GET https://YOUR-API-ADDRESS/v1/customers/<external_id>/credits \
-H "Authorization: Bearer $PAYRUDDER_API_KEY"
POST /v1/customers/{external_id}/credits/grant #
Add credits to a customer
For a promotion, a goodwill gesture or a sale made outside Payrudder. With an idempotency_key (or the Idempotency-Key header) a repeat of the call adds nothing and returns replayed: true; the same key with other values is billing.credits.key_reused.
Parameters
| Name | In | Type | Description |
|---|
external_id required | path | string | |
Request body
| Field | Type | Description |
|---|
credits required | string · int64 | int64, above zero (a number is accepted too) |
source required | promo | manual | |
expire_time | string · date-time | Must lie in the future; leave out for credits that never expire |
reason | string | |
idempotency_key | string | |
Example
{
"credits": "string",
"source": "promo"
}
Responses
Example response
{
"balance": "string",
"replayed": false
}
curl
curl -X POST https://YOUR-API-ADDRESS/v1/customers/<external_id>/credits/grant \
-H "Authorization: Bearer $PAYRUDDER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"credits":"string","source":"promo"}'
POST /v1/customers/{external_id}/credits/consume #
Spend credits
Takes the credits that expire first. With too few credits nothing is taken and the answer is 409 billing.credits.insufficient. An idempotency_key (or the Idempotency-Key header) is required: a retried call returns the first result with replayed: true instead of charging twice.
Parameters
| Name | In | Type | Description |
|---|
external_id required | path | string | |
Request body
| Field | Type | Description |
|---|
credits required | string · int64 | int64, above zero (a number is accepted too) |
reason | string | |
idempotency_key required | string | Required, here or in the Idempotency-Key header |
Example
{
"credits": "string",
"idempotency_key": "string"
}
Responses
Example response
{
"balance": "string",
"replayed": false
}
curl
curl -X POST https://YOUR-API-ADDRESS/v1/customers/<external_id>/credits/consume \
-H "Authorization: Bearer $PAYRUDDER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"credits":"string","idempotency_key":"string"}'
GET /v1/customers/{external_id}/credits/ledger #
Every change to a customer's credits, newest first
Parameters
| Name | In | Type | Description |
|---|
external_id required | path | string | |
page_size | query | integer | |
page_token | query | string | |
Responses
Example response
{
"entries": [
{
"id": "0192f0b4-6f6e-7c3a-9a3e-6a1f2b3c4d5e",
"lot_id": "0192f0b4-6f6e-7c3a-9a3e-6a1f2b3c4d5e",
"kind": "grant",
"amount": "string",
"reason": "string",
"idempotency_key": "string",
"source": "purchase",
"create_time": "2026-11-03T10:15:00Z"
}
],
"next_page_token": "string"
}
curl
curl -X GET https://YOUR-API-ADDRESS/v1/customers/<external_id>/credits/ledger \
-H "Authorization: Bearer $PAYRUDDER_API_KEY"
POST /v1/customers/{external_id}/coupons #
Give a customer a coupon that their next eligible checkout uses without a code
One grant per (customer, source, source_ref); repeating it grants nothing more.
Parameters
| Name | In | Type | Description |
|---|
external_id required | path | string | |
Request body
| Field | Type | Description |
|---|
coupon_code required | string | |
source required | string | Who gives it, e.g. operator or affiliate |
source_ref required | string | |
Example
{
"coupon_code": "string",
"source": "string",
"source_ref": "string"
}
Responses
Example response
{
"granted": false
}
curl
curl -X POST https://YOUR-API-ADDRESS/v1/customers/<external_id>/coupons \
-H "Authorization: Bearer $PAYRUDDER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"coupon_code":"string","source":"string","source_ref":"string"}'
POST /v1/customers/{external_id}/referral #
Say which partner brought a customer
For your own sign-up, which reads the ?ref= of the link. First touch wins: a customer who has an attribution keeps it. A refusal is a normal answer (attributed false and a reason), not an error: already_attributed, unknown_code, program_inactive, affiliate_inactive, expired, same_email, same_domain, same_payment_method.
Parameters
| Name | In | Type | Description |
|---|
external_id required | path | string | |
Request body
| Field | Type | Description |
|---|
code required | string | |
source | link | code | api | |
touch_time | string · date-time | When the visitor followed the link; default now |
Example
{
"code": "string"
}
Responses
Example response
{
"attributed": false,
"reason": "string"
}
curl
curl -X POST https://YOUR-API-ADDRESS/v1/customers/<external_id>/referral \
-H "Authorization: Bearer $PAYRUDDER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"code":"string"}'
POST /v1/customers/{external_id}/portal-links #
Make the link to a customer's payment page
Shows the customer's invoices, payments, PDFs and receipts, read-only, with a pay button on open invoices. Works until expires_in_days (default 30, at most 365) or until revoked; the token is returned once.
Parameters
| Name | In | Type | Description |
|---|
external_id required | path | string | |
Request body
| Field | Type | Description |
|---|
expires_in_days | integer | |
Example
{}
Responses
Example response
{
"token": "string",
"url": "string",
"expires_at": "2026-11-03T10:15:00Z",
"customer_id": "string"
}
curl
curl -X POST https://YOUR-API-ADDRESS/v1/customers/<external_id>/portal-links \
-H "Authorization: Bearer $PAYRUDDER_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'
DELETE /v1/customers/{external_id}/portal-links #
Make every portal link of the customer stop working
Parameters
| Name | In | Type | Description |
|---|
external_id required | path | string | |
Responses
Example response
{
"revoked": 1
}
curl
curl -X DELETE https://YOUR-API-ADDRESS/v1/customers/<external_id>/portal-links \
-H "Authorization: Bearer $PAYRUDDER_API_KEY"
GET /v1/customers/{external_id}/payments #
The customer's invoices and the payments recorded for them
The same rows the customer sees on their payment page, newest first (charges and refunds from the ledger; an invoice may have several attempts).
Parameters
| Name | In | Type | Description |
|---|
external_id required | path | string | |
limit | query | integer | How many invoices to read; there is no page_token, so a customer with more invoices cannot be listed completely |
Responses
Example response
{
"invoices": [
{
"id": "string",
"customer_id": "string",
"customer_external_id": "string",
"period_id": "string",
"kind": "REGULAR",
"number": "INV-2026-000123",
"currency": "string",
"subtotal_minor": "string",
"total_minor": "string",
"status": "draft",
"saga_state": "string",
"create_time": "2026-11-03T10:15:00Z",
"finalize_time": "2026-11-03T10:15:00Z",
"lines": [
{
"line_no": 1,
"kind": "BASE_FEE",
"meter_code": "string",
"origin_period_id": "string",
"quantity": "1.250",
"amount_minor": "string",
"description": "string",
"service_from": "2026-11-03T10:15:00Z",
"service_to": "2026-11-03T10:15:00Z"
}
],
"payments": [
{
"id": "string",
"invoice_id": "string",
"method": "bank_transfer",
"amount_minor": "string",
"currency": "string",
"received_at": "2026-11-03T10:15:00Z",
"reference": "string",
"note": "string",
"recorded_by": "string",
"recorded_at": "2026-11-03T10:15:00Z"
}
],
"plan_version_id": "string",
"pdf_object_key": "string",
"credit_surplus_minor": "string"
}
],
"payments": [
{
"invoice_id": "0192f0b4-6f6e-7c3a-9a3e-6a1f2b3c4d5e",
"invoice_number": "string",
"kind": "charge",
"status": "succeeded",
"amount_minor": "string",
"currency": "string",
"provider": "string",
"environment": "sandbox",
"occurred_at": "2026-11-03T10:15:00Z"
}
]
}
curl
curl -X GET https://YOUR-API-ADDRESS/v1/customers/<external_id>/payments \
-H "Authorization: Bearer $PAYRUDDER_API_KEY"
Models
Address
| Field | Type | Description |
|---|
line1 required | string | |
line2 required | string | |
city required | string | |
region required | string | State, province or county |
postal_code required | string | |
country required | string | ISO 3166-1 alpha-2 |
AttributeCustomerRequest
| Field | Type | Description |
|---|
code required | string | |
source | link | code | api | |
touch_time | string · date-time | When the visitor followed the link; default now |
AttributeCustomerResponse
| Field | Type | Description |
|---|
attributed required | boolean | |
reason required | string | |
BlockCustomerRequest
| Field | Type | Description |
|---|
reason | string | Your note on why; never shown to the customer. |
category | CustomerBlockCategory | Why the customer is blocked. fraud and chargeback also refuse paying an invoice that is open. |
blocked_until | string · date-time | When the block ends by itself; must be in the future. Absent: until you lift it. |
suspend_service | boolean | Also suspend the customer's service: every entitlement check answers allowed false (suspended true) until the block is lifted or ends. Usage is still accepted and counted. Default false. |
ContractAcceptance
| Field | Type | Description |
|---|
id required | string · uuid | |
group_id required | string · uuid | The versions accepted together share it. |
customer_id required | string | Empty for a guest payment. |
version_id required | string · uuid | |
kind required | ContractKind | |
audience required | ContractAudience | A business customer gets the business series when one is published, else the consumer's. |
version_number required | integer · int32 | |
version_sha256 required | string | |
locale_requested required | string | |
locale_served required | string | |
body_sha256 required | string | Hex sha256 of the text served. |
context_kind required | hosted_invoice | api | |
context_ref required | string | |
source required | hosted | api | |
observed required | object | ip, user_agent, time, text: true when Payrudder observed it, false when the seller claimed it. |
checkbox_text required | string | |
immediate_start_consent required | boolean | |
immediate_start_text required | string | |
withdrawal_waiver_acknowledged required | boolean | |
withdrawal_waiver_text required | string | |
variables required | object | |
snapshot_sha256 required | string | |
ip required | string | Blank once the retention period passed. |
user_agent required | string | |
accept_time required | string · date-time | |
customer_external_id required | string | |
ContractAcceptanceItem
| Field | Type | Description |
|---|
version_id required | string · uuid | |
checkbox_text required | string | The words next to the box, as the customer saw them. |
ContractAudience
consumer | business
ContractKind
distance_sales | pre_info | tos | privacy
ContractOrder
| Field | Type | Description |
|---|
description | string | |
total | string | Formatted for a person, e.g. 12.00. |
currency | string | |
ContractRequirement
| Field | Type | Description |
|---|
kind required | ContractKind | |
version_id required | string · uuid | |
version_number required | integer · int32 | |
audience required | ContractAudience | A business customer gets the business series when one is published, else the consumer's. |
locale required | string | The language of the text served. |
body_html required | string | The text as safe HTML, variables resolved. |
body_sha256 required | string | |
accepted required | boolean | |
accept_time required | string · date-time | |
has_template_notice required | boolean | |
ContractWithdrawal
| Field | Type | Description |
|---|
id required | string · uuid | |
customer_id required | string · uuid | |
customer_external_id required | string | |
subscription_id required | string | |
invoice_id required | string | |
statement required | string | |
source required | api | console | hosted | |
status required | received | accepted | rejected | refunded | |
receive_time required | string · date-time | |
decide_time required | string · date-time | |
decided_by required | string | |
decision_note required | string | |
credit_note_id required | string | The credit note billing made to refund the invoice, once one was requested (GET /v1/credit-notes/{id} says how the refund went). |
refund_state required | none | requesting | requested | refunded | refund_failed | outside | failed | none: 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 required | string | |
refund_time required | string · date-time | |
CreateContractWithdrawalRequest
| Field | Type | Description |
|---|
subscription_id | string · uuid | |
invoice_id | string · uuid | |
statement | string | |
receive_time | string · date-time | When the statement reached you; empty is now. |
source | api | console | |
CreateCustomerRequest
| Field | Type | Description |
|---|
external_id required | string | |
name required | string | |
email required | string · email | |
payment_method | string | |
country | string | ISO 3166-1 alpha-2 |
billing_currency | string | ISO 4217; default is the tenant's currency |
address | AddressInput | A postal address as printed on an invoice. Every part is optional. |
locale | en | tr | de | fr | es | ar | The language of the customer's mails, receipts and payment pages |
customer_type | individual | business | A person or a taxpayer |
phone | string | The customer's mobile number in international form, e.g. +90 532 123 45 67 or 0090 532 123 45 67; stored as E.164 (+905321234567). A number without the + or 00 prefix is refused: it cannot be read without a country. |
referral_code | string | The code of the partner whose link or code brought this customer (phase 47). A code that cannot attribute does not fail the creation. |
referral_touch_time | string · date-time | When the visitor followed that link; default now |
CreatePaymentMethodSetupRequest
| Field | Type | Description |
|---|
provider | stripe | The provider whose page it is; only Stripe has one |
return_url required | string · uri | Where the provider sends the customer after the page. `https` only |
CreatePortalLinkRequest
| Field | Type | Description |
|---|
expires_in_days | integer | |
CreatePortalLinkResponse
| Field | Type | Description |
|---|
token required | string | |
url required | string | |
expires_at required | string · date-time | |
customer_id required | string | |
CreditBalance
| Field | Type | Description |
|---|
balance required | string · int64 | |
next_expire_time required | string · date-time | When some of the credits run out; null when none does |
lots required | array of CreditLot | |
CreditLedgerEntry
| Field | Type | Description |
|---|
id required | string · uuid | |
lot_id required | string · uuid | |
kind required | grant | consume | expire | revoke | |
amount required | string · int64 | int64 as a string; negative for consume, expire and revoke (a revoke takes back the credits of a credit pack whose invoice was voided or credited; 0 when none of them was left to take, and its reason says how many could not be) |
reason required | string | |
idempotency_key required | string | |
source required | purchase | promo | manual | Where the credits it touched came from; a purchase is a credit pack that was paid for |
create_time required | string · date-time | |
CreditLedgerPage
| Field | Type | Description |
|---|
entries required | array of CreditLedgerEntry | |
next_page_token required | string | |
CreditLot
| Field | Type | Description |
|---|
id required | string · uuid | |
granted required | string · int64 | |
remaining required | string · int64 | |
source required | purchase | promo | manual | |
expire_time required | string · date-time | Null: the credits never expire |
create_time required | string · date-time | |
CreditResult
| Field | Type | Description |
|---|
balance required | string · int64 | int64 as a string: what the customer can spend after the call |
replayed required | boolean | True when the key had been used: nothing changed |
Customer
| Field | Type | Description |
|---|
id required | string · uuid | |
external_id required | string | |
name required | string | |
email required | string | |
payment_method required | string | |
create_time required | string · date-time | |
country required | string | ISO 3166-1 alpha-2 |
billing_currency required | string | ISO 4217 |
address required | any | |
tax_id required | string | |
tax_office required | string | |
e_invoice_registered required | boolean | |
locale required | string | The language of the customer's mails, receipts and payment pages: en, tr, de, fr, es or ar. Empty is the browser's language (pages) and English (mails). |
customer_type required | string | individual (a person) or business (a taxpayer with a tax id). Empty is unknown. |
block_time | string · date-time | Set while the customer is blocked: no new subscription, plan change or purchase (existing subscriptions run on). A block whose blocked_until has passed has ended, whatever this says. |
block_reason required | string | The seller's own note on the block; never shown to the customer. |
block_category required | string | Why: fraud, chargeback, abuse, request or other; empty when none was given. |
blocked_until | string · date-time | When the block ends by itself; absent: until it is lifted. |
service_suspended required | boolean | The block also suspends the customer's service: every entitlement check answers allowed false. Read it with block_time and blocked_until, it holds only while the block does. |
phone required | string | The customer's mobile number as E.164 (+905321234567); empty when none. |
tax_id_validated_at | string · date-time | When tax_id last passed the local check (a TCKN or VKN checksum, the shape of a European VAT id). Not a registry lookup: no VIES, no GİB query. Absent when the id is empty or not recognised. |
tax_id_warning required | string | One of tr_individual, tr_business, tr_any, tr_is_tckn, tr_is_vkn, eu_vat, or empty. A hint, never a refusal: the id does not look like the kind of number this customer should have (tr_individual: not a TCKN; tr_business: not a VKN; tr_any: neither; tr_is_tckn: a business was given a TCKN; tr_is_vkn: an individual was given a VKN; eu_vat: a business in the EU has no VAT id of its country's shape). Worked out from the stored id, country and customer_type, so it follows a change of any of them. Empty: nothing to say. |
CustomerBlockAppeal
| Field | Type | Description |
|---|
id required | string · uuid | |
status required | open | accepted | rejected | closed | |
statement required | string | The customer's own words. Untrusted: show as text only |
answer required | string | Your answer; empty until decided, and for an accepted appeal that had none |
decided_by required | string | A person's address, key:<api key id>, or system for a closed appeal |
create_time required | string · date-time | |
decide_time | string · date-time | |
CustomerBlockCategory
fraud | chargeback | abuse | request | other
CustomerBlockEvent
| Field | Type | Description |
|---|
id required | string · uuid | |
action required | blocked | unblocked | |
category required | string | Empty when none was given; else a CustomerBlockCategory |
reason required | string | |
blocked_until | string · date-time | |
suspend_service required | boolean | On a block: whether it also suspended the customer's service |
actor required | string | A person's address, key:<api key id>, or operator |
create_time required | string · date-time | |
CustomerCards
| Field | Type | Description |
|---|
provider required | string | The provider that holds the cards; empty when the customer has none |
cards required | array of StoredCard | |
CustomerPayment
| Field | Type | Description |
|---|
invoice_id required | string · uuid | |
invoice_number required | string | |
kind required | charge | refund | |
status required | succeeded | declined | failed | pending | |
amount_minor required | string · int64 | |
currency required | string | |
provider required | string | |
environment required | sandbox | live | |
occurred_at required | string · date-time | |
CustomerTax
| Field | Type | Description |
|---|
tax_id | string | VKN/TCKN (Turkey) or VAT id (EU) |
tax_office | string | Vergi dairesi (Turkey) |
e_invoice_registered | boolean | The customer is registered for e-fatura |
DecideCustomerBlockAppealRequest
| Field | Type | Description |
|---|
decision required | accepted | rejected | |
answer | string | Required to reject |
DeletedCustomerCard
| Field | Type | Description |
|---|
provider required | string | |
deleted required | boolean | |
was_in_use required | boolean | The deleted card was the one the customer's payment method names: set a new payment method |
EntitlementOverride
| Field | Type | Description |
|---|
customer_external_id required | string | |
meter_code required | string | |
create_time required | string · date-time | |
update_time required | string · date-time | |
limit required | string | Decimal in meter units; "0" = unlimited |
alert_thresholds_pct required | array of integer | Strictly ascending percentages of the limit at which an alert fires; empty = 80 and 100 |
window required | QuotaWindow | What a limit counts over, in the tenant's time zone. Unspecified is the month (the billing period). A year is the calendar year (twelve billing periods); a lifetime limit never starts again. |
mode required | QuotaMode | What reaching the limit means for `allowed` (Payrudder never refuses usage events). HARD (also unspecified): allowed turns false at the
limit. SOFT: allowed stays true and the usage over the limit is billed at the meter's price, which the package must have. NOTIFY: allowed
stays true; only the alerts are sent.
|
EntitlementStatus
| Field | Type | Description |
|---|
customer_external_id required | string | |
meter_code required | string | |
period_id required | string | |
used required | string | Exact decimal with the meter's scale, examples: ["10.500"] |
limit required | string,null | Exact decimal; null when unlimited, examples: ["10.500"] |
unlimited required | boolean | |
allowed required | boolean | (unlimited, used < limit, or a soft or notify limit) and not suspended |
as_of required | string,null · date-time | |
window required | hour | day | week | month | year | lifetime | What the limit counts over; month for a meter without a limit |
window_id required | string | The window used counts in: period_id for a month, 2026-11-05T13, 2026-11-05, 2026-W45, 2026 for a year or all for the lifetime |
resets_at required | string,null · date-time | When the window ends and used starts again from zero; null for the lifetime window |
mode required | hard | soft | notify | |
over_limit required | boolean | not unlimited and used >= limit, whatever the mode |
overridden required | boolean | The limit is the customer's own override, not its package's |
suspended required | boolean | You suspended this customer's service (a block with suspend_service): allowed is false on every meter, with or without a limit. Usage is still accepted and counted. |
EntitlementTerms
| Field | Type | Description |
|---|
limit required | string | Decimal in meter units; "0" = unlimited |
alert_thresholds_pct | array of integer | Strictly ascending percentages of the limit at which an alert fires; empty = 80 and 100 |
window | QuotaWindow | What a limit counts over, in the tenant's time zone. Unspecified is the month (the billing period). A year is the calendar year (twelve billing periods); a lifetime limit never starts again. |
mode | QuotaMode | What reaching the limit means for `allowed` (Payrudder never refuses usage events). HARD (also unspecified): allowed turns false at the
limit. SOFT: allowed stays true and the usage over the limit is billed at the meter's price, which the package must have. NOTIFY: allowed
stays true; only the alerts are sent.
|
Error
| Field | Type | Description |
|---|
error required | object | |
GetContractRequirementsResponse
| Field | Type | Description |
|---|
enforced required | boolean | The seller requires agreements at all. |
requirements required | array of ContractRequirement | |
satisfied required | boolean | |
immediate_start required | boolean | A consumer is asked for the request to start at once and the waiver acknowledgement. |
missing_kinds required | array of ContractKind | Required kinds with no published version: a payment is refused. |
audience required | ContractAudience | A business customer gets the business series when one is published, else the consumer's. |
GetCustomerUsageResponse
| Field | Type | Description |
|---|
customer_external_id required | string | |
period_id required | string | |
usage required | array of GetCustomerUsageUsage | |
GetCustomerUsageUsage
| Field | Type | Description |
|---|
meter_code required | string | |
quantity required | string | |
event_count required | string · int64 | |
GrantCustomerCouponRequest
| Field | Type | Description |
|---|
coupon_code required | string | |
source required | string | Who gives it, e.g. operator or affiliate |
source_ref required | string | |
GrantCustomerCouponResponse
| Field | Type | Description |
|---|
granted required | boolean | |
Invoice
| Field | Type | Description |
|---|
id required | string | |
customer_id required | string | |
customer_external_id required | string | |
period_id required | string | |
kind required | REGULAR | CORRECTION | FEE | LINK | FEE: a fixed fee invoiced in advance for one period, or what a plan change moved. LINK: made from an ad-hoc payment link |
number required | string | |
currency required | string | |
subtotal_minor required | string · int64 | |
total_minor required | string · int64 | |
status required | draft | open | paid | uncollectible | void | |
saga_state required | string | |
create_time required | string · date-time | |
finalize_time required | string · date-time | |
lines required | array of InvoiceLine | |
payments required | array of InvoicePayment | Payments recorded by hand by the operator (they do not come through a payment provider), oldest first. Only the single-invoice reads fill it. |
plan_version_id required | string | |
pdf_object_key required | string | |
credit_surplus_minor required | string · int64 | What the lines came to below zero (late-usage corrections larger than everything else on the invoice). The total is never negative, so this was added to the customer's credit balance instead, once per invoice, and their next invoices use it. 0 for every other invoice |
InvoiceLine
| Field | Type | Description |
|---|
line_no required | integer | |
kind required | BASE_FEE | USAGE | LATE_USAGE | CREDIT | CORRECTION | DISCOUNT | TAX | |
meter_code required | string | |
origin_period_id required | string | |
quantity required | string | |
amount_minor required | string · int64 | |
description required | string | |
service_from required | string · date-time | The service period the line covers, nullable: true |
service_to required | string · date-time | |
InvoicePayment
| Field | Type | Description |
|---|
id required | string | |
invoice_id required | string | |
method required | bank_transfer | cash | other | |
amount_minor required | string · int64 | |
currency required | string | |
received_at required | string · date-time | |
reference required | string | |
note required | string | |
recorded_by required | string | |
recorded_at required | string · date-time | |
ListContractAcceptancesResponse
| Field | Type | Description |
|---|
acceptances required | array of ContractAcceptance | |
next_page_token required | string | Pass it as page_token for the next page; empty on the last page |
ListCustomerBlockAppealsResponse
ListCustomerBlockEventsResponse
ListCustomerPaymentsResponse
ListCustomersResponse
| Field | Type | Description |
|---|
customers required | array of Customer | |
next_page_token required | string | |
ListEntitlementOverridesResponse
PaymentMethodSetup
| Field | Type | Description |
|---|
url required | string | The provider's page: send it to the customer |
ref required | string | The provider's reference of the page (Stripe's Checkout Session id) |
QuotaMode
QUOTA_MODE_UNSPECIFIED | QUOTA_MODE_HARD | QUOTA_MODE_SOFT | QUOTA_MODE_NOTIFY
QuotaWindow
QUOTA_WINDOW_UNSPECIFIED | QUOTA_WINDOW_MONTH | QUOTA_WINDOW_HOUR | QUOTA_WINDOW_DAY | QUOTA_WINDOW_WEEK | QUOTA_WINDOW_YEAR | QUOTA_WINDOW_LIFETIME
RecordContractAcceptanceRequest
| Field | Type | Description |
|---|
locale | string | The language the page was shown in. |
context_ref | string | Your reference for the checkout (an order id). |
items required | array of ContractAcceptanceItem | |
immediate_start_consent | boolean | |
immediate_start_text | string | |
withdrawal_waiver_acknowledged | boolean | |
withdrawal_waiver_text | string | |
ip | string | Your claim about the customer's address. |
user_agent | string | Your claim about the customer's browser. |
accept_time | string · date-time | When the customer accepted; empty is now. |
customer_type | individual | business | |
order | ContractOrder | |
RecordContractAcceptanceResponse
| Field | Type | Description |
|---|
group_id required | string · uuid | |
acceptances required | array of ContractAcceptance | |
RevokePortalLinksResponse
| Field | Type | Description |
|---|
revoked required | integer | |
SetPaymentMethodRequest
| Field | Type | Description |
|---|
payment_method required | string | |
StoredCard
| Field | Type | Description |
|---|
token required | string | The provider's card token (cardToken): what the delete names |
alias required | string | |
bin required | string | The first digits of the number (the BIN) |
last4 required | string | |
type required | string | CREDIT_CARD, DEBIT_CARD or PREPAID_CARD |
association required | string | VISA, MASTER_CARD, ... |
family required | string | |
bank required | string | |
expire_month required | string | |
expire_year required | string | |
in_use required | boolean | The customer's payment method names this card |
UpcomingInvoice
| Field | Type | Description |
|---|
estimate required | boolean | Always true. The preview is never the invoice |
customer_external_id required | string | |
period_id required | string | The period whose invoice this is, in the tenant's time zone |
period_start required | string · date-time | |
period_end required | string · date-time | |
currency required | string | |
lines required | array of InvoiceLine | The lines as the invoice would have them, in order: fixed fee, usage, late usage, tax, and the credit |
subtotal_minor required | string · int64 | Before tax and after the credit, as on an invoice |
tax_minor required | string · int64 | |
credit_minor required | string · int64 | The credit balance the invoice would use, a positive number |
total_minor required | string · int64 | What would be charged; never negative |
credit_surplus_minor required | string · int64 | What the lines come to below zero, which the real invoice would add to the customer's credit balance instead of charging a negative total; 0 normally |
as_of required | string · date-time | The clock of the estimate |
has_invoice required | boolean | False when the customer has no subscription in the period and no late usage to bill |