Partner API

The Partner API lets a reseller or ISP tenant provision, manage, and monitor end-user ZDrive accounts on behalf of its own customers - for example, bundling storage into a broadband plan and creating an account automatically when a customer signs up. It is a separate, server-to-server API from the consumer-facing ZDrive API, authenticated by API key rather than a login session, and is only available to onboarded partners.

Base URL https://zhdrive.in/api/partner/v1

Authentication

Every request must include two headers - a key/secret pair, the same shape as Razorpay's key_id/key_secret:

  • X-Partner-Key - a public, non-secret identifier (e.g. pk_...). Safe to keep visible in your own dashboards/logs.
  • X-Partner-Secret - the actual credential (e.g. sk_...). Shown to you exactly once, at issuance or regeneration - we only ever keep a hash of it and can't recover a lost secret for you.

Sign in to the partner portal to view your API Key, and to regenerate your key/secret pair whenever you need to (e.g. if a secret is compromised, or you just don't have it saved anymore - regenerating immediately revokes the old pair and issues a new one).

Keys are tenant-scoped: every user, and every byte of usage, you create or read through this API is confined to your own tenant. There is no cross-tenant visibility in either direction.

curl -X POST https://zhdrive.in/api/partner/v1/users \
  -H "X-Partner-Key: <your-api-key>" \
  -H "X-Partner-Secret: <your-api-secret>" \
  -H "Content-Type: application/json" \
  -d '{"email":"customer@example.com","name":"Asha Rao","planCode":"PRO"}'

Rate limits & errors

Rate limits are tracked per tenant (per API key), not per IP - so provisioning many users from a single backend server doesn’t compete with a limit sized for one caller. Each endpoint below lists its limit; exceeding it returns 429 Too Many Requests. Errors otherwise follow a standard shape:

{ "statusCode": 404, "message": "User not found", "error": "Not Found" }

Common status codes: 400 invalid request body, 401 missing/invalid/revoked API key or a suspended tenant, 404 unknown user or plan code, 409 conflicting state (duplicate email, over-quota downgrade).

The User object

FieldType
idstring
emailstring
namestring | null
planstring
accountStatus"ACTIVE" | "SUSPENDED"
storageUsedstring (bytes)
storageLimitstring (bytes)
createdAtstring (ISO date)

Endpoints

POST/api/partner/v1/users 300 requests / 60s per tenant

Provision a new end-user account under your tenant. We email the user a set-password link - you never handle their password.

Request body

NameTypeRequiredNotes
emailstringyes
namestringno
planCodestringyesA plan code we’ve set up for your tenant, e.g. FREE / PRO / BUSINESS - ask your account manager for the exact codes and storage allocations available to you.

Response

User object (see "The User object" below).
  • Email addresses are unique platform-wide, not just within your tenant. If the address is already registered (by you, another tenant, or a direct ZDrive signup) this returns 409 Conflict with a generic "Email already registered" message - we never reveal which of those cases it is, to avoid leaking account existence across tenant boundaries.
  • The account is created with a random password nobody knows; the user sets their own via the emailed link, which stays valid for 7 days.
GET/api/partner/v1/users 100 requests / 60s per tenant

List end-user accounts provisioned under your tenant, paginated.

Query parameters

NameTypeRequiredNotes
pagenumbernodefault 1
pageSizenumbernodefault 50, max 200

Response

{ items: User[], total: number, page: number, pageSize: number }
GET/api/partner/v1/users/:id 100 requests / 60s per tenant

Fetch a single end-user account by id.

Response

User object.
  • If the id doesn’t exist, or exists but belongs to a different tenant, this returns the same 404 Not Found either way - so an id you don’t recognize never confirms whether it belongs to someone else.
PATCH/api/partner/v1/users/:id 100 requests / 60s per tenant

Change a provisioned user's plan and/or account status.

Request body

NameTypeRequiredNotes
planCodestringnoMove the user to a different plan.
accountStatus"ACTIVE" | "SUSPENDED"noReinstate or cut off a user, e.g. when their bundle with you lapses or renews.

Response

Updated User object.
  • A plan change is rejected with 409 Conflict if the user is already storing more data than the target plan allows - we won’t silently leave someone over quota.
DELETE/api/partner/v1/users/:id 100 requests / 60s per tenant

Suspend a provisioned user.

Response

{ success: true }
  • This is a soft suspend (sets accountStatus to SUSPENDED), not a hard delete - the user’s files and data are preserved. Reactivate later with PATCH /users/:id { "accountStatus": "ACTIVE" }.
GET/api/partner/v1/usage 100 requests / 60s per tenant

Aggregate usage across every user provisioned under your tenant - the numbers we bill you on.

Response

{ userCount: number, storageUsedBytes: string, storageAllocatedBytes: string }
  • storageUsedBytes and storageAllocatedBytes are returned as strings since they can exceed what a JSON number can represent exactly.

Not yet a partner, or need a key rotated? Email us at info@zennialhub.in.