Pincer: Purchase

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.

Endpoints

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

EndpointMethodPurpose
/api/v1/machine/licenses/purchasePOSTStart a license purchase
/api/v1/machine/licenses/purchases/:purchaseId/statusGETPoll purchase status and pending vault handoff
/api/v1/machine/licenses/purchases/:purchaseId/vault-itemPOSTComplete the encrypted vault-item handoff
/api/v1/machine/licenses/purchases/:purchaseId/resumePOSTResume a failed purchase from saved state
/api/v1/machine/licenses/:licenseInstanceId/environmentGETRead 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(...).

Basic Flow

  1. Create or choose the vault where the license secrets should be stored.
  2. Call POST /api/v1/machine/licenses/purchase with the license slug or ID in licenseId and, if known, the destination vaultId.
  3. Poll GET /api/v1/machine/licenses/purchases/:purchaseId/status.
  4. If the job returns awaiting_vault_item, encrypt the handoff fields into a standard vault item.
  5. Call POST /api/v1/machine/licenses/purchases/:purchaseId/vault-item with the new vaultItemId.
  6. Poll again until the purchase is succeeded or failed.

Finding IDs

Use human-readable license slugs for new integrations.

  • License slug: open the public license catalog. API-purchasable license rows show a copy button in the Details column. Copy that value into licenseId.
  • Vault ID: open Platform, go to Vaults, open the vault row's More actions menu, then choose Copy vault ID. Use that value as vault.vaultId when vault.mode is existing.

Start A Purchase

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
}

Request Fields

FieldRequiredDescription
licenseIdYesLicense catalog slug or ID to purchase. Prefer the slug copied from the public license catalog.
tenantIdNoTenant to provision into. If omitted, R4 uses the authenticated machine session's default tenant.
quantityNoQuantity to purchase. Defaults to 1.
externalLicenseIdNoCaller-owned ID stored on created license instances.
configurationNoProduct-specific configuration selections.
domainNoDomain preference for products that need a domain. Defaults to automatic purchase/allocation.
vaultNoRequested vault destination for the final encrypted vault item.
projectNoOptional project association. Defaults to no project.
dryRunNoWhen true, test the request without creating paid external resources.
browserActivationNoOptional browser automation controls. Omit this for normal purchases.

Domain Options

If domain is omitted, R4 uses automatic mode.

ModeRequired valueBehavior
automaticNone, or domainLet R4 purchase or allocate a domain. If domain is supplied, R4 requests that domain.
existing-domaindomainUse an existing domain string in the selected tenant.
existing-domain-tenantdomainTenantIdUse an existing R4 domain-tenant binding.

Vault Options

ModeRequired valueBehavior
existingvaultIdAsk R4 to direct the handoff to an existing vault. Copy this ID from Platform > Vaults > vault row More actions > Copy vault ID.
newnameAsk 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.

Project Options

ModeRequired valueBehavior
noneNoneDo not associate the purchase with a project.
existingprojectIdAssociate the purchase with an existing project.
newnameCreate project context during provisioning.

When project.mode is new, project.externalId stores a caller-owned project ID on the created project.

Browser Activation

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.

Poll Purchase Status

GET /api/v1/machine/licenses/purchases/job_123/status
X-API-Key: <access-key>.<secret>

Poll until status is one of:

StatusMeaning
in_progressR4 is still provisioning. Keep polling.
awaiting_vault_itemProvider setup succeeded and R4 is waiting for the client-encrypted vault item.
succeededPurchase and vault handoff are complete.
failedThe job stopped. Use failedStep and errorMessage, then resume if appropriate.

Complete The Vault Handoff

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.

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

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.

pincer - R4 Docs