openapi: 3.2.0 info: title: Vatly API version: '1.0' description: | Vatly is a Merchant of Record billing platform for European SaaS companies. This API enables you to manage checkouts, customers, orders, subscriptions, refunds, and more. ## Authentication The Vatly API uses Bearer token authentication. All API requests must include an `Authorization` header: ``` Authorization: Bearer {your_api_token} ``` ### Live vs Test Mode API tokens determine the environment mode: - Tokens prefixed with `live_` access **production** data - Tokens prefixed with `test_` access **sandbox** data Resources created in one mode cannot be accessed or referenced from the other mode. For example, a checkout created with a test token cannot reference a customer created with a live token. ## Pagination List endpoints use cursor-based pagination with the following query parameters: | Parameter | Type | Description | |-----------|------|-------------| | `limit` | integer | Number of results per page (default: 10, max: 100) | | `startingAfter` | string | Cursor ID to fetch results after | | `endingBefore` | string | Cursor ID to fetch results before | `startingAfter` and `endingBefore` are mutually exclusive. All list responses are wrapped in a pagination envelope: ```json { "data": [ ... ], "count": 2, "links": { "self": { "href": "https://api.vatly.com/v1/orders", "type": "application/json" }, "next": { "href": "https://api.vatly.com/v1/orders?startingAfter=order_abc", "type": "application/json" }, "prev": null } } ``` ## Money Format All monetary values are represented as objects with `value` (string) and `currency` (ISO 4217 code): ```json { "value": "99.99", "currency": "EUR" } ``` Values are strings to preserve decimal precision. ## Errors The API returns standard HTTP status codes and JSON error responses: | Status | Description | |--------|-------------| | 400 | Bad Request - Invalid request format | | 401 | Unauthorized - Missing or invalid token | | 403 | Forbidden - Token invalid or insufficient permissions | | 404 | Not Found - Resource doesn't exist | | 422 | Unprocessable Entity - Validation failed | | 429 | Too Many Requests - Rate limit exceeded | | 500 | Internal Server Error | contact: name: Vatly Support url: https://vatly.com email: support@vatly.com license: name: Proprietary url: https://vatly.com/terms servers: - url: https://api.vatly.com/v1 description: Production API - url: https://api.staging.vatly.com/v1 description: Staging API security: - BearerAuth: [] tags: - name: Checkouts description: | Create and manage hosted checkout sessions. Checkouts allow customers to purchase one-off products and subscription plans through a hosted payment page. - name: Customers description: | Manage customer records. Customers are identified by email and can have multiple subscriptions and orders. - name: One-Off Products description: | View available one-off products. Products are configured in the Vatly dashboard and can be added to checkouts. - name: Subscription Plans description: | View available subscription plans. Plans define recurring billing intervals and pricing. - name: Orders description: | View orders and request invoice address updates. Orders are created when checkouts complete or subscriptions renew. - name: Refunds description: | Create and manage refunds for paid orders. Supports both partial (per-item) and full refunds. - name: Chargebacks description: | View chargebacks initiated by payment providers. Chargebacks are created automatically when a customer disputes a payment. - name: Subscriptions description: | Manage customer subscriptions. Update plans, quantities, billing details, or cancel subscriptions. - name: Webhook Events description: | View webhook events that were sent to your webhook endpoints. Each event contains the full resource payload at the time the event occurred. - name: Test Helpers description: | Sandbox-only endpoints for simulating billing events. These endpoints require a `test_` prefixed API token. paths: /checkouts: get: operationId: listCheckouts summary: List all checkouts description: | Returns a paginated list of checkouts for the authenticated merchant. Results are filtered by the testmode determined from the API token. tags: - Checkouts parameters: - $ref: '#/components/parameters/limit' - $ref: '#/components/parameters/startingAfter' - $ref: '#/components/parameters/endingBefore' responses: '200': description: List of checkouts content: application/json: schema: type: object required: - data - count - links properties: data: type: array items: $ref: '#/components/schemas/Checkout' count: type: integer description: Number of items in the current page example: 1 links: $ref: '#/components/schemas/PaginationLinks' example: data: - id: checkout_QdEpFhdSrG4Y3DnfsdqsH resource: checkout orderId: null testmode: false redirectUrlSuccess: https://example.com/success redirectUrlCanceled: https://example.com/canceled metadata: {} status: created expiresAt: '2024-01-16T10:30:00Z' createdAt: '2024-01-15T10:30:00Z' links: checkoutUrl: href: https://checkout.vatly.com/checkout_QdEpFhdSrG4Y3DnfsdqsH type: text/html self: href: https://api.vatly.com/v1/checkouts/checkout_QdEpFhdSrG4Y3DnfsdqsH type: application/json order: null count: 1 links: self: href: https://api.vatly.com/v1/checkouts type: application/json next: null prev: null '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '422': $ref: '#/components/responses/ValidationFailed' post: operationId: createCheckout summary: Create a checkout description: | Creates a new hosted checkout session. The checkout URL in the response can be used to redirect customers to complete their purchase. Checkouts expire after a configurable period (default: 24 hours). **Products:** - Include one or more products using their `prod_` or `plan_` IDs - Mix one-off products and subscription plans in the same checkout - Override prices for specific products using the `price` field - Add trial periods to subscription plans using `trialDays` **Customer association:** - Optionally link to an existing customer using `customerId` - If not provided, a new customer is created based on checkout form input tags: - Checkouts requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreateCheckoutRequest' examples: oneOffProduct: summary: Checkout with one-off product value: redirectUrlSuccess: https://example.com/success redirectUrlCanceled: https://example.com/canceled products: - id: one_off_product_Vr8kQdFhSrG4Y3DnfsdqH quantity: 1 subscriptionWithTrial: summary: Subscription plan with trial value: redirectUrlSuccess: https://example.com/success redirectUrlCanceled: https://example.com/canceled customerId: customer_Fp2kQrSvWm8NjLhYbUcP products: - id: subscription_plan_Bm7xNvPwKr3YjTgHcZaE trialDays: 14 customPrice: summary: Product with custom price value: redirectUrlSuccess: https://example.com/success redirectUrlCanceled: https://example.com/canceled products: - id: one_off_product_Vr8kQdFhSrG4Y3DnfsdqH quantity: 2 price: value: '49.99' currency: EUR metadata: campaign: summer-sale responses: '201': description: Checkout created successfully content: application/json: schema: $ref: '#/components/schemas/Checkout' example: id: checkout_Bm7xNvPwKr3YjTgHcZaE resource: checkout orderId: null testmode: false redirectUrlSuccess: https://example.com/success redirectUrlCanceled: https://example.com/canceled metadata: campaign: summer-sale status: created expiresAt: '2024-01-16T10:30:00Z' createdAt: '2024-01-15T10:30:00Z' links: checkoutUrl: href: https://checkout.vatly.com/checkout_Bm7xNvPwKr3YjTgHcZaE type: text/html self: href: https://api.vatly.com/v1/checkouts/checkout_Bm7xNvPwKr3YjTgHcZaE type: application/json order: null '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '422': $ref: '#/components/responses/ValidationFailed' /checkouts/{checkoutId}: get: operationId: getCheckout summary: Get a checkout description: | Retrieves a specific checkout by its ID. Use this to check the status of a checkout or get the order ID after completion. tags: - Checkouts parameters: - $ref: '#/components/parameters/checkoutId' responses: '200': description: Checkout details content: application/json: schema: $ref: '#/components/schemas/Checkout' example: id: checkout_QdEpFhdSrG4Y3DnfsdqsH resource: checkout orderId: order_Jk4pQrSvWm8NjLhYbUcP testmode: false redirectUrlSuccess: https://example.com/success redirectUrlCanceled: https://example.com/canceled metadata: campaign: summer-sale status: paid expiresAt: '2024-01-16T10:30:00Z' createdAt: '2024-01-15T10:30:00Z' links: checkoutUrl: href: https://checkout.vatly.com/checkout_QdEpFhdSrG4Y3DnfsdqsH type: text/html self: href: https://api.vatly.com/v1/checkouts/checkout_QdEpFhdSrG4Y3DnfsdqsH type: application/json order: href: https://api.vatly.com/v1/orders/order_Jk4pQrSvWm8NjLhYbUcP type: application/json '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' /customers: get: operationId: listCustomers summary: List all customers description: | Returns a paginated list of customers for the authenticated merchant. Results are filtered by the testmode determined from the API token. tags: - Customers parameters: - $ref: '#/components/parameters/limit' - $ref: '#/components/parameters/startingAfter' - $ref: '#/components/parameters/endingBefore' responses: '200': description: List of customers content: application/json: schema: type: object required: - data - count - links properties: data: type: array items: $ref: '#/components/schemas/Customer' count: type: integer description: Number of items in the current page example: 2 links: $ref: '#/components/schemas/PaginationLinks' example: data: - id: customer_7kBmRtPvXw2NjLhYcZaE resource: customer testmode: false email: john.doe@example.com createdAt: '2024-01-15T10:30:00Z' metadata: userId: user_Qp8kNvBxKw7RjTgYcZaE links: self: href: https://api.vatly.com/v1/customers/customer_7kBmRtPvXw2NjLhYcZaE type: application/json - id: customer_Lp3mNvBxKw7RjTgYcZaE resource: customer testmode: false email: jane.smith@acme.com createdAt: '2024-01-10T08:15:00Z' metadata: {} links: self: href: https://api.vatly.com/v1/customers/customer_Lp3mNvBxKw7RjTgYcZaE type: application/json count: 2 links: self: href: https://api.vatly.com/v1/customers type: application/json next: null prev: null '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '422': $ref: '#/components/responses/ValidationFailed' post: operationId: createCustomer summary: Create a customer description: | Creates a new customer record. Customers are uniquely identified by email within each testmode. Creating a customer with an email that already exists will return a validation error. **Use cases:** - Pre-create customers before checkout - Link existing users from your system to Vatly tags: - Customers requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreateCustomerRequest' example: email: customer@example.com metadata: userId: user_Qp8kNvBxKw7RjTgYcZaE responses: '201': description: Customer created successfully content: application/json: schema: $ref: '#/components/schemas/Customer' example: id: customer_7kBmRtPvXw2NjLhYcZaE resource: customer testmode: false email: customer@example.com createdAt: '2024-01-15T10:30:00Z' metadata: userId: user_Qp8kNvBxKw7RjTgYcZaE links: self: href: https://api.vatly.com/v1/customers/customer_7kBmRtPvXw2NjLhYcZaE type: application/json '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '422': $ref: '#/components/responses/ValidationFailed' /customers/{customerId}: get: operationId: getCustomer summary: Get a customer description: Retrieves a specific customer by their ID. tags: - Customers parameters: - $ref: '#/components/parameters/customerId' responses: '200': description: Customer details content: application/json: schema: $ref: '#/components/schemas/Customer' example: id: customer_7kBmRtPvXw2NjLhYcZaE resource: customer testmode: false email: john.doe@example.com createdAt: '2024-01-15T10:30:00Z' metadata: userId: user_Qp8kNvBxKw7RjTgYcZaE links: self: href: https://api.vatly.com/v1/customers/customer_7kBmRtPvXw2NjLhYcZaE type: application/json '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' /customers/{customerId}/subscriptions: get: operationId: listCustomerSubscriptions summary: List customer subscriptions description: | Returns a paginated list of subscriptions for a specific customer. Includes subscriptions in all states (active, canceled, etc.). tags: - Customers - Subscriptions parameters: - $ref: '#/components/parameters/customerId' - $ref: '#/components/parameters/limit' - $ref: '#/components/parameters/startingAfter' - $ref: '#/components/parameters/endingBefore' responses: '200': description: List of customer's subscriptions content: application/json: schema: type: object required: - data - count - links properties: data: type: array items: $ref: '#/components/schemas/Subscription' count: type: integer description: Number of items in the current page example: 1 links: $ref: '#/components/schemas/PaginationLinks' example: data: - id: subscription_Lp3mNvBxKw7RjTgYcZaE resource: subscription customerId: customer_Lp3mNvBxKw7RjTgYcZaE testmode: false name: Pro Monthly description: Full access to all Pro features billingAddress: fullName: John Doe companyName: Acme Corp streetAndNumber: 123 Main Street city: Berlin postalCode: '10115' country: DE basePrice: value: '29.00' currency: EUR quantity: 1 interval: month intervalCount: 1 status: active startedAt: '2024-01-15T10:30:00Z' endedAt: null cancelledAt: null renewedAt: '2024-02-15T10:30:00Z' renewedUntil: '2024-03-15T10:30:00Z' nextRenewalAt: '2024-03-15T10:30:00Z' trialUntil: null links: self: href: https://api.vatly.com/v1/subscriptions/subscription_Lp3mNvBxKw7RjTgYcZaE type: application/json customer: href: https://api.vatly.com/v1/customers/customer_Lp3mNvBxKw7RjTgYcZaE type: application/json count: 1 links: self: href: https://api.vatly.com/v1/customers/customer_Lp3mNvBxKw7RjTgYcZaE/subscriptions type: application/json next: null prev: null '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '422': $ref: '#/components/responses/ValidationFailed' /customers/{customerId}/subscriptions/{subscriptionId}: get: operationId: getCustomerSubscription summary: Get a customer subscription description: | Retrieves a specific subscription for a customer. The subscription must belong to the specified customer. tags: - Customers - Subscriptions parameters: - $ref: '#/components/parameters/customerId' - $ref: '#/components/parameters/subscriptionId' responses: '200': description: Subscription details content: application/json: schema: $ref: '#/components/schemas/Subscription' example: id: subscription_Lp3mNvBxKw7RjTgYcZaE resource: subscription customerId: customer_Lp3mNvBxKw7RjTgYcZaE testmode: false name: Pro Monthly description: Full access to all Pro features billingAddress: fullName: John Doe companyName: Acme Corp streetAndNumber: 123 Main Street city: Berlin postalCode: '10115' country: DE basePrice: value: '29.00' currency: EUR quantity: 1 interval: month intervalCount: 1 status: active startedAt: '2024-01-15T10:30:00Z' endedAt: null cancelledAt: null renewedAt: '2024-02-15T10:30:00Z' renewedUntil: '2024-03-15T10:30:00Z' nextRenewalAt: '2024-03-15T10:30:00Z' trialUntil: null links: self: href: https://api.vatly.com/v1/subscriptions/subscription_Lp3mNvBxKw7RjTgYcZaE type: application/json customer: href: https://api.vatly.com/v1/customers/customer_Lp3mNvBxKw7RjTgYcZaE type: application/json '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' /one-off-products: get: operationId: listOneOffProducts summary: List all one-off products description: | Returns a paginated list of one-off products for the authenticated merchant. Results are filtered by the testmode determined from the API token. Only products with `active` status can be used in checkouts. tags: - One-Off Products parameters: - $ref: '#/components/parameters/limit' - $ref: '#/components/parameters/startingAfter' - $ref: '#/components/parameters/endingBefore' responses: '200': description: List of one-off products content: application/json: schema: type: object required: - data - count - links properties: data: type: array items: $ref: '#/components/schemas/OneOffProduct' count: type: integer description: Number of items in the current page example: 1 links: $ref: '#/components/schemas/PaginationLinks' example: data: - id: one_off_product_Vr8kQdFhSrG4Y3DnfsdqH resource: one_off_product testmode: false name: Premium License description: Lifetime access to all premium features basePrice: value: '299.00' currency: EUR status: active createdAt: '2024-01-15T10:30:00Z' links: self: href: https://api.vatly.com/v1/one-off-products/one_off_product_Vr8kQdFhSrG4Y3DnfsdqH type: application/json count: 1 links: self: href: https://api.vatly.com/v1/one-off-products type: application/json next: null prev: null '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '422': $ref: '#/components/responses/ValidationFailed' /one-off-products/{oneOffProductId}: get: operationId: getOneOffProduct summary: Get a one-off product description: Retrieves a specific one-off product by its ID. tags: - One-Off Products parameters: - $ref: '#/components/parameters/oneOffProductId' responses: '200': description: One-off product details content: application/json: schema: $ref: '#/components/schemas/OneOffProduct' example: id: one_off_product_Vr8kQdFhSrG4Y3DnfsdqH resource: one_off_product testmode: false name: Premium License description: Lifetime access to all premium features basePrice: value: '299.00' currency: EUR status: active createdAt: '2024-01-15T10:30:00Z' links: self: href: https://api.vatly.com/v1/one-off-products/one_off_product_Vr8kQdFhSrG4Y3DnfsdqH type: application/json '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' /subscription-plans: get: operationId: listSubscriptionPlans summary: List all subscription plans description: | Returns a paginated list of subscription plans for the authenticated merchant. Results are filtered by the testmode determined from the API token. Only plans with `active` status can be used in checkouts. tags: - Subscription Plans parameters: - $ref: '#/components/parameters/limit' - $ref: '#/components/parameters/startingAfter' - $ref: '#/components/parameters/endingBefore' responses: '200': description: List of subscription plans content: application/json: schema: type: object required: - data - count - links properties: data: type: array items: $ref: '#/components/schemas/SubscriptionPlan' count: type: integer description: Number of items in the current page example: 2 links: $ref: '#/components/schemas/PaginationLinks' example: data: - id: subscription_plan_Bm7xNvPwKr3YjTgHcZaE resource: subscription_plan testmode: false name: Pro Monthly description: Full access to all Pro features, billed monthly basePrice: value: '29.00' currency: EUR interval: month intervalCount: 1 status: active createdAt: '2024-01-15T10:30:00Z' links: self: href: https://api.vatly.com/v1/subscription-plans/subscription_plan_Bm7xNvPwKr3YjTgHcZaE type: application/json - id: subscription_plan_Wt5mNvBxKw7YcZaEjLhR resource: subscription_plan testmode: false name: Pro Yearly description: Full access to all Pro features, billed yearly basePrice: value: '290.00' currency: EUR interval: year intervalCount: 1 status: active createdAt: '2024-01-15T10:30:00Z' links: self: href: https://api.vatly.com/v1/subscription-plans/subscription_plan_Wt5mNvBxKw7YcZaEjLhR type: application/json count: 2 links: self: href: https://api.vatly.com/v1/subscription-plans type: application/json next: null prev: null '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '422': $ref: '#/components/responses/ValidationFailed' /subscription-plans/{subscriptionPlanId}: get: operationId: getSubscriptionPlan summary: Get a subscription plan description: Retrieves a specific subscription plan by its ID. tags: - Subscription Plans parameters: - $ref: '#/components/parameters/subscriptionPlanId' responses: '200': description: Subscription plan details content: application/json: schema: $ref: '#/components/schemas/SubscriptionPlan' example: id: subscription_plan_Bm7xNvPwKr3YjTgHcZaE resource: subscription_plan testmode: false name: Pro Monthly description: Full access to all Pro features, billed monthly basePrice: value: '29.00' currency: EUR interval: month intervalCount: 1 status: active createdAt: '2024-01-15T10:30:00Z' links: self: href: https://api.vatly.com/v1/subscription-plans/subscription_plan_Bm7xNvPwKr3YjTgHcZaE type: application/json '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' /orders: get: operationId: listOrders summary: List all orders description: | Returns a paginated list of orders for the authenticated merchant. Results are filtered by the testmode determined from the API token. tags: - Orders parameters: - $ref: '#/components/parameters/limit' - $ref: '#/components/parameters/startingAfter' - $ref: '#/components/parameters/endingBefore' responses: '200': description: List of orders content: application/json: schema: type: object required: - data - count - links properties: data: type: array items: $ref: '#/components/schemas/Order' count: type: integer description: Number of items in the current page example: 1 links: $ref: '#/components/schemas/PaginationLinks' example: data: - id: order_Hn5xWqVfKm8RjTgYbUcP resource: order customerId: customer_Xk9pQrSvWm4NjLhYbUcP testmode: false metadata: {} paymentMethod: ideal createdAt: '2024-01-15T10:30:00Z' status: paid invoiceNumber: INV-2024-0001 total: value: '35.09' currency: EUR subtotal: value: '29.00' currency: EUR taxSummary: - taxRate: name: VAT percentage: 21 taxablePercentage: 100 amount: value: '6.09' currency: EUR lines: - id: order_item_Mn6xBtPvKw2RjTgYcZaE resource: orderline description: Pro Monthly Subscription quantity: 1 basePrice: value: '29.00' currency: EUR total: value: '35.09' currency: EUR subtotal: value: '29.00' currency: EUR taxes: - taxRate: name: VAT percentage: 21 taxablePercentage: 100 amount: value: '6.09' currency: EUR customerDetails: fullName: John Doe companyName: Acme Corp streetAndNumber: 123 Main Street city: Berlin postalCode: '10115' country: DE email: john@acme.com links: self: href: https://api.vatly.com/v1/orders/order_Hn5xWqVfKm8RjTgYbUcP type: application/json customer: href: https://api.vatly.com/v1/customers/customer_Xk9pQrSvWm4NjLhYbUcP type: application/json count: 1 links: self: href: https://api.vatly.com/v1/orders type: application/json next: null prev: null '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '422': $ref: '#/components/responses/ValidationFailed' /orders/{orderId}: get: operationId: getOrder summary: Get an order description: | Retrieves a specific order by its ID. Includes full order details with line items, totals, and billing information. tags: - Orders parameters: - $ref: '#/components/parameters/orderId' responses: '200': description: Order details content: application/json: schema: $ref: '#/components/schemas/Order' example: id: order_Hn5xWqVfKm8RjTgYbUcP resource: order customerId: customer_Xk9pQrSvWm4NjLhYbUcP testmode: false metadata: {} paymentMethod: ideal createdAt: '2024-01-15T10:30:00Z' status: paid invoiceNumber: INV-2024-0001 total: value: '35.09' currency: EUR subtotal: value: '29.00' currency: EUR taxSummary: - taxRate: name: VAT percentage: 21 taxablePercentage: 100 amount: value: '6.09' currency: EUR lines: - id: order_item_Jk4pQrSvWm8NjLhYbUcP resource: orderline description: Pro Monthly Subscription quantity: 1 basePrice: value: '29.00' currency: EUR total: value: '35.09' currency: EUR subtotal: value: '29.00' currency: EUR taxes: - taxRate: name: VAT percentage: 21 taxablePercentage: 100 amount: value: '6.09' currency: EUR customerDetails: fullName: John Doe companyName: Acme Corp streetAndNumber: 123 Main Street city: Berlin postalCode: '10115' country: DE email: john@acme.com links: self: href: https://api.vatly.com/v1/orders/order_Hn5xWqVfKm8RjTgYbUcP type: application/json customer: href: https://api.vatly.com/v1/customers/customer_Xk9pQrSvWm4NjLhYbUcP type: application/json '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' /orders/{orderId}/request-address-update-link: post: operationId: requestOrderAddressUpdateLink summary: Request address update link description: | Generates a signed URL that allows the customer to update their billing address for this order. The link is valid for a limited time (typically 24 hours) and can be sent to the customer to self-service update their invoice details. **Use cases:** - Customer needs to add/update VAT number - Customer needs to correct billing address - Customer needs to change company name on invoice tags: - Orders parameters: - $ref: '#/components/parameters/orderId' responses: '200': description: Address update link generated content: application/json: schema: $ref: '#/components/schemas/AddressUpdateLink' example: href: https://vatly.com/invoices/order_Hn5xWqVfKm8RjTgYbUcP/edit?signature=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... type: text/html '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' /orders/{orderId}/refunds: get: operationId: listOrderRefunds summary: List order refunds description: | Returns a paginated list of refunds for a specific order. Includes both pending and completed refunds. tags: - Orders - Refunds parameters: - $ref: '#/components/parameters/orderId' - $ref: '#/components/parameters/limit' - $ref: '#/components/parameters/startingAfter' - $ref: '#/components/parameters/endingBefore' responses: '200': description: List of order refunds content: application/json: schema: type: object required: - data - count - links properties: data: type: array items: $ref: '#/components/schemas/Refund' count: type: integer description: Number of items in the current page example: 1 links: $ref: '#/components/schemas/PaginationLinks' example: data: - id: refund_Bm7xNvPwKr3YjTgHcZaE resource: refund orderId: null customerId: customer_Wt5mNvBxKw7YcZaEjLhR testmode: false createdAt: '2024-01-20T14:00:00Z' status: pending originalOrderId: order_Fp2kQrSvWm8NjLhYbUcP total: value: '12.10' currency: EUR subtotal: value: '10.00' currency: EUR taxSummary: - taxRate: name: VAT percentage: 21 taxablePercentage: 100 amount: value: '2.10' currency: EUR lines: - id: refund_item_Jk4pQrSvWm8NjLhYbUcP resource: refundline description: Partial refund for service issue quantity: 1 basePrice: value: '10.00' currency: EUR total: value: '12.10' currency: EUR subtotal: value: '10.00' currency: EUR taxes: - taxRate: name: VAT percentage: 21 taxablePercentage: 100 amount: value: '2.10' currency: EUR links: self: href: https://api.vatly.com/v1/refunds/refund_Bm7xNvPwKr3YjTgHcZaE type: application/json originalOrder: href: https://api.vatly.com/v1/orders/order_Fp2kQrSvWm8NjLhYbUcP type: application/json order: null count: 1 links: self: href: https://api.vatly.com/v1/orders/order_Fp2kQrSvWm8NjLhYbUcP/refunds type: application/json next: null prev: null '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '422': $ref: '#/components/responses/ValidationFailed' post: operationId: createOrderRefund summary: Create a partial refund description: | Creates a partial refund for specific items in an order. **Requirements:** - Order must have `paid` status - Order must have a payment processor attached (Mollie) - Refund amount per item cannot exceed remaining refundable amount **Notes:** - Amounts are specified before taxes; taxes are calculated automatically - Multiple partial refunds can be created for the same order - Refunds are processed asynchronously through the payment provider tags: - Orders - Refunds parameters: - $ref: '#/components/parameters/orderId' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreateRefundRequest' examples: partialRefund: summary: Partial refund for one item value: items: - itemId: order_item_Jk4pQrSvWm8NjLhYbUcP amount: value: '15.00' currency: EUR description: 50% refund for service issue multipleItems: summary: Refund multiple items value: items: - itemId: order_item_Jk4pQrSvWm8NjLhYbUcP amount: value: '29.00' currency: EUR - itemId: order_item_Tk7mNvBxKw2RjTgYcZaE amount: value: '10.00' currency: EUR metadata: ticketId: SUPPORT-12345 responses: '201': description: Refund created successfully content: application/json: schema: $ref: '#/components/schemas/Refund' example: id: refund_Mn6xBtPvKw2RjTgYcZaE resource: refund orderId: null customerId: customer_Lp3mNvBxKw7RjTgYcZaE testmode: false createdAt: '2024-01-15T10:30:00Z' status: pending originalOrderId: order_Fp2kQrSvWm8NjLhYbUcP total: value: '18.15' currency: EUR subtotal: value: '15.00' currency: EUR taxSummary: - taxRate: name: VAT percentage: 21 taxablePercentage: 100 amount: value: '3.15' currency: EUR lines: - id: refund_item_Tk7mNvBxKw2RjTgYcZaE resource: refundline description: 50% refund for service issue quantity: 1 basePrice: value: '15.00' currency: EUR total: value: '18.15' currency: EUR subtotal: value: '15.00' currency: EUR taxes: - taxRate: name: VAT percentage: 21 taxablePercentage: 100 amount: value: '3.15' currency: EUR links: self: href: https://api.vatly.com/v1/refunds/refund_Mn6xBtPvKw2RjTgYcZaE type: application/json originalOrder: href: https://api.vatly.com/v1/orders/order_Fp2kQrSvWm8NjLhYbUcP type: application/json order: null '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '422': description: | Validation failed. Common errors: - Order is not in `paid` status - Refund amount exceeds remaining refundable amount - No payment processor attached to order content: application/json: schema: $ref: '#/components/schemas/ValidationError' examples: notPaid: summary: Order not paid value: message: The given data was invalid. errors: orderId: - Order must be in paid status to create a refund. overRefund: summary: Over-refunding value: message: The given data was invalid. errors: items.0.amount: - 'Refund amount exceeds remaining refundable amount. Maximum: 15.00 EUR' /orders/{orderId}/refunds/full: post: operationId: createFullOrderRefund summary: Create a full refund description: | Creates a full refund for an order, refunding all items. **Requirements:** - Order must have `paid` status - Order must have a payment processor attached (Mollie) - Order must not be already fully refunded **Notes:** - This is a convenience endpoint; it automatically calculates the full refundable amount - If partial refunds have already been issued, only the remaining amount is refunded tags: - Orders - Refunds parameters: - $ref: '#/components/parameters/orderId' requestBody: required: false content: application/json: schema: $ref: '#/components/schemas/CreateFullRefundRequest' example: metadata: reason: Customer requested cancellation responses: '201': description: Full refund created successfully content: application/json: schema: $ref: '#/components/schemas/Refund' example: id: refund_Rk5pQrSvWm8NjLhYbUcP resource: refund orderId: null customerId: customer_Wt5mNvBxKw7YcZaEjLhR testmode: false createdAt: '2024-01-21T09:00:00Z' status: pending originalOrderId: order_Fp2kQrSvWm8NjLhYbUcP total: value: '35.09' currency: EUR subtotal: value: '29.00' currency: EUR taxSummary: - taxRate: name: VAT percentage: 21 taxablePercentage: 100 amount: value: '6.09' currency: EUR lines: - id: refund_item_Bm7xNvPwKr3YjTgHcZaE resource: refundline description: Pro Monthly Subscription (Full Refund) quantity: 1 basePrice: value: '29.00' currency: EUR total: value: '35.09' currency: EUR subtotal: value: '29.00' currency: EUR taxes: - taxRate: name: VAT percentage: 21 taxablePercentage: 100 amount: value: '6.09' currency: EUR links: self: href: https://api.vatly.com/v1/refunds/refund_Rk5pQrSvWm8NjLhYbUcP type: application/json originalOrder: href: https://api.vatly.com/v1/orders/order_Fp2kQrSvWm8NjLhYbUcP type: application/json order: null '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '422': $ref: '#/components/responses/ValidationFailed' /orders/{orderId}/refunds/{refundId}: get: operationId: getOrderRefund summary: Get an order refund description: | Retrieves a specific refund for an order. The refund must belong to the specified order. tags: - Orders - Refunds parameters: - $ref: '#/components/parameters/orderId' - $ref: '#/components/parameters/refundId' responses: '200': description: Refund details content: application/json: schema: $ref: '#/components/schemas/Refund' example: id: refund_Xk9pQrSvWm4NjLhYbUcP resource: refund orderId: order_Bm7xNvPwKr3YjTgHcZaE customerId: customer_Wt5mNvBxKw7YcZaEjLhR testmode: false createdAt: '2024-01-20T14:00:00Z' status: refunded originalOrderId: order_Fp2kQrSvWm8NjLhYbUcP total: value: '18.15' currency: EUR subtotal: value: '15.00' currency: EUR taxSummary: - taxRate: name: VAT percentage: 21 taxablePercentage: 100 amount: value: '3.15' currency: EUR lines: - id: refund_item_Mn6xBtPvKw2RjTgYcZaE resource: refundline description: Pro Monthly Subscription (Refund) quantity: 1 basePrice: value: '15.00' currency: EUR total: value: '18.15' currency: EUR subtotal: value: '15.00' currency: EUR taxes: - taxRate: name: VAT percentage: 21 taxablePercentage: 100 amount: value: '3.15' currency: EUR links: self: href: https://api.vatly.com/v1/refunds/refund_Xk9pQrSvWm4NjLhYbUcP type: application/json originalOrder: href: https://api.vatly.com/v1/orders/order_Fp2kQrSvWm8NjLhYbUcP type: application/json order: href: https://api.vatly.com/v1/orders/order_Bm7xNvPwKr3YjTgHcZaE type: application/json '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' delete: operationId: cancelOrderRefund summary: Cancel a refund description: | Cancels a pending refund. **Requirements:** - Refund must be in `pending` status - Cannot cancel refunds that have already been processed **Notes:** - Once canceled, the refund cannot be restored - To refund again, create a new refund request tags: - Orders - Refunds parameters: - $ref: '#/components/parameters/orderId' - $ref: '#/components/parameters/refundId' responses: '204': description: Refund canceled successfully '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '422': description: Cannot cancel refund (not in pending status) content: application/json: schema: $ref: '#/components/schemas/Error' example: message: Only pending refunds can be canceled. /orders/{orderId}/chargebacks: get: operationId: listOrderChargebacks summary: List order chargebacks description: | Returns a paginated list of chargebacks for a specific order. Most orders have at most one chargeback. tags: - Orders - Chargebacks parameters: - $ref: '#/components/parameters/orderId' - $ref: '#/components/parameters/limit' - $ref: '#/components/parameters/startingAfter' - $ref: '#/components/parameters/endingBefore' responses: '200': description: List of order chargebacks content: application/json: schema: type: object required: - data - count - links properties: data: type: array items: $ref: '#/components/schemas/Chargeback' count: type: integer description: Number of items in the current page example: 1 links: $ref: '#/components/schemas/PaginationLinks' example: data: - id: chargeback_Fp2kQrSvWm8NjLhYbUcP resource: chargeback testmode: false createdAt: '2024-01-25T16:45:00Z' amount: value: '35.09' currency: EUR settlementAmount: value: '35.09' currency: EUR reason: product_not_received originalOrderId: order_Fp2kQrSvWm8NjLhYbUcP orderId: order_Rk5pQrSvWm8NjLhYbUcP links: self: href: https://api.vatly.com/v1/chargebacks/chargeback_Fp2kQrSvWm8NjLhYbUcP type: application/json originalOrder: href: https://api.vatly.com/v1/orders/order_Fp2kQrSvWm8NjLhYbUcP type: application/json order: href: https://api.vatly.com/v1/orders/order_Rk5pQrSvWm8NjLhYbUcP type: application/json count: 1 links: self: href: https://api.vatly.com/v1/orders/order_Fp2kQrSvWm8NjLhYbUcP/chargebacks type: application/json next: null prev: null '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '422': $ref: '#/components/responses/ValidationFailed' /orders/{orderId}/chargebacks/{chargebackId}: get: operationId: getOrderChargeback summary: Get an order chargeback description: | Retrieves a specific chargeback for an order. The chargeback must belong to the specified order. tags: - Orders - Chargebacks parameters: - $ref: '#/components/parameters/orderId' - $ref: '#/components/parameters/chargebackId' responses: '200': description: Chargeback details content: application/json: schema: $ref: '#/components/schemas/Chargeback' example: id: chargeback_Mn6xBtPvKw2RjTgYcZaE resource: chargeback testmode: false createdAt: '2024-01-25T16:45:00Z' amount: value: '35.09' currency: EUR settlementAmount: value: '35.09' currency: EUR reason: fraud originalOrderId: order_Fp2kQrSvWm8NjLhYbUcP orderId: order_Rk5pQrSvWm8NjLhYbUcP links: self: href: https://api.vatly.com/v1/chargebacks/chargeback_Mn6xBtPvKw2RjTgYcZaE type: application/json originalOrder: href: https://api.vatly.com/v1/orders/order_Fp2kQrSvWm8NjLhYbUcP type: application/json order: href: https://api.vatly.com/v1/orders/order_Rk5pQrSvWm8NjLhYbUcP type: application/json '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' /refunds: get: operationId: listRefunds summary: List all refunds description: | Returns a paginated list of all refunds for the authenticated merchant. Results are filtered by the testmode determined from the API token. tags: - Refunds parameters: - $ref: '#/components/parameters/limit' - $ref: '#/components/parameters/startingAfter' - $ref: '#/components/parameters/endingBefore' responses: '200': description: List of refunds content: application/json: schema: type: object required: - data - count - links properties: data: type: array items: $ref: '#/components/schemas/Refund' count: type: integer description: Number of items in the current page example: 1 links: $ref: '#/components/schemas/PaginationLinks' example: data: - id: refund_Xk9pQrSvWm4NjLhYbUcP resource: refund orderId: order_Bm7xNvPwKr3YjTgHcZaE customerId: customer_Wt5mNvBxKw7YcZaEjLhR testmode: false createdAt: '2024-01-20T14:00:00Z' status: refunded originalOrderId: order_Fp2kQrSvWm8NjLhYbUcP total: value: '18.15' currency: EUR subtotal: value: '15.00' currency: EUR taxSummary: - taxRate: name: VAT percentage: 21 taxablePercentage: 100 amount: value: '3.15' currency: EUR lines: - id: refund_item_Mn6xBtPvKw2RjTgYcZaE resource: refundline description: Pro Monthly Subscription (Refund) quantity: 1 basePrice: value: '15.00' currency: EUR total: value: '18.15' currency: EUR subtotal: value: '15.00' currency: EUR taxes: - taxRate: name: VAT percentage: 21 taxablePercentage: 100 amount: value: '3.15' currency: EUR links: self: href: https://api.vatly.com/v1/refunds/refund_Xk9pQrSvWm4NjLhYbUcP type: application/json originalOrder: href: https://api.vatly.com/v1/orders/order_Fp2kQrSvWm8NjLhYbUcP type: application/json order: href: https://api.vatly.com/v1/orders/order_Bm7xNvPwKr3YjTgHcZaE type: application/json count: 1 links: self: href: https://api.vatly.com/v1/refunds type: application/json next: null prev: null '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '422': $ref: '#/components/responses/ValidationFailed' /refunds/{refundId}: get: operationId: getRefund summary: Get a refund description: Retrieves a specific refund by its ID. tags: - Refunds parameters: - $ref: '#/components/parameters/refundId' responses: '200': description: Refund details content: application/json: schema: $ref: '#/components/schemas/Refund' example: id: refund_Xk9pQrSvWm4NjLhYbUcP resource: refund orderId: order_Bm7xNvPwKr3YjTgHcZaE customerId: customer_Wt5mNvBxKw7YcZaEjLhR testmode: false createdAt: '2024-01-20T14:00:00Z' status: refunded originalOrderId: order_Fp2kQrSvWm8NjLhYbUcP total: value: '18.15' currency: EUR subtotal: value: '15.00' currency: EUR taxSummary: - taxRate: name: VAT percentage: 21 taxablePercentage: 100 amount: value: '3.15' currency: EUR lines: - id: refund_item_Mn6xBtPvKw2RjTgYcZaE resource: refundline description: Pro Monthly Subscription (Refund) quantity: 1 basePrice: value: '15.00' currency: EUR total: value: '18.15' currency: EUR subtotal: value: '15.00' currency: EUR taxes: - taxRate: name: VAT percentage: 21 taxablePercentage: 100 amount: value: '3.15' currency: EUR links: self: href: https://api.vatly.com/v1/refunds/refund_Xk9pQrSvWm4NjLhYbUcP type: application/json originalOrder: href: https://api.vatly.com/v1/orders/order_Fp2kQrSvWm8NjLhYbUcP type: application/json order: href: https://api.vatly.com/v1/orders/order_Bm7xNvPwKr3YjTgHcZaE type: application/json '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' /chargebacks: get: operationId: listChargebacks summary: List all chargebacks description: | Returns a paginated list of all chargebacks for the authenticated merchant. Results are filtered by the testmode determined from the API token. **Notes:** - Chargebacks are created automatically by payment provider webhooks - They cannot be created manually through the API tags: - Chargebacks parameters: - $ref: '#/components/parameters/limit' - $ref: '#/components/parameters/startingAfter' - $ref: '#/components/parameters/endingBefore' responses: '200': description: List of chargebacks content: application/json: schema: type: object required: - data - count - links properties: data: type: array items: $ref: '#/components/schemas/Chargeback' count: type: integer description: Number of items in the current page example: 1 links: $ref: '#/components/schemas/PaginationLinks' example: data: - id: chargeback_Mn6xBtPvKw2RjTgYcZaE resource: chargeback testmode: false createdAt: '2024-01-15T10:30:00Z' amount: value: '35.09' currency: EUR settlementAmount: value: '35.09' currency: EUR reason: fraud originalOrderId: order_Fp2kQrSvWm8NjLhYbUcP orderId: order_Rk5pQrSvWm8NjLhYbUcP links: self: href: https://api.vatly.com/v1/chargebacks/chargeback_Mn6xBtPvKw2RjTgYcZaE type: application/json originalOrder: href: https://api.vatly.com/v1/orders/order_Fp2kQrSvWm8NjLhYbUcP type: application/json order: href: https://api.vatly.com/v1/orders/order_Rk5pQrSvWm8NjLhYbUcP type: application/json count: 1 links: self: href: https://api.vatly.com/v1/chargebacks type: application/json next: null prev: null '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '422': $ref: '#/components/responses/ValidationFailed' /chargebacks/{chargebackId}: get: operationId: getChargeback summary: Get a chargeback description: Retrieves a specific chargeback by its ID. tags: - Chargebacks parameters: - $ref: '#/components/parameters/chargebackId' responses: '200': description: Chargeback details content: application/json: schema: $ref: '#/components/schemas/Chargeback' example: id: chargeback_Mn6xBtPvKw2RjTgYcZaE resource: chargeback testmode: false createdAt: '2024-01-25T16:45:00Z' amount: value: '35.09' currency: EUR settlementAmount: value: '35.09' currency: EUR reason: fraud originalOrderId: order_Fp2kQrSvWm8NjLhYbUcP orderId: order_Rk5pQrSvWm8NjLhYbUcP links: self: href: https://api.vatly.com/v1/chargebacks/chargeback_Mn6xBtPvKw2RjTgYcZaE type: application/json originalOrder: href: https://api.vatly.com/v1/orders/order_Fp2kQrSvWm8NjLhYbUcP type: application/json order: href: https://api.vatly.com/v1/orders/order_Rk5pQrSvWm8NjLhYbUcP type: application/json '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' /webhook-events/{eventId}: get: operationId: getWebhookEvent summary: Get webhook event description: | Retrieves a specific webhook event by its ID. Returns the full event payload including the resource data at the time the event occurred. tags: - Webhook Events parameters: - $ref: '#/components/parameters/eventId' responses: '200': description: Webhook event details content: application/json: schema: $ref: '#/components/schemas/WebhookEvent' example: id: webhook_event_Qk8pRtSvWm2NjLhYcZaE resource: webhook_event eventName: order.paid entityType: order entityId: order_Hn5xWqVfKm8RjTgYbUcP object: id: order_Hn5xWqVfKm8RjTgYbUcP resource: order testmode: false status: paid total: value: '29.99' currency: EUR subtotal: value: '24.79' currency: EUR links: self: href: https://api.vatly.com/v1/webhook-events/webhook_event_Qk8pRtSvWm2NjLhYcZaE type: application/json '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' /subscriptions: get: operationId: listSubscriptions summary: List all subscriptions description: | Returns a paginated list of all subscriptions for the authenticated merchant. Results are filtered by the testmode determined from the API token. Includes subscriptions in all states (active, canceled, etc.). tags: - Subscriptions parameters: - $ref: '#/components/parameters/limit' - $ref: '#/components/parameters/startingAfter' - $ref: '#/components/parameters/endingBefore' responses: '200': description: List of subscriptions content: application/json: schema: type: object required: - data - count - links properties: data: type: array items: $ref: '#/components/schemas/Subscription' count: type: integer description: Number of items in the current page example: 2 links: $ref: '#/components/schemas/PaginationLinks' example: data: - id: subscription_Lp3mNvBxKw7RjTgYcZaE resource: subscription customerId: customer_Lp3mNvBxKw7RjTgYcZaE testmode: false name: Pro Monthly description: Full access to all Pro features billingAddress: fullName: John Doe companyName: Acme Corp streetAndNumber: 123 Main Street city: Berlin postalCode: '10115' country: DE basePrice: value: '29.00' currency: EUR quantity: 1 interval: month intervalCount: 1 status: active startedAt: '2024-01-15T10:30:00Z' endedAt: null cancelledAt: null renewedAt: '2024-02-15T10:30:00Z' renewedUntil: '2024-03-15T10:30:00Z' nextRenewalAt: '2024-03-15T10:30:00Z' trialUntil: null links: self: href: https://api.vatly.com/v1/subscriptions/subscription_Lp3mNvBxKw7RjTgYcZaE type: application/json customer: href: https://api.vatly.com/v1/customers/customer_Lp3mNvBxKw7RjTgYcZaE type: application/json - id: subscription_Wt5mNvBxKw7YcZaEjLhR resource: subscription customerId: customer_Mn6xBtPvKw2RjTgYcZaE testmode: false name: Enterprise Yearly description: Enterprise features with priority support billingAddress: fullName: Jane Smith companyName: TechCorp Ltd taxId: GB123456789 streetAndNumber: 456 Tech Lane city: London postalCode: EC1A 1BB country: GB basePrice: value: '990.00' currency: EUR quantity: 5 interval: year intervalCount: 1 status: active startedAt: '2024-01-01T00:00:00Z' endedAt: null cancelledAt: null renewedAt: '2024-01-01T00:00:00Z' renewedUntil: '2025-01-01T00:00:00Z' nextRenewalAt: '2025-01-01T00:00:00Z' trialUntil: null links: self: href: https://api.vatly.com/v1/subscriptions/subscription_Wt5mNvBxKw7YcZaEjLhR type: application/json customer: href: https://api.vatly.com/v1/customers/customer_Mn6xBtPvKw2RjTgYcZaE type: application/json count: 2 links: self: href: https://api.vatly.com/v1/subscriptions type: application/json next: null prev: null '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '422': $ref: '#/components/responses/ValidationFailed' /subscriptions/{subscriptionId}: get: operationId: getSubscription summary: Get a subscription description: Retrieves a specific subscription by its ID. tags: - Subscriptions parameters: - $ref: '#/components/parameters/subscriptionId' responses: '200': description: Subscription details content: application/json: schema: $ref: '#/components/schemas/Subscription' example: id: subscription_Lp3mNvBxKw7RjTgYcZaE resource: subscription customerId: customer_Lp3mNvBxKw7RjTgYcZaE testmode: false name: Pro Monthly description: Full access to all Pro features billingAddress: fullName: John Doe companyName: Acme Corp streetAndNumber: 123 Main Street city: Berlin postalCode: '10115' country: DE basePrice: value: '29.00' currency: EUR quantity: 1 interval: month intervalCount: 1 status: active startedAt: '2024-01-15T10:30:00Z' endedAt: null cancelledAt: null renewedAt: '2024-02-15T10:30:00Z' renewedUntil: '2024-03-15T10:30:00Z' nextRenewalAt: '2024-03-15T10:30:00Z' trialUntil: null links: self: href: https://api.vatly.com/v1/subscriptions/subscription_Lp3mNvBxKw7RjTgYcZaE type: application/json customer: href: https://api.vatly.com/v1/customers/customer_Lp3mNvBxKw7RjTgYcZaE type: application/json '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' patch: operationId: updateSubscription summary: Update a subscription description: | Updates a subscription's plan, quantity, or billing schedule. **Plan changes:** - Specify `subscriptionPlanId` to switch to a different plan - New plan must match the subscription's testmode **Quantity changes:** - Specify `quantity` to update the number of units (e.g., seats) **Proration:** - By default, changes are prorated - Set `prorate: false` to disable proration - Proration credits unused time and charges for new plan **Timing:** - By default, changes apply at the end of the current billing period - Set `applyImmediately: true` for immediate changes - Set `invoiceImmediately: true` to charge proration immediately **Trial/Anchor:** - Use `trialUntil` to extend or set a trial period - Use `anchor` to reset the billing anchor date - These options are mutually exclusive tags: - Subscriptions parameters: - $ref: '#/components/parameters/subscriptionId' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/UpdateSubscriptionRequest' examples: changePlan: summary: Upgrade to yearly plan value: subscriptionPlanId: subscription_plan_Wt5mNvBxKw7YcZaEjLhR prorate: true applyImmediately: true changeQuantity: summary: Add more seats value: quantity: 10 applyImmediately: true invoiceImmediately: true scheduledChange: summary: Schedule plan change for next cycle value: subscriptionPlanId: subscription_plan_Fp2kQrSvWm8NjLhYbUcP applyImmediately: false extendTrial: summary: Extend trial period value: trialUntil: '2024-02-28T00:00:00Z' responses: '200': description: Subscription updated successfully content: application/json: schema: $ref: '#/components/schemas/Subscription' example: id: subscription_Lp3mNvBxKw7RjTgYcZaE resource: subscription customerId: customer_Lp3mNvBxKw7RjTgYcZaE testmode: false name: Pro Yearly description: Full access to all Pro features, billed yearly billingAddress: fullName: John Doe companyName: Acme Corp streetAndNumber: 123 Main Street city: Berlin postalCode: '10115' country: DE basePrice: value: '290.00' currency: EUR quantity: 1 interval: year intervalCount: 1 status: active startedAt: '2024-01-15T10:30:00Z' endedAt: null cancelledAt: null renewedAt: '2024-02-15T10:30:00Z' renewedUntil: '2025-02-15T10:30:00Z' nextRenewalAt: '2025-02-15T10:30:00Z' trialUntil: null links: self: href: https://api.vatly.com/v1/subscriptions/subscription_Lp3mNvBxKw7RjTgYcZaE type: application/json customer: href: https://api.vatly.com/v1/customers/customer_Lp3mNvBxKw7RjTgYcZaE type: application/json '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '422': description: | Validation failed. Common errors: - Neither subscriptionPlanId nor quantity provided - Plan does not exist or is in wrong testmode - Both anchor and trialUntil specified content: application/json: schema: $ref: '#/components/schemas/ValidationError' delete: operationId: cancelSubscription summary: Cancel a subscription description: | Cancels a subscription. **Cancellation modes:** - **Default (grace period):** Subscription remains active until the end of the current billing period, then ends - **Immediate:** Subscription ends immediately when `immediately=true` is specified **Notes:** - Canceled subscriptions cannot be reactivated through the API - Customers retain access until `renewedUntil` date (unless canceled immediately) - No refunds are issued automatically; use the Refunds API if needed tags: - Subscriptions parameters: - $ref: '#/components/parameters/subscriptionId' - name: immediately in: query description: | Cancel immediately instead of at period end. - `false` (default): Cancel at end of current billing period - `true`: Cancel immediately required: false schema: type: boolean default: false responses: '204': description: Subscription canceled successfully '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '422': description: Subscription cannot be canceled (already canceled or ended) content: application/json: schema: $ref: '#/components/schemas/Error' /subscriptions/{subscriptionId}/update-billing: patch: operationId: updateSubscriptionBilling summary: Update billing details (hosted) description: | Initiates a hosted billing update flow for the subscription. Returns a redirect URL where the customer can update their billing address, VAT number, and other invoice details. **Flow:** 1. Call this endpoint with redirect URLs 2. Redirect customer to the returned URL 3. Customer updates their details on the hosted page 4. Customer is redirected to your success/canceled URL **Use cases:** - Customer needs to update billing address - Customer needs to add/update VAT number - Self-service invoice detail management tags: - Subscriptions parameters: - $ref: '#/components/parameters/subscriptionId' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/UpdateSubscriptionBillingRequest' example: redirectUrlSuccess: https://example.com/billing-updated redirectUrlCanceled: https://example.com/account/billing billingAddress: companyName: Acme Corp taxId: DE123456789 responses: '200': description: Billing update flow initiated content: application/json: schema: type: object required: - href - type properties: href: type: string format: uri description: URL to redirect customer for billing update example: https://vatly.com/subscriptions/subscription_Lp3mNvBxKw7RjTgYcZaE/billing?token=xyz... type: type: string const: text/html example: text/html '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '422': $ref: '#/components/responses/ValidationFailed' /test-helpers/subscriptions/{subscriptionId}/fast-forward-renewal: post: operationId: fastForwardSubscriptionRenewal summary: Fast-forward subscription renewal description: | Simulates a subscription renewal cycle for testing purposes. **Requirements:** - Only available in test mode (requires `test_` prefixed API token) - Subscription must belong to the authenticated merchant **Use cases:** - Test renewal billing flows without waiting for the actual billing cycle - Verify subscription lifecycle events and webhooks tags: - Test Helpers parameters: - $ref: '#/components/parameters/subscriptionId' responses: '200': description: Subscription renewed successfully content: application/json: schema: $ref: '#/components/schemas/Subscription' example: id: subscription_Lp3mNvBxKw7RjTgYcZaE resource: subscription customerId: customer_Lp3mNvBxKw7RjTgYcZaE testmode: true name: Pro Monthly description: Full access to all Pro features billingAddress: fullName: John Doe companyName: Acme Corp streetAndNumber: 123 Main Street city: Berlin postalCode: '10115' country: DE basePrice: value: '29.00' currency: EUR quantity: 1 interval: month intervalCount: 1 status: active startedAt: '2024-01-15T10:30:00Z' endedAt: null cancelledAt: null renewedAt: '2024-03-15T10:30:00Z' renewedUntil: '2024-04-15T10:30:00Z' nextRenewalAt: '2024-04-15T10:30:00Z' trialUntil: null links: self: href: https://api.vatly.com/v1/subscriptions/subscription_Lp3mNvBxKw7RjTgYcZaE type: application/json customer: href: https://api.vatly.com/v1/customers/customer_Lp3mNvBxKw7RjTgYcZaE type: application/json '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' /test-helpers/mandated-payments/{transactionId}/simulate-failure: post: operationId: simulatePaymentFailure summary: Simulate a payment failure description: | Simulates a failed mandated payment for testing purposes. **Requirements:** - Only available in test mode (requires `test_` prefixed API token) - Transaction must belong to the authenticated merchant **Use cases:** - Test payment failure handling and retry logic - Verify dunning flow behavior - Test webhook notifications for failed payments tags: - Test Helpers parameters: - name: transactionId in: path required: true description: ID of the mandated payment transaction to fail schema: type: string example: mollie_mandated_payment_Xk9pQrSvWm4NjLhYbUcP requestBody: required: false content: application/json: schema: type: object properties: reason: type: string description: | Reason for the simulated failure. Defaults to `general_failure` if not provided. enum: - insufficient_funds - invalid_mandate - mandate_canceled - account_closed - card_expired - authentication_failed - general_failure example: insufficient_funds example: reason: insufficient_funds responses: '200': description: Payment failure simulated content: application/json: schema: type: object required: - id - status - failureReason properties: id: type: string description: ID of the failed transaction example: mollie_mandated_payment_Xk9pQrSvWm4NjLhYbUcP status: type: string const: failed example: failed failureReason: type: string description: The failure reason applied example: insufficient_funds example: id: mollie_mandated_payment_Xk9pQrSvWm4NjLhYbUcP status: failed failureReason: insufficient_funds '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' components: securitySchemes: BearerAuth: type: http scheme: bearer description: | API token authentication using Bearer scheme. Tokens are prefixed to indicate the environment mode: - `live_` - Production mode, accesses real data - `test_` - Sandbox mode, accesses test data Obtain API tokens from the Vatly dashboard under Settings > API Keys. **Example:** ``` Authorization: Bearer test_abc123xyz... ``` **Important:** Resources are isolated by mode. A checkout created with a test token cannot reference customers or products created with a live token, and vice versa. bearerFormat: '{mode}_{token}' parameters: limit: name: limit in: query description: Maximum number of results to return per page required: false schema: type: integer minimum: 1 maximum: 100 default: 10 example: 25 startingAfter: name: startingAfter in: query description: | Cursor for forward pagination. Returns results after this resource ID. Mutually exclusive with `endingBefore`. required: false schema: type: string example: checkout_QdEpFhdSrG4Y3DnfsdqsH endingBefore: name: endingBefore in: query description: | Cursor for backward pagination. Returns results before this resource ID. Mutually exclusive with `startingAfter`. required: false schema: type: string example: checkout_Rk5pQrSvWm8NjLhYbUcP checkoutId: name: checkoutId in: path description: Unique identifier of the checkout required: true schema: type: string example: checkout_QdEpFhdSrG4Y3DnfsdqsH customerId: name: customerId in: path description: Unique identifier of the customer required: true schema: type: string example: customer_7kBmRtPvXw2NjLhYcZaE subscriptionId: name: subscriptionId in: path description: Unique identifier of the subscription required: true schema: type: string example: subscription_Lp3mNvBxKw7RjTgYcZaE oneOffProductId: name: oneOffProductId in: path description: Unique identifier of the one-off product required: true schema: type: string pattern: ^one_off_product_ example: one_off_product_Vr8kQdFhSrG4Y3DnfsdqH subscriptionPlanId: name: subscriptionPlanId in: path description: Unique identifier of the subscription plan required: true schema: type: string pattern: ^subscription_plan_ example: subscription_plan_Wt5mNvBxKw7YcZaEjLhR orderId: name: orderId in: path description: Unique identifier of the order required: true schema: type: string example: order_Hn5xWqVfKm8RjTgYbUcP refundId: name: refundId in: path description: Unique identifier of the refund required: true schema: type: string example: refund_Xk9pQrSvWm4NjLhYbUcP chargebackId: name: chargebackId in: path description: Unique identifier of the chargeback required: true schema: type: string example: chargeback_Mn6xBtPvKw2RjTgYcZaE eventId: name: eventId in: path description: Unique identifier of the webhook event required: true schema: type: string example: webhook_event_Qk8pRtSvWm2NjLhYcZaE responses: Unauthorized: description: Unauthorized - Authentication credentials were missing or invalid content: application/json: schema: $ref: '#/components/schemas/Error' example: message: Unauthenticated. Forbidden: description: | Forbidden - The API token is invalid or does not have permission for this operation. Common causes: - Token does not start with `live_` or `test_` - Token has been revoked - Attempting live operations on a non-live merchant account content: application/json: schema: $ref: '#/components/schemas/Error' example: message: Auth token must start with live_ or test_. ValidationFailed: description: | Unprocessable Entity - The request was well-formed but contained validation errors. The `errors` object contains field-specific error messages. content: application/json: schema: $ref: '#/components/schemas/ValidationError' example: message: The given data was invalid. errors: email: - The email field is required. - The email must be a valid email address. products.0.id: - The selected products.0.id is invalid. NotFound: description: Not Found - The requested resource does not exist content: application/json: schema: $ref: '#/components/schemas/Error' example: message: Checkout not found. BadRequest: description: Bad Request - The request was malformed or invalid content: application/json: schema: $ref: '#/components/schemas/Error' example: message: Invalid request format TestmodeMismatch: description: | Unprocessable Entity - A referenced resource exists but was created in a different mode. Switch between live/test API tokens to access the correct resources. content: application/json: schema: $ref: '#/components/schemas/ValidationError' example: message: The given data was invalid. errors: customerId: - Customer exists, but the wrong mode is used. Try switching live / test API keys. TooManyRequests: description: Too Many Requests - Rate limit exceeded content: application/json: schema: $ref: '#/components/schemas/Error' example: message: Too many requests. Please try again later. headers: Retry-After: description: Number of seconds to wait before retrying schema: type: integer example: 60 InternalServerError: description: Internal Server Error - An unexpected error occurred content: application/json: schema: $ref: '#/components/schemas/Error' example: message: An unexpected error occurred. Please try again later. schemas: Money: type: object description: Monetary value with currency required: - value - currency properties: value: type: string description: | The amount as a decimal string. Uses string type to preserve precision for financial calculations. example: '99.99' pattern: ^\d+(\.\d{1,2})?$ currency: type: string description: ISO 4217 currency code example: EUR minLength: 3 maxLength: 3 Link: type: object description: HATEOAS link to a related resource required: - href - type properties: href: type: string format: uri description: URL of the linked resource example: https://api.vatly.com/v1/orders/order_Hn5xWqVfKm8RjTgYbUcP type: type: string description: | Content type of the linked resource. - `application/json` for API resources - `text/html` for hosted pages enum: - application/json - text/html example: application/json BillingAddress: type: object description: Customer or merchant billing address properties: fullName: type: - string - 'null' description: Full name of the person or contact example: John Doe companyName: type: - string - 'null' description: Company or organization name example: Acme Corp taxId: type: - string - 'null' description: Tax identification number for tax purposes example: NL123456789B01 streetAndNumber: type: - string - 'null' description: Street address including building number example: 123 Main Street streetAdditional: type: - string - 'null' description: Additional address information (apartment, suite, etc.) example: Suite 456 city: type: - string - 'null' description: City name example: Amsterdam region: type: - string - 'null' description: State, province, or region example: North Holland postalCode: type: - string - 'null' description: Postal or ZIP code example: 1012 AB country: type: - string - 'null' description: ISO 3166-1 alpha-2 country code example: NL minLength: 2 maxLength: 2 BillingDetails: type: object description: Complete billing details including address and contact information properties: fullName: type: - string - 'null' description: Full name of the person or contact example: John Doe companyName: type: - string - 'null' description: Company or organization name example: Acme Corp taxId: type: - string - 'null' description: Tax identification number example: NL123456789B01 streetAndNumber: type: - string - 'null' description: Street address including building number example: 123 Main Street streetAdditional: type: - string - 'null' description: Additional address information example: Suite 456 city: type: - string - 'null' description: City name example: Amsterdam region: type: - string - 'null' description: State, province, or region example: North Holland postalCode: type: - string - 'null' description: Postal or ZIP code example: 1012 AB country: type: - string - 'null' description: ISO 3166-1 alpha-2 country code example: NL email: type: - string - 'null' format: email description: Email address example: billing@acme.com Metadata: type: - object - 'null' description: | Arbitrary key-value metadata for your application. Up to 50 keys, with key names up to 40 characters and values up to 500 characters. additionalProperties: type: string maxLength: 500 maxProperties: 50 example: orderId: internal-12345 campaign: summer-sale PaginationLinks: type: object description: Pagination links for navigating list results required: - self properties: self: allOf: - $ref: '#/components/schemas/Link' description: Link to the current page next: oneOf: - $ref: '#/components/schemas/Link' - type: 'null' description: Link to the next page (null if on the last page) prev: oneOf: - $ref: '#/components/schemas/Link' - type: 'null' description: Link to the previous page (null if on the first page) Error: type: object description: Standard error response required: - message properties: message: type: string description: Human-readable error message example: The requested resource was not found. ValidationError: type: object description: Validation error response with field-specific errors required: - message - errors properties: message: type: string description: General validation error message example: The given data was invalid. errors: type: object description: | Field-specific validation errors. Keys are field names (using dot notation for nested fields). Values are arrays of error messages. additionalProperties: type: array items: type: string example: email: - The email field is required. products.0.id: - The selected products.0.id is invalid. Checkout: type: object description: | A checkout session represents a hosted payment flow. Customers are redirected to the checkout URL to complete their purchase. required: - id - resource - testmode - redirectUrlSuccess - redirectUrlCanceled - metadata - status - createdAt - links properties: id: type: string description: Unique identifier for the checkout example: checkout_QdEpFhdSrG4Y3DnfsdqsH resource: type: string description: Resource type identifier const: checkout example: checkout orderId: type: - string - 'null' description: | ID of the order created from this checkout. Only present after checkout completion. example: order_Tk7mNvBxKw2RjTgYcZaE testmode: type: boolean description: Whether this checkout is in test mode example: false redirectUrlSuccess: type: string format: uri description: URL to redirect customers after successful payment example: https://example.com/success redirectUrlCanceled: type: string format: uri description: URL to redirect customers if they cancel the checkout example: https://example.com/canceled metadata: $ref: '#/components/schemas/Metadata' status: type: string description: | Current status of the checkout: - `created` - Checkout is active and awaiting payment - `paid` - Payment successful, order created - `canceled` - Checkout was canceled by the customer - `failed` - Payment failed - `expired` - Checkout expired without completion enum: - created - paid - canceled - failed - expired example: created expiresAt: type: - string - 'null' format: date-time description: When this checkout will expire (ISO 8601 format) example: '2024-01-15T14:30:00Z' createdAt: type: string format: date-time description: When this checkout was created (ISO 8601 format) example: '2024-01-15T10:30:00Z' links: type: object description: HATEOAS links to related resources required: - checkoutUrl - self properties: checkoutUrl: allOf: - $ref: '#/components/schemas/Link' description: Hosted checkout page URL (text/html) self: allOf: - $ref: '#/components/schemas/Link' description: Link to this checkout resource order: oneOf: - $ref: '#/components/schemas/Link' - type: 'null' description: Link to the created order (only after completion) CheckoutProduct: type: object description: A product to add to the checkout required: - id properties: id: type: string description: | Product identifier. Must be either: - A one-off product ID (starts with `one_off_product_`) - A subscription plan ID (starts with `subscription_plan_`) pattern: ^(one_off_product_|subscription_plan_) example: one_off_product_Vr8kQdFhSrG4Y3DnfsdqH quantity: type: integer description: Number of units to purchase minimum: 1 default: 1 example: 2 price: oneOf: - $ref: '#/components/schemas/Money' - type: 'null' description: | Custom price override for this product. If not provided, the product's default price is used. trialDays: type: - integer - 'null' description: | Trial period in days for subscription plans. Only applicable when `id` references a subscription plan. minimum: 0 example: 14 metadata: $ref: '#/components/schemas/Metadata' CreateCheckoutRequest: type: object description: Request body for creating a new checkout required: - redirectUrlSuccess - redirectUrlCanceled - products properties: redirectUrlSuccess: type: string format: uri description: URL to redirect customers after successful payment example: https://example.com/success?session_id=checkout_QdEpFhdSrG4Y3DnfsdqsH redirectUrlCanceled: type: string format: uri description: URL to redirect customers if they cancel the checkout example: https://example.com/canceled customerId: type: - string - 'null' description: | Existing customer ID to associate with this checkout. If provided, the customer's email will be pre-filled. Must match the testmode of the API token. example: customer_7kBmRtPvXw2NjLhYcZaE metadata: $ref: '#/components/schemas/Metadata' products: type: array description: Products to include in this checkout minItems: 1 items: $ref: '#/components/schemas/CheckoutProduct' example: - id: one_off_product_Vr8kQdFhSrG4Y3DnfsdqH quantity: 1 - id: subscription_plan_Rk5pQrSvWm8NjLhYbUcP trialDays: 14 Customer: type: object description: | A customer represents a person or organization that can make purchases. Customers are uniquely identified by their email address within each testmode. required: - id - resource - testmode - email - createdAt - metadata - links properties: id: type: string description: Unique identifier for the customer example: customer_7kBmRtPvXw2NjLhYcZaE resource: type: string description: Resource type identifier const: customer example: customer testmode: type: boolean description: Whether this customer is in test mode example: false email: type: string format: email description: Customer's email address example: customer@example.com createdAt: type: string format: date-time description: When this customer was created (ISO 8601 format) example: '2024-01-15T10:30:00Z' metadata: $ref: '#/components/schemas/Metadata' links: type: object description: HATEOAS links to related resources required: - self properties: self: $ref: '#/components/schemas/Link' description: Link to this customer resource CreateCustomerRequest: type: object description: Request body for creating a new customer required: - email properties: email: type: string format: email description: | Customer's email address. Must be unique within the merchant's account for the given testmode. example: customer@example.com metadata: $ref: '#/components/schemas/Metadata' OneOffProduct: type: object description: | A one-off product represents a single-purchase item. Products are configured in the Vatly dashboard and can be added to checkouts. required: - id - resource - testmode - name - description - basePrice - status - createdAt - links properties: id: type: string description: Unique identifier for the product (always starts with `one_off_product_`) pattern: ^one_off_product_ example: one_off_product_Vr8kQdFhSrG4Y3DnfsdqH resource: type: string description: Resource type identifier const: one_off_product example: one_off_product testmode: type: boolean description: Whether this product is in test mode example: false name: type: string description: Display name of the product example: Premium License description: type: string description: Detailed description of the product example: Lifetime access to all premium features basePrice: $ref: '#/components/schemas/Money' description: Default price of the product (can be overridden in checkout) status: type: string description: | Current status of the product: - `active` - Product is active and can be purchased - `pending` - Product is awaiting approval - `rejected` - Product has been rejected enum: - active - pending - rejected example: active createdAt: type: string format: date-time description: When this product was created (ISO 8601 format) example: '2024-01-15T10:30:00Z' links: type: object description: HATEOAS links to related resources required: - self properties: self: $ref: '#/components/schemas/Link' description: Link to this product resource SubscriptionPlan: type: object description: | A subscription plan defines recurring billing terms. Plans are configured in the Vatly dashboard and can be added to checkouts. required: - id - resource - testmode - name - description - basePrice - interval - intervalCount - status - createdAt - links properties: id: type: string description: Unique identifier for the plan (always starts with `subscription_plan_`) pattern: ^subscription_plan_ example: subscription_plan_Wt5mNvBxKw7YcZaEjLhR resource: type: string description: Resource type identifier const: subscription_plan example: subscription_plan testmode: type: boolean description: Whether this plan is in test mode example: false name: type: string description: Display name of the plan example: Pro Monthly description: type: string description: Detailed description of the plan example: Full access to all Pro features, billed monthly basePrice: $ref: '#/components/schemas/Money' description: Price per billing interval interval: type: string description: | Billing interval unit: - `day` - Daily billing - `week` - Weekly billing - `month` - Monthly billing - `year` - Yearly billing enum: - day - week - month - year example: month intervalCount: type: integer description: | Number of interval units between billing cycles. For example, `interval: month` with `intervalCount: 3` bills every 3 months. minimum: 1 example: 1 status: type: string description: | Current status of the plan: - `active` - Plan is active and can be subscribed to - `pending` - Plan is awaiting approval - `rejected` - Plan has been rejected enum: - active - pending - rejected example: active createdAt: type: string format: date-time description: When this plan was created (ISO 8601 format) example: '2024-01-15T10:30:00Z' links: type: object description: HATEOAS links to related resources required: - self properties: self: $ref: '#/components/schemas/Link' description: Link to this plan resource Order: type: object description: | An order represents a completed purchase. Orders are created when checkouts complete or subscriptions renew. required: - id - resource - testmode - metadata - createdAt - status - total - subtotal - taxSummary - lines - customerDetails - links properties: id: type: string description: Unique identifier for the order example: order_Hn5xWqVfKm8RjTgYbUcP resource: type: string description: Resource type identifier const: order example: order customerId: type: - string - 'null' description: ID of the customer who made this purchase. Only present when a customer is associated. example: customer_Lp3mNvBxKw7RjTgYcZaE testmode: type: boolean description: Whether this order is in test mode example: false metadata: $ref: '#/components/schemas/Metadata' paymentMethod: type: - string - 'null' description: | Payment method used for this order. Examples: `ideal`, `creditcard`, `bancontact`, `paypal` example: ideal createdAt: type: string format: date-time description: When this order was created (ISO 8601 format) example: '2024-01-15T10:30:00Z' status: type: string description: | Current status of the order: - `created` - Order has just been created - `pending` - Payment is being processed - `paid` - Payment successful - `canceled` - Order has been canceled - `expired` - Order has expired enum: - created - pending - paid - canceled - expired example: paid invoiceNumber: type: - string - 'null' description: Invoice number for this order (assigned after payment) example: INV-2024-0001 total: $ref: '#/components/schemas/Money' description: Total amount including taxes subtotal: $ref: '#/components/schemas/Money' description: Subtotal amount before taxes taxSummary: type: array description: Tax breakdown by rate items: $ref: '#/components/schemas/TaxSummaryItem' lines: type: array description: Line items in this order items: $ref: '#/components/schemas/OrderLine' customerDetails: $ref: '#/components/schemas/BillingDetails' description: Customer billing details (buyer) links: type: object description: HATEOAS links to related resources required: - self properties: self: allOf: - $ref: '#/components/schemas/Link' description: Link to this order resource customer: allOf: - $ref: '#/components/schemas/Link' description: Link to the customer who made this purchase. Only present when a customer is associated. customerInvoice: allOf: - $ref: '#/components/schemas/Link' description: Link to the customer-facing invoice in the customer portal OrderLine: type: object description: A line item in an order required: - id - resource - description - quantity - basePrice - total - subtotal - taxes properties: id: type: string description: Unique identifier for this line item example: order_item_Jk4pQrSvWm8NjLhYbUcP resource: type: string description: Resource type identifier const: orderline example: orderline description: type: string description: Description of the item example: Pro Monthly Subscription quantity: type: integer description: Number of units minimum: 1 example: 1 basePrice: $ref: '#/components/schemas/Money' description: Price per unit before taxes total: $ref: '#/components/schemas/Money' description: Total price including taxes (basePrice * quantity + taxes) subtotal: $ref: '#/components/schemas/Money' description: Subtotal before taxes (basePrice * quantity) taxes: type: array description: Tax breakdown by rate for this line items: $ref: '#/components/schemas/TaxSummaryItem' AddressUpdateLink: type: object description: A signed URL to update order billing address required: - href - type properties: href: type: string format: uri description: | Signed URL to the address update page. Valid for a limited time (typically 24 hours). example: https://vatly.com/invoices/order_Hn5xWqVfKm8RjTgYbUcP/edit?signature=abc123... type: type: string description: Content type of the linked page const: text/html example: text/html Refund: type: object description: | A refund represents a partial or full reversal of an order payment. Refunds are processed through the original payment provider. required: - id - resource - customerId - testmode - createdAt - status - originalOrderId - total - subtotal - taxSummary - lines - links properties: id: type: string description: Unique identifier for the refund example: refund_Xk9pQrSvWm4NjLhYbUcP resource: type: string description: Resource type identifier const: refund example: refund orderId: type: - string - 'null' description: | ID of the credit note order created for this refund. Only present after the refund is processed. example: order_Vr8kQdFhSrG4Y3DnfsdqH customerId: type: string description: ID of the customer receiving the refund example: customer_Lp3mNvBxKw7RjTgYcZaE testmode: type: boolean description: Whether this refund is in test mode example: false createdAt: type: string format: date-time description: When this refund was created (ISO 8601 format) example: '2024-01-15T10:30:00Z' status: type: string description: | Current status of the refund: - `pending` - Refund is ready to be sent to the bank - `queued` - Refund is queued due to a lack of balance - `processing` - Refund is being processed (cancellation no longer possible) - `refunded` - Refund has been processed successfully - `failed` - Refund has failed after processing - `canceled` - Refund was canceled enum: - pending - queued - processing - refunded - failed - canceled example: refunded originalOrderId: type: string description: ID of the original order being refunded example: order_Fp2kQrSvWm8NjLhYbUcP total: $ref: '#/components/schemas/Money' description: Total refund amount including taxes subtotal: $ref: '#/components/schemas/Money' description: Refund subtotal before taxes taxSummary: type: array description: Tax breakdown by rate being refunded items: $ref: '#/components/schemas/TaxSummaryItem' lines: type: array description: Refund line items items: $ref: '#/components/schemas/RefundLine' links: type: object description: HATEOAS links to related resources required: - self - originalOrder properties: self: allOf: - $ref: '#/components/schemas/Link' description: Link to this refund resource originalOrder: allOf: - $ref: '#/components/schemas/Link' description: Link to the original order order: oneOf: - $ref: '#/components/schemas/Link' - type: 'null' description: Link to the credit note order (if created) RefundLine: type: object description: A line item in a refund required: - id - resource - description - quantity - basePrice - total - subtotal - taxes properties: id: type: string description: Unique identifier for this refund line example: refund_item_Tk7mNvBxKw2RjTgYcZaE resource: type: string description: Resource type identifier const: refundline example: refundline description: type: string description: Description of the refunded item example: Pro Monthly Subscription (Refund) quantity: type: integer description: Number of units being refunded minimum: 1 example: 1 basePrice: $ref: '#/components/schemas/Money' description: Refund amount per unit before taxes total: $ref: '#/components/schemas/Money' description: Total refund amount including taxes subtotal: $ref: '#/components/schemas/Money' description: Refund subtotal before taxes taxes: type: array description: Tax breakdown by rate being refunded items: $ref: '#/components/schemas/TaxSummaryItem' CreateRefundRequest: type: object description: Request body for creating a partial refund required: - items properties: items: type: array description: Items to refund minItems: 1 items: $ref: '#/components/schemas/RefundItem' example: - itemId: order_item_Jk4pQrSvWm8NjLhYbUcP amount: value: '15.00' currency: EUR description: Partial refund metadata: $ref: '#/components/schemas/Metadata' CreateFullRefundRequest: type: object description: Request body for creating a full refund properties: metadata: $ref: '#/components/schemas/Metadata' Chargeback: type: object description: | A chargeback represents a payment dispute initiated by a customer through their bank or card issuer. Chargebacks are created automatically when payment providers notify Vatly of a dispute. required: - id - resource - testmode - createdAt - amount - settlementAmount - reason - originalOrderId - links properties: id: type: string description: Unique identifier for the chargeback example: chargeback_Mn6xBtPvKw2RjTgYcZaE resource: type: string description: Resource type identifier const: chargeback example: chargeback testmode: type: boolean description: Whether this chargeback is in test mode example: false createdAt: type: string format: date-time description: When this chargeback was created (ISO 8601 format) example: '2024-01-15T10:30:00Z' amount: $ref: '#/components/schemas/Money' description: Amount of the chargeback settlementAmount: $ref: '#/components/schemas/Money' description: | Amount that was deducted from the merchant's settlement. May differ from `amount` due to currency conversion or fees. reason: type: string description: | Reason code or description for the chargeback. Common reasons include: - `fraud` - Unauthorized transaction - `product_not_received` - Customer claims non-delivery - `product_unacceptable` - Customer claims product was defective - `duplicate` - Customer claims duplicate charge - `subscription_canceled` - Customer claims subscription was canceled example: fraud originalOrderId: type: string description: ID of the original order that was charged back example: order_Fp2kQrSvWm8NjLhYbUcP orderId: type: - string - 'null' description: | ID of the credit note order created for this chargeback. Only present after the chargeback is processed. example: order_Rk5pQrSvWm8NjLhYbUcP links: type: object description: HATEOAS links to related resources required: - self - originalOrder properties: self: allOf: - $ref: '#/components/schemas/Link' description: Link to this chargeback resource originalOrder: allOf: - $ref: '#/components/schemas/Link' description: Link to the original order order: oneOf: - $ref: '#/components/schemas/Link' - type: 'null' description: Link to the credit note order (if created) WebhookEvent: type: object description: | A webhook event represents a domain event that was sent to a webhook endpoint. Each event contains the full resource payload at the time the event occurred. required: - id - resource - eventName - entityType - entityId - object - links properties: id: type: string description: Unique identifier for the webhook event example: webhook_event_Qk8pRtSvWm2NjLhYcZaE resource: type: string description: Resource type identifier const: webhook_event example: webhook_event eventName: type: string description: | Name of the event that triggered this webhook. Possible values: - `order.paid` - Order payment was successful - `order.canceled` - Order was canceled - `order.chargeback_received` - Chargeback was received for an order - `order.chargeback_reversed` - Chargeback was reversed - `refund.completed` - Refund was processed successfully - `refund.failed` - Refund processing failed - `refund.canceled` - Refund was canceled - `subscription.started` - Subscription was started - `subscription.canceled_immediately` - Subscription was canceled immediately - `subscription.canceled_with_grace_period` - Subscription was canceled with a grace period - `subscription.cancellation_grace_period_completed` - Subscription grace period ended - `checkout.expired` - Checkout session expired example: order.paid entityType: type: string description: Type of the resource this event relates to example: order entityId: type: string description: ID of the resource this event relates to example: order_Hn5xWqVfKm8RjTgYbUcP object: type: object description: | The full resource payload at the time of the event. The shape depends on the `entityType` (e.g., Order, Refund, Chargeback, Subscription, Checkout). links: type: object description: HATEOAS links to related resources required: - self properties: self: allOf: - $ref: '#/components/schemas/Link' description: Link to this webhook event resource Subscription: type: object description: | A subscription represents a recurring billing relationship with a customer. Subscriptions automatically renew according to their billing interval. required: - id - resource - customerId - testmode - name - description - billingAddress - basePrice - quantity - interval - intervalCount - status - links properties: id: type: string description: Unique identifier for the subscription example: subscription_Lp3mNvBxKw7RjTgYcZaE resource: type: string description: Resource type identifier const: subscription example: subscription customerId: type: string description: ID of the customer who owns this subscription example: customer_Lp3mNvBxKw7RjTgYcZaE subscriptionPlanId: type: string description: ID of the subscription plan this subscription is based on example: subscription_plan_Wt5mNvBxKw7YcZaEjLhR testmode: type: boolean description: Whether this subscription is in test mode example: false name: type: string description: Name of the subscription (from the plan) example: Pro Monthly description: type: string description: Description of the subscription example: Full access to all Pro features billingAddress: $ref: '#/components/schemas/BillingAddress' description: Customer's billing address for this subscription basePrice: $ref: '#/components/schemas/Money' description: Price per billing cycle before taxes quantity: type: integer description: Number of subscription units (e.g., seats) minimum: 1 example: 1 interval: type: string description: Billing interval unit enum: - day - week - month - year example: month intervalCount: type: integer description: Number of interval units between billing cycles minimum: 1 example: 1 status: type: string description: | Current status of the subscription: - `active` - Subscription is active and will renew - `created` - Subscription has been created but not yet started - `trial` - Subscription is in trial period - `on_grace_period` - Subscription is canceled but still active until period ends - `paused` - Subscription is temporarily paused - `canceled` - Subscription has been canceled enum: - active - created - trial - on_grace_period - paused - canceled example: active startedAt: type: - string - 'null' format: date-time description: When the subscription started (ISO 8601 format) example: '2024-01-15T10:30:00Z' endedAt: type: - string - 'null' format: date-time description: When the subscription ended (ISO 8601 format) cancelledAt: type: - string - 'null' format: date-time description: When the subscription was canceled (ISO 8601 format) renewedAt: type: - string - 'null' format: date-time description: When the subscription was last renewed (ISO 8601 format) example: '2024-02-15T10:30:00Z' renewedUntil: type: - string - 'null' format: date-time description: Current billing period end date (ISO 8601 format) example: '2024-03-15T10:30:00Z' nextRenewalAt: type: - string - 'null' format: date-time description: | When the next renewal will be attempted (ISO 8601 format). Null if subscription is canceled or ended. example: '2024-03-15T10:30:00Z' trialUntil: type: - string - 'null' format: date-time description: | When the trial period ends (ISO 8601 format). Null if not in trial or trial has ended. links: type: object description: HATEOAS links to related resources required: - self - customer properties: self: allOf: - $ref: '#/components/schemas/Link' description: Link to this subscription resource customer: allOf: - $ref: '#/components/schemas/Link' description: Link to the customer who owns this subscription UpdateSubscriptionRequest: type: object description: | Request body for updating a subscription. At least one of `subscriptionPlanId` or `quantity` must be provided. properties: subscriptionPlanId: type: string description: | ID of the new subscription plan. Must match the testmode of the current subscription. pattern: ^subscription_plan_ example: subscription_plan_Wt5mNvBxKw7YcZaEjLhR quantity: type: integer description: New quantity (e.g., number of seats) minimum: 1 example: 5 prorate: type: boolean description: | Whether to prorate charges for the partial billing period. If true, the customer is credited for unused time on the old plan and charged for remaining time on the new plan. default: true example: true applyImmediately: type: boolean description: | Whether to apply changes immediately or at the end of the current billing period. - `true`: Changes take effect immediately (with proration if enabled) - `false`: Changes apply when the current period ends default: false example: true invoiceImmediately: type: boolean description: | Whether to generate and charge an invoice immediately for proration. Only applies when `applyImmediately` and `prorate` are both true. default: false example: false anchor: type: - string - 'null' format: date description: | Reset the billing anchor to this date. Cannot be combined with `trialUntil`. example: '2024-02-01' trialUntil: type: - string - 'null' format: date-time description: | Extend or set a trial period until this date (ISO 8601 format). Cannot be combined with `anchor`. example: '2024-02-15T00:00:00Z' UpdateSubscriptionBillingRequest: type: object description: Request body for updating subscription billing details via hosted flow required: - redirectUrlSuccess - redirectUrlCanceled properties: redirectUrlSuccess: type: string format: uri description: URL to redirect after successful billing update example: https://example.com/billing-updated redirectUrlCanceled: type: string format: uri description: URL to redirect if customer cancels the update example: https://example.com/billing-canceled billingAddress: oneOf: - $ref: '#/components/schemas/BillingAddress' - type: 'null' description: | Pre-fill billing address fields. Customer can modify these values in the hosted form. TaxSummaryRate: type: object description: Simplified tax rate information required: - name - percentage - taxablePercentage properties: name: type: string description: Human-readable name of the tax rate example: VAT percentage: type: number description: Tax rate percentage example: 21 taxablePercentage: type: number description: Percentage of the amount that is taxable example: 100 TaxSummaryItem: type: object description: A single tax rate entry with its calculated amount required: - taxRate - amount properties: taxRate: $ref: '#/components/schemas/TaxSummaryRate' amount: $ref: '#/components/schemas/Money' description: Tax amount for this rate RefundItem: type: object description: An item to refund from an order required: - itemId - amount properties: itemId: type: string description: ID of the order line item to refund example: order_item_Jk4pQrSvWm8NjLhYbUcP amount: $ref: '#/components/schemas/Money' description: | Amount to refund for this item (before taxes). Cannot exceed the remaining refundable amount for the item. description: type: - string - 'null' description: Custom description for this refund line example: Partial refund for service issue descriptionAdditionalLine: type: - string - 'null' description: Additional description line for the refund example: 'Ticket #12345'