Pincer purchase is R4's license provisioning surface for machine clients. The public API is intentionally small: callers can start a license purchase and poll status while R4 handles catalog lookup, quoting, order creation, and provider automation on the server.
Website catalog endpoints, product detail pages, product vault-field metadata, and catalog-admin provisioning routes are internal implementation details. They are not part of the public Pincer API.
All paths are relative to https://r4.dev and require machine authentication.
| Endpoint | Method | Purpose |
|---|---|---|
/api/v1/machine/licenses/purchase | POST | Purchase a license and start automated provisioning |
/api/v1/machine/licenses/purchases/:purchaseId/status | GET | Poll the purchase status and pending vault handoff |
/api/v1/machine/licenses/purchases/:purchaseId/vault-item | POST | Complete the client-encrypted vault-item handoff |
/api/v1/machine/licenses/purchases/:purchaseId/resume | POST | Resume a failed purchase from saved state |
POST /purchase and purchase resume require machine.license.write. Purchase
status polling requires machine.license.read. The machine key must also be
allowed to operate on the selected tenant.
POST /api/v1/machine/licenses/purchase
Content-Type: application/json
X-API-Key: <access-key>.<secret>{
"tenantId": "tenant_123",
"licenseId": "license_123",
"quantity": 1,
"externalLicenseId": "caller_license_456",
"configuration": [
{
"configId": "config_123",
"value": "\"feature_123\""
}
],
"domain": {
"mode": "automatic",
"domain": "example.com"
},
"vault": {
"mode": "new",
"name": "Provisioned licenses"
},
"project": {
"mode": "new",
"name": "Endpoint Security",
"externalId": "caller_project_789"
}
}Important request fields:
| Field | Type | Description |
|---|---|---|
tenantId | string | Tenant that will receive the purchased license |
licenseId | string | License to purchase |
quantity | number | Optional quantity; defaults to 1 |
externalLicenseId | string | Optional caller-owned ID to store on license instances |
configuration | array | Optional product configuration selections |
domain | object | Optional domain preference for provisioning |
vault | object | Optional destination for provisioned license outputs |
project | object | Optional project association |
domain.mode can be:
| Mode | Behavior |
|---|---|
automatic | Let R4 purchase or allocate a domain; if domain is provided, R4 requests that domain |
existing-domain | Use the supplied domain string in the selected tenant |
existing-domain-tenant | Use the supplied domainTenantId exactly |
If omitted, the domain mode defaults to automatic.
vault.mode can be:
| Mode | Behavior |
|---|---|
new | Return this as the requested destination for the vault handoff |
existing | Preselect vaultId as the requested destination for the handoff |
If omitted, the client chooses where to save the final vault item. The purchase job never writes long-lived credentials into a special server-managed vault.
project.mode can be:
| Mode | Behavior |
|---|---|
none | Do not associate the purchase with a project |
existing | Associate the purchase with projectId |
new | Create or provision project context using name and description |
If omitted, the project mode defaults to none. When project.mode is new,
project.externalId stores a caller-owned project ID on the created project.
The license list endpoint can filter by caller IDs saved during purchase:
GET /api/v1/machine/license-manager/licenses?externalLicenseId=caller_license_456
GET /api/v1/machine/license-manager/licenses?externalProjectId=caller_project_789externalLicenseId matches managed license instances created by Pincer.
externalProjectId matches licenses associated with a project whose
externalId is the supplied value. The returned license rows include
externalLicenseId and projectExternalId.
The purchase call returns immediately with a purchase status object:
{
"purchaseId": "job_123",
"status": "in_progress",
"orderId": "order_123",
"orderItemId": "order_item_123",
"attempts": 1,
"startedAt": "2026-05-28T08:30:00.000Z",
"updatedAt": "2026-05-28T08:30:00.000Z",
"finishedAt": null,
"failedStep": null,
"errorMessage": null
}GET /api/v1/machine/licenses/purchases/job_123/status
X-API-Key: <access-key>.<secret>Poll until status is awaiting_vault_item, succeeded, or failed.
{
"purchaseId": "job_123",
"status": "succeeded",
"orderId": "order_123",
"orderItemId": "order_item_123",
"attempts": 1,
"startedAt": "2026-05-28T08:30:00.000Z",
"updatedAt": "2026-05-28T08:31:00.000Z",
"finishedAt": "2026-05-28T08:31:00.000Z",
"failedStep": null,
"errorMessage": null
}If status is failed, failedStep and errorMessage explain the blocker.
For long-running provider work, a failure can mean the provisioning attempt
reached its runtime budget before the provider finished. In that case, resume
the same purchase instead of creating a new one.
{
"purchaseId": "job_123",
"status": "failed",
"orderId": "order_123",
"orderItemId": "order_item_123",
"attempts": 1,
"startedAt": "2026-05-28T08:30:00.000Z",
"updatedAt": "2026-05-28T08:42:00.000Z",
"finishedAt": "2026-05-28T08:42:00.000Z",
"failedStep": "pax8.provisioning.wait",
"errorMessage": "Pax8 subscription did not become Active before the runtime budget."
}When status is awaiting_vault_item, external provisioning has succeeded and
the response includes vaultItemHandoff. Encrypt each fields[].value with the
destination vault's normal DEK flow, create a standard vault item, then complete
the handoff.
{
"purchaseId": "job_123",
"status": "awaiting_vault_item",
"vaultItemHandoff": {
"itemName": "Falcon Defend",
"itemType": "SOFTWARE_LICENSE",
"websites": ["https://falcon.crowdstrike.com"],
"requestedVault": {
"mode": "existing",
"vaultId": "vault_123"
},
"fields": [
{
"name": "Username",
"type": "TEXT",
"value": "[email protected]"
}
]
}
}POST /api/v1/machine/licenses/purchases/job_123/vault-item
Content-Type: application/json
X-API-Key: <access-key>.<secret>{
"vaultItemId": "vault_item_123"
}R4 links the encrypted vault item to the license, creates the managed license
record, marks the purchase succeeded, and clears the temporary handoff fields
from the job.
POST /api/v1/machine/licenses/purchases/job_123/resume
X-API-Key: <access-key>.<secret>Resume only after the status endpoint returns failed. R4 carries forward the
saved resume state, so completed paid steps such as a domain purchase, Pax8
company creation, Pax8 order placement, and discovered provider tenant IDs are
not repeated.
The resume call returns the same purchase status shape, usually with
status: "in_progress" and attempts incremented.
Outside the temporary awaiting_vault_item handoff, the status response is
deliberately compact. It does not expose provider automation settings, browser
activation controls, provisioner logs, vault field payloads, or catalog-admin
resume state.