> For clean Markdown of any page, append .md to the page URL. > For a complete documentation index, see https://docs.solvimon.com/platform-guides/getting-started/onboarding-and-tutorials/bill-your-first-b2c-customer/llms.txt. > For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.solvimon.com/_mcp/server. # Bill your first B2C customer By the end of this tutorial a customer will have an active subscription and a finalized, paid first invoice. Solvimon will automatically generate and charge subsequent invoices each billing period. The full flow looks like this: 1. **Tokenize the card** in Adyen to get a stored payment method ID 2. **Create the customer** in Solvimon, linked to that Adyen shopper 3. **Initialize the subscription**, recording the first payment so the first invoice is immediately finalized and paid 4. **Set up webhooks** to handle future invoices and payment events **What you'll need:** * A Solvimon sandbox API key — see [Send your first API request](/platform-guides/getting-started/onboarding-and-tutorials/api-quickstart) * A pricing plan already created in your sandbox — [set one up in Desk](https://test.desk.solvimon.com/) first * A billing entity configured under **Settings → Billing entities** * An Adyen test account with a merchant account configured for recurring payments --- ## Step 1: Tokenize the card in Adyen Before creating the subscription, tokenize the customer's card details in Adyen. This stores the card and gives you a `recurring_detail_reference` you'll pass to Solvimon later. ### 1a. Submit the card payment to create the token ```bash curl -X POST https://checkout-test.adyen.com/v71/payments \ -H "X-API-KEY: " \ -H "Content-Type: application/json" \ -d '{ "amount": { "currency": "EUR", "value": 0 }, "paymentMethod": { "type": "scheme", "encryptedCardNumber": "test_4111111111111111", "encryptedExpiryMonth": "test_03", "encryptedExpiryYear": "test_2030", "encryptedSecurityCode": "test_737" }, "merchantAccount": "Adyen_B2C_Subscriptions", "recurringProcessingModel": "Subscription", "reference": "card_cust_1", "shopperReference": "cust_1", "storePaymentMethod": true }' ``` * `shopperReference`: Your identifier for this customer in Adyen. You'll use this same value as the Solvimon `custom_fields` reference in Step 2. * `storePaymentMethod: true`: Tells Adyen to store the card for future recurring charges. * `recurringProcessingModel: "Subscription"`: Required for subscription-type recurring payments. ### 1b. Retrieve the stored payment method ID ```bash curl -X POST https://checkout-test.adyen.com/v71/paymentMethods \ -H "X-API-KEY: " \ -H "Content-Type: application/json" \ -d '{ "merchantAccount": "Adyen_B2C_Subscriptions", "shopperReference": "cust_1" }' ``` Response: ```json { "storedPaymentMethods": [ { "id": "WC43X3RL9ZD3LTT5", "lastFour": "1111", "name": "VISA" } ] } ``` Note the `id` — this is the `recurring_detail_reference` you'll use in Step 3. --- ## Step 2: Create the customer Create the customer in Solvimon and link them to the Adyen shopper via `custom_fields`. Solvimon uses this to know which PSP payment methods belong to this customer. ```bash curl -X POST https://test.api.solvimon.com/v1/customers \ -H "X-API-KEY: " \ -H "Content-Type: application/json" \ -d '{ "reference": "cust_1", "type": "INDIVIDUAL", "email": "john.doe@gmail.com", "roles": ["DEFAULT"], "individual": { "name": { "first_name": "John", "last_name": "Doe" }, "residential_address": { "country": "NL" } }, "custom_fields": [ { "reference": "PAYMENT_GATEWAY:ADYEN:SHOPPER_REFERENCE", "value": "cust_1" } ] }' ``` **Parameter notes:** * `reference`: Your identifier for this customer. Used to reference them in subsequent API calls. * `custom_fields.reference`: The key identifying which PSP this links to. * `PAYMENT_GATEWAY:ADYEN:SHOPPER_REFERENCE` — for Adyen * `PAYMENT_GATEWAY:STRIPE:CUSTOMER_ID` — for Stripe (use the Stripe `cus_...` ID as the value) * `custom_fields.value`: The customer's identifier in the PSP system — must match the `shopperReference` used in Step 1. > **Note** > > 📘 You can only use payment methods that were created under the `shopperReference` set in `custom_fields`. Solvimon will reject payment attempts using methods belonging to a different shopper. > **Note** > > 📘 See the [Customers API reference](/api-docs/configuration-api/customers/get-a-list-of-all-customers) for all available fields. --- ## Step 3: Initialize the subscription `/init` creates the subscription and its first schedule in a single call. Providing `first_payment` tells Solvimon that the customer already paid (e.g. as part of checkout), which automatically finalizes the first invoice as paid. The `payment_method` stores the card so Solvimon can auto-charge future invoices. ```bash curl -X POST https://test.api.solvimon.com/v1/pricing-plan-subscriptions/init \ -H "X-API-KEY: " \ -H "Content-Type: application/json" \ -d '{ "pricing_plan_subscription": { "reference": "cust_1_monthly_eur_20240915", "customer_reference": "cust_1", "billing_entity_reference": "entity_nl", "billing_time": "EXACT", "billing_currency": "EUR" }, "pricing_plan_schedules": [ { "pricing_plan_version_selector": { "pricing_plan_reference": "monthly_eur" }, "start_at": "2024-09-15T00:00:00Z", "end_at": "2025-09-15T00:00:00Z" } ], "first_payment": { "payment_acceptor_reference": "adyen_b2c_subscriptions", "external_reference": "N9KKLBTLMJS8F6V5", "amount": { "quantity": "9.99", "currency": "EUR" }, "result": "AUTHORIZED" }, "payment_method": { "type": "CARD", "card": { "brand": "VISA", "last_four_digits": "1111" }, "integration_reference": "adyen", "integration_details": { "payment_gateway_variant": "ADYEN", "adyen": { "recurring_detail_reference": "WC43X3RL9ZD3LTT5" } } } }' ``` **Parameter notes:** `pricing_plan_subscription`: * `reference`: Your identifier for this subscription. * `customer_reference`: The reference of the customer created in Step 2. * `billing_entity_reference`: The billing entity this subscription is invoiced from. * `billing_time: "EXACT"`: Billing occurs on the same day of the month as `start_at` — e.g. if the subscription starts on the 15th, every subsequent invoice is on the 15th. Recommended for B2C. * `billing_currency`: The currency used for all invoices on this subscription. `pricing_plan_schedules`: * `pricing_plan_version_selector.pricing_plan_reference`: The pricing plan to use. By default the latest `ACTIVE` version is used. * `start_at`: Set to the date the customer paid and activated the subscription. * `end_at`: Optional. When set, the subscription ends and no further invoices are generated after this date. `first_payment`: * Use this when the first payment was collected outside of Solvimon (e.g. during your checkout flow). Providing it causes Solvimon to automatically finalize the first invoice as paid. * `external_reference`: The transaction reference from your PSP for this payment. * `result: "AUTHORIZED"`: Confirms the payment succeeded. `payment_method`: * `integration_reference`: The reference to the [payment provider integration](/integrations/paymentserviceproviders) configured in Solvimon. * `integration_details.adyen.recurring_detail_reference`: The stored payment method ID from Step 1b. Solvimon uses this to charge the customer's card for future invoices. > **Tip** > > **Default billing terms:** Instead of specifying `billing_time`, `billing_currency`, and `billing_period` on every subscription, you can configure defaults under [Settings → Default platform settings](/platform-guides/platform-configuration/default-platform-settings). They apply automatically when those fields are omitted. > **Tip** > > **Skipping payment collection?** Omit `first_payment` and `payment_method`. The subscription and schedule are still created and invoices will be generated — just not auto-charged. --- ## Alternative: Create customer and subscription in one call If you want to create or update the customer at the same time as initializing the subscription, pass a `customer` object directly in the init request instead of a `customer_reference`: ```bash curl -X POST https://test.api.solvimon.com/v1/pricing-plan-subscriptions/init \ -H "X-API-KEY: " \ -H "Content-Type: application/json" \ -d '{ "customer": { "reference": "cust_1", "type": "INDIVIDUAL", "email": "john.doe@gmail.com", "roles": ["DEFAULT"], "individual": { "name": { "first_name": "John", "last_name": "Doe" }, "residential_address": { "country": "NL" } }, "custom_fields": [ { "reference": "PAYMENT_GATEWAY:ADYEN:SHOPPER_REFERENCE", "value": "cust_1" } ] }, "pricing_plan_subscription": { "reference": "cust_1_monthly_eur_20240915", "billing_entity_reference": "entity_nl", "billing_time": "EXACT", "billing_currency": "EUR" }, "pricing_plan_schedules": [ { "pricing_plan_version_selector": { "pricing_plan_reference": "monthly_eur" }, "start_at": "2024-09-15T00:00:00Z", "end_at": "2025-09-15T00:00:00Z" } ], "first_payment": { "payment_acceptor_reference": "adyen_b2c_subscriptions", "external_reference": "N9KKLBTLMJS8F6V5", "amount": { "quantity": "9.99", "currency": "EUR" }, "result": "AUTHORIZED" }, "payment_method": { "type": "CARD", "card": { "brand": "VISA", "last_four_digits": "1111" }, "integration_reference": "adyen", "integration_details": { "payment_gateway_variant": "ADYEN", "adyen": { "recurring_detail_reference": "WC43X3RL9ZD3LTT5" } } } }' ``` Note that `customer_reference` is omitted from `pricing_plan_subscription` — the customer is identified via the `customer.reference` field instead. If a customer with that reference already exists, it will be updated. --- ## Step 4: Handle invoice and payment webhooks Solvimon calls your endpoint when invoices and payments change state. Configure a webhook under **Settings → Webhooks**. For a B2C subscription, handle these two events: | Event | When it fires | What to do | | ------------------- | ----------------------------- | ---------------------------------------------------------------- | | `invoice.finalized` | Invoice status moves to FINAL | Send a receipt, confirm the billing period in your system | | `payment.created` | A payment attempt is made | Check `result` — provision access on success, suspend on failure | You can use a single webhook endpoint for both events. > **Note** > > See the [Webhooks guide](/platform-guides/for-developers/webhooks) for payload shapes and verification. --- ## Step 5: Manage the subscription over time **Cancel at period end** — set `end_at` on the current schedule: ```bash curl -X PATCH https://test.api.solvimon.com/v1/pricing-plan-schedules/ \ -H "X-API-KEY: " \ -H "Content-Type: application/json" \ -d '{ "end_at": "2025-09-15T00:00:00Z" }' ``` **Upgrade to a new plan** — add a second schedule starting at the changeover date: ```bash curl -X POST https://test.api.solvimon.com/v1/pricing-plan-schedules \ -H "X-API-KEY: " \ -H "Content-Type: application/json" \ -d '{ "pricing_plan_subscription_reference": "cust_1_monthly_eur_20240915", "pricing_plan_version_selector": { "pricing_plan_reference": "new_plan_reference" }, "start_at": "2025-09-15T00:00:00Z" }' ``` **Update the payment method** — patch the subscription with the new `payment_method_id` when a customer updates their card. The updated method will be used for all subsequent invoices.