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

# PHP

> 使用 Dodo Payments PHP SDK 从 PHP 8.1+ 创建结账会话、客户和订阅，并获得类型化值对象、重试和分页支持。

PHP SDK 让 PHP 8.1+ 应用可以访问 Dodo Payments REST API。方法使用命名参数，响应为类型化对象，Composer 通过 PSR-4 自动加载加载 SDK。

## 安装

使用 Composer 安装 SDK：

```bash theme={null}
composer require "dodopayments/client 6.27.0"
```

> [!NOTE]
>
> SDK 要求 PHP 8.1.0 或更高版本以及 Composer。它会通过项目中的 PSR-18 HTTP client 发送请求，例如 Guzzle；SDK 会使用 `php-http/discovery` 找到该 client。

## 快速开始

创建 client，然后创建结账会话：

```php theme={null}
<?php

use Dodopayments\Client;

$client = new Client(
  bearerToken: getenv('DODO_PAYMENTS_API_KEY') ?: 'My Bearer Token',
  baseUrl: 'https://test.dodopayments.com',
);

$checkoutSessionResponse = $client->checkoutSessions->create(
  productCart: [["productID" => "pdt_123", "quantity" => 1]]
);

var_dump($checkoutSessionResponse->sessionID);
```

如果省略 `bearerToken`，client 会读取 `DODO_PAYMENTS_API_KEY` 环境变量。如果省略 `baseUrl`，client 会读取 `DODO_PAYMENTS_BASE_URL`；如果该变量也未设置，则连接到 live mode（`https://live.dodopayments.com`）。test mode API key 只能与 test mode URL `https://test.dodopayments.com` 一起使用。

> [!WARNING]
>
> 将 API keys 保存在环境变量或 secrets manager 中。切勿将其暴露在
> 代码库中，也不要将其提交到版本控制系统。

## 核心功能

> **PSR-4 Compliant**
>
> Composer 通过 PSR-4 自动加载加载 `Dodopayments` 命名空间。

> **Modern PHP**
>
> 专为 PHP 8.1 或更高版本构建，使用类型化参数和严格类型。

> **Extensive Testing**
>
> SDK repository 包含 API services 的测试套件。

> **Exception Handling**
>
> 每个 HTTP error status 都有对应的 exception class，另外还包括 timeout 和 connection exceptions。

## 值对象

方法使用命名参数，具有默认值的参数必须按名称传递。要构建值对象，请使用其静态 `with` 构造函数，并传入命名参数：

```php theme={null}
<?php

use Dodopayments\Payments\AttachExistingCustomer;

// Recommended: Use static 'with' constructor with named parameters
$customer = AttachExistingCustomer::with(customerID: "cus_123");
```

每个值对象也都有一个 builder：

```php theme={null}
<?php

use Dodopayments\Payments\AttachExistingCustomer;

// Alternative: Use builder pattern
$customer = (new AttachExistingCustomer)->withCustomerID("cus_123");
```

方法也接受使用相同 camelCase keys 的普通数组，例如 `["productID" => "pdt_123", "quantity" => 1]`。响应属性同样使用 camelCase 名称，例如 `$session->checkoutURL`。

## 配置

`Client` 构造函数接受 `bearerToken`、`webhookKey`、`baseUrl` 和 `requestOptions`。省略这些参数时，它会从环境中读取 `DODO_PAYMENTS_API_KEY`、`DODO_PAYMENTS_WEBHOOK_KEY`（你的 webhook signing secret）以及 `DODO_PAYMENTS_BASE_URL`。

要验证 webhook，请将原始请求正文和 headers 传递给 `$client->webhooks->unwrap($body, headers: $headers)`。它会使用你的 webhook key 检查签名，返回已解析的 event；如果检查失败，则抛出 `WebhookException`。如果省略 `headers`，`unwrap` 不会验证签名。`$client->webhooks->unsafeUnwrap($body)` 会在不验证签名的情况下解析正文，因此只能用于测试。请参阅 [Webhooks](/developer-resources/webhooks.md)。

### 重试配置

SDK 默认会对部分错误重试两次，并使用较短的 exponential backoff。以下错误会触发重试：

* Connection errors（网络连接问题）
* 408 Request Timeout
* 409 Conflict
* 429 Rate Limit
* 500+ Internal errors
* Timeouts

在 `requestOptions` 中设置 `maxRetries`，可以在 client 或单个 request 上进行设置：

```php theme={null}
<?php

use Dodopayments\Client;

// Configure default for all requests (disable retries)
$client = new Client(requestOptions: ['maxRetries' => 0]);

// Or, configure per-request
$result = $client->checkoutSessions->create(
  productCart: [["productID" => "pdt_123", "quantity" => 1]],
  requestOptions: ['maxRetries' => 5],
);
```

Requests 默认在 60 秒后超时。要更改此限制，请在同一个 `requestOptions` 数组中，以秒为单位设置 `timeout`。

## 常见操作

本节中的示例使用 [Quick Start](#quick-start) 中的 `$client`。

### 创建 Checkout Session

创建 checkout session，然后将 customer 重定向到返回的 `checkoutURL`：

```php theme={null}
$session = $client->checkoutSessions->create(
  productCart: [
    ["productID" => "pdt_123", "quantity" => 1]
  ],
  returnURL: "https://yourdomain.com/return"
);

header('Location: ' . $session->checkoutURL);
```

每个 checkout URL 只能使用一次，并会在 24 小时后过期。有关每个 session option 的信息，请参阅 [Checkout Sessions](/developer-resources/checkout-session.md)。

### 管理 Customers

使用 email address 和 name 创建 customer，然后通过 ID 检索它：

```php theme={null}
// Create a customer
$customer = $client->customers->create(
  email: "customer@example.com",
  name: "John Doe",
  metadata: [
    "user_id" => "12345"
  ]
);

// Retrieve customer
$customer = $client->customers->retrieve("cus_123");
echo "Customer: {$customer->name} ({$customer->email})";
```

### 处理 Subscriptions

创建 subscription；如果它是 on-demand subscription，则对其收费。

> [!WARNING]
>
> `POST /subscriptions`（SDK 的 `subscriptions->create` method）已**弃用**。它仍可用于现有集成，但新集成应通过 [Checkout Session](/developer-resources/checkout-session.md) 创建 subscriptions。

```php theme={null}
use Dodopayments\Payments\AttachExistingCustomer;
use Dodopayments\Payments\BillingAddress;

// Create a subscription
$subscription = $client->subscriptions->create(
  billing: BillingAddress::with(
    country: 'US',
    city: 'San Francisco',
    state: 'CA',
    street: '1 Market St',
    zipcode: '94105',
  ),
  customer: AttachExistingCustomer::with(customerID: 'cus_123'),
  productID: 'pdt_456',
  quantity: 1,
);

// Charge an on-demand subscription
// productPrice is in the lowest currency denomination (e.g., 2500 = $25.00 USD)
$charge = $client->subscriptions->charge(
  $subscription->subscriptionID,
  productPrice: 2500,
);
```

> [!NOTE]
>
> `billing` 只需要 `country`，即两个字母的 ISO country code。传递 `AttachExistingCustomer::with(customerID: '...')` 可关联现有 customer，传递 `NewCustomer::with(email: '...', name: '...')` 可创建 customer。这两个 class 都位于 `Dodopayments\Payments` namespace 中。`charge` 用于 [on-demand subscriptions](/developer-resources/ondemand-subscriptions.md)，而 `productPrice` 的单位是货币的最小单位。

## 分页

List methods 返回一个 page object。`getItems()` 返回当前页面中的 items，`pagingEachItem()` 返回从当前页面开始的所有 items，并在需要时请求更多页面：

```php theme={null}
$page = $client->payments->list();

var_dump($page);

// Fetch items from the current page
foreach ($page->getItems() as $item) {
  var_dump($item->brandID);
}

// Auto-paginate: fetch items from all pages
foreach ($page->pagingEachItem() as $item) {
  var_dump($item->brandID);
}
```

要逐页移动，请调用 `hasNextPage()` 和 `getNextPage()`。

## 错误处理

当 SDK 无法连接到 API，或 API 返回 4xx 或 5xx status 时，SDK 会抛出 `Dodopayments\Core\Exceptions\APIException` 的子类：

```php theme={null}
<?php

use Dodopayments\Core\Exceptions\APIConnectionException;
use Dodopayments\Core\Exceptions\RateLimitException;
use Dodopayments\Core\Exceptions\APIStatusException;

try {
  $checkoutSessionResponse = $client->checkoutSessions->create(
    productCart: [["productID" => "pdt_123", "quantity" => 1]]
  );
} catch (APIConnectionException $e) {
  echo "The server could not be reached", PHP_EOL;
  var_dump($e->getPrevious());
} catch (RateLimitException $_) {
  echo "A 429 status code was received; we should back off a bit.", PHP_EOL;
} catch (APIStatusException $e) {
  echo "Another non-200-range status code was received", PHP_EOL;
  echo $e->getMessage();
}
```

### 错误类型

exception class 取决于错误原因。所有 class 都位于 `Dodopayments\Core\Exceptions` namespace 中：

| Cause | Error Type |
| - | - |
| HTTP 400 | `BadRequestException` |
| HTTP 401 | `AuthenticationException` |
| HTTP 403 | `PermissionDeniedException` |
| HTTP 404 | `NotFoundException` |
| HTTP 409 | `ConflictException` |
| HTTP 422 | `UnprocessableEntityException` |
| HTTP 429 | `RateLimitException` |
| HTTP >= 500 | `InternalServerException` |
| Other HTTP error | `APIStatusException` |
| Timeout | `APITimeoutException` |
| Network error | `APIConnectionException` |

> [!TIP]
>
> 在 API calls 周围捕获这些 exceptions，以便应用显示清晰的
> 消息或稍后重试。对于可重试错误，SDK 只会在自动重试失败后抛出 exception。

## 高级用法

### 未记录的 Endpoints

要调用没有 SDK method 的 endpoint，请使用 `$client->request`。它会应用与 SDK methods 相同的 authentication 和 retries：

```php theme={null}
<?php

$response = $client->request(
  method: "post",
  path: '/undocumented/endpoint',
  query: ['dog' => 'woof'],
  headers: ['useful-header' => 'interesting-value'],
  body: ['hello' => 'world']
);
```

### 未记录的 Parameters

要发送 SDK 未定义的 parameters，请将其传入 `requestOptions`：

```php theme={null}
<?php

use Dodopayments\RequestOptions;

$checkoutSessionResponse = $client->checkoutSessions->create(
  productCart: [["productID" => "pdt_123", "quantity" => 1]],
  requestOptions: [
    'extraQueryParams' => ["my_query_parameter" => "value"],
    'extraBodyParams' => ["my_body_parameter" => "value"],
    'extraHeaders' => ["my-header" => "value"],
  ],
);
```

> [!NOTE]
>
> 与已记录 parameter 同名的 `extra*` parameter 会覆盖该 parameter。

## Framework 集成

### Laravel

将 client 封装在 service class 中。此示例从已配置的环境中设置 API URL：

```php theme={null}
<?php

namespace App\Services;

use Dodopayments\Client;

class PaymentService
{
    protected $client;

    public function __construct()
    {
        $this->client = new Client(
            bearerToken: config('services.dodo.api_key'),
            baseUrl: config('services.dodo.environment') === 'live_mode'
                ? 'https://live.dodopayments.com'
                : 'https://test.dodopayments.com',
        );
    }

    public function createCheckout(array $items)
    {
        return $this->client->checkoutSessions->create(
            productCart: $items,
            returnURL: route('checkout.return')
        );
    }
}
```

将设置添加到 `config/services.php`：

```php theme={null}
'dodo' => [
    'api_key' => env('DODO_PAYMENTS_API_KEY'),
    'environment' => env('DODO_PAYMENTS_ENVIRONMENT', 'test_mode')
],
```

### Symfony

创建一个通过其构造函数接收 API key 的 service：

```php theme={null}
<?php

namespace App\Service;

use Dodopayments\Client;

class DodoPaymentService
{
    private Client $client;

    public function __construct(string $apiKey)
    {
        $this->client = new Client(bearerToken: $apiKey);
    }

    public function createPayment(string $productId, string $customerId, array $billing): object
    {
        // Note: POST /payments is deprecated — prefer checkout sessions for new integrations
        return $this->client->payments->create(
            billing: $billing,
            customer: ['customerID' => $customerId],
            productCart: [['productID' => $productId, 'quantity' => 1]],
        );
    }
}
```

在 `config/services.yaml` 中注册 service：

```yaml theme={null}
services:
  App\Service\DodoPaymentService:
    arguments:
      $apiKey: "%env(DODO_PAYMENTS_API_KEY)%"
```

## 资源

> **[GitHub Repository](https://github.com/dodopayments/dodopayments-php)**
>
> 源代码、releases 和完整的 method list。

> **[API Reference](/api-reference/introduction.md)**
>
> 每个 endpoint、parameter 和 response。

> **[Discord Community](https://discord.gg/bYqAp4ayYh)**
>
> 提出问题并与其他 developers 交流。

> **[Report Issues](https://github.com/dodopayments/dodopayments-php/issues)**
>
> 报告 bugs 或请求 features。

## 支持

如需 PHP SDK 方面的帮助：

* **Discord**：加入 [community server](https://discord.gg/bYqAp4ayYh) 获取实时帮助。
* **Email**：联系 [support@dodopayments.com](mailto:support@dodopayments.com)。
* **GitHub**：在 [repository](https://github.com/dodopayments/dodopayments-php) 中提交 issue。

## 贡献

如需贡献代码，请阅读 [contributing guidelines](https://github.com/dodopayments/dodopayments-php/blob/main/CONTRIBUTING.md)。


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