# Donutwork AI API Reference

This document is designed for AI systems to understand and integrate with the Donutwork API.

## GET /ping.json
**Service:** authentication
**Version:** 2026-02-01

**Required Scope:** `ping:read`
**Permission Constant:** `ApiAccessPermission::PING_READ`

### Responses
#### 200 OK
API is operational and responding.

```json
{
  "status": "success",
  "env": "production",
  "RRT": "0.08 ms"
}
```

#### 401 Unauthorized
Invalid or revoked API key.

```json
{
  "error": "Invalid token"
}
```

---

## GET /connection.json
**Service:** authentication
**Version:** 2026-02-01

**Required Scope:** `connection:read`
**Permission Constant:** `ApiAccessPermission::CONNECTION_READ`

### Responses
#### 200 OK
Connection metadata retrieved successfully.

```json
{
  "client": {
    "userAgent": "axios/1.6.0",
    "ips": {
      "ipv4": "192.168.1.1"
    }
  },
  "endpoint": {
    "apiVersion": "2026-02-01",
    "env": "production",
    "protocol": "HTTP3"
  }
}
```

---

## GET /company.json
**Service:** company
**Version:** 2026-02-01

**Required Scope:** `company:read`
**Permission Constant:** `ApiAccessPermission::COMPANY_READ`

### Responses
#### 200 OK
Company profile retrieved successfully.

```json
{
  "id": "668ea32f5485467fd7149f48",
  "name": "Acme Corp"
}
```

---

## GET /company/modules.json
**Service:** company
**Version:** 2026-02-01

**Required Scope:** `company_modules:read`
**Permission Constant:** `ApiAccessPermission::COMPANY_MODULES_READ`

### Responses
#### 200 OK
List of organizational modules.

```json
[
  {
    "id": "recurring-payments",
    "description": "Automated subscription billing and payment orchestration.",
    "price": 0,
    "active": true
  },
  {
    "id": "email-gateway",
    "description": "Transactional email delivery via unified REST interface.",
    "price": 0,
    "active": true
  },
  {
    "id": "geoip",
    "description": "IPv4 geolocation and regional metadata resolution.",
    "price": 0,
    "active": true
  }
]
```

---

## GET /company/stats/intelligence.json
**Service:** company
**Version:** 2026-02-01

**Required Scope:** `company_stats:read`
**Permission Constant:** `ApiAccessPermission::COMPANY_STATS_READ`

### Responses
#### 200 OK
Company intelligence payload retrieved.

```json
{
  "kpi": {
    "mrr_growth": {
      "raw_percent": 12.3,
      "display_label": "12.30%"
    },
    "total_customers": 120,
    "active_subscriptions": 93
  },
  "usage": {
    "banner": {
      "show": false,
      "status": null,
      "upgrade_url": null
    },
    "widgets": []
  },
  "recent_activity": [],
  "revenue_chart": {
    "graph": [],
    "stats": {
      "one_shot": 0,
      "subscriptions": 0,
      "total": 0
    }
  },
  "revenue_insights": {
    "visible": false,
    "net_revenue": 0,
    "tax_total": 0,
    "discounts_total": 0,
    "services": [],
    "top_services": []
  },
  "meta": {
    "company_id": "668ea32f5485467fd7149f48",
    "year": 2026,
    "month": 4,
    "generated_at": "2026-04-15T10:00:00+00:00"
  }
}
```

---

## GET /company/{vatNumber}.json
**Service:** company
**Version:** 2026-02-01

**Required Scope:** `companies_open_data:read`
**Permission Constant:** `ApiAccessPermission::COMPANIES_OPEN_DATA_READ`

### Responses
#### 200 OK
Public company data found.

```json
{
  "vatNumber": "IT12345678901",
  "name": "Example Solutions S.r.l.",
  "address": "Corso Vittorio Emanuele II, 1, 00186 Roma RM, Italy",
  "vies_interrogation": {
    "valid": true
  }
}
```

#### 404 Not Found
No data available for the specified VAT number.

```json
{
  "error": "Company not found"
}
```

---

## GET /currencies.json
**Service:** currency
**Version:** 2026-02-01

**Required Scope:** `currencies:read`
**Permission Constant:** `ApiAccessPermission::CURRENCIES_READ`

### Responses
#### 200 OK
List of supported ISO 4217 currency codes (uppercase).

```json
[
  "EUR",
  "USD",
  "GBP"
]
```

---

## POST /currencies/{fromCurrency}/{toCurrency}.json
**Service:** currency
**Version:** 2026-02-01

**Required Scope:** `currencies:write`
**Permission Constant:** `ApiAccessPermission::CURRENCIES_WRITE`

### Parameters
- `amount` (number): The monetary value to be converted. Defaults to `0` when omitted.

### Request Body Example
```json
{
  "amount": 100
}
```

### Responses
#### 200 OK
Conversion successfully processed.

```json
{
  "from": "EUR",
  "to": "USD",
  "rate": 1.085,
  "amount": 108.5
}
```

#### 400 Bad Request
Unsupported base or destination currency code.

```json
{
  "error": "Invalid currency passed"
}
```

---

## GET /customers.json
**Service:** customer
**Version:** 2026-02-01

**Required Scope:** `customers:read`
**Permission Constant:** `ApiAccessPermission::CUSTOMERS_READ`

### Responses
#### 200 OK
A paginated list of customers.

```json
{
  "entities": "Customer",
  "count": 150,
  "per_page": 100,
  "pages": {
    "current": 1,
    "max": 2
  },
  "elements": [
    {
      "id": "67248941cbe2b1ff8b099a6c",
      "external_id": "CRM-UID-9921",
      "company_name": "Global Logistics S.A.",
      "email": "billing@globallogistics.com"
    }
  ]
}
```

---

## POST /customers.json
**Service:** customer
**Version:** 2026-02-01

**Required Scope:** `customers:write`
**Permission Constant:** `ApiAccessPermission::CUSTOMERS_WRITE`

### Parameters
- `customer.company_name` (string) *Required*: Official legal name of the organization.
- `customer.email` (string) *Required*: Primary contact email for billing and notifications.
- `customer.first_name` (string) *Required*: Contact person's first name.
- `customer.last_name` (string) *Required*: Contact person's last name.
- `customer.address.country` (string) *Required*: ISO 3166-1 alpha-2 country code (e.g., US, IT).
- `customer.externalId` (string): Your internal system identifier for cross-referencing.
- `customer.address.city` (string): City of residence or incorporation.
- `customer.address.address` (string): Street address including number.
- `customer.address.postal_code` (string): Postal or ZIP code.
- `customer.address.state` (string): State, province, or region.
- `customer.address.vat_number` (string): Tax identifier for business entities.
- `customer.properties` (array): Custom metadata fields for specialized integration logic.
- `customer.partner.id` (string): Donutwork identifier for a referring partner.

### Request Body Example
```json
{
  "customer": {
    "company_name": "Acme Corporation",
    "first_name": "Jane",
    "last_name": "Doe",
    "email": "jane.doe@acme.com",
    "externalId": "CRM-UID-9921",
    "address": {
      "country": "US",
      "city": "San Francisco",
      "address": "123 Market St"
    }
  }
}
```

### Responses
#### 201 Created
Customer profile successfully created.

```json
{
  "customer": {
    "id": "67c9...",
    "partner": null
  }
}
```

#### 409 Conflict
A profile with this email or externalId already exists.

```json
{
  "error": "A customer already exists with this email"
}
```

---

## GET /customers/{customerId}.json
**Service:** customer
**Version:** 2026-02-01

**Required Scope:** `customers:read`
**Permission Constant:** `ApiAccessPermission::CUSTOMERS_READ`

### Responses
#### 200 OK
Complete customer profile retrieved.

```json
{
  "id": "672489...",
  "email": "jane.doe@acme.com",
  "company_name": "Acme Corporation",
  "externalId": "CRM-UID-9921"
}
```

---

## GET /customers/customer.json
**Service:** customer
**Version:** 2026-02-01

**Required Scope:** `customers:read`
**Permission Constant:** `ApiAccessPermission::CUSTOMERS_READ`

### Responses
#### 200 OK
Customer profile found.

```json
{
  "id": "672489...",
  "email": "jane.doe@acme.com",
  "externalId": "CRM-UID-9921"
}
```

#### 404 Not Found
No customer matches the provided externalId.

```json
{
  "error": "This customer does not exist"
}
```

---

## PUT /customers/{customerId}.json
**Service:** customer
**Version:** 2026-02-01

**Required Scope:** `customers:write`
**Permission Constant:** `ApiAccessPermission::CUSTOMERS_WRITE`

### Parameters
- `customer.email` (string): The updated primary contact email.
- `customer.first_name` (string): Updated first name.
- `customer.last_name` (string): Updated last name.
- `customer.company_name` (string): Updated legal company name.
- `customer.tags` (array): A collection of labels for internal classification and reporting.
- `customer.address.country` (string): Updated ISO country code.

### Request Body Example
```json
{
  "customer": {
    "email": "updated.contact@acme.com",
    "tags": [
      "enterprise",
      "priority-support"
    ]
  }
}
```

### Responses
#### 200 OK
Customer profile successfully updated.

```json
{
  "customer": {
    "id": "6724..."
  }
}
```

---

## DELETE /customers/{customerId}.json
**Service:** customer
**Version:** 2026-02-01

**Required Scope:** `customers:write`
**Permission Constant:** `ApiAccessPermission::CUSTOMERS_WRITE`

### Responses
#### 202 Accepted
Deletion request accepted and queued for processing.

```json
{
  "id": "67c9...",
  "deleted": true
}
```

---

## GET /customers/{customerId}/properties.json
**Service:** customer
**Version:** 2026-02-01

**Required Scope:** `customer_properties:read`
**Permission Constant:** `ApiAccessPermission::CUSTOMER_PROPERTIES_READ`

### Responses
#### 200 OK
Collection of customer-specific properties retrieved.

```json
{
  "count": 2,
  "type": "CustomerProperties",
  "elements": {
    "crm_segment": "enterprise",
    "onboarding_status": "completed"
  }
}
```

---

## PUT /customers/{customerId}/properties.json
**Service:** customer
**Version:** 2026-02-01

**Required Scope:** `customer_properties:write`
**Permission Constant:** `ApiAccessPermission::CUSTOMER_PROPERTIES_WRITE`

### Parameters
- `CustomerProperties` (object) *Required*: An object containing the key-value pairs to persist.

### Request Body Example
```json
{
  "CustomerProperties": {
    "support_tier": "platinum",
    "preferred_language": "en"
  }
}
```

### Responses
#### 202 Accepted
Properties successfully updated.

```json
{
  "customer": {
    "id": "6724..."
  },
  "CustomerProperties": {
    "support_tier": "platinum",
    "preferred_language": "en"
  }
}
```

---

## GET /customers/{customerId}/payment_link.json
**Service:** customer
**Version:** 2026-02-01

**Required Scope:** `customers:read`
**Permission Constant:** `ApiAccessPermission::CUSTOMERS_READ`

### Responses
#### 200 OK
Secure payment link generated.

```json
{
  "url": "https://pay.donutwork.com/l/xxxxxxxxxx"
}
```

---

## GET /customers/{customerId}/subscriptions.json
**Service:** customer
**Version:** 2026-02-01

**Required Scope:** `customer_subscriptions:read`
**Permission Constant:** `ApiAccessPermission::CUSTOMER_SUBSCRIPTIONS_READ`

### Responses
#### 200 OK
A list of customer subscriptions.

```json
{
  "type": "CustomerSubscriptions",
  "elements": [
    {
      "id": "sub_123",
      "name": "Enterprise SaaS Plan",
      "status": "success",
      "next_renew": "2026-04-01",
      "price": {
        "amount": 499,
        "vat": {
          "percentage": 22,
          "name": "IVA"
        }
      }
    }
  ]
}
```

---

## POST /customers/{customerId}/subscriptions.json
**Service:** customer
**Version:** 2026-02-01

**Required Scope:** `customer_subscriptions:write`
**Permission Constant:** `ApiAccessPermission::CUSTOMER_SUBSCRIPTIONS_WRITE`

### Parameters
- `subscription.id` (string) *Required*: The identifier of the target plan.
- `subscription.taxes` (string) *Required*: The tax profile ID to apply to this subscription.
- `subscription.global_discount.value` (number): The absolute or percentage value of the discount.
- `subscription.global_discount.type` (string): The type of discount: 'percentage' or 'fixed'.
- `subscription.addons` (array): A list of addon overrides with their respective quantities.

### Request Body Example
```json
{
  "subscription": {
    "id": "PLAN_PREMIUM_V2",
    "taxes": "TAX_STANDARD_22",
    "global_discount": {
      "value": 15,
      "type": "percentage"
    },
    "addons": [
      {
        "element": "api_quota",
        "quantity": 10000
      }
    ]
  }
}
```

### Responses
#### 200 OK
Subscription successfully provisioned.

```json
{
  "id": "sub_67c9...",
  "name": "Starter Monthly",
  "status": "success",
  "next_renew": "2026-04-28",
  "price": {
    "amount": 39,
    "vat": {
      "percentage": 22,
      "name": "VAT Italy"
    }
  },
  "metering": {
    "active": false,
    "balance": {
      "amount": 0,
      "vat": {
        "percentage": 22,
        "name": "VAT Italy"
      }
    }
  },
  "limits": [],
  "addons": [],
  "discount": {
    "value": 0,
    "type": "fixed",
    "until": null
  },
  "lifecycle_status": "active",
  "cancel_at_period_end": false,
  "jobId": "123456"
}
```

---

## DELETE /customers/{customerId}/subscriptions/{subscriptionId}.json
**Service:** customer
**Version:** 2026-02-01

**Required Scope:** `customer_subscriptions:write`
**Permission Constant:** `ApiAccessPermission::CUSTOMER_SUBSCRIPTIONS_WRITE`

### Responses
#### 202 Accepted
Subscription detached from customer profile.

```json
{
  "id": "sub_67c9...",
  "deleted": true
}
```

---

## GET /customers/{customerId}/subscriptions/{subscriptionId}/status.json
**Service:** customer
**Version:** 2026-02-01

**Required Scope:** `customer_subscriptions:read`
**Permission Constant:** `ApiAccessPermission::CUSTOMER_SUBSCRIPTIONS_READ`

### Responses
#### 200 OK
Current status for the selected subscription.

```json
{
  "id": "sub_123",
  "status": "active",
  "next_renew": "2026-05-01"
}
```

#### 404 Not Found
Subscription does not exist for the specified customer.

```json
{
  "error": "This subscription does not exists for this customer"
}
```

---

## PUT /customers/{customerId}/subscriptions/{subscriptionId}/status.json
**Service:** customer
**Version:** 2026-02-01

**Required Scope:** `customer_subscriptions:write`
**Permission Constant:** `ApiAccessPermission::CUSTOMER_SUBSCRIPTIONS_WRITE`

### Parameters
- `subscription.status` (string) *Required*: Target status. Supported values: `active`, `dismiss`.

### Request Body Example
```json
{
  "subscription": {
    "status": "dismiss"
  }
}
```

### Responses
#### 200 OK
Status successfully updated.

```json
{
  "id": "sub_123",
  "status": "dismiss",
  "next_renew": null
}
```

---

## GET /customers/{customerId}/subscriptions/{subscriptionId}/lifecycle.json
**Service:** customer
**Version:** 2026-02-01

**Required Scope:** `customer_subscriptions:read`
**Permission Constant:** `ApiAccessPermission::CUSTOMER_SUBSCRIPTIONS_READ`

### Responses
#### 200 OK
Extended lifecycle metadata for the subscription.

```json
{
  "id": "sub_123",
  "status": "success",
  "lifecycle_status": "active",
  "cancel_at_period_end": false,
  "scheduled_change": null,
  "carryover_credit": 0
}
```

---

## PUT /customers/{customerId}/subscriptions/{subscriptionId}/lifecycle/pause.json
**Service:** customer
**Version:** 2026-02-01

**Required Scope:** `customer_subscriptions:write`
**Permission Constant:** `ApiAccessPermission::CUSTOMER_SUBSCRIPTIONS_WRITE`

### Parameters
- `lifecycle.idempotency_key` (string): Optional idempotency key for safe retries.

### Request Body Example
```json
{
  "lifecycle": {
    "idempotency_key": "lifecycle-evt-001"
  }
}
```

### Responses
#### 200 OK
Lifecycle transition applied.

```json
{
  "id": "sub_123",
  "lifecycle_status": "paused",
  "amendment": {
    "action": "pause",
    "status": "applied"
  }
}
```

---

## PUT /customers/{customerId}/subscriptions/{subscriptionId}/lifecycle/change-plan.json
**Service:** customer
**Version:** 2026-02-01

**Required Scope:** `customer_subscriptions:write`
**Permission Constant:** `ApiAccessPermission::CUSTOMER_SUBSCRIPTIONS_WRITE`

### Parameters
- `lifecycle.plan_id` (string) *Required*: Target plan identifier.
- `lifecycle.taxes` (string): Tax profile override.
- `lifecycle.when` (string): `immediate` (default) or `period_end`.
- `lifecycle.proration` (boolean): Enable or disable proration logic.

### Request Body Example
```json
{
  "lifecycle": {
    "plan_id": "PLAN_ENTERPRISE_V3",
    "taxes": "TAX_STANDARD_22",
    "when": "period_end",
    "proration": true
  }
}
```

### Responses
#### 200 OK
Plan change accepted (immediate or scheduled).

```json
{
  "id": "sub_123",
  "scheduled_change": {
    "type": "plan",
    "apply_on": "2026-06-01"
  },
  "amendment": {
    "action": "change_plan",
    "status": "applied"
  }
}
```

---

## PUT /customers/{customerId}/subscriptions/{subscriptionId}/lifecycle/change-addons.json
**Service:** customer
**Version:** 2026-02-01

**Required Scope:** `customer_subscriptions:write`
**Permission Constant:** `ApiAccessPermission::CUSTOMER_SUBSCRIPTIONS_WRITE`

### Request Body Example
```json
{
  "lifecycle": {
    "addons": [
      {
        "element": "workspace_seat",
        "quantity": 25
      }
    ],
    "when": "immediate",
    "proration": true
  }
}
```

### Responses
#### 200 OK
Addon amendment applied with optional proration.

```json
{
  "id": "sub_123",
  "carryover_credit": 18.5,
  "amendment": {
    "action": "change_addons",
    "status": "applied"
  }
}
```

---

## POST /customers/{customerId}/subscriptions/{subscriptionId}/lifecycle/preview.json
**Service:** customer
**Version:** 2026-02-01

**Required Scope:** `customer_subscriptions:read`
**Permission Constant:** `ApiAccessPermission::CUSTOMER_SUBSCRIPTIONS_READ`

### Request Body Example
```json
{
  "lifecycle": {
    "action": "change_addons",
    "addons": [
      {
        "element": "workspace_seat",
        "quantity": 40
      }
    ]
  }
}
```

### Responses
#### 200 OK
Economic preview of the amendment without persisting changes.

```json
{
  "action": "change_addons",
  "proration": {
    "old_due": 499,
    "new_due": 679,
    "delta": 180,
    "direction": "debit"
  }
}
```

---

## GET /customers/{customerId}/subscriptions/{subscriptionId}/amendments.json
**Service:** customer
**Version:** 2026-02-01

**Required Scope:** `customer_subscriptions:read`
**Permission Constant:** `ApiAccessPermission::CUSTOMER_SUBSCRIPTIONS_READ`

### Responses
#### 200 OK
Paginated amendment stream for audit and support operations.

```json
{
  "type": "CustomerSubscriptionAmendments",
  "elements": [
    {
      "action": "change_addons",
      "when": "immediate",
      "status": "applied"
    }
  ]
}
```

---

## GET /customers/{customerId}/subscriptions/{subscriptionId}/addons.json
**Service:** customer
**Version:** 2026-02-01

**Required Scope:** `customer_subscriptions:read`
**Permission Constant:** `ApiAccessPermission::CUSTOMER_SUBSCRIPTIONS_READ`

### Responses
#### 200 OK
List of provisioned addons.

```json
[
  {
    "element": "compute_units",
    "quantity": 10
  },
  {
    "element": "secondary_domains",
    "quantity": 2
  }
]
```

---

## PUT /customers/{customerId}/subscriptions/{subscriptionId}/addons.json
**Service:** customer
**Version:** 2026-02-01

**Required Scope:** `customer_subscriptions:write`
**Permission Constant:** `ApiAccessPermission::CUSTOMER_SUBSCRIPTIONS_WRITE`

### Parameters
- `addons` (array) *Required*: Addon collection to upsert.
- `addons[].element` (string) *Required*: Addon identifier.
- `addons[].quantity` (integer) *Required*: Requested addon quantity.

### Request Body Example
```json
{
  "addons": [
    {
      "element": "compute_units",
      "quantity": 15
    }
  ]
}
```

### Responses
#### 200 OK
Addon quantities successfully updated.

```json
{
  "status": "updated"
}
```

---

## POST /customers/{customerId}/subscriptions/simulate/{subscriptionId}.json
**Service:** customer
**Version:** 2026-02-01

**Required Scope:** `customer_subscriptions:write`
**Permission Constant:** `ApiAccessPermission::CUSTOMER_SUBSCRIPTIONS_WRITE`

### Responses
#### 200 OK
```json
{
  "status": "simulated_success"
}
```

---

## DELETE /customers/{customerId}/subscriptions/simulate/{subscriptionId}.json
**Service:** customer
**Version:** 2026-02-01

**Required Scope:** `customer_subscriptions:write`
**Permission Constant:** `ApiAccessPermission::CUSTOMER_SUBSCRIPTIONS_WRITE`

### Responses
#### 200 OK
```json
{
  "status": "simulated_failure"
}
```

---

## POST /customers/{customerId}/subscriptions/{subscriptionId}.json
**Service:** customer
**Version:** 2026-02-01

**Required Scope:** `customer_subscriptions:write`
**Permission Constant:** `ApiAccessPermission::CUSTOMER_SUBSCRIPTIONS_WRITE`

### Parameters
- `usage.amount` (number) *Required*: The monetary value or unit count to bill.
- `usage.value` (number) *Required*: The raw consumption value.
- `usage.value_type` (string) *Required*: The metric identifier (e.g., 'storage_gb', 'api_calls').
- `usage.externalId` (string) *Required*: A unique identifier for idempotency.

### Request Body Example
```json
{
  "usage": {
    "amount": 10.5,
    "value": 100,
    "value_type": "api_requests",
    "externalId": "evt_unique_uuid_123"
  }
}
```

### Responses
#### 200 OK
Usage successfully recorded.

```json
{
  "id": "usage_67c9...",
  "amount": 10.5
}
```

---

## GET /customers/{customerId}/subscriptions/{subscriptionId}.json
**Service:** customer
**Version:** 2026-02-01

**Required Scope:** `customer_subscriptions:read`
**Permission Constant:** `ApiAccessPermission::CUSTOMER_SUBSCRIPTIONS_READ`

### Responses
#### 200 OK
Paginated usage history retrieved.

```json
{
  "type": "CustomerSubscriptionUsages",
  "elements": []
}
```

---

## POST /customers/{customerId}/charges.json
**Service:** customer
**Version:** 2026-02-01

**Required Scope:** `charges:write`
**Permission Constant:** `ApiAccessPermission::CHARGES_WRITE`

### Parameters
- `charge.capture` (boolean): Whether to attempt immediate payment capture.
- `charge.services` (array) *Required*: A list of line items included in the charge.
- `charge.instruction` (string): Payment instruction (e.g., 'sepa_debit', 'manual').

### Request Body Example
```json
{
  "charge": {
    "capture": true,
    "services": [
      {
        "name": "Technical Consulting",
        "amount": 250,
        "taxProfile": "TAX_SERVICES_22"
      }
    ]
  }
}
```

### Responses
#### 200 OK
Charge created and payment status returned.

```json
{
  "status": "success",
  "id": "ch_777",
  "captured": true
}
```

---

## GET /customers/{customerId}/charges.json
**Service:** customer
**Version:** 2026-02-01

**Required Scope:** `charges:read`
**Permission Constant:** `ApiAccessPermission::CHARGES_READ`

### Responses
#### 200 OK
List of customer-specific charges.

```json
{
  "type": "CustomerCharges",
  "elements": []
}
```

---

## GET /customers/{customerId}/charges/{chargeId}.json
**Service:** customer
**Version:** 2026-02-01

**Required Scope:** `charges:read`
**Permission Constant:** `ApiAccessPermission::CHARGES_READ`

### Responses
#### 200 OK
Full charge metadata.

```json
{
  "id": "ch_777",
  "customer_id": "cust_123",
  "total": 305,
  "type": "one-shot",
  "status": "paid",
  "statuses": {
    "pending": false,
    "paid": true,
    "refunded": false
  },
  "date": {
    "date": "2026-03-01 10:00:00.000000",
    "timezone": "+00:00"
  }
}
```

---

## GET /customers/{customerId}/charges/{chargeId}/invoice.json
**Service:** customer
**Version:** 2026-02-01

**Required Scope:** `charges:read`
**Permission Constant:** `ApiAccessPermission::CHARGES_READ`

### Responses
#### 200 OK
Invoice synchronization details.

```json
{
  "number": "INV-2026-001",
  "date": "2026-03-01",
  "source": "accounting-system",
  "link": "https://docs.acme.com/inv/123.pdf"
}
```

---

## PUT /customers/{customerId}/charges/{chargeId}/invoice.json
**Service:** customer
**Version:** 2026-02-01

**Required Scope:** `charges:write`
**Permission Constant:** `ApiAccessPermission::CHARGES_WRITE`

### Parameters
- `invoice.number` (string) *Required*: Invoice number.
- `invoice.date` (string) *Required*: Invoice issue date.
- `invoice.source` (string): Originating source system identifier.
- `invoice.link` (string): Public or internal URL to invoice document.

### Request Body Example
```json
{
  "invoice": {
    "number": "INV-2026-001",
    "date": "2026-03-01",
    "source": "erp-system",
    "link": "https://erp.example.com/invoices/991.pdf"
  }
}
```

### Responses
#### 200 OK
```json
{
  "status": "success"
}
```

---

## GET /charges/{chargeId}.json
**Service:** customer
**Version:** 2026-02-01

**Required Scope:** `charges:read`
**Permission Constant:** `ApiAccessPermission::CHARGES_READ`

### Responses
#### 200 OK
Charge metadata resolved globally.

```json
{
  "id": "ch_777",
  "customer_id": "cust_123"
}
```

---

## POST /directory-monitor/{projectId}.json
**Service:** directory-monitor
**Version:** 2026-02-01

**Required Scope:** `directory_monitor:write`
**Permission Constant:** `ApiAccessPermission::DIRECTORY_MONITOR_WRITE`

### Parameters
- `ingressToken` (string): Security token for ingress authentication (can also be sent via X-Directory-Monitor-Token header).

### Request Body Example
```json
{
  "ingressToken": "DM_SECURE_TOKEN_XYZ"
}
```

### Responses
#### 200 OK
Monitor successfully initialized.

```json
{
  "status": "success",
  "projectId": "proj_123"
}
```

---

## PUT /directory-monitor/{projectId}.json
**Service:** directory-monitor
**Version:** 2026-02-01

**Required Scope:** `directory_monitor:write`
**Permission Constant:** `ApiAccessPermission::DIRECTORY_MONITOR_WRITE`

### Parameters
- `projectId` (string) *Required*: Must match the projectId in the path.
- `filename` (string) *Required*: Relative path of the affected file.
- `event` (string) *Required*: Type of event (e.g., created, modified, deleted, renamed).
- `filesize` (integer) *Required*: Size of the file in bytes.
- `filetype` (string): MIME type or file classification.
- `sha256` (string): SHA-256 hash of the file content for integrity verification.
- `uid` (integer): User ID of the process owner.
- `pid` (integer): Process ID that triggered the event.
- `timestampUtc` (string): ISO 8601 timestamp of the local event.
- `ingressToken` (string): Authentication token.

### Request Body Example
```json
{
  "projectId": "proj_123",
  "filename": "src/controllers/UserController.php",
  "event": "modified",
  "filesize": 4096,
  "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
  "uid": 1000,
  "pid": 4512
}
```

### Responses
#### 200 OK
Event successfully ingested and indexed.

```json
{
  "status": "success",
  "eventId": "evt_7721...",
  "projectId": "proj_123",
  "inserted": true,
  "workflowTriggered": true
}
```

---

## GET /systems/directory-monitor/{projectId}/events.json
**Service:** directory-monitor
**Version:** 2026-02-01

**Required Scope:** `directory_monitor:read`
**Permission Constant:** `ApiAccessPermission::DIRECTORY_MONITOR_READ`

### Responses
#### 200 OK
Collection of project events retrieved.

```json
{
  "status": "fetch",
  "projectId": "proj_123",
  "page": 1,
  "size": 50,
  "count": 120,
  "items": []
}
```

---

## GET /dns/capabilities.json
**Service:** dns
**Version:** 2026-02-01

**Required Scope:** `dns:read`
**Permission Constant:** `ApiAccessPermission::DNS_READ`

### Responses
#### 200 OK
Supported record types, default record types, and resolver catalog.

```json
{
  "recordTypes": [
    "A",
    "AAAA",
    "CNAME",
    "TXT",
    "MX",
    "NS",
    "SOA",
    "CAA",
    "SRV"
  ],
  "defaultRecordTypes": [
    "A",
    "AAAA",
    "CNAME",
    "TXT"
  ],
  "resolvers": [
    {
      "id": "cloudflare_primary",
      "label": "Cloudflare (1.1.1.1)",
      "server": "1.1.1.1"
    },
    {
      "id": "google_primary",
      "label": "Google (8.8.8.8)",
      "server": "8.8.8.8"
    }
  ]
}
```

---

## GET /dns/lookup.json
**Service:** dns
**Version:** 2026-02-01

**Required Scope:** `dns:read`
**Permission Constant:** `ApiAccessPermission::DNS_READ`

### Responses
#### 200 OK
DNS lookup completed.

```json
{
  "target": "example.com",
  "generated_at": "2026-04-15T10:00:00+00:00",
  "recordTypes": [
    "A",
    "AAAA"
  ],
  "resolver_count": 2,
  "resolvers": [
    {
      "id": "cloudflare_primary",
      "label": "Cloudflare (1.1.1.1)",
      "server": "1.1.1.1"
    },
    {
      "id": "google_primary",
      "label": "Google (8.8.8.8)",
      "server": "8.8.8.8"
    }
  ],
  "propagation": {
    "A": {
      "is_consistent": true,
      "distinct_statuses": 1,
      "distinct_answers": 1
    }
  },
  "queries": {
    "A": [
      {
        "resolver_label": "Cloudflare (1.1.1.1)",
        "resolver": "1.1.1.1",
        "record_type": "A",
        "status": "NOERROR",
        "server": "1.1.1.1#53",
        "query_time_ms": 12,
        "answers": [
          {
            "name": "example.com.",
            "ttl": 300,
            "class": "IN",
            "type": "A",
            "value": "93.184.216.34"
          }
        ],
        "answer_signature": "A|93.184.216.34",
        "error": null
      }
    ]
  }
}
```

#### 400 Bad Request
Invalid or missing target.

```json
{
  "error": "target is required"
}
```

---

## POST /dns/lookup.json
**Service:** dns
**Version:** 2026-02-01

**Required Scope:** `dns:write`
**Permission Constant:** `ApiAccessPermission::DNS_WRITE`

### Parameters
- `target` (string) *Required*: Hostname or IP to resolve.
- `recordTypes` (array|string): Record types list (for example A, MX, TXT).
- `resolverPreset` (array|string): Resolver preset filter.
- `customResolvers` (string): Space/comma separated custom resolvers.
- `resolvers` (array): Additional custom resolver list.

### Request Body Example
```json
{
  "target": "example.com",
  "recordTypes": [
    "A",
    "AAAA"
  ],
  "resolverPreset": [
    "public"
  ],
  "customResolvers": "1.1.1.1 8.8.8.8",
  "resolvers": [
    "9.9.9.9"
  ]
}
```

### Responses
#### 200 OK
DNS lookup completed.

```json
{
  "target": "example.com",
  "generated_at": "2026-04-15T10:00:00+00:00",
  "recordTypes": [
    "A",
    "AAAA"
  ],
  "resolver_count": 2,
  "resolvers": [
    {
      "id": "cloudflare_primary",
      "label": "Cloudflare (1.1.1.1)",
      "server": "1.1.1.1"
    },
    {
      "id": "google_primary",
      "label": "Google (8.8.8.8)",
      "server": "8.8.8.8"
    }
  ],
  "propagation": {
    "A": {
      "is_consistent": true,
      "distinct_statuses": 1,
      "distinct_answers": 1
    }
  },
  "queries": {
    "A": [
      {
        "resolver_label": "Cloudflare (1.1.1.1)",
        "resolver": "1.1.1.1",
        "record_type": "A",
        "status": "NOERROR",
        "server": "1.1.1.1#53",
        "query_time_ms": 12,
        "answers": [
          {
            "name": "example.com.",
            "ttl": 300,
            "class": "IN",
            "type": "A",
            "value": "93.184.216.34"
          }
        ],
        "answer_signature": "A|93.184.216.34",
        "error": null
      }
    ]
  }
}
```

---

## GET /contentbox/contents.json
**Service:** dynamic-content
**Version:** 2026-02-01

**Required Scope:** `contentbox_contents:read`
**Permission Constant:** `ApiAccessPermission::CONTENTBOX_CONTENTS_READ`

### Responses
#### 200 OK
Collection of content entities retrieved.

```json
{
  "entities": "Contents",
  "count": 12,
  "per_page": 50,
  "elements": [
    {
      "id": "6768...",
      "type_id": "6751...",
      "title": "Q1 Product Launch",
      "state": "public",
      "data": {
        "headline": "Introducing the 2026 Fleet",
        "hero_image": "https://cdn.acme.com/img/l1.jpg",
        "featured": true
      }
    }
  ]
}
```

---

## POST /contentbox/contents.json
**Service:** dynamic-content
**Version:** 2026-02-01

**Required Scope:** `contentbox_contents:write`
**Permission Constant:** `ApiAccessPermission::CONTENTBOX_CONTENTS_WRITE`

### Parameters
- `content.title` (string) *Required*: Internal-facing title for the content entry.
- `content.type_id` (string) *Required*: The unique identifier of the target Content Type schema.
- `content.state` (string): Operational state (default: 'draft').
- `content.data` (object): Dictionary of custom fields defined in the type schema.

### Request Body Example
```json
{
  "content": {
    "title": "Annual Sustainability Report",
    "type_id": "675112233b498f30",
    "state": "draft",
    "data": {
      "period": "2025",
      "impact_score": 92
    }
  }
}
```

### Responses
#### 201 Created
Content entity successfully provisioned.

```json
{
  "id": "6768..."
}
```

---

## PUT /contentbox/contents/{contentId}.json
**Service:** dynamic-content
**Version:** 2026-02-01

**Required Scope:** `contentbox_contents:write`
**Permission Constant:** `ApiAccessPermission::CONTENTBOX_CONTENTS_WRITE`

### Parameters
- `content.title` (string): Update the internal title.
- `content.state` (string): Transition the lifecycle state.
- `content.data` (object): Update specific keys within the data object.

### Request Body Example
```json
{
  "content": {
    "state": "public",
    "data": {
      "revised_at": "2026-03-01T10:00:00Z"
    }
  }
}
```

### Responses
#### 200 OK
Content entity successfully updated.

```json
{
  "id": "6768...",
  "updated": true
}
```

---

## GET /contentbox/contents/{contentId}.json
**Service:** dynamic-content
**Version:** 2026-02-01

**Required Scope:** `contentbox_contents:read`
**Permission Constant:** `ApiAccessPermission::CONTENTBOX_CONTENTS_READ`

### Responses
#### 200 OK
Content entity retrieved.

```json
{
  "id": "6768...",
  "title": "Q1 Product Launch",
  "state": "public",
  "data": {}
}
```

#### 404 Not Found
Content entry does not exist.

```json
{
  "error": "Content Box not found"
}
```

---

## DELETE /contentbox/contents/{contentId}.json
**Service:** dynamic-content
**Version:** 2026-02-01

**Required Scope:** `contentbox_contents:write`
**Permission Constant:** `ApiAccessPermission::CONTENTBOX_CONTENTS_WRITE`

### Responses
#### 202 Accepted
Deletion request processed.

```json
{
  "id": "6768...",
  "deleted": true
}
```

---

## GET /contentbox/types.json
**Service:** dynamic-content
**Version:** 2026-02-01

**Required Scope:** `contentbox_types:read`
**Permission Constant:** `ApiAccessPermission::CONTENTBOX_TYPES_READ`

### Responses
#### 200 OK
Collection of content type definitions.

```json
{
  "entities": "Types",
  "count": 1,
  "elements": [
    {
      "id": "6751...",
      "title": "Corporate Blog",
      "description": "Schema for official news",
      "fields": {
        "author": {
          "label": "Author",
          "type": "string"
        }
      }
    }
  ]
}
```

---

## POST /contentbox/types.json
**Service:** dynamic-content
**Version:** 2026-02-01

**Required Scope:** `contentbox_types:write`
**Permission Constant:** `ApiAccessPermission::CONTENTBOX_TYPES_WRITE`

### Parameters
- `type.title` (string) *Required*: Human-readable name for the schema.
- `type.description` (string): Internal description of the schema's purpose.
- `type.fields` (object) *Required*: A map of field definitions (key -> {label, type}).

### Request Body Example
```json
{
  "type": {
    "title": "E-Commerce Product",
    "description": "Standardized schema for catalog items.",
    "fields": {
      "sku": {
        "label": "SKU",
        "type": "string"
      },
      "price": {
        "label": "Unit Price",
        "type": "string"
      },
      "in_stock": {
        "label": "Inventory Status",
        "type": "checkbox"
      }
    }
  }
}
```

### Responses
#### 201 Created
Content type definition created.

```json
{
  "id": "6751...",
  "title": "E-Commerce Product"
}
```

---

## GET /contentbox/types/{typeId}.json
**Service:** dynamic-content
**Version:** 2026-02-01

**Required Scope:** `contentbox_types:read`
**Permission Constant:** `ApiAccessPermission::CONTENTBOX_TYPES_READ`

### Responses
#### 200 OK
Full schema definition retrieved.

```json
{
  "id": "6751...",
  "title": "Corporate Blog",
  "fields": {}
}
```

---

## PUT /contentbox/types/{typeId}.json
**Service:** dynamic-content
**Version:** 2026-02-01

**Required Scope:** `contentbox_types:write`
**Permission Constant:** `ApiAccessPermission::CONTENTBOX_TYPES_WRITE`

### Parameters
- `type.title` (string): Updated schema title.
- `type.description` (string): Updated schema description.
- `type.fields` (object): Updated field map. Each field requires `label` and `type`.

### Request Body Example
```json
{
  "type": {
    "title": "Corporate Blog",
    "description": "Schema for official company news",
    "fields": {
      "author": {
        "label": "Author",
        "type": "string"
      },
      "hero_image": {
        "label": "Hero Image",
        "type": "url"
      }
    }
  }
}
```

### Responses
#### 200 OK
Content type updated.

```json
{
  "id": "6751...",
  "title": "Corporate Blog",
  "description": "Schema for official company news",
  "fields": {}
}
```

#### 400 Bad Request
Invalid fields payload or field type.

```json
{
  "error": "Fields must be an associative array"
}
```

---

## GET /email-gateway/templates.json
**Service:** email-gateway
**Version:** 2026-02-01

**Required Scope:** `email_templates:read`
**Permission Constant:** `ApiAccessPermission::EMAIL_TEMPLATES_READ`

### Responses
#### 200 OK
Template list returned.

```json
{
  "entities": "Email Templates",
  "count": 2,
  "per_page": 100,
  "pages": {
    "current": 1,
    "max": 1
  },
  "elements": [
    {
      "id": "welcome.html",
      "endpoint": [
        {
          "type": "POST",
          "action": "Send email using this template",
          "url": "https://api.hub.donutwork.com/2026-02-01/email-gateway/welcome.html/send.json"
        }
      ]
    }
  ]
}
```

---

## POST /email-gateway/templates.json
**Service:** email-gateway
**Version:** 2026-02-01

**Required Scope:** `email_templates:write`
**Permission Constant:** `ApiAccessPermission::EMAIL_TEMPLATES_WRITE`

### Parameters
- `template.id` (string) *Required*: Template filename identifier.
- `template.content` (string): Optional initial template content.

### Request Body Example
```json
{
  "template": {
    "id": "welcome.html",
    "content": "<h1>Hello FIRST_NAME</h1>"
  }
}
```

### Responses
#### 201 Created
Template created.

```json
{
  "id": "welcome.html"
}
```

#### 409 Conflict
Template already exists.

```json
{
  "error": "Template already exists"
}
```

---

## GET /email-gateway/templates/{templateId}.json
**Service:** email-gateway
**Version:** 2026-02-01

**Required Scope:** `email_templates:read`
**Permission Constant:** `ApiAccessPermission::EMAIL_TEMPLATES_READ`

### Responses
#### 200 OK
Template returned.

```json
{
  "id": "welcome.html",
  "content": "<h1>Hello FIRST_NAME</h1>"
}
```

#### 404 Not Found
Template not found.

```json
{
  "error": "Template not found"
}
```

---

## PUT /email-gateway/templates/{templateId}.json
**Service:** email-gateway
**Version:** 2026-02-01

**Required Scope:** `email_templates:write`
**Permission Constant:** `ApiAccessPermission::EMAIL_TEMPLATES_WRITE`

### Parameters
- `template.content` (string) *Required*: Template content to persist.

### Request Body Example
```json
{
  "template": {
    "content": "<h1>Hello FIRST_NAME</h1><p>Updated</p>"
  }
}
```

### Responses
#### 200 OK
Template updated.

```json
{
  "id": "welcome.html",
  "updated": true
}
```

---

## DELETE /email-gateway/templates/{templateId}.json
**Service:** email-gateway
**Version:** 2026-02-01

**Required Scope:** `email_templates:write`
**Permission Constant:** `ApiAccessPermission::EMAIL_TEMPLATES_WRITE`

### Responses
#### 202 Accepted
Template deleted.

```json
{
  "id": "welcome.html",
  "deleted": true
}
```

---

## POST /email-gateway/templates/{templateId}/preview.json
**Service:** email-gateway
**Version:** 2026-02-01

**Required Scope:** `email_templates:write`
**Permission Constant:** `ApiAccessPermission::EMAIL_TEMPLATES_WRITE`

### Parameters
- `preview.vars` (object): Variables used for server-side placeholder rendering.

### Request Body Example
```json
{
  "preview": {
    "vars": {
      "first_name": "Alex"
    }
  }
}
```

### Responses
#### 200 OK
Rendered HTML preview returned.

```json
{
  "template_id": "welcome.html",
  "html": "<h1>Hello Alex</h1>"
}
```

---

## POST /email-gateway/{templateId}/send.json
**Service:** email-gateway
**Version:** 2026-02-01

**Required Scope:** `email_messages:write`
**Permission Constant:** `ApiAccessPermission::EMAIL_MESSAGES_WRITE`

### Parameters
- `email.to` (string) *Required*: Primary recipient email.
- `email.subject` (string) *Required*: Message subject.
- `email.from` (string): Optional sender email from configured alternative senders.
- `email.cc` (array): CC recipients.
- `email.bcc` (array): BCC recipients.
- `email.vars` (object): Template variables.
- `email.attachments` (array): Attachments in base64 format.

### Request Body Example
```json
{
  "email": {
    "to": "recipient@example.com",
    "subject": "Operational Update",
    "from": "notifications@example.com",
    "cc": [
      "ops@example.com"
    ],
    "vars": {
      "first_name": "Alex"
    },
    "attachments": [
      {
        "content": "SGVsbG8gd29ybGQ=",
        "filename": "summary.txt",
        "type": "text/plain"
      }
    ]
  }
}
```

### Responses
#### 201 Created
Email accepted for delivery.

```json
{
  "email": {
    "id": "msg_123"
  }
}
```

#### 404 Not Found
Template not found.

```json
{
  "error": "Template not found or empty"
}
```

---

## GET /countries/countries.json
**Service:** general
**Version:** 2026-02-01

**Required Scope:** `countries:read`
**Permission Constant:** `ApiAccessPermission::COUNTRIES_READ`

### Responses
#### 200 OK
Global country directory retrieved.

```json
[
  {
    "code": "US",
    "name": "United States"
  },
  {
    "code": "GB",
    "name": "United Kingdom"
  },
  {
    "code": "IT",
    "name": "Italy"
  },
  {
    "code": "DE",
    "name": "Germany"
  },
  {
    "code": "FR",
    "name": "France"
  }
]
```

---

## GET /geoip/ip.json
**Service:** geo-ip
**Version:** 2026-02-01

**Required Scope:** `geoip:read`
**Permission Constant:** `ApiAccessPermission::GEOIP_READ`

### Responses
#### 200 OK
IP intelligence profile successfully resolved.

```json
{
  "requested_ip": "8.8.8.8",
  "geolocation": {
    "as_domain": "google.com",
    "as_name": "Google LLC",
    "asn": "AS15169",
    "continent": "NA",
    "country": "US",
    "country_name": "United States"
  },
  "country_metadata": {
    "name": "United States",
    "phone": [
      1
    ],
    "capital": "Washington D.C.",
    "currency": [
      "USD",
      "USN",
      "USS"
    ],
    "languages": [
      "en"
    ]
  },
  "threats": [
    "proxy",
    "vpn"
  ],
  "_credits": "IP address data powered by https://ipinfo.io"
}
```

#### 400 Bad Request
The provided IP address is malformed or resolution failed.

```json
{
  "error": "Unable to get info for this IP Address"
}
```

---

## POST /idp/user.json
**Service:** idp
**Version:** 2026-02-01

**Required Scope:** `idp:write`
**Permission Constant:** `ApiAccessPermission::IDP_WRITE`

### Parameters
- `user.external_id` (string) *Required*: Your system's unique identifier for the user (e.g., UUID or DB ID).

### Request Body Example
```json
{
  "user": {
    "external_id": "ORG_USR_9921_AFG"
  }
}
```

### Responses
#### 201 Created
User identity successfully provisioned.

```json
{
  "user": {
    "id": "6908bffd...",
    "external_id": "ORG_USR_9921_AFG",
    "status": "active"
  }
}
```

#### 409 Conflict
Identity already exists for the specified external_id.

```json
{
  "error": "User with this external_id already exists for this company"
}
```

---

## GET /idp/{externalUserId}.json
**Service:** idp
**Version:** 2026-02-01

**Required Scope:** `idp:read`
**Permission Constant:** `ApiAccessPermission::IDP_READ`

### Responses
#### 200 OK
Identity profile retrieved.

```json
{
  "id": "6908...",
  "external_id": "ORG_USR_9921_AFG",
  "status": "active",
  "has_otp": true,
  "has_passkeys": false,
  "is_locked": false,
  "failed_attempts": 0,
  "saas_client_id": "67c9..."
}
```

---

## POST /idp/{externalUserId}/otp.json
**Service:** idp
**Version:** 2026-02-01

**Required Scope:** `idp:write`
**Permission Constant:** `ApiAccessPermission::IDP_WRITE`

### Parameters
- `otp.issuer_name` (string) *Required*: The organization name displayed in the authenticator app.
- `otp.account_name` (string) *Required*: The specific account identifier displayed in the app.

### Request Body Example
```json
{
  "otp": {
    "issuer_name": "Acme Enterprise",
    "account_name": "alexander@enterprise.com"
  }
}
```

### Responses
#### 200 OK
New MFA secret successfully generated.

```json
{
  "user": {
    "external_id": "ORG_USR_9921_AFG",
    "new_otp_secret": "REDACTED_OTP_SECRET",
    "qrcode_payload": "otpauth://totp/Acme+Enterprise:alexander%40enterprise.com?secret=REDACTED_OTP_SECRET&issuer=Acme+Enterprise",
    "is_setup_complete": true
  }
}
```

---

## POST /idp/otp/verify.json
**Service:** idp
**Version:** 2026-02-01

**Required Scope:** `idp:write`
**Permission Constant:** `ApiAccessPermission::IDP_WRITE`

### Parameters
- `otp.id` (string) *Required*: The unique external user identifier.
- `otp.code` (string) *Required*: The 6-digit code or numeric backup code.

### Request Body Example
```json
{
  "otp": {
    "id": "ORG_USR_9921_AFG",
    "code": "552192"
  }
}
```

### Responses
#### 200 OK
Authentication successful.

```json
{
  "status": "success",
  "id": "ORG_USR_9921_AFG",
  "message": "OTP verified successfully."
}
```

#### 401 Unauthorized
Invalid credentials or code expired.

```json
{
  "error": "Invalid credentials or access denied"
}
```

---

## POST /idp/{externalUserId}/backupcodes.json
**Service:** idp
**Version:** 2026-02-01

**Required Scope:** `idp:write`
**Permission Constant:** `ApiAccessPermission::IDP_WRITE`

### Responses
#### 200 OK
Set of 10 backup codes generated.

```json
{
  "user": {
    "id": "ORG_USR_9921_AFG",
    "backupCodes": [
      "ABCD-1234",
      "EFGH-5678",
      "..."
    ]
  }
}
```

---

## POST /idp/{externalUserId}/passkey/options.json
**Service:** idp
**Version:** 2026-02-01

**Required Scope:** `idp:write`
**Permission Constant:** `ApiAccessPermission::IDP_WRITE`

### Parameters
- `passkey.display_name` (string): Display name shown during registration.
- `passkey.account_name` (string): Account name bound to the credential.

### Request Body Example
```json
{
  "passkey": {
    "display_name": "Alexander",
    "account_name": "alexander@enterprise.com"
  }
}
```

### Responses
#### 200 OK
Registration options generated.

```json
{
  "status": "success",
  "passkey": {
    "challenge_id": "ch_01J...",
    "options": {
      "challenge": "BASE64_CHALLENGE",
      "rp": {
        "id": "example.com",
        "name": "Donutwork"
      }
    }
  }
}
```

---

## POST /idp/{externalUserId}/passkey/confirm.json
**Service:** idp
**Version:** 2026-02-01

**Required Scope:** `idp:write`
**Permission Constant:** `ApiAccessPermission::IDP_WRITE`

### Parameters
- `passkey.challenge_id` (string) *Required*: Challenge reference from options endpoint.
- `passkey.payload` (string|object) *Required*: Serialized PublicKeyCredential payload.
- `passkey.device` (string): Client device fingerprint for audit.

### Responses
#### 200 OK
Passkey registered successfully.

```json
{
  "status": "success",
  "passkey": {
    "id": "pk_01J...",
    "external_id": "ORG_USR_9921_AFG",
    "registered": true
  }
}
```

---

## POST /idp/passkey/challenge.json
**Service:** idp
**Version:** 2026-02-01

**Required Scope:** `idp:write`
**Permission Constant:** `ApiAccessPermission::IDP_WRITE`

### Parameters
- `passkey.id` (string) *Required*: External user identifier.

### Request Body Example
```json
{
  "passkey": {
    "id": "ORG_USR_9921_AFG"
  }
}
```

### Responses
#### 200 OK
Authentication challenge generated.

```json
{
  "status": "success",
  "passkey": {
    "challenge_id": "ch_01J...",
    "options": {
      "challenge": "BASE64_CHALLENGE",
      "rpId": "example.com"
    }
  }
}
```

---

## POST /idp/passkey/verify.json
**Service:** idp
**Version:** 2026-02-01

**Required Scope:** `idp:write`
**Permission Constant:** `ApiAccessPermission::IDP_WRITE`

### Parameters
- `passkey.id` (string) *Required*: External user identifier.
- `passkey.challenge_id` (string) *Required*: Challenge reference from challenge endpoint.
- `passkey.payload` (string|object) *Required*: Serialized PublicKeyCredential assertion payload.

### Responses
#### 200 OK
Passkey authentication successful.

```json
{
  "status": "success",
  "id": "ORG_USR_9921_AFG",
  "message": "Passkey verified successfully."
}
```

---

## DELETE /idp/{externalUserId}/passkey/{credentialId}.json
**Service:** idp
**Version:** 2026-02-01

**Required Scope:** `idp:write`
**Permission Constant:** `ApiAccessPermission::IDP_WRITE`

### Responses
#### 200 OK
Credential removed successfully.

```json
{
  "status": "success",
  "id": "ORG_USR_9921_AFG",
  "message": "Passkey removed successfully."
}
```

---

## POST /sentinel/verify.json
**Service:** idp
**Version:** 2026-02-01

**Required Scope:** `sentinel:write`
**Permission Constant:** `ApiAccessPermission::SENTINEL_WRITE`

### Parameters
- `sentinel.id` (string) *Required*: External user identifier for the risk evaluation.
- `sentinel.context.ip` (string) *Required*: Source IP address of the session.
- `sentinel.context.ua` (string) *Required*: User-Agent value for the session.
- `sentinel.context.user_id` (string): Optional explicit user identifier override.

### Request Body Example
```json
{
  "sentinel": {
    "id": "ORG_USR_9921_AFG",
    "context": {
      "ip": "1.1.1.1",
      "ua": "EnterpriseAgent/1.0"
    }
  }
}
```

### Responses
#### 200 OK
Risk assessment completed.

```json
{
  "success": true,
  "event_id": "67f4...",
  "user_id": "ORG_USR_9921_AFG",
  "ip": "1.1.1.1",
  "geo_country": "US",
  "risk_score": 0.62,
  "risk_band": "high",
  "decision_advice": "challenge_mfa",
  "decision": "challenge_mfa",
  "recommended_factor": "passkey_or_otp",
  "reasons": [
    "High source IP velocity detected."
  ],
  "verification_cost_ms": 18
}
```

#### 400 Bad Request
Missing input fields.

```json
{
  "success": false,
  "message": "Missing required parameters: user_id, ip, or user_agent."
}
```

---

## GET /integrations.json
**Service:** integrations
**Version:** 2026-02-01

**Required Scope:** `integrations:read`
**Permission Constant:** `ApiAccessPermission::INTEGRATIONS_READ`

### Responses
#### 200 OK
Integration directory successfully retrieved.

```json
{
  "entities": "Integration",
  "count": 1,
  "per_page": 100,
  "pages": {
    "current": 1,
    "max": 1
  },
  "elements": [
    {
      "id": "6908bffd...",
      "handler": "STRIPE_CONNECT",
      "name": "Stripe Global Payments",
      "status": "connected"
    }
  ]
}
```

---

## PUT /integrations.json
**Service:** integrations
**Version:** 2026-02-01

**Required Scope:** `integrations:write`
**Permission Constant:** `ApiAccessPermission::INTEGRATIONS_WRITE`

### Parameters
- `capabilities` (array) *Required*: Definition list of actions and their schema.
- `app_token` (string): Authorization token to be used when DonutWork calls your service.

### Request Body Example
```json
{
  "app_token": "ext_auth_token_9921",
  "capabilities": [
    {
      "action": "SYNC_INVENTORY",
      "method": "POST",
      "endpoint": "https://api.myapp.com/v1/sync",
      "inputs": [
        {
          "name": "sku",
          "type": "string",
          "required": true
        },
        {
          "name": "quantity",
          "type": "number",
          "required": true
        }
      ]
    }
  ]
}
```

### Responses
#### 200 OK
Capabilities successfully registered.

```json
{
  "success": true,
  "message": "Capabilities declared successfully for MY_CUSTOM_APP",
  "app_handler": "MY_CUSTOM_APP",
  "actions_count": 1
}
```

---

## GET /integrations/{appHandler}.json
**Service:** integrations
**Version:** 2026-02-01

**Required Scope:** `integrations:read`
**Permission Constant:** `ApiAccessPermission::INTEGRATIONS_READ`

### Responses
#### 200 OK
Detailed integration profile retrieved.

```json
{
  "id": "6908...",
  "handler": "SLACK_ENT",
  "status": "connected",
  "actions": [
    {
      "name": "SEND_MESSAGE",
      "method": "POST"
    }
  ],
  "metadata": {
    "workspace": "AcmeHQ"
  }
}
```

---

## POST /integrations/{appHandler}/{appAction}.json
**Service:** integrations
**Version:** 2026-02-01

**Required Scope:** `integrations:write`
**Permission Constant:** `ApiAccessPermission::INTEGRATIONS_WRITE`

### Responses
#### 200 OK
Action executed and external response relayed.

```json
{
  "success": true,
  "integration": "SLACK_ENT",
  "action": "SEND_MESSAGE",
  "external_status": 200,
  "response": {
    "ok": true,
    "ts": "123456789.0001"
  }
}
```

---

## GET /integrations/{appHandler}/{appAction}.json
**Service:** integrations
**Version:** 2026-02-01

**Required Scope:** `integrations:read`
**Permission Constant:** `ApiAccessPermission::INTEGRATIONS_READ`

### Responses
#### 200 OK
Action executed using GET forwarding.

```json
{
  "success": true,
  "integration": "SLACK_ENT",
  "action": "GET_CHANNEL_INFO",
  "external_status": 200,
  "response": {}
}
```

---

## PUT /integrations/{appHandler}/{appAction}.json
**Service:** integrations
**Version:** 2026-02-01

**Required Scope:** `integrations:write`
**Permission Constant:** `ApiAccessPermission::INTEGRATIONS_WRITE`

### Responses
#### 200 OK
Action executed using PUT forwarding.

```json
{
  "success": true,
  "integration": "SLACK_ENT",
  "action": "UPSERT_TEMPLATE",
  "external_status": 200,
  "response": {}
}
```

---

## DELETE /integrations/{appHandler}/{appAction}.json
**Service:** integrations
**Version:** 2026-02-01

**Required Scope:** `integrations:write`
**Permission Constant:** `ApiAccessPermission::INTEGRATIONS_WRITE`

### Responses
#### 200 OK
Action executed using DELETE forwarding.

```json
{
  "success": true,
  "integration": "SLACK_ENT",
  "action": "DELETE_MESSAGE",
  "external_status": 200,
  "response": {}
}
```

---

## POST /integrations/{appHandler}/events/{eventName}/emit.json
**Service:** integrations
**Version:** 2026-02-01

**Required Scope:** `integration_events:write`
**Permission Constant:** `ApiAccessPermission::INTEGRATION_EVENTS_WRITE`

### Parameters
- `metadata` (object): Event payload metadata object.
- `entity_id` (string): Entity identifier. If omitted, the app handler is used.

### Request Body Example
```json
{
  "metadata": {
    "message_id": "msg_001",
    "status": "sent"
  },
  "entity_id": "SLACK_ENT"
}
```

### Responses
#### 200 OK
Event accepted and dispatched.

```json
{
  "success": true,
  "app_handler": "SLACK",
  "event": "Slack.MESSAGE_SENT",
  "queued_workflows": 1
}
```

---

## GET /job-runner.json
**Service:** job-runner
**Version:** 2026-02-01

**Required Scope:** `job_runner:read`
**Permission Constant:** `ApiAccessPermission::JOB_RUNNER_READ`

### Responses
#### 200 OK
Job runner list returned.

```json
{
  "entities": "JobRunner",
  "count": 1,
  "per_page": 50,
  "pages": {
    "current": 1,
    "max": 1
  },
  "elements": [
    {
      "id": "681f10...",
      "title": "Sync CRM Contacts",
      "method": "POST",
      "url": "https://api.partner.com/sync",
      "content_type": "application/json",
      "has_body": true,
      "schedulation": [
        "08:00",
        "14:30"
      ]
    }
  ]
}
```

---

## POST /job-runner.json
**Service:** job-runner
**Version:** 2026-02-01

**Required Scope:** `job_runner:write`
**Permission Constant:** `ApiAccessPermission::JOB_RUNNER_WRITE`

### Parameters
- `jobrunner` (object) *Required*: Job runner configuration payload.

### Request Body Example
```json
{
  "jobrunner": {
    "title": "Sync CRM Contacts",
    "method": "POST",
    "url": "https://api.partner.com/sync",
    "content_type": "application/json",
    "body": "{\"scope\":\"daily\"}",
    "schedulation": [
      "08:00",
      "14:30"
    ]
  }
}
```

### Responses
#### 201 Created
Job runner created.

```json
{
  "id": "681f10...",
  "created": true
}
```

#### 422 Unprocessable Entity
Validation error on payload.

```json
{
  "error": "Invalid schedulation time \"24:30\". Use HH:mm format"
}
```

---

## POST /job-runner/{jobRunnerId}/run.json
**Service:** job-runner
**Version:** 2026-02-01

**Required Scope:** `job_runner:write`
**Permission Constant:** `ApiAccessPermission::JOB_RUNNER_WRITE`

### Responses
#### 200 OK
Job execution completed.

```json
{
  "job_runner_id": "681f10...",
  "status": "success",
  "headers": [
    "HTTP/1.1 200 OK"
  ],
  "response": "{\"ok\":true}",
  "ms": 122.45
}
```

---

## DELETE /job-runner/{jobRunnerId}.json
**Service:** job-runner
**Version:** 2026-02-01

**Required Scope:** `job_runner:write`
**Permission Constant:** `ApiAccessPermission::JOB_RUNNER_WRITE`

### Responses
#### 202 Accepted
Job runner deleted.

```json
{
  "id": "681f10...",
  "deleted": true
}
```

---

## GET /kms.json
**Service:** kms
**Version:** 2026-02-01

**Required Scope:** `kms:read`
**Permission Constant:** `ApiAccessPermission::KMS_READ`

### Responses
#### 200 OK
Secret inventory successfully retrieved.

```json
{
  "entities": "KMSEntry",
  "count": 12,
  "per_page": 100,
  "pages": {
    "current": 1,
    "max": 1
  },
  "elements": [
    {
      "id": "6835c2cd...",
      "name": "Production AWS S3 Access",
      "handler": "aws-s3-prod-credentials"
    }
  ]
}
```

---

## GET /kms/{handler}.json
**Service:** kms
**Version:** 2026-02-01

**Required Scope:** `kms:read`
**Permission Constant:** `ApiAccessPermission::KMS_READ`

### Responses
#### 200 OK
Secret configuration retrieved.

```json
{
  "id": "6835c2cd...",
  "name": "Production AWS S3 Access",
  "handler": "aws-s3-prod-credentials",
  "whitelist": [
    "52.1.2.3",
    "54.0.0.1"
  ],
  "properties": {
    "region": "us-east-1"
  }
}
```

#### 404 Not Found
The specified handler does not exist in the vault.

```json
{
  "error": "This KMSEntry does not exist"
}
```

---

## GET /kms/reveal/{handler}.json
**Service:** kms
**Version:** 2026-02-01

**Required Scope:** `kms:read`
**Permission Constant:** `ApiAccessPermission::KMS_READ`

### Responses
#### 200 OK
Secret successfully decrypted and returned.

```json
{
  "content": "EXAMPLE_ACCESS_KEY_REDACTED"
}
```

#### 403 Forbidden
Requesting IP is not in the authorized whitelist or permissions are insufficient.

```json
{
  "error": "Unauthorized to reveal this KMS Entry"
}
```

---

## GET /media-library/files.json
**Service:** media-library
**Version:** 2026-02-01

**Required Scope:** `media_library:read`
**Permission Constant:** `ApiAccessPermission::MEDIA_LIBRARY_READ`

### Responses
#### 200 OK
Media file list returned.

```json
{
  "entities": "MediaLibraryFile",
  "count": 1,
  "per_page": 60,
  "pages": {
    "current": 1,
    "max": 1
  },
  "elements": [
    {
      "filename": "invoice-apr-2026.pdf",
      "size": 58211,
      "etag": "15d6a30e7a6f0d...",
      "last_modified": "2026-04-20T08:55:10+00:00"
    }
  ]
}
```

---

## POST /media-library/files/upload-link.json
**Service:** media-library
**Version:** 2026-02-01

**Required Scope:** `media_library:write`
**Permission Constant:** `ApiAccessPermission::MEDIA_LIBRARY_WRITE`

### Parameters
- `file` (object) *Required*: Upload target metadata (filename/content type/optional size).

### Request Body Example
```json
{
  "file": {
    "filename": "invoice-apr-2026.pdf",
    "content_type": "application/pdf",
    "size_bytes": 58211
  }
}
```

### Responses
#### 200 OK
Presigned direct upload link generated.

```json
{
  "strategy": "direct_presigned_put",
  "file": {
    "filename": "invoice-apr-2026.pdf",
    "content_type": "application/pdf",
    "max_size_bytes": 524288000
  },
  "upload": {
    "method": "PUT",
    "url": "https://storage.example.com/prod-.../invoice-apr-2026.pdf?...",
    "expires_in": 1200,
    "headers": {
      "Content-Type": "application/pdf"
    }
  }
}
```

---

## POST /media-library/files.json
**Service:** media-library
**Version:** 2026-02-01

**Required Scope:** `media_library:write`
**Permission Constant:** `ApiAccessPermission::MEDIA_LIBRARY_WRITE`

### Parameters
- `file` (object) *Required*: Fallback upload payload using base64 content.

### Request Body Example
```json
{
  "file": {
    "filename": "small-note.txt",
    "content_type": "text/plain",
    "content_base64": "U2NoZWR1bGVkIG5vdGUgZnJvbSBBUEk="
  }
}
```

### Responses
#### 201 Created
File uploaded.

```json
{
  "filename": "small-note.txt",
  "size": 24,
  "uploaded": true
}
```

---

## POST /media-library/files/download-link.json
**Service:** media-library
**Version:** 2026-02-01

**Required Scope:** `media_library:write`
**Permission Constant:** `ApiAccessPermission::MEDIA_LIBRARY_WRITE`

### Parameters
- `file` (object) *Required*: Target file descriptor for secure download URL generation.

### Request Body Example
```json
{
  "file": {
    "filename": "invoice-apr-2026.pdf"
  }
}
```

### Responses
#### 200 OK
Download link generated.

```json
{
  "filename": "invoice-apr-2026.pdf",
  "url": "https://app.example.com/file-download/download?file=..."
}
```

---

## POST /mobile/push-token.json
**Service:** mobile
**Version:** 2026-02-01

**Required Scope:** `mobile_push:write`
**Permission Constant:** `ApiAccessPermission::MOBILE_PUSH_WRITE`

### Parameters
- `device.device_id` (string) *Required*: Device identifier (8-128 chars, allowed: letters, numbers, . _ : -).
- `device.push_token` (string) *Required*: APNs push token (20-1024 chars).
- `device.platform` (string): Platform value. Only `ios` is accepted.
- `device.app_version` (string): Client application version.
- `device.environment` (string): Push environment (`sandbox` or `production`).

### Request Body Example
```json
{
  "device": {
    "device_id": "ios_device_001",
    "push_token": "f6ad7d6f0a3b82d91fd89e88d4d4c6f3e0f9a7f6",
    "platform": "ios",
    "app_version": "1.2.3",
    "environment": "production"
  }
}
```

### Responses
#### 200 OK
Push token saved or updated.

```json
{
  "status": "success",
  "message": "Push token saved",
  "device": {
    "device_id": "ios_device_001",
    "platform": "ios",
    "environment": "production"
  }
}
```

#### 403 Forbidden
API key is not mobile-scoped.

```json
{
  "error": "Mobile API key required for this endpoint"
}
```

---

## DELETE /mobile/push-token.json
**Service:** mobile
**Version:** 2026-02-01

**Required Scope:** `mobile_push:write`
**Permission Constant:** `ApiAccessPermission::MOBILE_PUSH_WRITE`

### Parameters
- `device.device_id` (string): Device identifier when passed via JSON body. Required if not present in `device_id` query param.

### Request Body Example
```json
{
  "device": {
    "device_id": "ios_device_001"
  }
}
```

### Responses
#### 200 OK
Push token deleted or already absent.

```json
{
  "status": "success",
  "message": "Push token removed",
  "deleted": true,
  "device_id": "ios_device_001"
}
```

#### 400 Bad Request
Device identifier missing or invalid.

```json
{
  "error": "Missing required field: device_id"
}
```

---

## GET /newsletters.json
**Service:** newsletter
**Version:** 2026-02-01

**Required Scope:** `newsletters:read`
**Permission Constant:** `ApiAccessPermission::NEWSLETTERS_READ`

### Responses
#### 200 OK
Newsletter list returned.

```json
{
  "entities": "Newsletter",
  "count": 1,
  "per_page": 100,
  "pages": {
    "current": 1,
    "max": 1
  },
  "elements": [
    {
      "id": "672489...",
      "title": "Launch Campaign",
      "subject": "New release",
      "template_id": "welcome.html",
      "total_recipients": 210,
      "status": "draft",
      "created_at": 1704067200
    }
  ]
}
```

---

## POST /newsletters.json
**Service:** newsletter
**Version:** 2026-02-01

**Required Scope:** `newsletters:write`
**Permission Constant:** `ApiAccessPermission::NEWSLETTERS_WRITE`

### Parameters
- `newsletter.title` (string) *Required*: Internal campaign name.
- `newsletter.subject` (string) *Required*: Subject line used during sending.
- `newsletter.template_id` (string) *Required*: Template filename to use for this campaign.
- `newsletter.contact_ids` (array): Optional initial recipients list.

### Request Body Example
```json
{
  "newsletter": {
    "title": "Launch Campaign",
    "subject": "New release",
    "template_id": "welcome.html",
    "contact_ids": [
      "cust_1",
      "cust_2"
    ]
  }
}
```

### Responses
#### 201 Created
Newsletter draft created.

```json
{
  "id": "672489...",
  "status": "draft",
  "skipped_suppressed": 0,
  "skipped_not_found": 1
}
```

---

## GET /newsletters/{newsletterId}.json
**Service:** newsletter
**Version:** 2026-02-01

**Required Scope:** `newsletters:read`
**Permission Constant:** `ApiAccessPermission::NEWSLETTERS_READ`

### Responses
#### 200 OK
Campaign details returned.

```json
{
  "id": "672489...",
  "title": "Launch Campaign",
  "subject": "New release",
  "template_id": "welcome.html",
  "total_recipients": 210,
  "status": "queued",
  "scheduled_at": null,
  "created_at": 1704067200
}
```

---

## PUT /newsletters/{newsletterId}.json
**Service:** newsletter
**Version:** 2026-02-01

**Required Scope:** `newsletters:write`
**Permission Constant:** `ApiAccessPermission::NEWSLETTERS_WRITE`

### Parameters
- `newsletter.title` (string): Updated title. Allowed only in draft status.
- `newsletter.subject` (string): Updated subject. Allowed only in draft status.
- `newsletter.template_id` (string): Updated template id. Allowed only in draft status.

### Request Body Example
```json
{
  "newsletter": {
    "title": "Launch Campaign v2",
    "subject": "Release update",
    "template_id": "welcome-v2.html"
  }
}
```

### Responses
#### 200 OK
Campaign metadata updated.

```json
{
  "id": "672489...",
  "title": "Launch Campaign v2",
  "subject": "Release update",
  "template_id": "welcome-v2.html",
  "total_recipients": 210,
  "status": "draft",
  "scheduled_at": null,
  "created_at": 1704067200
}
```

#### 409 Conflict
Campaign is not in draft status.

```json
{
  "error": "Only newsletters in draft status can be updated"
}
```

---

## DELETE /newsletters/{newsletterId}.json
**Service:** newsletter
**Version:** 2026-02-01

**Required Scope:** `newsletters:write`
**Permission Constant:** `ApiAccessPermission::NEWSLETTERS_WRITE`

### Responses
#### 202 Accepted
Campaign and related queue entries deleted.

```json
{
  "id": "672489...",
  "deleted": true
}
```

---

## GET /newsletters/{newsletterId}/recipients.json
**Service:** newsletter
**Version:** 2026-02-01

**Required Scope:** `newsletters:read`
**Permission Constant:** `ApiAccessPermission::NEWSLETTERS_READ`

### Responses
#### 200 OK
Recipients snapshot returned.

```json
{
  "newsletter_status": "draft",
  "selected_ids": [
    "cust_1",
    "cust_2"
  ],
  "all_customers": [
    {
      "id": "cust_1",
      "name": "Alex Doe",
      "email": "alex@example.com",
      "tags": [
        "beta"
      ],
      "subscription_count": 1,
      "has_consent": true,
      "is_suppressed": false
    }
  ]
}
```

---

## PUT /newsletters/{newsletterId}/recipients.json
**Service:** newsletter
**Version:** 2026-02-01

**Required Scope:** `newsletters:write`
**Permission Constant:** `ApiAccessPermission::NEWSLETTERS_WRITE`

### Parameters
- `newsletter.contact_ids` (array) *Required*: Recipient customer IDs to store on the campaign.

### Request Body Example
```json
{
  "newsletter": {
    "contact_ids": [
      "cust_1",
      "cust_2",
      "cust_3"
    ]
  }
}
```

### Responses
#### 200 OK
Recipients synchronized.

```json
{
  "newsletter_id": "672489...",
  "saved_recipients": 2,
  "skipped_suppressed": 1,
  "skipped_not_found": 0
}
```

---

## POST /newsletters/{newsletterId}/queue.json
**Service:** newsletter
**Version:** 2026-02-01

**Required Scope:** `newsletters:write`
**Permission Constant:** `ApiAccessPermission::NEWSLETTERS_WRITE`

### Responses
#### 200 OK
Campaign queued for sending.

```json
{
  "newsletter_id": "672489...",
  "status": "queued",
  "queued_recipients": 150,
  "skipped_suppressed": 0,
  "skipped_not_found": 0
}
```

#### 409 Conflict
Invalid state or usage limit reached.

```json
{
  "error": "This newsletter is already queued and cannot be queued again"
}
```

---

## POST /newsletters/{newsletterId}/test.json
**Service:** newsletter
**Version:** 2026-02-01

**Required Scope:** `newsletters:write`
**Permission Constant:** `ApiAccessPermission::NEWSLETTERS_WRITE`

### Parameters
- `newsletter.test_email` (string) *Required*: Target email for test send.

### Request Body Example
```json
{
  "newsletter": {
    "test_email": "qa@example.com"
  }
}
```

### Responses
#### 201 Created
Test email sent.

```json
{
  "newsletter_id": "672489...",
  "test_email": "qa@example.com",
  "sent": true
}
```

---

## GET /newsletters/{newsletterId}/stats.json
**Service:** newsletter
**Version:** 2026-02-01

**Required Scope:** `newsletters:read`
**Permission Constant:** `ApiAccessPermission::NEWSLETTERS_READ`

### Responses
#### 200 OK
Campaign stats returned.

```json
{
  "newsletter": {
    "id": "672489...",
    "title": "Launch Campaign",
    "subject": "New release",
    "template_id": "welcome.html",
    "total_recipients": 150,
    "status": "queued",
    "scheduled_at": null,
    "created_at": 1704067200
  },
  "stats": {
    "pending": 12,
    "processing": 3,
    "sent": 120,
    "failed": 10,
    "skipped": 5,
    "total": 150
  },
  "progress": {
    "processed": 135,
    "total": 150,
    "overall_progress": 90,
    "delivery_rate": 80
  },
  "failures": []
}
```

---

## GET /newsletters/unsubscribes.json
**Service:** newsletter
**Version:** 2026-02-01

**Required Scope:** `newsletter_unsubscribes:read`
**Permission Constant:** `ApiAccessPermission::NEWSLETTER_UNSUBSCRIBES_READ`

### Responses
#### 200 OK
Suppression list returned.

```json
{
  "entities": "Unsubscribes",
  "count": 1,
  "per_page": 100,
  "pages": {
    "current": 1,
    "max": 1
  },
  "elements": [
    {
      "email": "user@example.com",
      "reason": "Manual unsubscribe via API",
      "unsubscribed_at": 1704067200
    }
  ]
}
```

---

## POST /newsletters/unsubscribes.json
**Service:** newsletter
**Version:** 2026-02-01

**Required Scope:** `newsletter_unsubscribes:write`
**Permission Constant:** `ApiAccessPermission::NEWSLETTER_UNSUBSCRIBES_WRITE`

### Parameters
- `unsubscribe.email` (string) *Required*: Email to suppress.
- `unsubscribe.reason` (string): Optional reason for audit trail.

### Request Body Example
```json
{
  "unsubscribe": {
    "email": "user@example.com",
    "reason": "Support request"
  }
}
```

### Responses
#### 201 Created
Email added to suppression list.

```json
{
  "email": "user@example.com",
  "unsubscribed": true
}
```

---

## POST /newsletters/unsubscribes/resubscribe.json
**Service:** newsletter
**Version:** 2026-02-01

**Required Scope:** `newsletter_unsubscribes:write`
**Permission Constant:** `ApiAccessPermission::NEWSLETTER_UNSUBSCRIBES_WRITE`

### Parameters
- `unsubscribe.email` (string) *Required*: Email to remove from suppression list.

### Request Body Example
```json
{
  "unsubscribe": {
    "email": "user@example.com"
  }
}
```

### Responses
#### 200 OK
Email removed from suppression list.

```json
{
  "email": "user@example.com",
  "resubscribed": true
}
```

#### 404 Not Found
Email not found in suppression list.

```json
{
  "error": "Email not found in suppression list"
}
```

---

## GET /partners/groups.json
**Service:** partner-group
**Version:** 2026-02-01

**Required Scope:** `partner_groups:read`
**Permission Constant:** `ApiAccessPermission::PARTNER_GROUPS_READ`

### Responses
#### 200 OK
Partner group directory successfully retrieved.

```json
{
  "entities": "PartnerGroup",
  "count": 4,
  "per_page": 100,
  "pages": {
    "current": 1,
    "max": 1
  },
  "elements": [
    {
      "id": "68f76721...",
      "name": "Standard Managed Agency",
      "external_id": "P-GROUP-ADVANCED",
      "default": true
    }
  ]
}
```

---

## GET /partners/groups/{groupId}.json
**Service:** partner-group
**Version:** 2026-02-01

**Required Scope:** `partner_groups:read`
**Permission Constant:** `ApiAccessPermission::PARTNER_GROUPS_READ`

### Responses
#### 200 OK
Group configuration and rules engine definition retrieved.

```json
{
  "id": "68f76721...",
  "name": "Standard Managed Agency",
  "external_id": "P-GROUP-ADVANCED",
  "rules": [
    {
      "type": "new_customer_time_tier",
      "max_months": 12,
      "percentage": 50,
      "description": "Introductory 12-month high-incentive tier."
    },
    {
      "type": "recurring",
      "percentage": 15,
      "description": "Standard recurring commission (post-time-tier)."
    },
    {
      "type": "partner_ltv_upgrade",
      "min_ltv_total": 10000,
      "upgrade_percentage": 5,
      "description": "LTV Performance Bonus (Threshold: 10,000€)."
    }
  ],
  "tags": "managed,high-volume",
  "description": "Default group for high-performance managed agencies."
}
```

---

## POST /partners/groups.json
**Service:** partner-group
**Version:** 2026-02-01

**Required Scope:** `partner_groups:write`
**Permission Constant:** `ApiAccessPermission::PARTNER_GROUPS_WRITE`

### Parameters
- `partnerGroup.name` (string) *Required*: Partner group display name.
- `partnerGroup.rules` (array) *Required*: Rules array. Must include one recurring fallback rule.
- `partnerGroup.description` (string): Optional group description.
- `partnerGroup.external_id` (string): Optional external identifier.
- `partnerGroup.tags` (string): Comma-separated tags.
- `partnerGroup.default` (boolean): Mark this group as default for new partners.

### Request Body Example
```json
{
  "partnerGroup": {
    "name": "Performance Agencies",
    "description": "Tier for high-volume agencies",
    "external_id": "P-GROUP-PERF",
    "tags": "managed,performance",
    "default": false,
    "rules": [
      {
        "type": "new_customer_time_tier",
        "max_months": 6,
        "percentage": 30
      },
      {
        "type": "recurring",
        "percentage": 12
      }
    ]
  }
}
```

### Responses
#### 201 Created
Partner group created.

```json
{
  "group": {
    "id": "68f76721..."
  }
}
```

---

## PUT /partners/groups/{partnerGroupId}.json
**Service:** partner-group
**Version:** 2026-02-01

**Required Scope:** `partner_groups:write`
**Permission Constant:** `ApiAccessPermission::PARTNER_GROUPS_WRITE`

### Parameters
- `partnerGroup.name` (string): Updated group name.
- `partnerGroup.description` (string): Updated description.
- `partnerGroup.external_id` (string): Updated external identifier.
- `partnerGroup.tags` (string): Updated comma-separated tags.
- `partnerGroup.default` (boolean): Update default flag.
- `partnerGroup.rules` (array): Updated rules array; if provided, must include recurring fallback.

### Request Body Example
```json
{
  "partnerGroup": {
    "name": "Performance Agencies v2",
    "default": true,
    "rules": [
      {
        "type": "recurring",
        "percentage": 14
      }
    ]
  }
}
```

### Responses
#### 202 Accepted
Partner group updated.

```json
{
  "group": {
    "id": "68f76721..."
  }
}
```

---

## DELETE /partners/groups/{partnerGroupId}.json
**Service:** partner-group
**Version:** 2026-02-01

**Required Scope:** `partner_groups:write`
**Permission Constant:** `ApiAccessPermission::PARTNER_GROUPS_WRITE`

### Responses
#### 202 Accepted
Partner group deleted.

```json
{
  "group": {
    "id": "68f76721...",
    "deleted": true
  }
}
```

---

## POST /partners/groups/simulate-rules.json
**Service:** partner-group
**Version:** 2026-02-01

**Required Scope:** `partner_groups:write`
**Permission Constant:** `ApiAccessPermission::PARTNER_GROUPS_WRITE`

### Parameters
- `partnerGroupSimulation.rules` (array) *Required*: Rules set to simulate. Must include recurring fallback.
- `partnerGroupSimulation.simulation` (object) *Required*: Simulation context (charge amount, lifecycle and partner KPIs).

### Request Body Example
```json
{
  "partnerGroupSimulation": {
    "rules": [
      {
        "type": "new_customer_time_tier",
        "max_months": 3,
        "percentage": 25
      },
      {
        "type": "recurring",
        "percentage": 10
      }
    ],
    "simulation": {
      "charge_amount": 299.9,
      "customer_months": 2,
      "partner_ltv": 4500,
      "qualified_customers": 12,
      "first_paid_customer_bootstrap": false
    }
  }
}
```

### Responses
#### 200 OK
Rules simulation completed.

```json
{
  "status": "success",
  "result": {
    "final_fee": 74.98
  }
}
```

---

## GET /partners.json
**Service:** partner
**Version:** 2026-02-01

**Required Scope:** `partners:read`
**Permission Constant:** `ApiAccessPermission::PARTNERS_READ`

### Responses
#### 200 OK
Partner directory successfully retrieved.

```json
{
  "entities": "Partner",
  "count": 24,
  "per_page": 100,
  "pages": {
    "current": 1,
    "max": 1
  },
  "elements": [
    {
      "id": "675d...",
      "name": "Global Solutions Agency",
      "external_id": "GSA-9921",
      "partner_code": "GOLD-PARTNER-X"
    }
  ]
}
```

---

## POST /partners.json
**Service:** partner
**Version:** 2026-02-01

**Required Scope:** `partners:write`
**Permission Constant:** `ApiAccessPermission::PARTNERS_WRITE`

### Parameters
- `partner.name` (string) *Required*: Legal entity name of the partner.
- `partner.email` (string) *Required*: Primary contact for financial and operational notifications.
- `partner.partner_group_id` (string): The ID of the Partner Group define rules. If empty, the default group is used.
- `partner.address.country` (string) *Required*: ISO 3166-1 alpha-2 country code.

### Request Body Example
```json
{
  "partner": {
    "name": "Apex Marketing Group",
    "email": "channel@apex-marketing.com",
    "external_id": "APEX_001",
    "code": "APEXPROMO",
    "partner_group_id": "66bf22b0...",
    "address": {
      "vat_number": "IT09876543210",
      "country": "IT",
      "city": "Milan"
    }
  }
}
```

### Responses
#### 201 Created
Partner successfully provisioned.

```json
{
  "partner": {
    "id": "6768..."
  }
}
```

---

## GET /partners/{partnerId}.json
**Service:** partner
**Version:** 2026-02-01

**Required Scope:** `partners:read`
**Permission Constant:** `ApiAccessPermission::PARTNERS_READ`

### Responses
#### 200 OK
Partner profile retrieved.

```json
{
  "id": "66b136b9...",
  "name": "Apex Marketing Group",
  "status": "active",
  "tags": [
    "tier-1",
    "mfa-enabled"
  ],
  "email": "channel@apex-marketing.com",
  "address": {
    "city": "Milan",
    "country": "IT",
    "vat_number": "IT098..."
  }
}
```

---

## GET /partners/{partnerId}/customers.json
**Service:** partner
**Version:** 2026-02-01

**Required Scope:** `partners:read`
**Permission Constant:** `ApiAccessPermission::PARTNERS_READ`

### Responses
#### 200 OK
Attributed customer list retrieved.

```json
{
  "entities": "PartnerCustomers",
  "count": 142,
  "elements": [
    {
      "id": "68d2...",
      "company_name": "Acme Corp",
      "email": "procurement@acme.com",
      "status": "active"
    }
  ]
}
```

---

## GET /partners/{partnerId}/stats.json
**Service:** partner
**Version:** 2026-02-01

**Required Scope:** `partners:read`
**Permission Constant:** `ApiAccessPermission::PARTNERS_READ`

### Responses
#### 200 OK
Aggregated performance statistics retrieved.

```json
{
  "total_revenue": "45200.00",
  "commission_earned": "4520.00",
  "currency": "EUR"
}
```

---

## GET /partners/{partnerId}/fees.json
**Service:** partner
**Version:** 2026-02-01

**Required Scope:** `partners:read`
**Permission Constant:** `ApiAccessPermission::PARTNERS_READ`

### Responses
#### 200 OK
Commission ledger retrieved.

```json
{
  "entities": "PartnerFees",
  "elements": [
    {
      "id": "fee_991",
      "source_charge": "ch_123",
      "fee_value": 15.5,
      "status": "pending"
    }
  ]
}
```

---

## POST /partners/payouts.json
**Service:** partner
**Version:** 2026-02-01

**Required Scope:** `partner_payouts:write`
**Permission Constant:** `ApiAccessPermission::PARTNER_PAYOUTS_WRITE`

### Parameters
- `payout.partner_id` (string) *Required*: The partner identifier.
- `payout.transactions` (array) *Required*: Collection of fee entry IDs.
- `payout.invoice.number` (string) *Required*: Reference number for the partner settlement invoice.

### Request Body Example
```json
{
  "payout": {
    "partner_id": "675d...",
    "transactions": [
      "fee_991",
      "fee_992"
    ],
    "invoice": {
      "number": "INV-2026-001",
      "date": "2026-03-01"
    },
    "vat_settings": {
      "tax_id": "tax_vat_22"
    }
  }
}
```

### Responses
#### 201 Created
Payout request successfully generated.

```json
{
  "id": "pay_5521",
  "total": "1250.00"
}
```

---

## GET /partners/{partnerId}/payouts/{payoutId}/report.json
**Service:** partner
**Version:** 2026-02-01

**Required Scope:** `partner_payouts:read`
**Permission Constant:** `ApiAccessPermission::PARTNER_PAYOUTS_READ`

### Responses
#### 200 OK
PDF documentation retrieved.

```json
{
  "stream": {
    "type": "application/pdf",
    "base64_content": "JVBER..."
  }
}
```

---

## GET /partners/partner.json
**Service:** partner
**Version:** 2026-02-01

**Required Scope:** `partners:read`
**Permission Constant:** `ApiAccessPermission::PARTNERS_READ`

### Responses
#### 200 OK
Partner record retrieved.

```json
{
  "id": "675d...",
  "name": "Apex Marketing Group",
  "email": "channel@apex-marketing.com"
}
```

#### 422 Unprocessable Entity
Neither `externalId` nor `email` was provided.

```json
{
  "error": "A valid \"externalId\" or \"email\" must be specified in the request"
}
```

---

## PUT /partners/{partnerId}.json
**Service:** partner
**Version:** 2026-02-01

**Required Scope:** `partners:write`
**Permission Constant:** `ApiAccessPermission::PARTNERS_WRITE`

### Parameters
- `partner.name` (string): Updated partner legal name.
- `partner.email` (string): Updated partner contact email.
- `partner.description` (string): Updated profile description.
- `partner.external_id` (string): Updated external identifier.
- `partner.code` (string): Updated partner code.
- `partner.partner_group_id` (string): Partner group assignment (empty string removes current group).
- `partner.tags` (array|string): Updated tags list.
- `partner.address` (object): Partial address update object.

### Request Body Example
```json
{
  "partner": {
    "name": "Apex Marketing Group - Enterprise",
    "email": "enterprise@apex-marketing.com",
    "description": "Updated profile",
    "external_id": "APEX_001",
    "code": "APEXPROMO",
    "partner_group_id": "66bf22b0...",
    "tags": [
      "tier-1",
      "priority"
    ],
    "address": {
      "country": "IT",
      "city": "Milan"
    }
  }
}
```

### Responses
#### 200 OK
Partner updated.

```json
{
  "id": "675d...",
  "name": "Apex Marketing Group - Enterprise"
}
```

---

## DELETE /partners/{partnerId}.json
**Service:** partner
**Version:** 2026-02-01

**Required Scope:** `partners:write`
**Permission Constant:** `ApiAccessPermission::PARTNERS_WRITE`

### Responses
#### 202 Accepted
Partner deleted.

```json
{
  "id": "675d...",
  "deleted": true
}
```

#### 406 Not Acceptable
Partner has still attached customers.

```json
{
  "error": "Unable to remove this partner. Customer attached to partner: ..."
}
```

---

## GET /partners/{partnerId}/fees/{feeId}.json
**Service:** partner
**Version:** 2026-02-01

**Required Scope:** `partners:read`
**Permission Constant:** `ApiAccessPermission::PARTNERS_READ`

### Responses
#### 200 OK
Partner fee entry retrieved.

```json
{
  "id": "fee_991",
  "partner_id": "675d...",
  "fee_value": 15.5,
  "status": "pending"
}
```

---

## GET /partners/payouts.json
**Service:** partner
**Version:** 2026-02-01

**Required Scope:** `partner_payouts:read`
**Permission Constant:** `ApiAccessPermission::PARTNER_PAYOUTS_READ`

### Responses
#### 200 OK
Paginated payout list across all partners.

```json
{
  "entities": "PartnerPayout",
  "count": 3,
  "elements": []
}
```

---

## GET /partners/{partnerId}/payouts.json
**Service:** partner
**Version:** 2026-02-01

**Required Scope:** `partner_payouts:read`
**Permission Constant:** `ApiAccessPermission::PARTNER_PAYOUTS_READ`

### Responses
#### 200 OK
Paginated payout list for the specified partner.

```json
{
  "entities": "PartnerPayout",
  "count": 2,
  "elements": []
}
```

---

## GET /partners/{partnerId}/payouts/{payoutId}.json
**Service:** partner
**Version:** 2026-02-01

**Required Scope:** `partner_payouts:read`
**Permission Constant:** `ApiAccessPermission::PARTNER_PAYOUTS_READ`

### Responses
#### 200 OK
Payout details retrieved.

```json
{
  "id": "pay_5521",
  "partner_id": "675d...",
  "status": "pending",
  "total": 1250
}
```

---

## GET /partners/payouts/{payoutId}.json
**Service:** partner
**Version:** 2026-02-01

**Required Scope:** `partner_payouts:read`
**Permission Constant:** `ApiAccessPermission::PARTNER_PAYOUTS_READ`

### Responses
#### 200 OK
Payout details retrieved.

```json
{
  "id": "pay_5521",
  "partner_id": "675d...",
  "status": "pending",
  "total": 1250
}
```

---

## PUT /partners/payouts/{payoutId}/status.json
**Service:** partner
**Version:** 2026-02-01

**Required Scope:** `partner_payouts:write`
**Permission Constant:** `ApiAccessPermission::PARTNER_PAYOUTS_WRITE`

### Parameters
- `payout.status` (string) *Required*: Next payout status. Allowed values: pending, paid, refused.
- `payout.metadata` (object): Optional metadata merged into payout metadata.

### Request Body Example
```json
{
  "payout": {
    "status": "paid",
    "metadata": {
      "reference": "BANK-TRX-2026-8891"
    }
  }
}
```

### Responses
#### 200 OK
Payout status updated and related fee entries synchronized.

```json
{
  "payout": {
    "id": "pay_5521",
    "status": "paid"
  }
}
```

#### 409 Conflict
Invalid status transition.

```json
{
  "error": "Paid payouts cannot be updated"
}
```

---

## GET /partners/{partnerId}/payouts/{payoutId}/report.pdf
**Service:** partner
**Version:** 2026-02-01

**Required Scope:** `partner_payouts:read`
**Permission Constant:** `ApiAccessPermission::PARTNER_PAYOUTS_READ`

### Responses
#### 200 OK
Inline PDF stream response.

```json
{
  "note": "Response is streamed as application/pdf."
}
```

---

## GET /recurring-payments/settings.json
**Service:** recurring-payments
**Version:** 2026-02-01

**Required Scope:** `recurring_settings:read`
**Permission Constant:** `ApiAccessPermission::RECURRING_SETTINGS_READ`

### Responses
#### 200 OK
Operational settings successfully retrieved.

```json
{
  "status": "success",
  "settings": {
    "retry_policy": "exponential_backoff",
    "max_retries": 5,
    "next_cycle_offset": "24 hours",
    "dunning_notifications": true
  }
}
```

---

## GET /recurring-payments/subscriptions.json
**Service:** recurring-payments
**Version:** 2026-02-01

**Required Scope:** `recurring_subscriptions:read`
**Permission Constant:** `ApiAccessPermission::RECURRING_SUBSCRIPTIONS_READ`

### Responses
#### 200 OK
Subscription inventory retrieved.

```json
{
  "type": "RecurringSubscriptions",
  "count": 1250,
  "per_page": 100,
  "elements": [
    {
      "id": "67bdf...",
      "customerId": "66a15...",
      "subscription_reference": "sub_premium_9921",
      "status": "active",
      "next_renewal_date": "2026-04-01T00:00:00Z",
      "last_payment_status": "success"
    }
  ]
}
```

---

## GET /scheduler/events.json
**Service:** scheduler
**Version:** 2026-02-01

**Required Scope:** `scheduler_events:read`
**Permission Constant:** `ApiAccessPermission::SCHEDULER_EVENTS_READ`

### Responses
#### 200 OK
Events fetched in the requested range.

```json
{
  "status": "fetch",
  "count": 2,
  "range": {
    "start": "2026-04-01T00:00:00+02:00",
    "end": "2026-04-30T23:59:59+02:00"
  },
  "events": [
    {
      "id": "681f0f...",
      "event_type": "appointment",
      "title": "Quarterly Review",
      "schedule_date": "2026-04-12T09:00:00+02:00",
      "end_date": "2026-04-12T10:00:00+02:00"
    }
  ]
}
```

---

## POST /scheduler/events.json
**Service:** scheduler
**Version:** 2026-02-01

**Required Scope:** `scheduler_events:write`
**Permission Constant:** `ApiAccessPermission::SCHEDULER_EVENTS_WRITE`

### Parameters
- `event` (object) *Required*: Scheduler event payload.

### Request Body Example
```json
{
  "event": {
    "event_type": "action",
    "title": "Run Workflow Daily",
    "schedule_date": "2026-04-20T07:30:00+02:00",
    "end_date": "2026-04-20T07:30:00+02:00",
    "is_all_day": false,
    "color": "primary",
    "action_type": "workflow",
    "action_details": {
      "workflow_id": "67ffac1f8a3f0f2f88f9dd10",
      "payload": {
        "source": "api"
      }
    },
    "recurrence": {
      "type": "week",
      "interval": 1,
      "endDate": "2026-12-31"
    }
  }
}
```

### Responses
#### 201 Created
Event created.

```json
{
  "id": "681f0f...",
  "event": {
    "id": "681f0f...",
    "event_type": "action",
    "action_type": "workflow"
  }
}
```

#### 422 Unprocessable Entity
Validation error on event payload.

```json
{
  "error": "Invalid \"action_type\". Allowed values: charge, job_runner, workflow"
}
```

---

## PUT /scheduler/events/{eventId}.json
**Service:** scheduler
**Version:** 2026-02-01

**Required Scope:** `scheduler_events:write`
**Permission Constant:** `ApiAccessPermission::SCHEDULER_EVENTS_WRITE`

### Parameters
- `event` (object) *Required*: Partial event payload to update.

### Request Body Example
```json
{
  "event": {
    "title": "Run Workflow - Updated",
    "recurrence": {
      "type": "month",
      "interval": 1,
      "endDate": "2027-04-30"
    }
  }
}
```

### Responses
#### 200 OK
Event updated.

```json
{
  "id": "681f0f...",
  "event": {
    "id": "681f0f...",
    "title": "Run Workflow - Updated"
  }
}
```

---

## DELETE /scheduler/events/{eventId}.json
**Service:** scheduler
**Version:** 2026-02-01

**Required Scope:** `scheduler_events:write`
**Permission Constant:** `ApiAccessPermission::SCHEDULER_EVENTS_WRITE`

### Responses
#### 202 Accepted
Event deleted.

```json
{
  "id": "681f0f...",
  "deleted": true
}
```

---

## GET /share-secrets.json
**Service:** share-secrets
**Version:** 2026-02-01

**Required Scope:** `share_secrets:read`
**Permission Constant:** `ApiAccessPermission::SHARE_SECRETS_READ`

### Responses
#### 200 OK
Secret directory successfully retrieved.

```json
{
  "entities": "ShareSecret",
  "count": 5,
  "per_page": 100,
  "pages": {
    "current": 1,
    "max": 1
  },
  "elements": [
    {
      "id": "6739782b...",
      "name": "Database Migration Credentials",
      "url": "https://hub.donutwork.com/ss/b6a9532aa4a06...",
      "readed": false
    }
  ]
}
```

---

## POST /share-secrets.json
**Service:** share-secrets
**Version:** 2026-02-01

**Required Scope:** `share_secrets:write`
**Permission Constant:** `ApiAccessPermission::SHARE_SECRETS_WRITE`

### Parameters
- `shareSecret.name` (string) *Required*: Descriptive label for internal tracking.
- `shareSecret.content` (string) *Required*: The sensitive payload to be shared (OTV).
- `shareSecret.sendTo.email` (string): Recipient email for automated notification.
- `shareSecret.sendTo.message` (string): Optional custom message included in notification email.

### Request Body Example
```json
{
  "shareSecret": {
    "name": "Deployment API Token",
    "content": "secret_value_redacted",
    "sendTo": {
      "email": "engineer@partner-company.com",
      "message": "The requested production API token is now available for one-time retrieval."
    }
  }
}
```

### Responses
#### 200 OK
Secret link successfully provisioned.

```json
{
  "id": "67397a4c...",
  "name": "Deployment API Token",
  "url": "https://hub.donutwork.com/ss/fb89f610...",
  "readed": false,
  "readerInfo": {
    "ip": null,
    "ua": null,
    "isoDate": null,
    "ts": null
  },
  "sendTo": {
    "status": true,
    "messageId": "msg_9921"
  }
}
```

---

## GET /share-secrets/{secretId}.json
**Service:** share-secrets
**Version:** 2026-02-01

**Required Scope:** `share_secrets:read`
**Permission Constant:** `ApiAccessPermission::SHARE_SECRETS_READ`

### Responses
#### 200 OK
Access metadata successfully retrieved.

```json
{
  "id": "6739782b...",
  "name": "Database Migration Credentials",
  "readed": true,
  "readerInfo": {
    "ip": "82.1.4.22",
    "ua": "Mozilla/5.0...",
    "isoDate": "03/03/2026 11:20:00",
    "ts": 1772536800
  }
}
```

---

## DELETE /share-secrets/{secretId}.json
**Service:** share-secrets
**Version:** 2026-02-01

**Required Scope:** `share_secrets:write`
**Permission Constant:** `ApiAccessPermission::SHARE_SECRETS_WRITE`

### Responses
#### 202 Accepted
Secret link successfully revoked and record purged.

```json
{
  "id": "67397a4c...",
  "deleted": true
}
```

---

## GET /shortlinks.json
**Service:** shortlinks
**Version:** 2026-02-01

**Required Scope:** `shortlinks:read`
**Permission Constant:** `ApiAccessPermission::SHORTLINKS_READ`

### Responses
#### 200 OK
Shortlink inventory successfully retrieved.

```json
{
  "entities": "Shortlink",
  "count": 42,
  "per_page": 100,
  "pages": {
    "current": 1,
    "max": 1
  },
  "elements": [
    {
      "id": "675d9fea...",
      "title": "Spring 2026 Campaign",
      "original_url": "https://marketing.acme.com/promo/spring",
      "short_code": "k9x2m-spr26",
      "url": "https://d.dw2.it/r/k9x2m-spr26",
      "is_active": true
    }
  ]
}
```

---

## POST /shortlinks.json
**Service:** shortlinks
**Version:** 2026-02-01

**Required Scope:** `shortlinks:write`
**Permission Constant:** `ApiAccessPermission::SHORTLINKS_WRITE`

### Parameters
- `shortlink.title` (string) *Required*: Administrative label for the link.
- `shortlink.original_url` (string) *Required*: The full destination URL (must include protocol).
- `shortlink.fragment` (string): Custom shortlink suffix (3-48 chars, letters/numbers/hyphens). Alias: `shortlink.short_code`.
- `shortlink.is_active` (boolean): Operational status of the link. Defaults to true.

### Request Body Example
```json
{
  "shortlink": {
    "title": "Product Launch Announcement",
    "original_url": "https://acme.com/products/new-gen-ai",
    "fragment": "launch-2026",
    "is_active": true
  }
}
```

### Responses
#### 201 Created
Shortlink successfully provisioned.

```json
{
  "shortlink": {
    "id": "6768440..."
  },
  "short_code": "k9x2m-launch-2026",
  "url": "https://d.dw2.it/r/k9x2m-launch-2026"
}
```

#### 409 Conflict
Requested custom fragment is already in use.

```json
{
  "error": "This shortlink fragment is already in use"
}
```

---

## GET /shortlinks/{shortlinkId}.json
**Service:** shortlinks
**Version:** 2026-02-01

**Required Scope:** `shortlinks:read`
**Permission Constant:** `ApiAccessPermission::SHORTLINKS_READ`

### Responses
#### 200 OK
Shortlink configuration retrieved.

```json
{
  "id": "675d9fea...",
  "title": "Spring 2026 Campaign",
  "original_url": "https://marketing.acme.com/promo/spring",
  "short_code": "k9x2m-spr26",
  "url": "https://d.dw2.it/r/k9x2m-spr26",
  "is_active": true
}
```

---

## PUT /shortlinks/{shortlinkId}.json
**Service:** shortlinks
**Version:** 2026-02-01

**Required Scope:** `shortlinks:write`
**Permission Constant:** `ApiAccessPermission::SHORTLINKS_WRITE`

### Parameters
- `shortlink.title` (string) *Required*: Updated shortlink title.
- `shortlink.original_url` (string) *Required*: Updated destination URL.
- `shortlink.fragment` (string): Updated custom suffix (3-48 chars, letters/numbers/hyphens). Alias: `shortlink.short_code`.
- `shortlink.is_active` (boolean): Enable or disable link redirection.

### Request Body Example
```json
{
  "shortlink": {
    "title": "Revised Spring Campaign",
    "original_url": "https://marketing.acme.com/promo/spring-final",
    "fragment": "spring-final",
    "is_active": true
  }
}
```

### Responses
#### 200 OK
Configuration updated successfully.

```json
{
  "shortlink": {
    "id": "675d9fea..."
  },
  "short_code": "k9x2m-spring-final",
  "url": "https://d.dw2.it/r/k9x2m-spring-final"
}
```

#### 409 Conflict
Requested custom fragment is already in use.

```json
{
  "error": "This shortlink fragment is already in use"
}
```

---

## DELETE /shortlinks/{shortlinkId}.json
**Service:** shortlinks
**Version:** 2026-02-01

**Required Scope:** `shortlinks:write`
**Permission Constant:** `ApiAccessPermission::SHORTLINKS_WRITE`

### Responses
#### 202 Accepted
Shortlink successfully revoked.

```json
{
  "id": "675d9fea...",
  "deleted": true
}
```

---

## GET /shortlinks/{shortlinkId}/stats.json
**Service:** shortlinks
**Version:** 2026-02-01

**Required Scope:** `shortlinks:read`
**Permission Constant:** `ApiAccessPermission::SHORTLINKS_READ`

### Responses
#### 200 OK
Engagement metrics successfully aggregated.

```json
{
  "shortlink": {
    "id": "675d9fea...",
    "title": "Spring 2026 Campaign",
    "original_url": "https://marketing.acme.com/promo/spring",
    "short_code": "k9x2m-spr26",
    "is_active": true,
    "url": "https://d.dw2.it/r/k9x2m-spr26",
    "created_at": 1772536800
  },
  "metrics": {
    "summary": {
      "human": 1530,
      "bot": 12,
      "total": 1542
    },
    "view_density": [
      {
        "country": "IT",
        "count": 600
      },
      {
        "country": "US",
        "count": 420
      }
    ],
    "referrers": {
      "Direct": 900,
      "linkedin.com": 350,
      "newsletter.acme.com": 292
    },
    "bots": {
      "Google": 7,
      "Facebook": 5
    },
    "browsers": {
      "Chrome": 1100,
      "Safari": 320,
      "Firefox": 110
    },
    "os": {
      "Windows": 620,
      "macOS": 410,
      "iOS": 320,
      "Android": 180
    }
  }
}
```

---

## GET /taxes.json
**Service:** taxes
**Version:** 2026-02-01

**Required Scope:** `taxes:read`
**Permission Constant:** `ApiAccessPermission::TAXES_READ`

### Responses
#### 200 OK
Tax profile directory successfully retrieved.

```json
{
  "entities": "Taxes",
  "count": 5,
  "per_page": 100,
  "pages": {
    "current": 1,
    "max": 1
  },
  "elements": [
    {
      "id": "66a151b7...",
      "name": "Standard EU VAT (22%)",
      "percentage": 22,
      "description": "Standard Value Added Tax for European Union member states."
    }
  ]
}
```

---

## POST /taxes.json
**Service:** taxes
**Version:** 2026-02-01

**Required Scope:** `taxes:write`
**Permission Constant:** `ApiAccessPermission::TAXES_WRITE`

### Parameters
- `tax.name` (string) *Required*: Unique tax profile label.
- `tax.percentage` (number) *Required*: Tax percentage value. Must be >= 0.
- `tax.description` (string): Optional internal description.
- `tax.default` (boolean): Marks the profile as default when true.

### Request Body Example
```json
{
  "tax": {
    "name": "Standard EU VAT (22%)",
    "description": "EU default VAT profile",
    "percentage": 22,
    "default": false
  }
}
```

### Responses
#### 201 Created
Tax profile created.

```json
{
  "status": "success",
  "tax": {
    "id": "tax_001",
    "name": "Standard EU VAT (22%)",
    "percentage": 22
  }
}
```

---

## PUT /taxes/{taxId}.json
**Service:** taxes
**Version:** 2026-02-01

**Required Scope:** `taxes:write`
**Permission Constant:** `ApiAccessPermission::TAXES_WRITE`

### Parameters
- `tax.name` (string): Updated tax profile label.
- `tax.description` (string): Updated profile description.
- `tax.percentage` (number): Updated percentage value. Must be >= 0.
- `tax.default` (boolean): Update default profile flag.

### Request Body Example
```json
{
  "tax": {
    "name": "EU VAT 2026",
    "description": "Updated profile metadata",
    "percentage": 23,
    "default": true
  }
}
```

### Responses
#### 200 OK
Tax profile updated.

```json
{
  "status": "success",
  "tax": {
    "id": "tax_001",
    "name": "EU VAT 2026",
    "percentage": 23
  }
}
```

---

## DELETE /taxes/{taxId}.json
**Service:** taxes
**Version:** 2026-02-01

**Required Scope:** `taxes:write`
**Permission Constant:** `ApiAccessPermission::TAXES_WRITE`

### Responses
#### 200 OK
Tax profile deleted.

```json
{
  "status": "success",
  "tax": {
    "id": "tax_001",
    "deleted": true
  }
}
```

#### 404 Not Found
Tax profile not found.

```json
{
  "error": "This tax profile does not exists"
}
```

---

## GET /webhooks.json
**Service:** webhook
**Version:** 2026-02-01

**Required Scope:** `webhooks:read`
**Permission Constant:** `ApiAccessPermission::WEBHOOKS_READ`

### Responses
#### 200 OK
Paginated list of webhook subscriptions.

```json
{
  "entities": "Webhook",
  "count": 2,
  "per_page": 100,
  "pages": {
    "current": 1,
    "max": 1
  },
  "elements": [
    {
      "id": "wh_001",
      "name": "Billing Events",
      "description": "Receive invoice and payment updates",
      "url": "https://example.com/webhooks/billing",
      "events": [
        "RecurringPayments.charge.paid"
      ],
      "token": "redacted"
    }
  ]
}
```

---

## POST /webhooks.json
**Service:** webhook
**Version:** 2026-02-01

**Required Scope:** `webhooks:write`
**Permission Constant:** `ApiAccessPermission::WEBHOOKS_WRITE`

### Parameters
- `webhook.name` (string) *Required*: Display name of the webhook subscription.
- `webhook.url` (string) *Required*: HTTPS endpoint that receives webhook payloads.
- `webhook.events` (array|string) *Required*: Subscribed event names. A single event string is also accepted.
- `webhook.description` (string): Optional free-text description for internal use.

### Request Body Example
```json
{
  "webhook": {
    "name": "Billing Events",
    "description": "Receive invoice and payment updates",
    "url": "https://example.com/webhooks/billing",
    "events": [
      "RecurringPayments.charge.paid"
    ]
  }
}
```

### Responses
#### 201 Created
Webhook created successfully.

```json
{
  "id": "wh_001",
  "name": "Billing Events",
  "description": "Receive invoice and payment updates",
  "url": "https://example.com/webhooks/billing",
  "events": [
    "RecurringPayments.charge.paid"
  ],
  "token": "generated_webhook_token"
}
```

#### 412 Precondition Failed
Name, url, or events missing; or TLS certificate validation failed.

```json
{
  "error": "A valid \"url\" must be specified."
}
```

#### 422 Unprocessable Entity
URL format invalid or unsupported event specified.

```json
{
  "error": "Some events are not available"
}
```

---

## GET /webhooks/types.json
**Service:** webhook
**Version:** 2026-02-01

**Required Scope:** `webhooks:read`
**Permission Constant:** `ApiAccessPermission::WEBHOOKS_READ`

### Responses
#### 200 OK
List of available webhook event names for the company context.

```json
[
  "RecurringPayments.charge.paid",
  "RecurringPayments.charge.failed"
]
```

---

## GET /webhooks/{webhookId}.json
**Service:** webhook
**Version:** 2026-02-01

**Required Scope:** `webhooks:read`
**Permission Constant:** `ApiAccessPermission::WEBHOOKS_READ`

### Responses
#### 200 OK
Webhook details.

```json
{
  "id": "wh_001",
  "name": "Billing Events",
  "description": "Receive invoice and payment updates",
  "url": "https://example.com/webhooks/billing",
  "events": [
    "RecurringPayments.charge.paid"
  ],
  "token": "redacted"
}
```

#### 404 Not Found
Webhook resource not found.

```json
{
  "error": "Webhook not found."
}
```

---

## DELETE /webhooks/{webhookId}.json
**Service:** webhook
**Version:** 2026-02-01

**Required Scope:** `webhooks:write`
**Permission Constant:** `ApiAccessPermission::WEBHOOKS_WRITE`

### Responses
#### 202 Accepted
Webhook deletion accepted.

```json
{
  "id": "wh_001",
  "deleted": true
}
```

#### 404 Not Found
Webhook resource not found.

```json
{
  "error": "Webhook not found. Unable to delete unknown resource"
}
```

---

## GET /workflow.json
**Service:** workflow
**Version:** 2026-02-01

**Required Scope:** `workflow:read`
**Permission Constant:** `ApiAccessPermission::WORKFLOW_READ`

### Responses
#### 200 OK
Workflow inventory successfully retrieved.

```json
{
  "entities": "Workflow",
  "count": 12,
  "per_page": 100,
  "pages": {
    "current": 1,
    "max": 1
  },
  "elements": [
    {
      "id": "6724bffd...",
      "name": "Enterprise Onboarding Logic",
      "active": true,
      "tasks_count": 8,
      "description": "Orchestrates account provisioning and initial compliance checks."
    }
  ]
}
```

---

## POST /workflow/{workflowId}.json
**Service:** workflow
**Version:** 2026-02-01

**Required Scope:** `workflow:write`
**Permission Constant:** `ApiAccessPermission::WORKFLOW_WRITE`

### Parameters
- `data` (object) *Required*: Dynamic context data injected into the workflow execution.

### Request Body Example
```json
{
  "data": {
    "customer_id": "cust_9921",
    "priority": "high",
    "metadata": {
      "source": "api_v2"
    }
  }
}
```

### Responses
#### 200 OK
Workflow execution completed. Detailed stage results returned.

```json
{
  "success": true,
  "execution_id": "exe_8821abd033",
  "stages": [
    {
      "node": "validate_identity",
      "status": "completed",
      "output": {
        "valid": true
      }
    }
  ]
}
```

#### 404 Not Found
The specified workflow identifier does not exist.

```json
{
  "error": "This workflow does not exists"
}
```

---

## GET /workflow/{workflowId}/traces.json
**Service:** workflow
**Version:** 2026-02-01

**Required Scope:** `workflow_traces:read`
**Permission Constant:** `ApiAccessPermission::WORKFLOW_TRACES_READ`

### Responses
#### 200 OK
Trace list retrieved.

```json
{
  "entities": "WorkflowTrace",
  "count": 2,
  "per_page": 50,
  "pages": {
    "current": 1,
    "max": 1
  },
  "elements": [
    {
      "id": "6803f0f1...",
      "workflow_id": "67ffac1f...",
      "uuid": "d76d716e-0f91-4f7f-b37f-4475e573f807",
      "run_date": "2026-04-20T08:41:12+00:00",
      "status": "executed"
    }
  ]
}
```

#### 404 Not Found
Workflow not found.

```json
{
  "error": "This workflow does not exists"
}
```

---

## GET /workflow/{workflowId}/traces/{traceId}.json
**Service:** workflow
**Version:** 2026-02-01

**Required Scope:** `workflow_traces:read`
**Permission Constant:** `ApiAccessPermission::WORKFLOW_TRACES_READ`

### Responses
#### 200 OK
Trace retrieved.

```json
{
  "id": "6803f0f1...",
  "workflow_id": "67ffac1f...",
  "uuid": "d76d716e-0f91-4f7f-b37f-4475e573f807",
  "run_date": "2026-04-20T08:41:12+00:00",
  "status": "executed",
  "response": {
    "input": {
      "customer_id": "cust_9921"
    },
    "result": {
      "workflow_status": "executed"
    },
    "stages": [
      {
        "node_name": "validate_identity",
        "status": "SUCCESS",
        "duration": 0.1281
      }
    ]
  }
}
```

#### 404 Not Found
Trace not found for workflow.

```json
{
  "error": "Trace not found for this workflow."
}
```

---

