<!-- Generated by `just docs` from catalog/toolkits/paypal.yaml, catalog/expansions/paypal.yaml, catalog/evals/scorecard.json. Edit the source, not this file. -->

# PayPal

Payments and billing. Create and capture orders, authorize and refund payments, send payouts, issue invoices, and run subscriptions.

| Property | Value |
| --- | --- |
| Slug | `paypal` |
| Definition version | `0.1.0` |
| Base URL | `https://api-m.paypal.com` |
| Auth schemes | `oauth2`, `api_key` |
| Action tools | 38 |
| By class | 14 read, 16 write, 8 destructive |
| Triggers | 0 |
| Provider rate limit | not declared, so outbound calls are unpaced |

## Measured routing accuracy

51 golden cases replayed through the router over the whole index: measured over corpus `ea4f12ad2948` (65 toolkits, 2283 tools indexed and 13 declared uncallable), 37 cases written by hand and 14 cases from the paraphrase pass. A case counts as top-1 when its gold tool ranked first and top-8 when it reached the slate at all.

| Measure | Cases | Share |
| --- | --- | --- |
| top-1 | 36/51 | 70.6% |
| top-8 | 49/51 | 96.1% |

One of the 38 action tools listed above is declared uncallable, so it is indexed nowhere and answers none of these cases. The counts here are scored over the other 37.

The sweep is offline: the reranker is a deterministic identity fake that returns candidates in the order retrieval produced them, so top-1 measures retrieval order rather than a reranked slate. `just eval-live` measures the same cases through the live reranker.

## Authentication

Connect an entity with `ConnectionsService.InitiateConnection`, naming this toolkit's slug. Credentials stay in the connections vault; callers hold connected-account ids only.

### `oauth2`

| Property | Value |
| --- | --- |
| Authorization URL | `https://www.paypal.com/connect` |
| Token URL | `https://api-m.paypal.com/v1/oauth2/token` |
| Default scopes | `openid`, `https://uri.paypal.com/services/payments/payment` |
| Refresh tokens | yes, the refresh daemon renews ahead of expiry |

### `api_key`

| Property | Value |
| --- | --- |
| Placement | `header` |
| Name | `Authorization` |
| Rendered as | `Bearer {key}` |

Submit the key with `ConnectionsService` rather than putting it in a request; it is sealed at rest and never returned.

## Tools

38 action tools. The catalog-wide slug is `paypal.<tool>`, which is what `search_tools` returns and `call_tool` takes.

### `paypal.create_order`

Create a PayPal order for a checkout, specifying the amount to authorize or capture. Use when the user wants to start, set up, or begin a PayPal payment or checkout before the buyer approves it. Intent controls whether funds are captured immediately or just held.

Class `write` (writes, no confirmation needed). No scopes beyond the connection's defaults. Calls `POST /v2/checkout/orders`.

Arguments:

| Argument | Type | Required | Notes |
| --- | --- | --- | --- |
| `cancel_url` | string | no | Where PayPal sends the buyer if they cancel the checkout. |
| `currency_code` | string | **yes** | Three-letter ISO currency code, e.g. "USD". |
| `custom_id` | string | no | Your own order or invoice reference, e.g. an internal order id. |
| `description` | string | no | Text shown to the buyer describing the purchase. |
| `intent` | string, one of CAPTURE, AUTHORIZE | **yes** | CAPTURE to take the money right away, AUTHORIZE to just place a hold. |
| `return_url` | string | no | Where PayPal sends the buyer after they approve the order. |
| `value` | string | **yes** | Order amount as a decimal string, e.g. "49.99". |

Result fields (the payload is trimmed to these before it reaches the model):

| Field | Type | Notes |
| --- | --- | --- |
| `id` | string |  |
| `links` | array of object |  |
| `links[].href` | string |  |
| `links[].rel` | string |  |
| `status` | string |  |

Also retrieved by: "set up a checkout for this purchase", "get a paypal payment going for the buyer", "I need to bill someone through paypal", "open a new transaction for this sale", "start a paypal checkout session".

### `paypal.get_order`

Get one PayPal order by id: its status, amount, and buyer details. Use when the user asks whether an order was approved, wants to check a checkout's state, or names a specific order id.

Class `read` (reads only). No scopes beyond the connection's defaults. Calls `GET /v2/checkout/orders/{{params.order_id}}`.

Arguments:

| Argument | Type | Required | Notes |
| --- | --- | --- | --- |
| `order_id` | string | **yes** | PayPal order id, e.g. "5O190127TN364715T". |

Result fields (the payload is trimmed to these before it reaches the model):

| Field | Type | Notes |
| --- | --- | --- |
| `id` | string |  |
| `intent` | string |  |
| `payer` | object |  |
| `payer.email_address` | string |  |
| `payer.payer_id` | string |  |
| `purchase_units` | array of object |  |
| `purchase_units[].amount` | object |  |
| `purchase_units[].amount.currency_code` | string |  |
| `purchase_units[].amount.value` | string |  |
| `status` | string |  |

Also retrieved by: "did the buyer approve this yet", "check the state of this checkout", "what's happening with this transaction", "pull up the details on this purchase".

### `paypal.update_order`

Change a field on an existing PayPal order before it is captured, such as its amount or description. Use when the user wants to correct or adjust an order that has not been paid yet. For paying it, use capture_order or authorize_order instead.

Class `write` (writes, no confirmation needed). No scopes beyond the connection's defaults. Calls `PATCH /v2/checkout/orders/{{params.order_id}}`.

Arguments:

| Argument | Type | Required | Notes |
| --- | --- | --- | --- |
| `order_id` | string | **yes** | PayPal order id to update. |
| `path` | string | **yes** | JSON pointer to the field being replaced, e.g. "/purchase_units/@reference_id=='default'/amount". |
| `value` | object | **yes** | New value for the field named by path. |

Result fields (the payload is trimmed to these before it reaches the model):

| Field | Type | Notes |
| --- | --- | --- |
| `updated` | boolean |  |

Also retrieved by: "fix the amount on this checkout before it's paid", "the buyer needs a different total on this purchase", "correct something on this pending transaction".

### `paypal.authorize_order`

Place a hold on funds for an approved PayPal order without collecting them yet. Use when the user wants to authorize, pre-approve, or reserve payment before shipping, then capture the hold later with capture_authorized_payment.

Class `write` (writes, no confirmation needed). No scopes beyond the connection's defaults. Calls `POST /v2/checkout/orders/{{params.order_id}}/authorize`.

Arguments:

| Argument | Type | Required | Notes |
| --- | --- | --- | --- |
| `order_id` | string | **yes** | Approved PayPal order id to authorize. |

Result fields (the payload is trimmed to these before it reaches the model):

| Field | Type | Notes |
| --- | --- | --- |
| `id` | string |  |
| `purchase_units` | array of object |  |
| `purchase_units[].payments` | object |  |
| `purchase_units[].payments.authorizations` | array of object |  |
| `status` | string |  |

Also retrieved by: "put a hold on the buyer's card for now", "reserve the funds but don't take them yet", "lock in the money until we ship".

### `paypal.capture_order`

Collect payment on an approved PayPal order right away. Use when the user wants to charge, capture, or finish collecting on an order the buyer has approved. For an order that only holds funds so far, capture the resulting authorization with capture_authorized_payment instead.

Class `write` (writes, no confirmation needed). No scopes beyond the connection's defaults. Calls `POST /v2/checkout/orders/{{params.order_id}}/capture`.

Arguments:

| Argument | Type | Required | Notes |
| --- | --- | --- | --- |
| `order_id` | string | **yes** | Approved PayPal order id to capture. |

Result fields (the payload is trimmed to these before it reaches the model):

| Field | Type | Notes |
| --- | --- | --- |
| `id` | string |  |
| `purchase_units` | array of object |  |
| `purchase_units[].payments` | object |  |
| `purchase_units[].payments.captures` | array of object |  |
| `status` | string |  |

Also retrieved by: "go ahead and take the buyer's money", "finish collecting on this purchase", "actually charge them for the sale", "process the payment they approved".

### `paypal.get_authorization`

Get one payment authorization by id: its status, held amount, and expiration time. Use when the user asks whether a hold is still valid or how much was reserved on a card or PayPal balance.

Class `read` (reads only). No scopes beyond the connection's defaults. Calls `GET /v2/payments/authorizations/{{params.authorization_id}}`.

Arguments:

| Argument | Type | Required | Notes |
| --- | --- | --- | --- |
| `authorization_id` | string | **yes** | PayPal authorization id, e.g. "0GP08407JV292432P". |

Result fields (the payload is trimmed to these before it reaches the model):

| Field | Type | Notes |
| --- | --- | --- |
| `amount` | object |  |
| `amount.currency_code` | string |  |
| `amount.value` | string |  |
| `expiration_time` | string |  |
| `id` | string |  |
| `status` | string |  |

Also retrieved by: "is that hold still good", "check how much we reserved on their card", "when does this reserved amount expire".

### `paypal.capture_authorized_payment`

Capture funds from a payment authorization that is currently held. Use when the user wants to collect, take, or finalize a hold placed earlier, e.g. once an order has shipped. Supports a partial amount and marking it the final capture.

Class `write` (writes, no confirmation needed). Scopes `https://uri.paypal.com/services/payments/payment`. Calls `POST /v2/payments/authorizations/{{params.authorization_id}}/capture`.

Arguments:

| Argument | Type | Required | Notes |
| --- | --- | --- | --- |
| `authorization_id` | string | **yes** | PayPal authorization id to capture. |
| `currency_code` | string | no | Currency code for a partial capture amount. |
| `final_capture` | boolean | no | True to release any remaining held amount after this capture. |
| `note_to_payer` | string | no | Note shown to the payer describing this capture. |
| `value` | string | no | Amount to capture as a decimal string. Omit to capture the full held amount. |

Result fields (the payload is trimmed to these before it reaches the model):

| Field | Type | Notes |
| --- | --- | --- |
| `amount` | object |  |
| `amount.currency_code` | string |  |
| `amount.value` | string |  |
| `final_capture` | boolean |  |
| `id` | string |  |
| `status` | string |  |

Also retrieved by: "grab the funds we reserved earlier", "collect on that hold now that we shipped", "finalize the money we set aside", "take the reserved amount now".

### `paypal.void_authorization`

Void a payment authorization, releasing its held funds back to the payer without collecting anything. Irreversible; a voided authorization cannot be captured afterward. Use when the user wants to void, release, or drop a hold that will never be charged.

Class `destructive` (held by the mutation gate until the call's own arguments carry `"confirm": true`). No scopes beyond the connection's defaults. Calls `POST /v2/payments/authorizations/{{params.authorization_id}}/void`.

Arguments:

| Argument | Type | Required | Notes |
| --- | --- | --- | --- |
| `authorization_id` | string | **yes** | PayPal authorization id to void. |

Result fields (the payload is trimmed to these before it reaches the model):

| Field | Type | Notes |
| --- | --- | --- |
| `voided` | boolean |  |

Also retrieved by: "release that hold, we don't need it", "never mind, let go of the reserved funds", "cancel the reservation on their card", "drop the pending hold entirely".

### `paypal.get_capture`

Get one payment capture by id: its status, amount, and whether it has been refunded. Use when the user asks about a specific completed PayPal charge. For refunding it, use refund_capture.

Class `read` (reads only). No scopes beyond the connection's defaults. Calls `GET /v2/payments/captures/{{params.capture_id}}`.

Arguments:

| Argument | Type | Required | Notes |
| --- | --- | --- | --- |
| `capture_id` | string | **yes** | PayPal capture id, e.g. "2GG279541U471931P". |

Result fields (the payload is trimmed to these before it reaches the model):

| Field | Type | Notes |
| --- | --- | --- |
| `amount` | object |  |
| `amount.currency_code` | string |  |
| `amount.value` | string |  |
| `final_capture` | boolean |  |
| `id` | string |  |
| `status` | string |  |

Also retrieved by: "was this specific charge refunded", "look up the details on a completed transaction", "pull up this finished payment".

### `paypal.refund_capture`

Refund a captured PayPal payment, in full or in part. Irreversible once processed; the money returns to the payer's original funding source. Use when the user wants to refund, reverse, or give money back for a completed charge.

Class `destructive` (held by the mutation gate until the call's own arguments carry `"confirm": true`). Scopes `https://uri.paypal.com/services/payments/refund`. Calls `POST /v2/payments/captures/{{params.capture_id}}/refund`.

Arguments:

| Argument | Type | Required | Notes |
| --- | --- | --- | --- |
| `capture_id` | string | **yes** | PayPal capture id to refund. |
| `currency_code` | string | no | Currency code for a partial refund amount. |
| `note_to_payer` | string | no | Note shown to the payer explaining the refund. |
| `value` | string | no | Amount to refund as a decimal string. Omit to refund in full. |

Result fields (the payload is trimmed to these before it reaches the model):

| Field | Type | Notes |
| --- | --- | --- |
| `amount` | object |  |
| `amount.currency_code` | string |  |
| `amount.value` | string |  |
| `id` | string |  |
| `status` | string |  |

Also retrieved by: "give the buyer their money back", "reverse this transaction", "send money back to whoever paid", "undo this charge, they want a refund", "return funds for this purchase".

### `paypal.get_refund`

Get one refund by id: its status, amount, and the capture it applies to. Use when the user asks whether a specific PayPal refund went through or how much was returned.

Class `read` (reads only). No scopes beyond the connection's defaults. Calls `GET /v2/payments/refunds/{{params.refund_id}}`.

Arguments:

| Argument | Type | Required | Notes |
| --- | --- | --- | --- |
| `refund_id` | string | **yes** | PayPal refund id, e.g. "1JU08415K6789061P". |

Result fields (the payload is trimmed to these before it reaches the model):

| Field | Type | Notes |
| --- | --- | --- |
| `amount` | object |  |
| `amount.currency_code` | string |  |
| `amount.value` | string |  |
| `id` | string |  |
| `status` | string |  |

Also retrieved by: "did that money-back request go through", "check the status of a returned payment", "how much did we send back".

### `paypal.create_payout`

Send a PayPal payout of money to one or more recipients by email, phone, or PayPal account id. Irreversible once processed; funds move immediately to a claimed recipient. Use when the user wants to pay out, disburse, or send money to sellers, affiliates, or workers in bulk.

Class `destructive` (held by the mutation gate until the call's own arguments carry `"confirm": true`). Scopes `https://uri.paypal.com/services/payments/payouts`. Calls `POST /v1/payments/payouts`.

Arguments:

| Argument | Type | Required | Notes |
| --- | --- | --- | --- |
| `currency_code` | string | **yes** | Three-letter ISO currency code, e.g. "USD". |
| `email_subject` | string | no | Subject line of the email PayPal sends the recipient. |
| `note` | string | no | Note shown to the recipient about why they were paid. |
| `receiver` | string | **yes** | Recipient's email address, phone number, or PayPal account id. |
| `sender_batch_id` | string | **yes** | Your own unique id for this payout batch, to prevent sending it twice. |
| `value` | string | **yes** | Payout amount as a decimal string, e.g. "150.00". |

Result fields (the payload is trimmed to these before it reaches the model):

| Field | Type | Notes |
| --- | --- | --- |
| `batch_header` | object |  |
| `batch_header.batch_status` | string |  |
| `batch_header.payout_batch_id` | string |  |

Also retrieved by: "pay these people through paypal", "send money to a bunch of sellers at once", "disburse funds to our affiliates", "wire everyone their earnings this week", "bulk pay a list of recipients".

### `paypal.get_payout`

Get the status of a whole PayPal payout batch by its id, including every item in it. Use when the user asks whether a bulk payout run finished or wants a summary of a batch. For one recipient's status, use get_payout_item.

Class `read` (reads only). No scopes beyond the connection's defaults. Calls `GET /v1/payments/payouts/{{params.payout_batch_id}}`.

Arguments:

| Argument | Type | Required | Notes |
| --- | --- | --- | --- |
| `payout_batch_id` | string | **yes** | PayPal payout batch id, e.g. "CDJHDNW6BFKSA". |

Result fields (the payload is trimmed to these before it reaches the model):

| Field | Type | Notes |
| --- | --- | --- |
| `batch_header` | object |  |
| `batch_header.batch_status` | string |  |
| `batch_header.payout_batch_id` | string |  |
| `items` | array of object |  |
| `items[].payout_item` | object |  |
| `items[].payout_item.amount` | object |  |
| `items[].payout_item.receiver` | string |  |
| `items[].payout_item_id` | string |  |
| `items[].transaction_status` | string |  |

Also retrieved by: "did the bulk payment run finish", "check on that mass payment we sent out", "what's the status of everyone getting paid".

### `paypal.get_payout_item`

Get one recipient's status within a payout batch: whether it was claimed, is pending, or failed. Use when the user asks about a single person's payout rather than the whole batch.

Class `read` (reads only). No scopes beyond the connection's defaults. Calls `GET /v1/payments/payouts-item/{{params.payout_item_id}}`.

Arguments:

| Argument | Type | Required | Notes |
| --- | --- | --- | --- |
| `payout_item_id` | string | **yes** | PayPal payout item id, e.g. "CTC9YEUCUB782". |

Result fields (the payload is trimmed to these before it reaches the model):

| Field | Type | Notes |
| --- | --- | --- |
| `errors` | object |  |
| `errors.message` | string |  |
| `payout_item` | object |  |
| `payout_item.amount` | object |  |
| `payout_item.amount.currency` | string |  |
| `payout_item.amount.value` | string |  |
| `payout_item.receiver` | string |  |
| `payout_item_id` | string |  |
| `transaction_status` | string |  |

Also retrieved by: "did this one person get their money", "check if a specific recipient claimed their payout", "is this payment to them still pending".

### `paypal.cancel_payout_item`

Cancel one unclaimed item in a payout batch, returning those funds to the sender's balance. Only works while the recipient has not yet claimed it. Use when the user wants to cancel, pull back, or stop an unclaimed payout to one person.

Class `destructive` (held by the mutation gate until the call's own arguments carry `"confirm": true`). Scopes `https://uri.paypal.com/services/payments/payouts`. Calls `POST /v1/payments/payouts-item/{{params.payout_item_id}}/cancel`.

Arguments:

| Argument | Type | Required | Notes |
| --- | --- | --- | --- |
| `payout_item_id` | string | **yes** | PayPal unclaimed payout item id to cancel. |

Result fields (the payload is trimmed to these before it reaches the model):

| Field | Type | Notes |
| --- | --- | --- |
| `payout_item_id` | string |  |
| `transaction_status` | string |  |

Also retrieved by: "pull back the money we sent them, they never claimed it", "stop this one payout before it's picked up", "take back an unclaimed payment".

### `paypal.create_invoice`

Create a draft PayPal invoice billing a recipient for one or more line items. Use when the user wants to draft, start, or open a new invoice or bill before sending it. Send it afterward with send_invoice.

Class `write` (writes, no confirmation needed). Scopes `https://uri.paypal.com/services/invoicing`. Calls `POST /v2/invoicing/invoices`.

Arguments:

| Argument | Type | Required | Notes |
| --- | --- | --- | --- |
| `currency_code` | string | **yes** | Three-letter ISO currency code, e.g. "USD". |
| `due_date` | string | no | Date payment is due, as YYYY-MM-DD. |
| `item_amount` | string | **yes** | Unit price of the line item as a decimal string, e.g. "500.00". |
| `item_name` | string | **yes** | Name of the line item on the invoice, e.g. "Consulting hours". |
| `item_quantity` | string | no | Quantity of the line item. Defaults to "1". |
| `note` | string | no | Note shown to the recipient on the invoice. |
| `recipient_email` | string | **yes** | Email address of the person being billed. |
| `recipient_name` | string | no | Full name of the person being billed. |

Result fields (the payload is trimmed to these before it reaches the model):

| Field | Type | Notes |
| --- | --- | --- |
| `id` | string |  |
| `status` | string |  |

Also retrieved by: "draft a bill for this client", "I need to invoice someone through paypal", "set up a paypal bill before I send it", "start a new invoice for consulting work".

### `paypal.get_invoice`

Get one PayPal invoice by id: its status, amount due, amount paid, and recipient. Use when the user names a specific invoice or asks whether it has been paid.

Class `read` (reads only). No scopes beyond the connection's defaults. Calls `GET /v2/invoicing/invoices/{{params.invoice_id}}`.

Arguments:

| Argument | Type | Required | Notes |
| --- | --- | --- | --- |
| `invoice_id` | string | **yes** | PayPal invoice id, e.g. "INV2-XXXX-XXXX-XXXX-XXXX". |

Result fields (the payload is trimmed to these before it reaches the model):

| Field | Type | Notes |
| --- | --- | --- |
| `amount` | object |  |
| `amount.value` | string |  |
| `detail` | object |  |
| `detail.currency_code` | string |  |
| `due_amount` | object |  |
| `due_amount.value` | string |  |
| `id` | string |  |
| `status` | string |  |

Also retrieved by: "has this bill been paid yet", "pull up the details on this bill", "check what's owed on this invoice".

### `paypal.list_invoices`

Search PayPal invoices by recipient email or status such as draft, sent, or paid. Use when the user asks about a customer's invoices, unpaid bills, or billing history. For one known invoice, use get_invoice.

Class `read` (reads only). No scopes beyond the connection's defaults. Calls `POST /v2/invoicing/invoices/search-invoices`.

Arguments:

| Argument | Type | Required | Notes |
| --- | --- | --- | --- |
| `page` | integer | no | Page number to return. Defaults to 1. |
| `page_size` | integer | no | Results per page, max 100. Defaults to 20. |
| `recipient_email` | string | no | Only invoices billed to this email address. |
| `status` | string, one of DRAFT, SENT, PAID, MARKED_AS_PAID, CANCELLED, REFUNDED | no | Only invoices in this state. |

Result fields (the payload is trimmed to these before it reaches the model):

| Field | Type | Notes |
| --- | --- | --- |
| `items` | array of object |  |
| `items[].amount` | object |  |
| `items[].amount.value` | string |  |
| `items[].id` | string |  |
| `items[].status` | string |  |
| `total_items` | integer |  |

Also retrieved by: "what bills are still unpaid", "show every invoice we've sent this client", "search for their outstanding invoices", "what's our billing history look like".

### `paypal.update_invoice`

Replace the details of a draft PayPal invoice: its line items, note, or due date. Use when the user wants to edit, fix, or change a draft invoice before it has been sent. Only works while the invoice is still a draft.

Class `write` (writes, no confirmation needed). No scopes beyond the connection's defaults. Calls `PUT /v2/invoicing/invoices/{{params.invoice_id}}`.

Arguments:

| Argument | Type | Required | Notes |
| --- | --- | --- | --- |
| `currency_code` | string | **yes** | Three-letter ISO currency code, e.g. "USD". |
| `due_date` | string | no | Replacement due date, as YYYY-MM-DD. |
| `invoice_id` | string | **yes** | PayPal draft invoice id to update. |
| `item_amount` | string | **yes** | Replacement unit price as a decimal string. |
| `item_name` | string | **yes** | Replacement name of the line item. |
| `item_quantity` | string | no | Replacement quantity. Defaults to "1". |
| `note` | string | no | Replacement note shown to the recipient. |

Result fields (the payload is trimmed to these before it reaches the model):

| Field | Type | Notes |
| --- | --- | --- |
| `updated` | boolean |  |

Also retrieved by: "fix a line item before I send this bill", "the due date on this draft bill is wrong", "change something on this unsent invoice".

### `paypal.send_invoice`

Email a draft PayPal invoice to its recipient so they can pay it. Use when the user wants to send, deliver, or mail an invoice to whoever owes it. Moves the invoice from draft to sent.

Class `write` (writes, no confirmation needed). No scopes beyond the connection's defaults. Calls `POST /v2/invoicing/invoices/{{params.invoice_id}}/send`.

Arguments:

| Argument | Type | Required | Notes |
| --- | --- | --- | --- |
| `invoice_id` | string | **yes** | PayPal draft invoice id to send. |
| `note` | string | no | Note included in the email to the recipient. |
| `send_to_recipient` | boolean | no | True to email the recipient directly. Defaults to true. |

Result fields (the payload is trimmed to these before it reaches the model):

| Field | Type | Notes |
| --- | --- | --- |
| `id` | string |  |
| `status` | string |  |

Also retrieved by: "email this bill to the client", "go ahead and deliver the invoice", "get this bill in front of whoever owes it".

### `paypal.cancel_invoice`

Cancel a PayPal invoice that has already been sent, notifying the recipient it no longer needs paying. Irreversible; the invoice stays on record marked cancelled instead of being deleted. Use when the user wants to void, kill, or invalidate an invoice sent by mistake.

Class `destructive` (held by the mutation gate until the call's own arguments carry `"confirm": true`). No scopes beyond the connection's defaults. Calls `POST /v2/invoicing/invoices/{{params.invoice_id}}/cancel`.

Arguments:

| Argument | Type | Required | Notes |
| --- | --- | --- | --- |
| `invoice_id` | string | **yes** | PayPal sent invoice id to cancel. |
| `note` | string | no | Reason shown to the recipient for the cancellation. |
| `send_to_recipient` | boolean | no | True to notify the recipient by email. Defaults to true. |

Result fields (the payload is trimmed to these before it reaches the model):

| Field | Type | Notes |
| --- | --- | --- |
| `cancelled` | boolean |  |

Also retrieved by: "this bill was sent by mistake, kill it", "the client doesn't owe this anymore", "void a bill that already went out".

### `paypal.delete_invoice`

Permanently delete a draft PayPal invoice that has not been sent. Irreversible and only works while the invoice is still a draft. For a sent invoice that should never be paid, use cancel_invoice instead.

Class `destructive` (held by the mutation gate until the call's own arguments carry `"confirm": true`). No scopes beyond the connection's defaults. Calls `DELETE /v2/invoicing/invoices/{{params.invoice_id}}`.

Arguments:

| Argument | Type | Required | Notes |
| --- | --- | --- | --- |
| `invoice_id` | string | **yes** | PayPal draft invoice id to delete. |

Result fields (the payload is trimmed to these before it reaches the model):

| Field | Type | Notes |
| --- | --- | --- |
| `deleted` | boolean |  |

Also retrieved by: "scrap this draft bill entirely", "get rid of an invoice before it's sent", "wipe this unsent bill out".

### `paypal.create_product`

Create a product in the PayPal catalog, to attach a billing plan to later. Use when the user wants to add or register a new product or service they will sell through PayPal subscriptions. Follow with create_plan to price it.

Class `write` (writes, no confirmation needed). No scopes beyond the connection's defaults. Calls `POST /v1/catalogs/products`.

Arguments:

| Argument | Type | Required | Notes |
| --- | --- | --- | --- |
| `category` | string | no | PayPal product category, e.g. "SOFTWARE". |
| `description` | string | no | Description of what the product or service is. |
| `name` | string | **yes** | Product name shown to subscribers. |
| `type` | string, one of PHYSICAL, DIGITAL, SERVICE | **yes** | What kind of product this is. |

Result fields (the payload is trimmed to these before it reaches the model):

| Field | Type | Notes |
| --- | --- | --- |
| `id` | string |  |
| `name` | string |  |
| `type` | string |  |

Also retrieved by: "register what we're selling for subscriptions", "add a new offering to the catalog", "set up a service we'll bill recurring for".

### `paypal.get_product`

Get one PayPal catalog product by id: its name, type, and category. Use when the user names a specific product they sell through PayPal.

Class `read` (reads only). No scopes beyond the connection's defaults. Calls `GET /v1/catalogs/products/{{params.product_id}}`.

Arguments:

| Argument | Type | Required | Notes |
| --- | --- | --- | --- |
| `product_id` | string | **yes** | PayPal product id, e.g. "PROD-XXXX1234XXXX". |

Result fields (the payload is trimmed to these before it reaches the model):

| Field | Type | Notes |
| --- | --- | --- |
| `category` | string |  |
| `description` | string |  |
| `id` | string |  |
| `name` | string |  |
| `type` | string |  |

Also retrieved by: "pull up details on this catalog listing", "what is this thing we sell", "check the category on this item".

### `paypal.list_products`

List products in the PayPal catalog. Use when the user asks what products or services are set up for subscriptions, or wants to browse the catalog before creating a plan.

Class `read` (reads only). No scopes beyond the connection's defaults. Calls `GET /v1/catalogs/products`.

Arguments:

| Argument | Type | Required | Notes |
| --- | --- | --- | --- |
| `page` | integer | no | Page number to return. Defaults to 1. |
| `page_size` | integer | no | Results per page, max 100. Defaults to 20. |

Result fields (the payload is trimmed to these before it reaches the model):

| Field | Type | Notes |
| --- | --- | --- |
| `products` | array of object |  |
| `products[].id` | string |  |
| `products[].name` | string |  |
| `products[].type` | string |  |
| `total_items` | integer |  |

Also retrieved by: "what do we have set up to subscribe to", "browse everything in our catalog", "show me our subscription offerings".

### `paypal.create_plan`

Create a billing plan on a PayPal product, setting its recurring price and frequency. Use when the user wants to set up, define, or price a new subscription plan or tier. Subscribe someone to it with create_subscription.

Class `write` (writes, no confirmation needed). No scopes beyond the connection's defaults. Calls `POST /v1/billing/plans`.

Arguments:

| Argument | Type | Required | Notes |
| --- | --- | --- | --- |
| `currency_code` | string | **yes** | Three-letter ISO currency code, e.g. "USD". |
| `description` | string | no | Description of what the plan includes. |
| `frequency` | string, one of DAY, WEEK, MONTH, YEAR | **yes** | Billing cycle unit. |
| `interval_count` | integer | **yes** | Number of frequency units between charges, e.g. 1 for monthly. |
| `name` | string | **yes** | Plan name shown to subscribers, e.g. "Pro monthly". |
| `product_id` | string | **yes** | PayPal product id this plan belongs to. |
| `value` | string | **yes** | Recurring charge amount as a decimal string, e.g. "29.00". |

Result fields (the payload is trimmed to these before it reaches the model):

| Field | Type | Notes |
| --- | --- | --- |
| `id` | string |  |
| `name` | string |  |
| `product_id` | string |  |
| `status` | string |  |

Also retrieved by: "price out a new subscription tier", "set the monthly cost for this plan", "define how much and how often we charge".

### `paypal.get_plan`

Get one PayPal billing plan by id: its price, frequency, and whether it is active. Use when the user asks what a specific subscription plan or tier costs or includes.

Class `read` (reads only). No scopes beyond the connection's defaults. Calls `GET /v1/billing/plans/{{params.plan_id}}`.

Arguments:

| Argument | Type | Required | Notes |
| --- | --- | --- | --- |
| `plan_id` | string | **yes** | PayPal plan id, e.g. "P-5ML4271244454362XMJZJZQI". |

Result fields (the payload is trimmed to these before it reaches the model):

| Field | Type | Notes |
| --- | --- | --- |
| `billing_cycles` | array of object |  |
| `billing_cycles[].frequency` | object |  |
| `billing_cycles[].frequency.interval_count` | integer |  |
| `billing_cycles[].frequency.interval_unit` | string |  |
| `billing_cycles[].pricing_scheme` | object |  |
| `billing_cycles[].pricing_scheme.fixed_price` | object |  |
| `id` | string |  |
| `name` | string |  |
| `product_id` | string |  |
| `status` | string |  |

Also retrieved by: "what does this subscription tier cost", "pull up the pricing on this plan", "is this tier still active".

### `paypal.list_plans`

List billing plans, optionally filtered by product or status. Use when the user asks what subscription plans or pricing tiers exist for a product. For one known plan, use get_plan.

Class `read` (reads only). No scopes beyond the connection's defaults. Calls `GET /v1/billing/plans`.

Arguments:

| Argument | Type | Required | Notes |
| --- | --- | --- | --- |
| `page` | integer | no | Page number to return. Defaults to 1. |
| `page_size` | integer | no | Results per page, max 100. Defaults to 20. |
| `product_id` | string | no | Only plans belonging to this product id. |
| `status` | string, one of CREATED, INACTIVE, ACTIVE | no | Only plans in this state. |

Result fields (the payload is trimmed to these before it reaches the model):

| Field | Type | Notes |
| --- | --- | --- |
| `plans` | array of object |  |
| `plans[].id` | string |  |
| `plans[].name` | string |  |
| `plans[].product_id` | string |  |
| `plans[].status` | string |  |
| `total_items` | integer |  |

Also retrieved by: "what tiers do we offer for this product", "show every pricing option available", "browse the billing tiers on this product".

### `paypal.update_plan_pricing`

Change the recurring price of an existing PayPal billing plan. Use when the user wants to raise, lower, or repriced a subscription plan for its billing cycle. Existing subscribers move to the new price on their next renewal.

Class `write` (writes, no confirmation needed). No scopes beyond the connection's defaults. Calls `POST /v1/billing/plans/{{params.plan_id}}/update-pricing-schemes`.

Arguments:

| Argument | Type | Required | Notes |
| --- | --- | --- | --- |
| `currency_code` | string | **yes** | Three-letter ISO currency code, e.g. "USD". |
| `plan_id` | string | **yes** | PayPal plan id to reprice. |
| `value` | string | **yes** | New recurring charge amount as a decimal string. |

Result fields (the payload is trimmed to these before it reaches the model):

| Field | Type | Notes |
| --- | --- | --- |
| `updated` | boolean |  |

Also retrieved by: "raise the price on this subscription tier", "change what we charge going forward", "reprice this plan for new subscribers".

### `paypal.deactivate_plan`

Deactivate a PayPal billing plan so no one can subscribe to it again. Irreversible through this action; existing subscribers keep billing normally. Use when the user wants to retire, sunset, or discontinue a subscription plan or tier.

Class `destructive` (held by the mutation gate until the call's own arguments carry `"confirm": true`). No scopes beyond the connection's defaults. Calls `POST /v1/billing/plans/{{params.plan_id}}/deactivate`.

Arguments:

| Argument | Type | Required | Notes |
| --- | --- | --- | --- |
| `plan_id` | string | **yes** | PayPal plan id to deactivate. |

Result fields (the payload is trimmed to these before it reaches the model):

| Field | Type | Notes |
| --- | --- | --- |
| `deactivated` | boolean |  |

Also retrieved by: "retire this subscription tier", "stop letting people sign up for this plan", "sunset an old pricing option".

### `paypal.create_subscription`

Start a recurring PayPal subscription for a subscriber on a billing plan. Use when the user wants to subscribe, sign up, or put someone on a recurring PayPal plan. The subscriber approves it through the returned PayPal link before billing starts.

Class `write` (writes, no confirmation needed). Scopes `https://uri.paypal.com/services/subscriptions`. Calls `POST /v1/billing/subscriptions`.

Arguments:

| Argument | Type | Required | Notes |
| --- | --- | --- | --- |
| `cancel_url` | string | no | Where PayPal sends the subscriber if they cancel approval. |
| `plan_id` | string | **yes** | PayPal plan id to subscribe to. |
| `quantity` | string | no | Quantity of the plan being subscribed to. Defaults to "1". |
| `return_url` | string | no | Where PayPal sends the subscriber after they approve it. |
| `subscriber_email` | string | no | Email address of the person subscribing. |
| `subscriber_name` | string | no | Full name of the person subscribing. |

Result fields (the payload is trimmed to these before it reaches the model):

| Field | Type | Notes |
| --- | --- | --- |
| `id` | string |  |
| `links` | array of object |  |
| `links[].href` | string |  |
| `links[].rel` | string |  |
| `plan_id` | string |  |
| `status` | string |  |

Also retrieved by: "sign this person up for a recurring plan", "put them on a subscription", "enroll a customer in our monthly billing".

### `paypal.get_subscription`

Get one PayPal subscription by id: its status, plan, next billing time, and any outstanding balance. Use when the user asks about a specific customer's plan or subscription state.

Class `read` (reads only). No scopes beyond the connection's defaults. Calls `GET /v1/billing/subscriptions/{{params.subscription_id}}`.

Arguments:

| Argument | Type | Required | Notes |
| --- | --- | --- | --- |
| `subscription_id` | string | **yes** | PayPal subscription id, e.g. "I-BW452GLLEP1G". |

Result fields (the payload is trimmed to these before it reaches the model):

| Field | Type | Notes |
| --- | --- | --- |
| `billing_info` | object |  |
| `billing_info.next_billing_time` | string |  |
| `billing_info.outstanding_balance` | object |  |
| `billing_info.outstanding_balance.currency_code` | string |  |
| `billing_info.outstanding_balance.value` | string |  |
| `id` | string |  |
| `plan_id` | string |  |
| `status` | string |  |
| `subscriber` | object |  |
| `subscriber.email_address` | string |  |

Also retrieved by: "when do they get billed next", "check the state of this customer's plan", "is this subscription still active".

### `paypal.update_subscription`

Change an active PayPal subscription's plan or quantity. Use when the user wants to upgrade, downgrade, or swap a subscriber to a different plan or tier. To end it instead of changing it, use cancel_subscription.

Class `write` (writes, no confirmation needed). No scopes beyond the connection's defaults. Calls `POST /v1/billing/subscriptions/{{params.subscription_id}}/revise`.

Arguments:

| Argument | Type | Required | Notes |
| --- | --- | --- | --- |
| `plan_id` | string | **yes** | New plan id to move the subscriber onto. |
| `quantity` | string | no | New quantity of the plan. Defaults to "1". |
| `subscription_id` | string | **yes** | PayPal subscription id to change. |

Result fields (the payload is trimmed to these before it reaches the model):

| Field | Type | Notes |
| --- | --- | --- |
| `plan_id` | string |  |
| `status` | string |  |

Also retrieved by: "move them to a different tier", "upgrade this customer's plan", "swap them onto a new subscription level".

### `paypal.suspend_subscription`

Pause an active PayPal subscription so billing stops until it is reactivated. Use when the user wants to pause, freeze, or put a subscription on hold without canceling it outright. Resume it later with reactivate_subscription.

Class `write` (writes, no confirmation needed). No scopes beyond the connection's defaults. Calls `POST /v1/billing/subscriptions/{{params.subscription_id}}/suspend`.

Arguments:

| Argument | Type | Required | Notes |
| --- | --- | --- | --- |
| `reason` | string | no | Reason for suspending, shown to the subscriber. |
| `subscription_id` | string | **yes** | PayPal subscription id to suspend. |

Result fields (the payload is trimmed to these before it reaches the model):

| Field | Type | Notes |
| --- | --- | --- |
| `suspended` | boolean |  |

Also retrieved by: "pause their billing for now", "freeze this subscription temporarily", "put their plan on hold".

### `paypal.reactivate_subscription`

Resume a suspended PayPal subscription, restarting its billing cycle. Use when the user wants to reactivate, unpause, or bring back a subscription that was previously paused.

Class `write` (writes, no confirmation needed). No scopes beyond the connection's defaults. Calls `POST /v1/billing/subscriptions/{{params.subscription_id}}/activate`.

Arguments:

| Argument | Type | Required | Notes |
| --- | --- | --- | --- |
| `reason` | string | no | Reason for reactivating, shown to the subscriber. |
| `subscription_id` | string | **yes** | PayPal subscription id to reactivate. |

Result fields (the payload is trimmed to these before it reaches the model):

| Field | Type | Notes |
| --- | --- | --- |
| `activated` | boolean |  |

Also retrieved by: "turn their subscription back on", "resume billing for this customer", "unpause a plan we froze earlier".

### `paypal.cancel_subscription`

End a PayPal subscription immediately, stopping all future billing. Irreversible; a canceled subscription cannot be resumed and needs a new one. Use when the user wants to cancel, stop, or terminate a subscription entirely, not just pause it.

Class `destructive` (held by the mutation gate until the call's own arguments carry `"confirm": true`). No scopes beyond the connection's defaults. Calls `POST /v1/billing/subscriptions/{{params.subscription_id}}/cancel`.

Arguments:

| Argument | Type | Required | Notes |
| --- | --- | --- | --- |
| `reason` | string | no | Reason for canceling, shown to the subscriber. |
| `subscription_id` | string | **yes** | PayPal subscription id to cancel. |

Result fields (the payload is trimmed to these before it reaches the model):

| Field | Type | Notes |
| --- | --- | --- |
| `cancelled` | boolean |  |

Also retrieved by: "end this recurring plan for good", "the customer wants to stop their subscription", "terminate their billing entirely".

### `paypal.capture_subscription_payment`

Capture an outstanding balance on a PayPal subscription right away, such as a failed renewal charge. Use when the user wants to collect, retry, or force payment on a subscription's unpaid balance rather than waiting for the next billing cycle.

Class `write` (writes, no confirmation needed). No scopes beyond the connection's defaults. Calls `POST /v1/billing/subscriptions/{{params.subscription_id}}/capture`.

Arguments:

| Argument | Type | Required | Notes |
| --- | --- | --- | --- |
| `currency_code` | string | **yes** | Three-letter ISO currency code, e.g. "USD". |
| `note` | string | no | Note shown to the subscriber about this capture. |
| `subscription_id` | string | **yes** | PayPal subscription id with a balance to capture. |
| `value` | string | **yes** | Amount to capture as a decimal string. |

Result fields (the payload is trimmed to these before it reaches the model):

| Field | Type | Notes |
| --- | --- | --- |
| `amount` | object |  |
| `amount.currency_code` | string |  |
| `amount.value` | string |  |
| `id` | string |  |
| `status` | string |  |

Also retrieved by: "collect what they owe on their plan right now", "retry a failed renewal charge", "force through the balance they still owe".

### `paypal.list_subscription_transactions`

List the billing transactions for a PayPal subscription over a date range: each charge, its status, and amount. Use when the user asks for a subscription's payment history or wants to see what a customer has been charged over time.

Class `read` (reads only). No scopes beyond the connection's defaults. Calls `GET /v1/billing/subscriptions/{{params.subscription_id}}/transactions`.

Arguments:

| Argument | Type | Required | Notes |
| --- | --- | --- | --- |
| `end_time` | string | **yes** | End of the date range, RFC 3339, e.g. "2026-07-01T00:00:00Z". |
| `start_time` | string | **yes** | Start of the date range, RFC 3339, e.g. "2026-01-01T00:00:00Z". |
| `subscription_id` | string | **yes** | PayPal subscription id to list transactions for. |

Result fields (the payload is trimmed to these before it reaches the model):

| Field | Type | Notes |
| --- | --- | --- |
| `total_items` | integer |  |
| `transactions` | array of object |  |
| `transactions[].amount_with_breakdown` | object |  |
| `transactions[].amount_with_breakdown.gross_amount` | object |  |
| `transactions[].id` | string |  |
| `transactions[].status` | string |  |
| `transactions[].time` | string |  |

Also retrieved by: "show everything this subscriber has been charged", "pull their billing history for the plan", "what payments has this customer made over time".
