Products

View as Markdown

Products are reusable catalogue items, each with a fixed price and its own hosted checkout URL. List them to power the "fixed product → share a URL" flow: create the product once in the dashboard, then hand its url to a shopper to take a payment. No per-charge API call required. Storefronts that hold those products are Storefronts.

GET    https://api.worthypayments.com/v1/products

Scope: products:read.


List products#

GET /products

Query parameters#

ParameterTypeDefaultNotes
limitinteger10Page size. Capped at 100.
starting_afterstring—The opaque next_cursor from the previous page. Not a product id.

Paging is cursor-based, so there is no page parameter and no active filter. Unrecognized query parameters are silently ignored, so filtering client-side on the active field is the only option.

Example#

bash
curl "https://api.worthypayments.com/v1/products?limit=10" \
  -H "x-api-key: sk_live_xxx"

Response#

json
{
  "object": "list",
  "data": [
    {
      "id": "4b1e77a0-2c93-45de-8f0a-6d5c39ab72e1",
      "object": "product",
      "name": "Pro Plan",
      "active": true,
      "url": "https://app.worthypayments.com/checkout/proplan"
    }
  ],
  "has_more": false,
  "next_cursor": "djJ8MjAyNi0wOC0yNFQxNDo0Njo1Nlp8NGIxZTc3YTA"
}

See Pagination for the cursor list model.

FieldTypeNotes
idstringProduct id.
objectstringAlways "product".
namestringDisplay name.
activebooleanWhether the product is purchasable.
urlstring | nullThe product's hosted checkout page. Share this to take a payment. null when the product has no active checkout link.

Price is not returned. The list carries no amount or currency, so you cannot render a price from this endpoint. Read it from the dashboard or from the hosted checkout page itself.


The fixed-product flow#

  1. Create a product in the dashboard (name, price, currency).
  2. GET /products to retrieve its url.
  3. Put the URL anywhere a shopper can click it: an email, an invoice, a button, a QR code.
  4. The hosted page runs fraud, routing, and 3-D Secure, then collects payment. Nothing else to build.

This is the same hosted engine as a checkout link, with the product carrying a fixed price and a stable URL. To bind a custom checkout link to a product, pass product_id to POST /checkout-links.


Tax rates#

Your own store (WooCommerce, a custom cart) can use the tax rates you keep with us: create the rates, attach them to products, and ask what each cart line owes at checkout.

POST   https://api.worthypayments.com/v1/tax_rates
GET    https://api.worthypayments.com/v1/tax_rates
GET    https://api.worthypayments.com/v1/tax_rates/{id}
POST   https://api.worthypayments.com/v1/tax_rates/{id}
DELETE https://api.worthypayments.com/v1/tax_rates/{id}
POST   https://api.worthypayments.com/v1/products/{id}/tax_rates
DELETE https://api.worthypayments.com/v1/products/{id}/tax_rates/{tax_rate}
POST   https://api.worthypayments.com/v1/tax/calculate

Scopes: tax:read (list, retrieve, calculate) and tax:write (everything else). tax:write is server-only. Neither is on a new key by default: tick them in Dashboard → Developers → API keys.

1. Create a rate#

percentage is a percent: 7.25 means 7.25 %. It comes back as the string "7.25". Creating requires an Idempotency-Key, so a retry never makes a second rate.

bash
curl https://api.worthypayments.com/v1/tax_rates \
  -H "x-api-key: sk_live_xxx" \
  -H "Idempotency-Key: 5d0c7a52-3f1e-4c8b-9d2a-6e4f1b7c8a90" \
  -H "Content-Type: application/json" \
  -d '{"display_name":"CA sales tax","percentage":7.25,"tax_type":"sales_tax","country":"US","state":"CA"}'

Updating (POST /tax_rates/{id}) changes only the fields you send. Deleting stops the rate applying at once; the record is kept so past tax stays explained. To pause a rate, send active: false instead. The default rate and global rates are set in the dashboard.

2. Attach it to a product#

bash
curl https://api.worthypayments.com/v1/products/4b1e77a0-2c93-45de-8f0a-6d5c39ab72e1/tax_rates \
  -H "x-api-key: sk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{"tax_rate":"6f1c2a4e-1d7b-4b8e-9b0a-2f5d3c9e7a11"}'

A product can carry several rates, and they stack. The product id is not checked against the catalog: use the same id you will send as line_items[].product when you calculate.

3. Calculate at checkout#

bash
curl https://api.worthypayments.com/v1/tax/calculate \
  -H "x-api-key: sk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{"currency":"usd","address":{"country":"US","state":"CA"},
       "line_items":[{"product":"4b1e77a0-2c93-45de-8f0a-6d5c39ab72e1","amount":2000,"quantity":2,"reference":"cart-item-1"}]}'

amount is the line total in cents. The response gives each line its amount_tax and a tax_breakdown per rate, plus amount_subtotal, tax_amount_exclusive, tax_amount_inclusive and amount_total. The call writes nothing, so run it every time the cart changes.

Each line picks its rates on its own, in this order: a global rate, then the rates attached to its product, then your rates for the ship-to address, then your default rate. A line with none of these pays no tax. Tax on an inclusive rate is already inside amount, so only exclusive tax is added to amount_total. Shipping is not taxed by this call. At most 100 lines per call.