API Reference
Introduction
The Subscriptions API allows merchants to manage subscription lifecycles — creating customers, memberships, and sessions — through a secure REST interface. Built for seamless integration with Paytiko subscription services.
Prerequisites
Before integrating with the Paytiko Subscriptions API, ensure that the following requirements are met:
You must have valid API credentials (issued by Paytiko).
All communication must be over HTTPS only.
You must know your
processorKey
, and be able to retrieve and persist thecustomerKey
andmembershipKey
via the API.Your backend must support JWT-based authentication for including the
Authorization: Bearer <token>
header.You should implement secure storage of credentials, tokens, and keys (never expose secrets to the client/browser).
You must configure and expose a publicly accessible webhook endpoint to receive subscription and payment event notifications from Paytiko.
You should handle idempotency when processing webhook events (e.g., avoid duplicate handling).
Ensure your system’s time zone and clocks are synchronized (UTC recommended), since subscription cycles and
endDate
validation are time-sensitive.Your customer and product data should meet validation requirements (ISO country codes, valid email/phone formats, well-formed URIs).
You must implement error handling for API responses (HTTP 4xx, 5xx) to gracefully manage failed requests.
For checkout and portal sessions, ensure you can redirect customers to the hosted Paytiko pages and handle return URLs.
Best Practices
To build a robust and reliable integration, consider the following recommendations:
Token Management:
Refresh tokens before they expire (tokens are short-lived).
Do not hardcode tokens; request them dynamically when needed.
Webhook Reliability:
Treat all webhook requests as asynchronous events.
Always return HTTP 200 OK after successful processing.
Implement a retry strategy: if your system fails temporarily, Paytiko may resend webhooks — handle duplicates safely.
Security:
Verify incoming webhook requests (e.g., by checking signatures or IP allowlists if provided by Paytiko).
Use HTTPS everywhere; never log sensitive data such as passwords or full card numbers.
Data Integrity:
Validate incoming fields against your business logic (currency, amounts, interval counts).
Store
customerKey
andmembershipKey
in your database to link Paytiko records with your own user accounts.
Error Handling:
Retry failed API calls using exponential backoff.
Log both request and response data (excluding sensitive information) for debugging and reconciliation.
Technical Flow
This section describes the end-to-end lifecycle of how a subscription is created, purchased, and billed using the Paytiko Subscriptions API. The process covers authentication, customer creation, checkout, payment confirmation, invoicing, and recurring billing.
Customer requests a subscription The flow begins when a customer chooses a subscription plan on the merchant’s website or application.
Merchant authenticates The merchant uses its Paytiko-issued API credentials to obtain a secure access token. This token is required for all subsequent API requests.
Merchant creates a customer Using the customer’s details (name, email, phone, billing info), the merchant calls Paytiko to register a new customer. Paytiko returns a unique
customerKey
, which the merchant stores in its own database.Merchant creates a membership The merchant associates the customer with a subscription plan by creating a membership. This defines pricing, billing intervals, and product details. Paytiko returns a
membershipKey
.Merchant initiates a checkout session To complete the purchase, the merchant creates a checkout session linked to the
customerKey
andmembershipKey
. Paytiko responds with aredirectUrl
, and the merchant redirects the customer to the hosted checkout page.Customer confirms identity and pays The customer interacts with Paytiko’s secure checkout to confirm their identity and complete payment.
Paytiko notifies the merchant Upon successful payment (or failure), Paytiko sends a webhook notification to the merchant. At the same time, an invoice or receipt is emailed directly to the customer.
Recurring billing cycles run automatically On each billing cycle, Paytiko processes the recurring charge. The merchant receives webhook notifications with charge results, while the customer receives invoices by email.
Endpoints
This section provides detailed documentation for all available Paytiko Subscriptions API endpoints. Each endpoint description includes:
Method & Path – The HTTP method (e.g.,
POST
,GET
) and full URI.Overview – A short description of the purpose of the endpoint.
Headers – Required and optional HTTP headers.
Request Body – JSON model with all fields and validation rules.
Response – Example success and error responses.
All requests must be authenticated using a JWT bearer token obtained via the Authentication endpoint.
Try It Yourself — Postman Collection
To get started quickly, you can import our Postman Collection, which contains ready-to-use requests for all endpoints:
Preconfigured with request URLs and headers
Includes example payloads for authentication, customer creation, membership creation, and checkout
Helps you test the flow end-to-end before integrating into your system
Authentication
POST
/api/subscriptions/v1/auth
The authentication endpoint is used to obtain a JWT bearer token. This token is required in the Authorization
header for all other API requests.
Request Headers
Content-Type
application/json
Request Body
userName
string
User name
password
string
Password
Response
{
"token": "<token>",
"expiresIn": 720 // seconds.
}
Customers
Create Customer
POST
/api/subscriptions/v1/customer
This endpoint registers a new customer in the subscription system. The customer is the entity that owns memberships, billing details, and sessions.
Use case: When a new end user signs up, you must create their customer profile before adding memberships.
Customer uniqueness A customer is uniquely identified by their email address within the scope of a single merchant.
This request is idempotent
If a customer with the same email already exists, the API will return the existing
customerKey
.If no such customer exists, the API will create a new record and return the new
customerKey
.No duplication error will be raised when re-sending the same request with the same email.
Request Headers
Content-Type
application/json
Authorization
Bearer <token>
Request Body
processorKey
string (UUID)
Processor identifier.
Must be a non-empty GUID (canonical UUID).
firstName
string
Customer first name.
Must match ^\p{L}+(?:[ -]\p{L}+)*$
→ letters only (Unicode), hyphens and spaces.
lastName
string
Customer last name.
Must match ^\p{L}+(?:[ -]\p{L}+)*$
→ letters only (Unicode), hyphens and spaces.
email
string
Customer email.
Must pass server email validation, standard name@domain.tld
.
phone
string
Customer phone number.
Must match the E.164 international format (regex pattern is ^+[1-9]\d{7,14}$).
Must begin with a “+” sign followed by the country code and subscriber number
Cannot start with
0
after the+
Must be between 8 and 15 digits total (excluding the
+
)No spaces, hyphens, or special characters allowed.
countryCode
string
Country (ISO-3166-1 alpha-2).
Exactly 2 letters and must be recognized by the server’s country list; case-insensitive (use uppercase like US
, PL
).
address1
string
Street address line 1.
Optional; no additional validation in current model.
address2
string
Apartment/Suite.
Optional; no additional validation.
city
string
City/Locality.
Optional; no additional validation.
state
string
State/Region/Province.
Optional; no additional validation.
zipCode
string
Postal/ZIP code.
Optional; no additional validation.
taxIds
array
Business tax identifiers. Present in cURL examples but not in the provided C# model/validator.
Each item is typically { "type": string, "value": string }
. No explicit server-side validation rules provided in the shared code.
Response
{
"result": {
"customerKey": "cstmr_cc0067638c2240999c53824a45db0360"
}
}
Get Customer by Key
GET
/api/subscriptions/v1/customer/{customerKey}
Retrieves full details of a previously created customer.
Use case: Fetch customer information to display in your UI or confirm that a customer exists before assigning memberships.
Headers
Authorization
Bearer <token>
Response
{
"result": {
"key": "cstmr_737120202a0241888b307766308cb330",
"firstName": "Alice",
"lastName": "Smith",
"countryCode": "GB",
"email": "alice.smith@example.com",
"phone": "+447700900123",
"address1": "221B Baker Street",
"address2": "Flat 2",
"city": "London",
"state": "London",
"zipCode": "NW16XE",
"taxIds": [],
"createdDate": "2025-08-21T09:35:18.818714+00:00",
"updatedDate": null
}
}
Memberships
Create Membership
POST
/api/subscriptions/v1/membership
This endpoint registers a new membership for a customer. A membership defines the subscription relationship, including product details, pricing, and billing cycle.
Use case: When a customer purchases a subscription plan, the merchant must create a membership linked to that customer, ensuring the subscription can be billed and managed.
Membership uniqueness
A membership is uniquely identified by its orderId
(external order identifier) within the scope of a single customer.
This request is idempotent
If a membership with the same
orderId
already exists for the customer, the API will return the existingmembershipKey
.If no such membership exists, the API will create a new record and return the new
membershipKey
.No duplication error will be raised when re-sending the same request with the same
orderId
.
Request Headers
Content-Type
application/json
Authorization
Bearer <token>
Request Body
customerKey
string
Customer identifier.
Must start with prefix cstmr_
. Used to link the membership to an existing customer.
subscriptionName
string
Human-readable plan name.
Must be non-empty. Shown in invoices/portal and useful for your internal reporting.
endDate
string
Optional subscription end date.
Must be in UTC ISO-8601 format (e.g.
YYYY-MM-DDTHH:mm:ss
).Must be at least 1 hour ahead of the current UTC time.
If provided, no new billing cycles will start after this moment.
If not provided, the subscription will be infinite and continue to run until it is explicitly cancelled.
Valid examples:
2025-09-01T12:00:00
→ valid, 1 September 2025 at 12:00 UTC2025-08-21T19:45:00
→ valid if current UTC < 18:45 UTC (at least +1h ahead)
webhookUrl
string
Callback for lifecycle events.
Must be a well-formed absolute URL (HTTPS only).
Paytiko posts events like payment success/failure, subscription status changes, etc.
Your endpoint must return 2xx on success and be idempotent.
chargeEmitterQueue
string
Optional test/seed events.
If provided, cannot be an empty array. Each item must have transactionStatus
Success
or a negative enum value (per server).
Intended for test mode and QA scenarios.
See chargeEmitterQueue.
productInfo
orderId
string
External order ID from your system.
Required to be unique to prevent accidental duplication.
description
string
Product description.
Optional, free-text product/order description (shown in UIs/invoices if supported).
pricingInfo
currency
string
Currency code. Must be a 3-letter ISO 4217 code (e.g., USD
, EUR
).
totalAmount
string
Total subscription amount. Must be greater than 0.
If pricePerUnit
and quantity
are provided, then: totalAmount = pricePerUnit × quantity
.
pricePerUnit
number
Price per unit.
Must be greater than 0 if provided. If provided together with quantity
, their multiplication must equal totalAmount
.
quantity
integer
Quantity of units.
Must be greater than 0 if provided. If provided together with pricePerUnit
, their multiplication must equal totalAmount
.
billingCycle
intervalType
string
Billing interval.
Defines the base recurrence unit.
Must be one of: Daily
, Weekly
, Monthly
, Annually
.
intervalCount
integer
Interval multiplier.
Optional. Defines how many intervalType
units between charges. Must be an integer ≥1 if provided.
If not provided, defaults to 1
.
Examples:
intervalType=Weekly
, intervalCount=2
→ every 2
intervalType=Monthly
, intervalCount=3
→ every 3 months (quarterly)
Monthly Billing Date Edge-Cases are Safely-Handled
When a subscription renews monthly, special rules apply if the chosen billing day does not exist in the following month:
31st of the month → In shorter months (Feb, Apr, Jun, Sep, Nov), renewal happens on the last available day (e.g., Jan 31 → Feb 28, Apr 30).
30th of the month → If the next month has only 29 or 28 days, it shifts to the last day (e.g., May 30 → Jun 30 → Jul 30 → Aug 30 → Sep 30, but Feb only has 28/29).
Once adjusted, all future renewals continue from that shifted day (e.g., Jan 31 → Feb 28 → Mar 28 → Apr 28 …).
Leap years are respected (e.g., Jan 31 → Feb 29 → Mar 29).
Key takeaway Subscriptions billed on the 30th or 31st will always renew on the last available day of shorter months. Customers will still be billed once per month, with consistent timing.
chargeEmitterQueue[]
transactionStatus
string
Transaction status filter.
Must be either:
Success
→ charge is processed successfully.Rejected
→ charge is simulated as failed.
description
string
Error message returned when transactionStatus
is Rejected
.
Defaults to "Insufficient funds."
if not provided.
When testing subscriptions in sandbox/test mode, the payment gateway normally supports only success-resulting test cards. That means all recurring charges would succeed by default.
To simulate real-world billing conditions (e.g., declines, retries, eventual success), you can provide a chargeEmitterQueue
— an array that defines the outcome of each scheduled charge.
How it works
Each item in the array represents the result of the next charge attempt in sequence.
Allowed values are:
success
→ charge is processed successfully.rejected
→ charge fails with a simulated decline.
Once all items in the array are consumed, the emitter stops and all subsequent charges default to
success
(unless you provide a longer array).This applies only to recurring charges triggered by billing cycles.
The initial checkout payment is not affected by
chargeEmitter
(it always follows test card rules).
Expanation
1st charge →
success
→ The first billing cycle succeeds.2nd charge →
rejected
→ The next billing attempt is rejected.3rd charge →
rejected
→ Another failure is simulated.4th charge →
rejected
→ Third consecutive failure.5th charge →
success
→ Billing finally succeeds again.
Rules
The queue defines charge behavior only (not the initial checkout payment).
If the queue has fewer items than the number of cycles, all remaining charges default to
success
.If no
chargeEmitter
is provided, all charges default tosuccess
.
Key points to remember
If
chargeEmitterQueue
is not provided, all charges are assumed successful.You can use this feature to test retry logic, dunning flows, and webhook handling without needing special test cards.
Make sure your webhook implementation is idempotent, since rejected charges will trigger failure events you may want to retry.
Response
{
"result": {
"membershipKey": "mmbrsp_cc0067638c2240999c53824a45db0360"
}
}
Get Membership by Key
GET
/api/subscriptions/v1/membership/{membershipKey}
Retrieves the full details of a previously created membership.
Use cases:
Fetch membership information to display in your UI (e.g., plan details, pricing, status).
Verify that a membership exists and check its current state (active, cancelled, expired) before performing further actions.
Request Headers
Authorization
Bearer <token>
Response
{
"result": {
"key": "mmbrshp_3cf7488e4c4545a998634c664161665a",
"customerKey": "cstmr_737120202a0241888b307766308cb330",
"name": "Premium Plan",
"status": "Incomplete",
"settings": {
"intervalType": "Daily",
"intervalCount": 1
},
"invoices": [],
"createdDate": "2025-08-21T10:08:11.684394+00:00",
"updatedDate": null,
"activationDate": null,
"endDate": "2027-08-21T19:45:00+00:00",
"nextRenewalDate": null,
"orderId": "bff0757d-5aee-406a-b165-461cce42f349",
"productDescription": "My product",
"totalAmount": 99.98,
"pricePerUnit": 49.99,
"quantity": 2,
"currency": "USD"
}
}
Cancel Membership
POST
/api/subscriptions/v1/membership/cancel/{membershipKey}
Cancels an active membership immediately. After cancellation:
No new billing cycles will be started.
Any open invoices (not yet finalized/paid) will be automatically transitioned to status
Void
.Already paid or failed invoices remain unchanged.
Use cases
Let customers stop their subscription through your UI (e.g., “Cancel Subscription” button).
Programmatically end a trial or paid membership when business rules require.
Safely retry cancel calls without risk of duplication or errors.
Request Headers
Authorization
Bearer <token>
Response
{} // Empty object.
UI Sessions
Create Checkout Session
POST
/api/subscriptions/v1/checkout/session
Creates a hosted checkout session for a specific customer and membership. It returns a redirect URL where the customer completes identity confirmation and payment.
How it works
Your backend calls this endpoint with a valid
customerKey
andmembershipKey
.The API returns
checkoutRedirectUrl
.You redirect the customer’s browser to that URL.
The customer completes checkout on Paytiko’s hosted page.
Your system is notified via webhooks configured on the membership (e.g., payment succeeded/failed), and the customer receives an invoice email.
Use cases
Start the initial payment for a newly created membership.
Re-issue a checkout when a previous session expired.
Provide a pay now link from your app or email.
Request Headers
Content-Type
application/json
Authorization
Bearer <token>
Request Body
customerKey
string
Customer identifier.
Must start with cstmr_
.
membershipKey
string
Membership identifier.
Must start with mmbrshp_
.
returnToWebsiteLink
string (URL)
Optional absolute return URL.
A full URL where the customer is redirected after leaving the portal.
Must be a valid absolute URL (e.g., https://example.com/return
).
Response
{
"result": {
"checkoutRedirectLink": "{checkoutBaseUrl}/daf8f4f7-5a4d-4b9e-9fc3-959781c226b3"
}
}
Create Portal Session
POST
/api/subscriptions/v1/checkout/session
Creates a customer portal session URL. The portal is a hosted, self-service page where customers can view and manage their subscriptions (e.g., see plan details, invoices, update payment method—exact features depend on your configuration).
How it works
Your backend calls this endpoint with the customer’s key.
The API returns
portalRedirectUrl
.You redirect or link the customer to this URL to self-manage their billing profile.
Common use cases
Provide a “Manage subscription” link in your app.
Let customers view invoices or update payment details without building UI yourself.
Offer a self-service experience that reduces support workload.
Request Headers
Content-Type
application/json
Authorization
Bearer <token>
Request Body
customerKey
string
Customer identifier.
Must start with cstmr_
.
returnToWebsiteLink
string (URL)
Optional absolute return URL.
A full URL where the customer is redirected after leaving the portal.
Must be a valid absolute URL (e.g., https://example.com/return
).
Response
{
"result": {
"portalRedirectLink": "{portalBaseUrl}/f1092c5c-b384-4058-aedb-6b9350fc58a7"
}
}
Webhooks
Overview
Paytiko sends webhooks to notify your system about important subscription events. There are two categories of webhook events:
Transaction status updates — covers payments, refunds, charge attempts, etc.
In the webhook payload, the
Action
field will be set to:"TRANSACTION_DATA_UPDATE"
Full reference for transaction webhooks can be found here.
Membership status updates — covers subscription lifecycle changes (e.g., activation, past due, cancellation).
In the webhook payload, the
Action
field will be set to:"SUBSCRIPTION_STATUS_CHANGE"
Detailed documentation for membership webhooks is provided below in this section.
Membership Status Update Webhook
What is it? A webhook sent whenever a membership (subscription) changes status. The payload includes the updated membership object and recent invoices for context.
How it works
Your
webhookUrl
(set during Create Membership) receives an HTTP POST with JSON.The
Status
field in the payload reflects the new, updated subscription status.You should update your local records and trigger any downstream logic (access enable/disable, emails, etc.).
Possible membership statuses
Active
PastDue
Unpaid
IncompleteExpired
Canceled
Completed
Only the status changes between events; the rest of the schema remains the same.
Delivery & Retries
Paytiko attempts to deliver each webhook event by sending an HTTP POST
request to the merchant’s configured webhookUrl
.
If your endpoint responds with an HTTP 2xx status code, the delivery is considered successful.
If your endpoint responds with a non-2xx status (e.g., 4xx, 5xx) or times out, the system will retry delivery.
Retry policy
Each webhook delivery has 1 initial attempt plus up to 6 retry attempts (7 attempts total).
A custom backoff schedule is applied:
The initial attempt is sent immediately.
The first retry is delayed by 5 minutes.
The second retry is delayed by 30 minutes.
Each subsequent retry doubles the delay (1 hour, 2 hours, 4 hours, 8 hours).
Attempt #1 — Initial — Immediate Attempt #2 — Retry #1 — 5 minutes Attempt #3 — Retry #2 — 30 minutes Attempt #4 — Retry #3 — 1 hour Attempt #5 — Retry #4 — 2 hours Attempt #6 — Retry #5 — 4 hours Attempt #7 — Retry #6 — 8 hours
If all retry attempts fail, the event is marked as undeliverable and no further retries will be attempted.
All retry scheduling is based on UTC time, ensuring consistent behavior across time zones and daylight saving changes.
Best practices
Always return a 2xx response as quickly as possible — queue the work internally if needed.
Log incoming
ActionId
andMembership.Key
values so you can reconcile missed events if a retry sequence is exhausted.Keep your webhook endpoint highly available and resilient to ensure timely state synchronization.
Payload Handling Recommendations
Respond with 2xx quickly. Process heavy work asynchronously.
Idempotency: use
ActionId
(or your own event ID map) to ignore duplicates.Security: verify authenticity (e.g., shared secret/signature) if your integration provides one.
Audit: log
Action
,ActionId
,Membership.Key
,Membership.Status
, andIssuedAt
.State sync: treat webhook as source of truth for membership state changes and update your DB accordingly.
Signature Verification
For security, every webhook request is signed so that your system can verify it originates from Paytiko and has not been tampered with.
How it’s generated
The signature is generated using SHA-256 hashing of the merchant’s secret key together with the membership’s OrderId
.
Formula:
Signature = SHA256("{SecretKey}:{OrderId}")
SecretKey
— your merchant’s private secret key (never exposed publicly).OrderId
— the order identifier associated with the membership or transaction.
Example
If your merchant secret key is:
sk_test_123456
and the OrderId
in the webhook payload is:
6a954f17-0eae-475c-9f51-8fc215abb512
then the string to be hashed is:
sk_test_123456:6a954f17-0eae-475c-9f51-8fc215abb512
The resulting SHA-256 hash will be the signature value you should compare against the one provided in the webhook headers.
Validation Steps
Extract the
OrderId
from the webhook payload.Concatenate your SecretKey and
OrderId
with a colon (:
).Generate the SHA-256 hash of this string.
Compare the result with the signature sent in the webhook header.
If they match → the webhook is authentic.
If not → reject the webhook.
IP Whitelisting
In addition to signature validation, you must also whitelist Paytiko’s official webhook source IP addresses in your firewall or API gateway.
Why this is required
Webhooks are sent over the public internet, and malicious actors could attempt to mimic Paytiko’s payload format.
Even if a payload looks correct, if it does not come from Paytiko’s trusted infrastructure, it must be rejected.
IP whitelisting ensures your server accepts webhook traffic only from Paytiko’s infrastructure.
How it works
Paytiko will provide a list of static outbound IP addresses.
Your system must configure these IPs as allowed sources for webhook requests.
Requests from any other IP must be blocked before signature validation is even attempted.
FAQ
Last updated
Was this helpful?