Create and Confirm Subscription
Create a subscription and take the first payment in one request. Use this when your server has the card details or a saved payment method. To collect the card on a checkout page instead, use Create Subscription and Confirm Subscription.
POST /subscriptions
The first period is charged immediately. If the payment succeeds, the subscription is active, the card is saved, and the next charge is scheduled for the end of the first period.
Headers
| Header | Type | Required | Description |
|---|---|---|---|
api-key | string | Yes | Your secret API key. |
X-Profile-Id | string | No | Business profile to create the subscription under, when profile_id is not in the body. Leave both out to use your default profile. |
Body Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
profile_id | string | No | Business profile the subscription belongs to. It decides which connector charges the subscription and which webhook URL receives its events. If left out, the X-Profile-Id header is used, then your default profile, as on Create Payment. Send it if your account has no default profile. |
merchant_reference_id | string | Yes | Your unique reference for this subscription, such as your order ID. A second create with the same reference is refused while the first subscription is not failed, so a retried request cannot charge twice. |
customer_id | string | Yes | ID of the customer. Must exist unless customer is also sent. |
customer | object | No | Details for a customer that does not exist yet. See Customer. |
amount | integer | Yes | Amount charged every period, in the smallest currency unit (e.g. 1500 for $15.00). Must be greater than zero. |
currency | string | Yes | Three-letter ISO 4217 currency code (e.g. USD). |
billing_interval | string | Yes | Length of a billing period: day, week, month or year. |
interval_count | integer | Yes | Number of billing_interval units in one period. 1 with month bills monthly; 3 with month bills quarterly. At least 1. |
total_billing_cycles | integer | No | Total number of payments, including the first. The subscription ends by itself after the last one. Leave out for a subscription that renews until cancelled. |
payment_details | object | Yes | How to take the first payment. See Payment details. |
billing | object | No | Billing address, passed to the first payment. |
shipping | object | No | Shipping address, passed to the first payment. |
plan_id | string | No | Your own plan label. Stored and returned; it does not change the price. |
item_price_id | string | No | Your own price label. Stored and returned; it does not change the price. |
Customer
| Field | Type | Description |
|---|---|---|
name | string | Customer's name. |
email | string | Customer's email address. |
phone | string | Phone number without the country code. |
phone_country_code | string | Country code of the phone number (e.g. +1). |
If customer_id does not exist and at least one of these fields is set, the customer is created with them before the subscription. If the customer already exists, these fields are ignored and the customer is not changed.
Payment details
| Field | Type | Required | Description |
|---|---|---|---|
payment_method | string | With a new card | card. |
payment_method_type | string | No | credit or debit. |
payment_method_data | object | Yes* | The card: card_number, card_exp_month, card_exp_year, card_holder_name, card_cvc. |
payment_method_id | string | Yes* | A card the customer already saved. Use instead of payment_method_data. |
setup_future_usage | string | With a new card | Must be off_session so the card is saved for renewals. |
customer_acceptance | object | With a new card | Record of the customer agreeing to future charges: acceptance_type (online), accepted_at, and online.ip_address and online.user_agent. Without it the card is not saved and no renewal could be charged, so new card details without it are refused (IR_06). |
authentication_type | string | No | three_ds or no_three_ds. |
return_url | string | No | Where the customer is sent after a 3D Secure challenge. |
browser_info | object | No | Browser details for 3D Secure and fraud checks: ip_address, user_agent, accept_header, language, color_depth, screen_height, screen_width, time_zone, java_enabled, java_script_enabled. |
* Send either payment_method_data (a new card) or payment_method_id (a card the customer already saved).
3D Secure. If the card needs authentication, the response has status: "created" and payment.next_action holds a redirect URL. Redirect the customer there. After they complete it, the subscription becomes active and you receive invoice_paid.
Request Example
curl -X POST 'https://api.moonlinkpay.com/subscriptions' \ -H "Content-Type: application/json" \ -H "api-key: snd_YOUR_API_KEY" \ -d '{ "profile_id": "pro_YOUR_PROFILE_ID", "merchant_reference_id": "order_1001", "customer_id": "cus_jane_42", "customer": { "name": "Jane Doe", "email": "jane@example.com" }, "amount": 1500, "currency": "USD", "billing_interval": "month", "interval_count": 1, "total_billing_cycles": 12, "payment_details": { "payment_method": "card", "payment_method_type": "credit", "setup_future_usage": "off_session", "authentication_type": "no_three_ds", "return_url": "https://example.com/return", "payment_method_data": { "card": { "card_number": "4242424242424242", "card_exp_month": "12", "card_exp_year": "30", "card_holder_name": "Jane Doe", "card_cvc": "123" } }, "customer_acceptance": { "acceptance_type": "online", "accepted_at": "2026-11-03T10:00:00Z", "online": { "ip_address": "203.0.113.10", "user_agent": "Mozilla/5.0" } } }}'Response
{"id": "sub_YZQbEYEnzrjzBorzniG3","merchant_reference_id": "order_1001","status": "active","customer_id": "cus_jane_42","profile_id": "pro_YOUR_PROFILE_ID","total_billing_cycles": 12,"remaining_billing_cycles": 11,"billing_cycle_count": 0,"next_billing_at": "2026-12-03T18:01:10.526Z","cancel_at_period_end": false,"plan_id": null,"item_price_id": null,"payment": { "payment_id": "sub_7f12f1899ad117a4798ca211_0_0", "status": "succeeded", "amount": 1500, "currency": "USD", "payment_method_id": "pm_lyJgCvOfYecQKaH1acPk", "payment_method_type": "credit", "next_action": null, "error_code": null, "error_message": null},"invoice": { "id": "invoice_8wGNC5ismdSdKrTe3czi", "subscription_id": "sub_YZQbEYEnzrjzBorzniG3", "payment_intent_id": "sub_7f12f1899ad117a4798ca211_0_0", "amount": 1500, "currency": "USD", "status": "invoice_paid", "billing_cycle_count": 0, "period_start": "2026-11-03T18:01:10.526Z", "period_end": "2026-12-03T18:01:10.526Z", "attempt_count": 0, "last_error_code": null, "last_error_message": null}}next_billing_at is when the next renewal is charged. billing_cycle_count counts completed renewals: 0 after signup, 1 after the first renewal. remaining_billing_cycles is how many payments are left when total_billing_cycles is set.
Errors
| Code | When |
|---|---|
HE_01 | A subscription with this merchant_reference_id already exists. |
HE_02 | customer_id does not exist and no customer details were sent, or profile_id is not one of your business profiles. |
IR_06 | A field is missing or invalid, for example setup_future_usage is not off_session, an unknown field was sent, new card details were sent without customer_acceptance, or profile_id and X-Profile-Id name different profiles. |
IR_04 | No profile was given and your account has no default profile. |
If the payment is refused before reaching the card network, for example by fraud screening, the response carries that error and the subscription ends as failed. A declined first payment also ends as failed: create a new subscription to try again. You can reuse the same merchant_reference_id.