> ## Documentation Index
> Fetch the complete documentation index at: https://docs.flouci.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Create Subscription

> Create a recurring subscription and get the hosted checkout link where the customer approves and pays the first charge.

This endpoint creates a subscription in the `incomplete` state together with its first charge, and returns the checkout link to redirect your customer to. The subscription becomes `active` once that first charge is paid — see the [lifecycle](/api-reference/recurring-payments/overview#lifecycle).

<RequestExample>
  ```bash cURL theme={null}
  curl -X POST 'https://developers.flouci.com/api/v2/subscriptions' \
    -H 'Authorization: Bearer <PUBLIC_KEY>:<PRIVATE_KEY>' \
    -H 'Content-Type: application/json' \
    -d '{
      "amount": 15000,
      "interval": "month",
      "interval_count": 1,
      "name": "Gold plan",
      "description": "Full access, billed monthly",
      "developer_tracking_id": "sub-2026-000418",
      "client_id": "customer-9f3a",
      "success_link": "https://your-website.com/subscriptions/success",
      "fail_link": "https://your-website.com/subscriptions/fail",
      "webhook": "https://your-website.com/flouci/webhooks"
    }'
  ```
</RequestExample>

### Body

<ParamField body="amount" type="integer" required>
  Amount debited at each cycle, in millimes. Minimum `100`.
</ParamField>

<ParamField body="currency" type="string" default="TND">
  Only `TND` is accepted.
</ParamField>

<ParamField body="interval" type="string" required>
  Billing cadence unit: `day`, `week`, `month` or `year`.
</ParamField>

<ParamField body="interval_count" type="integer" default="1">
  Number of `interval` units per cycle. A cycle may not exceed one year: at most `366` for `day`, `52` for `week`, `12` for `month`, `1` for `year`.
</ParamField>

<ParamField body="name" type="string" required>
  Plan name shown on the checkout and in the customer's app. Maximum 50 characters.
</ParamField>

<ParamField body="description" type="string">
  Optional description, maximum 200 characters.
</ParamField>

<ParamField body="developer_tracking_id" type="string" required>
  Your reference for this subscription, 1–50 characters. **Unique per merchant**: repeating one returns HTTP 409 with the existing subscription instead of creating a second one.
</ParamField>

<ParamField body="success_link" type="string" required>
  HTTPS URL the customer is redirected to after paying the first charge.
</ParamField>

<ParamField body="fail_link" type="string" required>
  HTTPS URL the customer is redirected to when the first charge fails or expires.
</ParamField>

<ParamField body="webhook" type="string">
  HTTPS URL that receives the signed [subscription events](/api-reference/recurring-payments/webhooks). Strongly recommended — it is the only way to learn about renewals without polling.
</ParamField>

<ParamField body="session_timeout" type="integer" default="1200">
  How long the customer has to pay the first charge, in seconds. Between `1200` and `7200`. After that the subscription becomes `incomplete_expired`.
</ParamField>

<ParamField body="client_id" type="string">
  Your identifier for the customer, maximum 255 characters. Lets you filter [List Subscriptions](/api-reference/recurring-payments/list-subscriptions) by customer.
</ParamField>

<ParamField body="max_cycles" type="integer">
  Total number of payments to collect (installments), first charge included. Omit for an open-ended subscription. When the last payment is collected the subscription is canceled with `cancellation_reason: completed`.
</ParamField>

<ParamField body="accept_card" type="boolean" default="false">
  Card subscriptions are coming soon. Sending `true` is refused with `card_recurring_not_enabled` unless card recurring is enabled on your affiliation.
</ParamField>

<ResponseExample>
  ```json Success theme={null}
  {
    "result": {
      "success": true,
      "subscription_id": "s7Qm3kLpTq2e9hZx0bYw1A",
      "payment_id": "AgCKuBm0S5uLPghBo571MQ",
      "link": "https://checkout.flouci.com/company_name/AgCKuBm0S5uLPghBo571MQ",
      "status": "incomplete",
      "developer_tracking_id": "sub-2026-000418"
    },
    "name": "developers",
    "code": 0,
    "version": "v2"
  }
  ```

  ```json Duplicate (409) theme={null}
  {
    "result": {
      "success": false,
      "error": "duplicate_developer_tracking_id",
      "details": "duplicate_developer_tracking_id",
      "subscription_id": "s7Qm3kLpTq2e9hZx0bYw1A",
      "payment_id": "AgCKuBm0S5uLPghBo571MQ",
      "link": "https://checkout.flouci.com/company_name/AgCKuBm0S5uLPghBo571MQ"
    },
    "name": "developers",
    "code": 1,
    "version": "1.0.0"
  }
  ```

  ```json Invalid field (400) theme={null}
  {
    "interval_count": [
      "interval_count for 'month' must be at most 12 (one year)."
    ]
  }
  ```

  ```json Refused by the platform (400) theme={null}
  {
    "result": {
      "success": false,
      "error": "card_recurring_not_enabled",
      "details": "card_recurring_not_enabled"
    },
    "name": "developers",
    "code": 1,
    "version": "1.0.0"
  }
  ```
</ResponseExample>

### Response Fields

<ResponseField name="subscription_id" type="string" required>
  Identifier of the subscription. Use it on every other subscription endpoint.
</ResponseField>

<ResponseField name="payment_id" type="string" required>
  Identifier of the first charge. You can follow it with [Verify Payment](/api-reference/verify-transaction) like any payment.
</ResponseField>

<ResponseField name="link" type="string" required>
  Hosted checkout URL to redirect the customer to.
</ResponseField>

<ResponseField name="status" type="string" required>
  Always `incomplete` at creation.
</ResponseField>

### Errors

Two shapes: a field that fails validation comes back as `{"<field>": ["<reason>"]}` (no envelope); a refusal by the platform comes back enveloped, with the code in `result.error`.

| HTTP | Where · code | Meaning |
| - | - | - |
| 400 | field `amount` | Below 100 millimes, or not a number. |
| 400 | field `currency` | Not `TND` — subscriptions are TND only. |
| 400 | field `interval` / `interval_count` | Unknown unit, or the cycle exceeds one year (`interval_count for 'month' must be at most 12 (one year).`). |
| 400 | field `session_timeout` | Outside 1200–7200 seconds. |
| 400 | field `destination` | Split payments cannot be attached to a subscription. |
| 400 | field `success_link` / `fail_link` / `webhook` | Not an `https` URL. |
| 400 | `result.error` = `card_recurring_not_enabled` | `accept_card: true` while card recurring is not enabled on your affiliation. |
| 400 | `result.error` = `card_recurring_not_implemented` | Card recurring is enabled for you but not yet live. |
| 403 | `result.error` = `merchant_not_allowed` / `merchant_wallet_inactive` / `affiliation_inactive` | Your account cannot create subscriptions right now — [contact support](/essentials/debug-support). |
| 409 | `result.error` = `duplicate_developer_tracking_id` | A subscription with this `developer_tracking_id` exists; its ids are returned in `result`. |
| 429 | `detail` | More than 60 creations per minute for this app (`Request was throttled…`). |
| 503 | `result.error` = `recurring_payments_disabled` | Recurring payments are temporarily paused platform-wide. Retry later. |

<Warning>
  Treat a 409 as success for your retry logic: read `result.subscription_id` and `result.link` rather than generating a new `developer_tracking_id`.
</Warning>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.