API Fundamentals

Base URL, path naming, money/timestamp formats, pagination, sorting, the response format, and rate limits — read this before wiring anything up; every other page assumes you already know these rules.

View as Markdown

Base URL, path naming & versioning

Every endpoint lives under /api on your environment's URL (e.g. $REBATE_PAY_BASE_URL/api/Product). Paths follow /api/{Resource}[/{resourceId}][/{Action}]: resources are singular PascalCase nouns (Product, PaymentLink, WebhookEndpoint), a single item adds {resourceId}, and non-CRUD actions come last (/api/Subscription/{subscriptionId}/Cancel, /api/Payment/{paymentId}/Reconcile). Paths match case-insensitively, but the docs always use PascalCase.

HTTP methodUsed forExample
GETList or retrieveGET /api/Product, GET /api/Product/{productId}
POSTCreate a resource or run an actionPOST /api/Product, POST /api/Refund, POST /api/PaymentLink/{paymentLinkId}/Archive
PUTUpdate a resource (send only the fields to change)PUT /api/Product/{productId}
DELETEDelete a resourceDELETE /api/PaymentMethod/{paymentMethodId}

Developer API paths have no prefix; ReBate Pay's own console APIs use Admin* (platform console), Merchant* (merchant console) and Member* (consumer wallet) prefixes and sign in with JWTs (see Authentication). Full spec: GET /api/OpenApi?audience=developer. The API version is a date string (e.g. 2026-08-30), returned in the x-rebatepay-version response header.

This API currently serves Sandbox only. Any request, with or without an environment parameter, resolves to sandbox; a Production endpoint isn't available yet.

Object ID format

Every resource ID is a prefix plus a random string. The prefix tells you the resource type at a glance and gives your code something cheap to sanity-check:

PrefixResource
prod_Product
price_Price
cus_Customer
sub_Subscription
pay_Payment
re_Refund
plink_Payment Link
evt_Webhook Event
wda_Webhook Delivery Attempt

Money: integers, no decimal places

Unlike many payment APIs: amount here is not a minor unit like cents. TWD has no decimal places, so amount: 200 means NT$200, not NT$2. If you're porting the "multiply by 100" convention from another API, you'll overcharge by 100x — adjust it.

Time: ISO 8601, UTC

Every timestamp field is an ISO 8601 string in UTC (e.g. 2026-08-30T00:00:00.000Z). The dashboard converts to Taipei time for display; raw API fields are always UTC — don't assume Asia/Taipei.

Pagination: page / pageSize

Every list endpoint takes the same page-number parameters, and the response carries the total count and page count:

ParameterMeaning
pagePage number, starting at 1 (default 1)
pageSizeItems per page, 1–200 (default 20)
Response page / pageSizeThe page and page size actually used
Response totalCount / totalPagesMatching items and pages; page < totalPages means there's another page
curl -sS "$BASE/api/Product?page=1&pageSize=20" -H "Authorization: Bearer $API_KEY"
# Next page:
curl -sS "$BASE/api/Product?page=2&pageSize=20" -H "Authorization: Bearer $API_KEY"

Filtering & sorting

ParameterMeaning
orderByField to sort by (a response field name such as createdAt or amount), at most 50 characters; newest first when omitted
orderDirectionASC or DESC (default DESC)
createdFrom / createdToCreation-time range, ISO 8601 date-time
statusEndpoint-specific status as a PascalCase enum value (e.g. Active, Succeeded)
keyword (or q)Free-text search, at most 200 characters

Fields & enum values

JSON fields are always camelCase (customerId, successUrl). Status, type and interval values are PascalCase: payment status Pending, Succeeded, Failed, Unknown; subscription status Trialing, Active, PastDue, Canceled; price type OneTime, Recurring; interval Month, Year. Event types keep their dotted form (payment.succeeded).

Response format

On success the body is in data; on failure it's in error and the HTTP status reflects the kind of error. Every response carries an x-request-id header — include it when contacting support:

{
  "data": { "id": "plink_...", "status": "Active", "url": "https://.../pay/..." }
}

error.nextAction is a human-readable suggestion (currently zh-TW); error.code is the stable string your code should branch on. Full error code reference: Troubleshooting / Error Catalog.

Rate limits

Each API key defaults to 120 requests per 60-second fixed window (not a sliding window). Every response carries:

HeaderMeaning
x-ratelimit-limitTotal quota for this window
x-ratelimit-remainingRequests left in this window
x-ratelimit-resetWhen the quota resets (Unix timestamp, seconds)

Exceeding the limit returns 429 RATE_LIMITED with a Retry-After header (seconds) — wait exactly that long before retrying instead of guessing a fixed backoff.

Retries & Idempotency-Key

GETs are always safe to retry. Any financial mutation (payment, refund, checkout) requires an Idempotency-Key header — omit it and you get 400 IDEMPOTENCY_KEY_REQUIRED. Resending the same key with the same idempotency key returns the original result (with x-idempotent-replay: true) instead of executing it again. Full details: Refunds & Idempotency.