Pincer purchase is R4's license provisioning API for machine clients. Start a purchase, poll the job, then store the returned setup fields in a normal client-encrypted vault item when the job asks for a vault handoff.
Catalog browsing, cart management, 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 | Start a license purchase |
/api/v1/machine/licenses/purchases/:purchaseId/status | GET | Poll purchase status and pending vault handoff |
/api/v1/machine/licenses/purchases/:purchaseId/vault-item | POST | Complete the encrypted vault-item handoff |
/api/v1/machine/licenses/purchases/:purchaseId/resume | POST | Resume a failed purchase from saved state |
/api/v1/machine/licenses/:licenseInstanceId/environment | GET | Read the zero-trust environment bundle for a provisioned license |
POST /purchase, POST /vault-item, and purchase resume require
machine.license.write. Status polling requires machine.license.read. The
machine key must also be allowed to operate on the target tenant.
GET /licenses/:licenseInstanceId/environment requires
machine.vault.secret.read. It returns the wrapped keys, signer directories,
and encrypted environment fields for the vault items linked to a provisioned
license, so an agent runtime can decrypt the license credentials locally after
a purchase completes. The CLI exposes this as r4 licenses env <licenseInstanceId> [command...], and the SDK as
R4.create({ licenseInstanceId }) or client.getLicenseEnvironment(...).
POST /api/v1/machine/licenses/purchase with the license slug or ID in
licenseId and, if known, the destination vaultId.GET /api/v1/machine/licenses/purchases/:purchaseId/status.awaiting_vault_item, encrypt the handoff fields into a
standard vault item.POST /api/v1/machine/licenses/purchases/:purchaseId/vault-item with
the new vaultItemId.succeeded or failed.Use human-readable license slugs for new integrations.
licenseId.vault.vaultId when vault.mode is existing.POST /api/v1/machine/licenses/purchase
Content-Type: application/json
X-API-Key: <access-key>.<secret>Most callers only need the license slug in licenseId and a destination vault:
{
"licenseId": "defend",
"vault": {
"mode": "existing",
"vaultId": "507f1f77bcf86cd799439011"
}
}The response returns immediately with a purchase job:
{
"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
}| Field | Required | Description |
|---|---|---|
licenseId | Yes | License catalog slug or ID to purchase. Prefer the slug copied from the public license catalog. |
tenantId | No | Tenant to provision into. If omitted, R4 uses the authenticated machine session's default tenant. |
quantity | No | Quantity to purchase. Defaults to 1. |
externalLicenseId | No | Caller-owned ID stored on created license instances. |
configuration | No | Product-specific configuration selections. |
domain | No | Domain preference for products that need a domain. Defaults to automatic purchase/allocation. |
vault | No | Requested vault destination for the final encrypted vault item. |
project | No | Optional project association. Defaults to no project. |
dryRun | No | When true, test the request without creating paid external resources. |
browserActivation | No | Optional browser automation controls. Omit this for normal purchases. |
If domain is omitted, R4 uses automatic mode.
| Mode | Required value | Behavior |
|---|---|---|
automatic | None, or domain | Let R4 purchase or allocate a domain. If domain is supplied, R4 requests that domain. |
existing-domain | domain | Use an existing domain string in the selected tenant. |
existing-domain-tenant | domainTenantId | Use an existing R4 domain-tenant binding. |
| Mode | Required value | Behavior |
|---|---|---|
existing | vaultId | Ask R4 to direct the handoff to an existing vault. Copy this ID from Platform > Vaults > vault row More actions > Copy vault ID. |
new | name | Ask R4 to create or use a new vault destination during provisioning. |
If vault is omitted, the status response can still return a vault handoff. The
client then chooses where to create the final encrypted vault item.
| Mode | Required value | Behavior |
|---|---|---|
none | None | Do not associate the purchase with a project. |
existing | projectId | Associate the purchase with an existing project. |
new | name | Create project context during provisioning. |
When project.mode is new, project.externalId stores a caller-owned project
ID on the created project.
For supported products, R4 completes browser activation by default. Normal
callers should omit browserActivation.
Optional controls:
{
"browserActivation": {
"enabled": true,
"headless": true,
"maxSteps": 240
}
}Set browserActivation.enabled to false only when you intentionally want to
skip provider browser activation.
GET /api/v1/machine/licenses/purchases/job_123/status
X-API-Key: <access-key>.<secret>Poll until status is one of:
| Status | Meaning |
|---|---|
in_progress | R4 is still provisioning. Keep polling. |
awaiting_vault_item | Provider setup succeeded and R4 is waiting for the client-encrypted vault item. |
succeeded | Purchase and vault handoff are complete. |
failed | The job stopped. Use failedStep and errorMessage, then resume if appropriate. |
When status is awaiting_vault_item, the response includes
vaultItemHandoff. These values are temporary plaintext setup fields. Do not log
them. Encrypt them 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": {
"status": "pending",
"itemName": "Falcon Defend - example.com",
"itemType": "SOFTWARE_LICENSE",
"websites": ["https://falcon.crowdstrike.com"],
"requestedVault": {
"mode": "existing",
"vaultId": "vault_123"
},
"fields": [
{
"productVaultFieldId": "field_username",
"name": "Username",
"type": "TEXT",
"extension": null,
"required": true,
"value": "[email protected]",
"isSecret": false
},
{
"productVaultFieldId": "field_password",
"name": "Password",
"type": "PASSWORD",
"extension": null,
"required": true,
"value": "<temporary plaintext password>",
"isSecret": true
}
]
}
}After creating the encrypted vault item:
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 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 saved
resume state, so completed paid steps such as 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.
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.