name: acp-client description: > Intent-driven ACP (Adaptive Commerce Platform) client. Handles natural-language purchase requests by executing checkout, cart, and order flows against OpenLink's ACP API. Integrates Stripe test SPT generation for checkout completion. Supports product resolution from OpenLink offer catalog, checkout updates, cancellation, and subscription payment link detection. version: 1.1.0 type: skill
ACP Client Skill
Execute checkout, cart, and order operations against the OpenLink Adaptive
Commerce Platform (ACP) API using composable curl recipes. Triggered by
natural-language purchase intents.
When to Use
- "I want to purchase
{product}" / "Buy{product}" / "Get me a license for{product}" - "Checkout
{product}" / "Create a checkout for{offer-id}" - "Update checkout
{id}" / "Change quantity for checkout{id}" - "Cancel checkout
{id}" / "Cancel my order" - "Complete checkout
{id}" / "Pay for checkout{id}" - "Add
{product}to cart" / "Create a cart for{product}" - "Get order
{order-id}" / "Check status of order{order-id}" - "Get a Stripe test token" / "Generate SPT for
{amount}" - "Use balance" / "Pay with balance"
- Any request referencing the ACP API, checkout sessions, carts, or OpenLink software license purchases.
Prerequisites
curlinstalledjqrecommended (fallbackawkJSON parsers provided)ACP_AUTH_TOKENenvironment variable set, or user must obtain one manuallySTRIPE_API_KEYrequired forcompleteandsptflows
ACP Instances
Known ACP API endpoints. The default is shop.openlinksw.com; override via ACP_BASE_URL:
| Instance | URL |
|---|---|
| Shop (default) | https://shop.openlinksw.com/acp |
| QA / Staging | https://ods-qa.openlinksw.com/acp |
To use a non-default instance, set ACP_BASE_URL before invoking the skill:
export ACP_BASE_URL="https://ods-qa.openlinksw.com/acp"
Environment Variables
| Variable | Required | Default |
|---|---|---|
ACP_BASE_URL |
No | https://shop.openlinksw.com/acp |
ACP_API_VERSION |
No | 2026-01-30 |
ACP_AUTH_TOKEN |
Yes | Prompted if missing |
ACP_ITEM_ID |
No | Resolved from product catalog or user input |
STRIPE_API_KEY |
Yes (for complete/spt) | Prompted if missing |
STRIPE_PAYMENT_METHOD |
No | pm_card_visa |
STRIPE_SPT_CURRENCY |
No | usd |
STRIPE_SPT_MAX_AMOUNT |
No | 1000 |
STRIPE_SPT_EXPIRES_AT |
No | now + 1 hour (auto-computed) |
Intent-to-Flow Mapping
When the user expresses a natural-language intent, map it to the corresponding ACP flow:
| User Intent | Skill Flow |
|---|---|
"I want to purchase {product}" |
Full purchase: create_checkout → get_checkout_total → (balance or spt) → complete_checkout |
"Checkout {product}" |
create_checkout → return checkout session ID and total |
"Update checkout {id}" |
update_checkout — change items/quantity |
"Cancel checkout {id}" |
cancel_checkout — cancel with reason_code: buyer_cancelled |
"Complete checkout {id}" |
complete_checkout — fetch total, get SPT, complete |
"Add {product} to cart" |
create_cart → return cart ID |
"Get order {order-id}" |
get_order |
| "Get Stripe SPT" | get_test_spt |
| "Use balance" / "Pay with balance" | complete_checkout with handler_id: "balance" |
Product Resolution
When the user names a product (e.g., "JDBC to ODBC bridge driver"), resolve it
to an offer IRI using the catalog in references/product-catalog.md. Match
against:
schema:nameskos:prefLabelskos:altLabelschema:description
If no match is found, ask the user for the full offer IRI or product URL.
Bearer Token Acquisition (Manual)
If ACP_AUTH_TOKEN is missing or invalid:
- Prompt the user: "ACP bearer token not found. Please obtain one from the OAuth applications page."
- Provide URLs:
- Primary:
https://ods-qa.openlinksw.com/oauth/applications.vsp - Alternative:
https://shop.openlinksw.com/oauth/applications.vsp - Additional: any other Virtuoso instance the user specifies
- Primary:
- Instructions:
- Navigate to the URL
- Log in via the authentication form (Digest, WebID-TLS, or social login)
- Register a new OAuth application
- Copy the generated bearer token
- Export as
ACP_AUTH_TOKENor paste when prompted
Browser Automation
The skill uses Playwright (playwright-cli) for
browser automation. PinchTab is a fallback if Playwright is unavailable.
Set the wrapper script path before use:
export PWCLI="/Users/kidehen/Documents/Management/Development/ai-agent-skills/.opencode/skills/playwright/scripts/playwright_cli.sh"
Prerequisites
npx(comes with Node.js/npm)- Playwright browsers installed (first use):
npx playwright install chromium
Workflow
- Open page in headed mode:
"$PWCLI" open <url> --headed - Snapshot for element refs:
"$PWCLI" snapshot - Interact with elements by ref (e.g.,
"$PWCLI" click e79) - Capture screenshots or PDFs as needed
Subscription Payment Detection
After complete_checkout, the response may contain a links array with a
subscription_payment entry. When present:
- Extract the
hrefvalue from the link withrel: "subscription_payment" - Open the link with Playwright:
"$PWCLI" open <href> --headed "$PWCLI" snapshot - Present the snapshot to the user showing the payment form.
- Ask the user if they want to proceed with payment.
Checkout Body Format
The create_checkout and update_checkout operations use items (not
line_items) and capabilities as an empty object:
{
"items": [
{ "id": "http://data.openlinksw.com/oplweb/offer/Offer-2020-10-virtuoso-8-app-developer-development-WKS-ANY#this", "quantity": 1 }
],
"currency": "usd",
"capabilities": {}
}
Output Format
- Default: Human-readable summary (checkout ID, order ID, status, total, receipt, subscription payment link if present)
--jsonflag: Raw JSON from the API response, stable machine-readable output for agent consumption
Post-Purchase File Access Verification
After a checkout is completed and the subscription payment is processed, verify that the purchased file/resource is accessible:
Resolve the resource URL from the offer IRI — typically the offer's
schema:subjectOfor the resource's canonical DAV/WebDAV path on the ACP instance.Fetch with On-Behalf-Of delegation using the ACP bearer token:
curl -sI -H "Authorization: Bearer ${ACP_AUTH_TOKEN}" \ -H "On-Behalf-Of: <resource-iri>" \ "<resource-url>"200 OK→ access granted, file is available401 Unauthorized→ provisioning may be async; retry after a short delay403 Forbidden→ access not granted; check order/subscription status404 Not Found→ wrong resource URL; verify path
Report result to the user: confirmed accessible, or explain the issue.
Error Handling
401 Unauthorized→ Bearer token missing or invalid; direct user to OAuth applications page404 Not Found→ Checkout/cart/order ID does not exist409 Conflict→ Idempotency key collision; retry with new UUID- Stripe errors → Report Stripe error message and raw response
- Missing
jq→ Fall back to bundledawkJSON parsers (_json_str,_json_total,_json_sub_payment_url)
JSON Helper Functions
The skill bundles three portable JSON extraction functions that work with or
without jq:
_json_str FIELD— extract a top-level string field from stdin JSON_json_total— extractamountwheretype=="total"from thetotalsarray_json_sub_payment_url— extractsubscription_paymenthref fromlinks[]
See references/acp-api-operations.md for implementation details.
References
references/acp-api-operations.md— Full curl recipes for every endpointreferences/oauth-token-setup.md— Step-by-step manual token guidereferences/product-catalog.md— Offer IRI mappings from TTL sources
Anti-Drift Protocol
⛔ PRE-BUILD CHECK: Before producing any curl command or output, re-read the
relevant operation section in references/acp-api-operations.md. Confirm headers,
body shape, and placeholder substitution. Build to pass — do not retro-fit.
Examples
See examples/checkout-flow.sh and examples/cart-flow.sh for complete
executable workflows.
Attribution
Derived from acp_curl.sh — reworked into composable curl recipes for agent use.