Pincer: Purchase

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.

Endpoints

All paths are relative to https://r4.dev and require machine authentication.

EndpointMethodPurpose
/api/v1/machine/licenses/purchasePOSTPurchase a license and start automated provisioning
/api/v1/machine/licenses/purchases/:purchaseId/statusGETPoll the purchase status and pending vault handoff
/api/v1/machine/licenses/purchases/:purchaseId/vault-itemPOSTComplete the client-encrypted vault-item handoff
/api/v1/machine/licenses/purchases/:purchaseId/resumePOSTResume 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.

Purchase A License

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:

FieldTypeDescription
tenantIdstringTenant that will receive the purchased license
licenseIdstringLicense to purchase
quantitynumberOptional quantity; defaults to 1
externalLicenseIdstringOptional caller-owned ID to store on license instances
configurationarrayOptional product configuration selections
domainobjectOptional domain preference for provisioning
vaultobjectOptional destination for provisioned license outputs
projectobjectOptional project association

Domain

domain.mode can be:

ModeBehavior
automaticLet R4 purchase or allocate a domain; if domain is provided, R4 requests that domain
existing-domainUse the supplied domain string in the selected tenant
existing-domain-tenantUse the supplied domainTenantId exactly

If omitted, the domain mode defaults to automatic.

Vault

vault.mode can be:

ModeBehavior
newReturn this as the requested destination for the vault handoff
existingPreselect 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

project.mode can be:

ModeBehavior
noneDo not associate the purchase with a project
existingAssociate the purchase with projectId
newCreate 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.

Lookup By Caller IDs

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_789

externalLicenseId 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.

Purchase Response

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
}

Check Status

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]"
      }
    ]
  }
}

Complete The Vault Handoff

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.

Resume A Failed Purchase

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.

pincer - R4 Docs