Airwallex Contract to Billing
Reads a customer document (PO, contract, quote), extracts line items, and creates a fully populated invoice or subscription in Airwallex Billing. Uses the Airwallex MCP billing tools and operates on live production data — there is no sandbox.
When to use
- User uploads or references a purchase order, contract, quote, or billing document
- User asks to "create an invoice" from a document
- User wants to extract billing details and set up products/prices/customers
- User says "bill this customer" with a document attached
When NOT to use
This skill covers Billing-domain operations exposed by this connector: invoices (list, retrieve, create, update, finalize, void, mark-as-paid, list line items, add line items), products (list, create), prices (list, create), customers (list, retrieve, create, update), subscriptions (create, list items), coupons (list, create, update), and meters (list, create, update).
Not exposed by this connector — direct the user to the Airwallex Dashboard for: line-item update/delete (correct by voiding and re-issuing instead), credit notes, subscription cancellation, payment-source listing, and billing-transaction listing.
If the task requires anything outside the Billing domain, stop — this is the wrong skill. Redirect the user:
- Wire transfers / paying suppliers → not available through this connector (use the Airwallex Dashboard)
- Setting up suppliers / beneficiaries → airwallex-beneficiary-creation skill
- FX conversions, balances, treasury → airwallex-manage-cashflow skill
- Provisioning corporate cards → airwallex-card-provisioning skill
Non-negotiables
Terminology
- Invoices = receivables (money in). Issued BY the user TO their customers. Never say "obligation" for invoices.
- Invoice lifecycle. DRAFT → add line items → finalize → FINALIZED (immutable). To correct after finalize: void → create new.
- Products & prices. Every invoice line item needs a product. For document-specific ad-hoc fees (shipping, handling, setup fees, tax), always use the inline price mechanism (see Path B) with a newly created product rather than matching existing fee products — fee amounts vary per order. Only reuse existing products for the core goods/services sold.
- Invoice vs Subscription. One-time quote → Invoice. Recurring terms → Subscription. Choose before creating.
- ONE_OFF vs RECURRING. Baked in at price creation — cannot flip later.
collection_method mapping from document language:
| Document says |
API value |
| "send invoice", "bank transfer", "wire transfer", "offline payment", "pay by bank" |
OUT_OF_BAND |
| "online payment", "checkout", "payment link", "pay online" |
CHARGE_ON_CHECKOUT |
| "auto-debit", "direct debit", "auto-charge" |
AUTO_CHARGE |
Never use SEND_INVOICE, MANUAL, AUTOMATIC, or any value not in the exact list: AUTO_CHARGE, CHARGE_ON_CHECKOUT, OUT_OF_BAND. Always ask the user if the document language is ambiguous.
Operational rules
- For ambiguous-intent requests, do not start the workflow until the action is confirmed.
- NEVER fabricate or assume missing information. If any required field is uncertain, absent, or ambiguous — STOP and ask the user. Do NOT fill in defaults, placeholder values, or "reasonable guesses".
- Flag extraction uncertainty with
[?] — never guess currencies, quantities, or amounts.
- Never round or modify extracted amounts.
- Always fetch fresh data — re-fetch before every step.
- Prefer business labels over raw IDs in user-facing output. Show customer names and product names first; surface IDs only when operationally necessary or when the user asks.
- One wallet, multiple currencies. Say "AUD balance" — never "AUD wallet."
- Live production data. Treat every write as a real production write. Show extracted data in five tables and get user confirmation before any API call.
- Search for existing customers and core products/prices before creating — avoid duplicates. (Ad-hoc fee products like shipping/handling are exempt — see Terminology.)
- Always confirm before finalizing — finalization is irreversible.
- Prices must match target: ONE_OFF for invoice line items, RECURRING for subscription items.
- Infer collection method from the document using the mapping table. If the document clearly implies a method, use it and note the choice; ask the user when the language is genuinely ambiguous or absent. If the inferred method is
CHARGE_ON_CHECKOUT, ask for linked_payment_account_id — without it the invoice has no checkout link and is unusable.
- Never claim external payment-gateway setup. This skill creates Airwallex Billing resources only. If the user also asks for an unsupported extra (e.g., Stripe gateway), complete the Airwallex Billing setup first, then separately state what was not configured and why.
- Never invent billing automation fields. If dunning, reminder cadence, or external collection support is unconfirmed, say so plainly and omit guessed JSON fields.
- Write safety. Show the full payload and get confirmation before every write — invoice create / line-item add / finalize / void / mark-paid / subscription create. Action commands (finalize / void / mark-paid) need the same confirmation as create/update.
Invoice & subscription constraints
legal_entity_id — Before creating any invoice or subscription, ask the user: "Does your account have multiple legal entities? If so, please provide the legal_entity_id (available in the Airwallex Dashboard)." If the account has multiple legal entities and this field is omitted, the API rejects with "Need to specify the legal_entity_id in the request". This ID is not discoverable via API. If the user confirms only one legal entity, omit the field.
collection_method MUST be set BEFORE finalize — set at create time or via the invoice update operation.
- Invoice body shape. Amounts live in line items (no top-level amount field); customer is
billing_customer_id; notes go in memo. There is no description field on invoices.
- Amounts come from line items, not the invoice create body —
invoice_items in the create body is silently ignored. Add items via the dedicated add-line-items operation after the draft exists. (Convenience: this connector also accepts line_items on the invoice create — it creates the draft, attaches the items, and returns the refreshed invoice. If that attach step fails you get the draft back with a warnings entry, so always check the returned total before finalizing.)
- Pick
due_at OR days_until_due — passing both is rejected.
- Timestamp format: include an explicit timezone — bare dates are rejected. Most body fields accept both
+0000 and Z. Tested exception: the invoice listing only accepts +0000 — Z returns a 400. Do NOT pre-encode the offset to %2B0000.
- Line items body shape. The add operation wraps the array in
line_items. Bare arrays are rejected. Line items only accept ONE_OFF + PER_UNIT/FLAT prices — RECURRING, VOLUME, GRADUATED are rejected. If the contract has tiered pricing, split into separate PER_UNIT line items per band.
- Inline price objects do NOT include
currency — inherited from the invoice.
- Verify the draft has items (
total_amount > 0) before finalize. A draft with no line items fails to finalize — and invoice_items in the create body is silently dropped, so this state is easy to land in by accident.
- Correcting line items: this connector exposes add + list line items, but not update or delete. To change a line item on a DRAFT, void the draft and re-create, or direct the user to the Airwallex Dashboard.
- Discounts: use coupons (
"discounts": [{"type": "COUPON", "coupon": {"id": "..."}}]), not negative amounts. Credit notes are not exposed by this connector — direct the user to the Airwallex Dashboard.
- Coupons: PERCENTAGE vs FLAT are mutually exclusive. PERCENTAGE →
percentage_off (0–100), no currency/amount_off. FLAT → amount_off + currency, no percentage_off. duration_type: CUSTOM needs a duration object with both period and period_unit.
metadata replaces entirely on update — omit to keep existing.
- Tiered pricing uses
upper_bound (not up_to); the last tier omits upper_bound entirely.
- Price immutability: cannot change
currency, pricing_model, amount, or tiers via update — deactivate the old price and create a new one.
starts_at (subscriptions) must be strictly future. Compute dynamically — never hardcode. Omit to default to "now".
- Subscription
items[*].price_id must reference RECURRING prices — ONE_OFF rejected. AUTO_CHARGE requires payment_source_id — ask the user. legal_entity_id may also be required on subscription create in multi-entity accounts.
- Tax handling — Airwallex Billing has no built-in tax-rate engine. If the document includes GST, VAT, or sales tax, extract the tax amount and create it as an explicit line item (with a dedicated "Tax"/"GST" product) or include the tax-inclusive amount in the unit price. Flag
[?] if it is unclear whether prices are tax-inclusive or exclusive, and ask. Do NOT silently compute tax.
- The connector auto-generates
request_id for create operations — you do not need to supply it.
- Pagination:
page_size minimum 10 across billing list endpoints. Most billing listings use cursor pagination — pass the returned page_after bookmark into the next call. Repeat until the cursor is absent.
Workflow
Phase 1: Extract
Step 1 — Get the document. Accept local files (.pdf .docx .txt .md .png .jpg .webp) or pasted text. If the host cannot read a PDF/image reliably, do not pretend it was read — ask the user to re-upload, paste the text, or provide a readable format before extracting.
Step 2 — Extract billing details. Read the entire document. Distinguish the product catalog (all products/pricing defined in the contract) from the current order (specific items being billed now). Identify: customer (name, address, email), document reference, currency, payment terms, all products and pricing, fees, and subscription terms if applicable.
Step 3 — Build five tables (always structured tables, not prose; show a table marked N/A if a section does not apply):
- Products — name, description, unit, active, in current order?
- Prices — product, unit price, currency, frequency, pricing model, tiers
- Customers — name, email (required), location
- Subscriptions — only if the document has recurring terms (N/A otherwise)
- Invoices & Fees — shipping, setup fees, tax (rate and whether prices are tax-inclusive or exclusive), reference, payment terms, due date
Step 4 — Validate and confirm. Cross-check against API requirements. List all gaps explicitly. Accept natural-language corrections and loop until the user approves. Do NOT proceed to any create/finalize call until every required field is complete and the user confirms.
Phase 2: Match & Create
Step 5 — Confirm live data. Validate required fields for all planned operations.
Step 6 — Match existing resources. Search customers by email (filter on the customers list). The products list has no name filter — paginate fully and match by name client-side. Search prices by product_id. Present matches and get confirmation. Only match core goods/services. Do NOT match existing products for per-order ad-hoc fees (shipping, handling, setup) — always create fresh products for these and use inline prices in line items.
Step 7 — Create missing resources. Create ALL missing products and needed prices from the contract (full catalog), not just the current order. Price type: N/A (Table 4) → ONE_OFF; has subscription data → RECURRING. Pricing model: FLAT (fixed), PER_UNIT (per-seat), VOLUME/GRADUATED (tiered).
Step 7b — Confirm collection method. Use the method inferred from the document; if ambiguous or silent, ask now. If CHARGE_ON_CHECKOUT, require linked_payment_account_id from the user — do not guess.
Step 8 — Route based on Table 4:
| Table 4 |
Action |
| Has subscription data |
→ Create subscription |
| N/A (one-time) |
→ Create invoice |
| Both |
→ Subscription for recurring + invoice for one-time fees |
Path A: Subscription
Create a subscription with billing_customer_id, currency, collection_method, and items (RECURRING prices). Verify after creation. Receivables note: remind the user this subscription generates recurring invoices (expected money in). Mention the subscription ID, currency, billing interval, and next billing date so they can cross-reference with the airwallex-manage-cashflow skill. (Note: this connector cannot cancel subscriptions — direct cancellation requests to the Airwallex Dashboard.)
Path B: Invoice
Create draft with billing_customer_id, currency, collection_method, optional days_until_due/due_at, and memo.
Add line items with the dedicated add operation after the draft exists. For an existing price: {"price_id": "...", "quantity": N}. For ad-hoc fees, use an inline price: {"price": {"product_id": "...", "pricing_model": "FLAT", "flat_amount": 350.00, "description": "Shipping"}, "quantity": 1}. Do NOT include currency in an inline price. Convert tiered pricing into invoice-compatible PER_UNIT/FLAT line items per band.
Finalize — confirm with the user first. Show a summary: resources created/reused, total, due date, pdf_url, hosted_url. Receivables note: after finalize, remind the user this invoice is now a receivable (expected money in). Mention the invoice ID, amount, currency, and due date. For a batch, also show a one-line aggregate of total outstanding per currency (e.g., "3 invoices totalling 47,200 GBP outstanding") so the cash-position impact is immediately visible.
Phase 3: Share with Customer (opt-in only)
Must be explicitly requested. After finalize, present:
pdf_url — direct link to the PDF (always available on finalized invoices).
hosted_url — online checkout page. Only available when collection_method is CHARGE_ON_CHECKOUT. For OUT_OF_BAND invoices, hosted_url may be absent — share the pdf_url and instruct the customer on bank transfer details.
Airwallex Billing has no API to email invoices directly — the agent cannot send on the user's behalf. Offer to draft a payment email the user can copy and send themselves.
Error handling
| Situation |
Action |
| Document unreadable |
Ask for the content another way and stop |
| Ambiguous extraction |
Flag with [?], ask the user, do not guess |
legal_entity_id required (missed pre-check) |
Account has multiple legal entities. Ask which legal_entity_id to use (not discoverable via API), include it in the body, and retry |
| Draft fails to finalize |
Verify total_amount > 0 — the draft likely has no line items; add them via the add-line-items operation first |
| User requests external gateway setup |
Explain it is outside this skill's scope; continue with Airwallex Billing only if the user still wants that |
| Credit note / line-item edit / subscription cancel requested |
Not exposed by this connector — direct the user to the Airwallex Dashboard |
| Auth expired |
The connector refreshes tokens automatically; if a tool keeps failing on auth, ask the user to re-authorize the Airwallex connection |
Workflow summary
Phase 1: Extract
get document → read → extract → build 5 tables → validate → user confirms
Phase 2: Match & Create
confirm live data → match existing → user confirms → create missing
→ confirm collection method
→ if recurring: subscription → if one-time: invoice → finalize
→ receivables note (cross-ref with airwallex-manage-cashflow)
Phase 3: Share (opt-in)
present URLs (pdf_url + hosted_url) → draft email if requested
Attribution
Adapted from Airwallex's official AgentOS contract-to-billing skill, licensed under the Apache License 2.0 (see LICENSE.txt). Modified for the ChatChat Airwallex connector: CLI-specific instructions and external URLs removed, supporting reference files inlined, workflow steps aligned to the operations this connector actually exposes, and unsupported operations redirected to the Airwallex Dashboard.
1---2name: airwallex-contract-to-billing3description: Use this skill when creating Airwallex invoices or subscriptions from a purchase order, contract, or quote — extract line items and match existing customers, products, and prices.4license: Apache-2.0. Complete terms in LICENSE.txt5---67# Airwallex Contract to Billing89Reads a customer document (PO, contract, quote), extracts line items, and creates a fully populated invoice or subscription in Airwallex Billing. Uses the Airwallex MCP billing tools and operates on **live production data** — there is no sandbox.1011## When to use1213- User uploads or references a purchase order, contract, quote, or billing document14- User asks to "create an invoice" from a document15- User wants to extract billing details and set up products/prices/customers16- User says "bill this customer" with a document attached1718## When NOT to use1920This skill covers Billing-domain operations exposed by this connector: invoices (list, retrieve, create, update, finalize, void, mark-as-paid, list line items, add line items), products (list, create), prices (list, create), customers (list, retrieve, create, update), subscriptions (create, list items), coupons (list, create, update), and meters (list, create, update).2122**Not exposed by this connector** — direct the user to the Airwallex Dashboard for: line-item update/delete (correct by voiding and re-issuing instead), credit notes, subscription cancellation, payment-source listing, and billing-transaction listing.2324If the task requires anything outside the Billing domain, **stop — this is the wrong skill.** Redirect the user:2526- Wire transfers / paying suppliers → not available through this connector (use the Airwallex Dashboard)27- Setting up suppliers / beneficiaries → **airwallex-beneficiary-creation** skill28- FX conversions, balances, treasury → **airwallex-manage-cashflow** skill29- Provisioning corporate cards → **airwallex-card-provisioning** skill3031## Non-negotiables3233### Terminology3435- **Invoices = receivables (money in).** Issued BY the user TO their customers. Never say "obligation" for invoices.36- **Invoice lifecycle.** **DRAFT → add line items → finalize → FINALIZED (immutable)**. To correct after finalize: void → create new.37- **Products & prices.** Every invoice line item needs a product. For document-specific ad-hoc fees (shipping, handling, setup fees, tax), always use the **inline price mechanism** (see Path B) with a newly created product rather than matching existing fee products — fee amounts vary per order. Only reuse existing products for the core goods/services sold.38- **Invoice vs Subscription.** One-time quote → Invoice. Recurring terms → Subscription. Choose before creating.39- **ONE_OFF vs RECURRING.** Baked in at price creation — cannot flip later.40- **`collection_method` mapping from document language:**4142| Document says | API value |43| --- | --- |44| "send invoice", "bank transfer", "wire transfer", "offline payment", "pay by bank" | `OUT_OF_BAND` |45| "online payment", "checkout", "payment link", "pay online" | `CHARGE_ON_CHECKOUT` |46| "auto-debit", "direct debit", "auto-charge" | `AUTO_CHARGE` |4748Never use `SEND_INVOICE`, `MANUAL`, `AUTOMATIC`, or any value not in the exact list: `AUTO_CHARGE`, `CHARGE_ON_CHECKOUT`, `OUT_OF_BAND`. Always ask the user if the document language is ambiguous.4950### Operational rules5152- **For ambiguous-intent requests, do not start the workflow until the action is confirmed.**53- **NEVER fabricate or assume missing information.** If any required field is uncertain, absent, or ambiguous — STOP and ask the user. Do NOT fill in defaults, placeholder values, or "reasonable guesses".54- **Flag extraction uncertainty with `[?]`** — never guess currencies, quantities, or amounts.55- **Never round or modify extracted amounts.**56- **Always fetch fresh data** — re-fetch before every step.57- **Prefer business labels over raw IDs in user-facing output.** Show customer names and product names first; surface IDs only when operationally necessary or when the user asks.58- **One wallet, multiple currencies.** Say "AUD balance" — never "AUD wallet."59- **Live production data.** Treat every write as a real production write. Show extracted data in five tables and get user confirmation before any API call.60- **Search for existing customers and core products/prices before creating** — avoid duplicates. (Ad-hoc fee products like shipping/handling are exempt — see Terminology.)61- **Always confirm before finalizing** — finalization is **irreversible**.62- **Prices must match target:** **ONE_OFF** for invoice line items, **RECURRING** for subscription items.63- **Infer collection method from the document** using the mapping table. If the document clearly implies a method, use it and note the choice; ask the user when the language is genuinely ambiguous or absent. If the inferred method is `CHARGE_ON_CHECKOUT`, ask for `linked_payment_account_id` — without it the invoice has no checkout link and is unusable.64- **Never claim external payment-gateway setup.** This skill creates Airwallex Billing resources only. If the user also asks for an unsupported extra (e.g., Stripe gateway), complete the Airwallex Billing setup first, then separately state what was not configured and why.65- **Never invent billing automation fields.** If dunning, reminder cadence, or external collection support is unconfirmed, say so plainly and omit guessed JSON fields.66- **Write safety.** Show the full payload and get confirmation before every write — invoice create / line-item add / finalize / void / mark-paid / subscription create. Action commands (finalize / void / mark-paid) need the same confirmation as create/update.6768### Invoice & subscription constraints6970- **`legal_entity_id`** — **Before creating any invoice or subscription**, ask the user: *"Does your account have multiple legal entities? If so, please provide the `legal_entity_id` (available in the Airwallex Dashboard)."* If the account has multiple legal entities and this field is omitted, the API rejects with `"Need to specify the legal_entity_id in the request"`. This ID is **not discoverable via API**. If the user confirms only one legal entity, omit the field.71- **`collection_method` MUST be set BEFORE finalize** — set at create time or via the invoice update operation.72- **Invoice body shape.** Amounts live in line items (no top-level amount field); customer is `billing_customer_id`; notes go in `memo`. There is no `description` field on invoices.73- **Amounts come from line items, not the invoice create body** — `invoice_items` in the create body is **silently ignored**. Add items via the dedicated add-line-items operation after the draft exists. (Convenience: this connector also accepts `line_items` on the invoice *create* — it creates the draft, attaches the items, and returns the refreshed invoice. If that attach step fails you get the draft back with a `warnings` entry, so always check the returned total before finalizing.)74- **Pick `due_at` OR `days_until_due`** — passing both is rejected.75- **Timestamp format:** include an explicit timezone — bare dates are rejected. Most body fields accept both `+0000` and `Z`. **Tested exception:** the invoice listing only accepts `+0000` — `Z` returns a 400. Do NOT pre-encode the offset to `%2B0000`.76- **Line items body shape.** The add operation wraps the array in `line_items`. Bare arrays are rejected. Line items only accept **ONE_OFF + PER_UNIT/FLAT** prices — RECURRING, VOLUME, GRADUATED are rejected. If the contract has tiered pricing, split into separate PER_UNIT line items per band.77- **Inline price objects do NOT include `currency`** — inherited from the invoice.78- **Verify the draft has items (`total_amount > 0`) before finalize.** A draft with no line items fails to finalize — and `invoice_items` in the create body is silently dropped, so this state is easy to land in by accident.79- **Correcting line items:** this connector exposes add + list line items, but not update or delete. To change a line item on a DRAFT, void the draft and re-create, or direct the user to the Airwallex Dashboard.80- **Discounts:** use coupons (`"discounts": [{"type": "COUPON", "coupon": {"id": "..."}}]`), not negative amounts. **Credit notes** are not exposed by this connector — direct the user to the Airwallex Dashboard.81- **Coupons:** PERCENTAGE vs FLAT are mutually exclusive. PERCENTAGE → `percentage_off` (0–100), no `currency`/`amount_off`. FLAT → `amount_off` + `currency`, no `percentage_off`. `duration_type: CUSTOM` needs a `duration` object with both `period` and `period_unit`.82- **`metadata`** replaces entirely on update — omit to keep existing.83- **Tiered pricing** uses `upper_bound` (not `up_to`); the last tier omits `upper_bound` entirely.84- **Price immutability:** cannot change `currency`, `pricing_model`, `amount`, or `tiers` via update — deactivate the old price and create a new one.85- **`starts_at`** (subscriptions) must be strictly future. Compute dynamically — never hardcode. Omit to default to "now".86- **Subscription `items[*].price_id`** must reference RECURRING prices — ONE_OFF rejected. **`AUTO_CHARGE`** requires `payment_source_id` — ask the user. `legal_entity_id` may also be required on subscription create in multi-entity accounts.87- **Tax handling** — Airwallex Billing has no built-in tax-rate engine. If the document includes GST, VAT, or sales tax, extract the tax amount and create it as an explicit line item (with a dedicated "Tax"/"GST" product) or include the tax-inclusive amount in the unit price. Flag `[?]` if it is unclear whether prices are tax-inclusive or exclusive, and ask. Do NOT silently compute tax.88- **The connector auto-generates `request_id`** for create operations — you do not need to supply it.89- **Pagination:** `page_size` minimum 10 across billing list endpoints. Most billing listings use cursor pagination — pass the returned `page_after` bookmark into the next call. Repeat until the cursor is absent.9091---9293## Workflow9495### Phase 1: Extract9697**Step 1 — Get the document.** Accept local files (`.pdf` `.docx` `.txt` `.md` `.png` `.jpg` `.webp`) or pasted text. If the host cannot read a PDF/image reliably, do **not** pretend it was read — ask the user to re-upload, paste the text, or provide a readable format before extracting.9899**Step 2 — Extract billing details.** Read the **entire** document. Distinguish the **product catalog** (all products/pricing defined in the contract) from the **current order** (specific items being billed now). Identify: customer (name, address, email), document reference, currency, payment terms, all products and pricing, fees, and subscription terms if applicable.100101**Step 3 — Build five tables** (always structured tables, not prose; show a table marked `N/A` if a section does not apply):1021031. **Products** — name, description, unit, active, in current order?1042. **Prices** — product, unit price, currency, frequency, pricing model, tiers1053. **Customers** — name, email (required), location1064. **Subscriptions** — only if the document has recurring terms (N/A otherwise)1075. **Invoices & Fees** — shipping, setup fees, tax (rate and whether prices are tax-inclusive or exclusive), reference, payment terms, due date108109**Step 4 — Validate and confirm.** Cross-check against API requirements. List all gaps explicitly. Accept natural-language corrections and loop until the user approves. Do NOT proceed to any create/finalize call until every required field is complete and the user confirms.110111### Phase 2: Match & Create112113**Step 5 — Confirm live data.** Validate required fields for all planned operations.114115**Step 6 — Match existing resources.** Search customers by `email` (filter on the customers list). The products list has **no name filter** — paginate fully and match by name client-side. Search prices by `product_id`. Present matches and get confirmation. **Only match core goods/services.** Do NOT match existing products for per-order ad-hoc fees (shipping, handling, setup) — always create fresh products for these and use inline prices in line items.116117**Step 7 — Create missing resources.** Create ALL missing products and needed prices from the contract (full catalog), not just the current order. Price type: N/A (Table 4) → ONE_OFF; has subscription data → RECURRING. Pricing model: FLAT (fixed), PER_UNIT (per-seat), VOLUME/GRADUATED (tiered).118119**Step 7b — Confirm collection method.** Use the method inferred from the document; if ambiguous or silent, ask now. If `CHARGE_ON_CHECKOUT`, require `linked_payment_account_id` from the user — do not guess.120121**Step 8 — Route based on Table 4:**122123| Table 4 | Action |124| --- | --- |125| Has subscription data | → Create subscription |126| N/A (one-time) | → Create invoice |127| Both | → Subscription for recurring + invoice for one-time fees |128129#### Path A: Subscription130131Create a subscription with `billing_customer_id`, `currency`, `collection_method`, and `items` (RECURRING prices). Verify after creation. **Receivables note:** remind the user this subscription generates recurring invoices (expected money in). Mention the subscription ID, currency, billing interval, and next billing date so they can cross-reference with the **airwallex-manage-cashflow** skill. (Note: this connector cannot cancel subscriptions — direct cancellation requests to the Airwallex Dashboard.)132133#### Path B: Invoice134135**Create draft** with `billing_customer_id`, `currency`, `collection_method`, optional `days_until_due`/`due_at`, and `memo`.136137**Add line items** with the dedicated add operation after the draft exists. For an existing price: `{"price_id": "...", "quantity": N}`. For ad-hoc fees, use an inline price: `{"price": {"product_id": "...", "pricing_model": "FLAT", "flat_amount": 350.00, "description": "Shipping"}, "quantity": 1}`. Do NOT include `currency` in an inline price. Convert tiered pricing into invoice-compatible PER_UNIT/FLAT line items per band.138139**Finalize** — confirm with the user first. Show a summary: resources created/reused, total, due date, `pdf_url`, `hosted_url`. **Receivables note:** after finalize, remind the user this invoice is now a receivable (expected money in). Mention the invoice ID, amount, currency, and due date. For a batch, also show a one-line aggregate of total outstanding per currency (e.g., "3 invoices totalling 47,200 GBP outstanding") so the cash-position impact is immediately visible.140141### Phase 3: Share with Customer (opt-in only)142143Must be explicitly requested. After finalize, present:144- **`pdf_url`** — direct link to the PDF (always available on finalized invoices).145- **`hosted_url`** — online checkout page. Only available when `collection_method` is `CHARGE_ON_CHECKOUT`. For `OUT_OF_BAND` invoices, `hosted_url` may be absent — share the `pdf_url` and instruct the customer on bank transfer details.146147Airwallex Billing has **no API to email invoices directly** — the agent cannot send on the user's behalf. Offer to draft a payment email the user can copy and send themselves.148149---150151## Error handling152153| Situation | Action |154| --- | --- |155| Document unreadable | Ask for the content another way and stop |156| Ambiguous extraction | Flag with `[?]`, ask the user, do not guess |157| `legal_entity_id` required (missed pre-check) | Account has multiple legal entities. Ask which `legal_entity_id` to use (not discoverable via API), include it in the body, and retry |158| Draft fails to finalize | Verify `total_amount > 0` — the draft likely has no line items; add them via the add-line-items operation first |159| User requests external gateway setup | Explain it is outside this skill's scope; continue with Airwallex Billing only if the user still wants that |160| Credit note / line-item edit / subscription cancel requested | Not exposed by this connector — direct the user to the Airwallex Dashboard |161| Auth expired | The connector refreshes tokens automatically; if a tool keeps failing on auth, ask the user to re-authorize the Airwallex connection |162163---164165## Workflow summary166167```168Phase 1: Extract169 get document → read → extract → build 5 tables → validate → user confirms170171Phase 2: Match & Create172 confirm live data → match existing → user confirms → create missing173 → confirm collection method174 → if recurring: subscription → if one-time: invoice → finalize175 → receivables note (cross-ref with airwallex-manage-cashflow)176177Phase 3: Share (opt-in)178 present URLs (pdf_url + hosted_url) → draft email if requested179```180181---182183## Attribution184185Adapted from Airwallex's official AgentOS `contract-to-billing` skill, licensed under the Apache License 2.0 (see LICENSE.txt). Modified for the ChatChat Airwallex connector: CLI-specific instructions and external URLs removed, supporting reference files inlined, workflow steps aligned to the operations this connector actually exposes, and unsupported operations redirected to the Airwallex Dashboard.