定制 nusii/nusii-php 二次开发

按需修改功能、优化性能、对接业务系统,提供一站式技术支持

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

nusii/nusii-php

Composer 安装命令:

composer require nusii/nusii-php

包简介

PHP client library for the Nusii proposal software API

README 文档

README

A PHP client library for the Nusii proposal software API.

Requires PHP 8.3+ and uses Guzzle for HTTP requests.

Installation

Install via Composer:

composer require nusii/nusii-php

Quick Start

use Nusii\Nusii;

$nusii = new Nusii('your-api-key');

// List your clients
$clients = $nusii->clients()->list();

foreach ($clients as $client) {
    echo $client['name'] . "\n";
}

Custom Base URL

For self-hosted or development environments:

$nusii = new Nusii('your-api-key', baseUrl: 'http://localhost:3000');

Resources

Account

// Get current account
$account = $nusii->accounts()->me();

echo $account['name'];       // "Acme Corp"
echo $account['email'];      // "owner@acme.com"
echo $account['currency'];   // "USD"
echo $account['subdomain'];  // "acme"

Clients

// List clients (paginated)
$clients = $nusii->clients()->list(page: 1, perPage: 10);

echo $clients->totalCount;   // 42
echo $clients->currentPage;  // 1
echo $clients->totalPages;   // 5

foreach ($clients as $client) {
    echo $client['name'];
}

// Get a single client
$client = $nusii->clients()->get(id: 123);

// Create a client
$client = $nusii->clients()->create([
    'name' => 'John',
    'surname' => 'Doe',
    'email' => 'john@example.com',
    'business' => 'Acme Inc',
    'telephone' => '555-1234',
    'address' => '123 Main St',
    'city' => 'New York',
    'postcode' => '10001',
    'country' => 'US',
    'state' => 'NY',
    'web' => 'https://acme.com',
    'currency' => 'USD',
    'locale' => 'en',
]);

// Update a client
$client = $nusii->clients()->update(123, [
    'name' => 'Jane',
    'business' => 'Updated Corp',
]);

// Delete a client
$nusii->clients()->delete(123);

Proposals

// List proposals
$proposals = $nusii->proposals()->list();

// Filter by status: draft, pending, accepted, rejected
$drafts = $nusii->proposals()->list(status: 'draft');

// Filter archived proposals
$archived = $nusii->proposals()->list(archived: true);

// Get a single proposal
$proposal = $nusii->proposals()->get(456);

// Create a proposal
$proposal = $nusii->proposals()->create([
    'title' => 'Website Redesign',
    'client_id' => 123,
    'expires_at' => '2025-12-31',
    'currency' => 'EUR',
    'theme' => 'clean',
]);

// Update a proposal
$proposal = $nusii->proposals()->update(456, [
    'title' => 'Updated Proposal Title',
]);

// Send a proposal
$result = $nusii->proposals()->send(
    id: 456,
    email: 'client@example.com',
    subject: 'Your Proposal',            // optional
    message: 'Please review attached.',   // optional
    cc: 'manager@example.com',            // optional
    bcc: 'archive@example.com',           // optional
);

// Archive a proposal
$proposal = $nusii->proposals()->archive(456);

// Delete a proposal
$nusii->proposals()->delete(456);

Sections

// List all sections
$sections = $nusii->sections()->list();

// List sections for a specific proposal
$sections = $nusii->sections()->list(proposalId: 456);

// List sections for a specific template
$sections = $nusii->sections()->list(templateId: 789);

// Include line items in the response
$sections = $nusii->sections()->list(proposalId: 456, includeLineItems: true);

// Get a single section
$section = $nusii->sections()->get(10);

// Create a section
$section = $nusii->sections()->create([
    'proposal_id' => 456,
    'title' => 'Project Scope',
    'body' => '<p>Detailed project scope description.</p>',
    'position' => 1,
    'section_type' => 'cost',    // "cost" or "text"
    'optional' => false,
    'include_total' => true,
    'page_break' => false,
]);

// Update a section
$section = $nusii->sections()->update(10, [
    'title' => 'Updated Section Title',
    'body' => '<p>Updated content.</p>',
]);

// Delete a section
$nusii->sections()->delete(10);

Line Items

Line items belong to sections. They must be created under a section.

// List line items for a section
$items = $nusii->lineItems()->listBySection(sectionId: 10);

// Get a single line item
$item = $nusii->lineItems()->get(50);

// Create a line item for a section
$item = $nusii->lineItems()->createForSection(sectionId: 10, attributes: [
    'name' => 'Design Work',
    'quantity' => 10,
    'amount' => 7500,          // in cents
    'cost_type' => 'per',      // "fixed", "recurring", "per" or "range"
    'per_type' => 'hour',
    'position' => 1,
]);

// Create a price range line item ("$5,000 – $8,000").
// "amount" is the low end and "maximum_amount" the high end, both in cents.
// Requires the price ranges feature to be enabled for your account.
$item = $nusii->lineItems()->createForSection(sectionId: 10, attributes: [
    'name' => 'Discovery & UX research',
    'cost_type' => 'range',
    'amount' => 500000,
    'maximum_amount' => 800000,
]);
echo $item['maximum_amount_in_cents'];   // 800000
echo $item['maximum_amount_formatted'];  // "$8,000.00"

// Update a line item
$item = $nusii->lineItems()->update(50, [
    'name' => 'Updated Design Work',
    'quantity' => 20,
]);

// Delete a line item
$nusii->lineItems()->delete(50);

Templates

Templates are read-only.

// List templates
$templates = $nusii->templates()->list();

// Get a single template
$template = $nusii->templates()->get(5);

echo $template['name'];  // "Web Project Template"

Proposal Activities

Proposal activities are read-only and track events like views, accepts, and rejections.

// List all activities
$activities = $nusii->proposalActivities()->list();

// Filter by proposal
$activities = $nusii->proposalActivities()->list(proposalId: 456);

// Filter by client
$activities = $nusii->proposalActivities()->list(clientId: 123);

// Get a single activity
$activity = $nusii->proposalActivities()->get(1);

echo $activity['activity_type'];    // "viewed", "accepted", "rejected"
echo $activity['proposal_title'];   // "Website Redesign"
echo $activity['client_email'];     // "john@example.com"

Users

Users are read-only.

// List users on the account
$users = $nusii->users()->list();

foreach ($users as $user) {
    echo $user['email'];
    echo $user['name'];
}

Themes

Themes are read-only. Note: this endpoint returns a plain array, not a paginated response.

// List available themes
$themes = $nusii->themes()->list();

foreach ($themes as $theme) {
    echo $theme['id'];
    echo $theme['name'];  // "Classic", "Modern", etc.
}

Webhook Endpoints

// List webhook endpoints
$webhooks = $nusii->webhookEndpoints()->list();

// Get a single webhook endpoint
$webhook = $nusii->webhookEndpoints()->get(1);

// Create a webhook endpoint
$webhook = $nusii->webhookEndpoints()->create([
    'target_url' => 'https://example.com/webhooks/nusii',
    'events' => [
        'proposal_created',
        'proposal_accepted',
        'proposal_rejected',
        'proposal_sent',
    ],
]);

// Delete a webhook endpoint
$nusii->webhookEndpoints()->delete(1);

Available webhook events:

Event Description
proposal_created A proposal was created
proposal_updated A proposal was updated
proposal_destroyed A proposal was deleted
proposal_accepted A proposal was accepted by the client
proposal_rejected A proposal was rejected by the client
proposal_sent A proposal was sent to the client
client_created A client was created
client_updated A client was updated
client_destroyed A client was deleted
proposal_activity_client_viewed A client viewed something
proposal_activity_client_viewed_proposal A client viewed a proposal

Pagination

All list endpoints return a PaginatedResponse object that is both countable and iterable:

$response = $nusii->clients()->list(page: 1, perPage: 10);

// Pagination metadata
$response->currentPage;   // 1
$response->nextPage;      // 2 (or null)
$response->prevPage;      // null (or int)
$response->totalPages;    // 5
$response->totalCount;    // 42

// Navigation helpers
$response->hasNextPage(); // true
$response->hasPrevPage(); // false

// Iterate directly
foreach ($response as $item) {
    echo $item['name'];
}

// Count
echo count($response); // items on current page

// Access raw data array
$response->data; // array of items

Paginating Through All Results

$page = 1;

do {
    $response = $nusii->clients()->list(page: $page, perPage: 50);

    foreach ($response as $client) {
        // Process each client
    }

    $page++;
} while ($response->hasNextPage());

Error Handling

The library throws specific exceptions for different HTTP error codes:

use Nusii\Exceptions\AuthenticationException;
use Nusii\Exceptions\NotFoundException;
use Nusii\Exceptions\ValidationException;
use Nusii\Exceptions\RateLimitException;
use Nusii\Exceptions\ServerException;
use Nusii\Exceptions\NusiiException;

try {
    $client = $nusii->clients()->get(99999);
} catch (AuthenticationException $e) {
    // 401 - Invalid API key
    echo $e->getMessage();
} catch (NotFoundException $e) {
    // 404 - Resource not found
    echo $e->getMessage();
} catch (ValidationException $e) {
    // 400, 403, 422 - Validation or permission errors
    echo $e->getMessage();
    echo $e->getCode();          // HTTP status code
    print_r($e->responseBody);   // Raw response body
} catch (RateLimitException $e) {
    // 429 - Rate limit exceeded (100 requests per 30 seconds)
    echo $e->retryAfter;         // Seconds to wait before retrying
} catch (ServerException $e) {
    // 500, 503 - Server errors
    echo $e->getMessage();
} catch (NusiiException $e) {
    // Catch-all for any other API errors
    echo $e->getMessage();
}

All exceptions extend NusiiException, so you can catch that to handle any API error.

Rate Limiting

The Nusii API allows 100 requests per 30 seconds. Rate limit information is tracked on the client instance:

$nusii->clients()->list();

echo $nusii->rateLimitRemaining;   // 99
echo $nusii->rateLimitRetryAfter;  // null (or seconds to wait)

Testing

Run the unit tests:

composer test

Or with Pest directly:

./vendor/bin/pest

Integration Tests

Integration tests run against a live API server. Set the environment variables and run:

NUSII_API_KEY=your-key NUSII_API_URL=http://localhost:3000 ./vendor/bin/pest tests/IntegrationTest.php

Integration tests are automatically skipped when NUSII_API_KEY is not set.

Authentication

The library uses token authentication. Include your API key when creating the client:

$nusii = new Nusii('your-api-key');

All requests include the header:

Authorization: Token token=your-api-key

You can find your API key in your Nusii account settings under Integrations.

Requirements

  • PHP 8.3 or higher
  • Guzzle 7.0 or higher

License

MIT

nusii/nusii-php 适用场景与选型建议

nusii/nusii-php 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 0 次下载、GitHub Stars 达 0, 最近一次更新时间为 2026 年 03 月 10 日, 在 PHP 生态内属于活跃度较高的组件。

它主要适用于以下技术方向: 「api」 「client」 「proposals」 「nusii」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。

我们在过去多个企业项目中使用过 nusii/nusii-php 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 nusii/nusii-php 我们能提供哪些服务?
定制开发 / 二次开发

基于 nusii/nusii-php 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 0
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 25
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2026-03-10