{
  "schema": "aaes/capability-pack/1",
  "provider": "netsuite",
  "version": "1.0.0",
  "description": "List NetSuite vendors, vendor bills, purchase orders, and customers, and create vendor bills. Lists return record references; bill creation is treated as approval-capable but does not schedule or move payment.",
  "notes": "The endpoint host 'netsuite-account.invalid' is a reserved non-production placeholder (an RFC 2606 reserved TLD): substitute the customer's own NetSuite account-specific host, whose documented form is <accountID>.suitetalk.api.netsuite.com, before enabling, in every endpoint, in every resource locator and in every egress allowlist entry. The allowlist matches exactly, so endpoints and allowlist must be substituted together, and substitution is a required deployment step — the reserved host being allowlisted does not make an unsubstituted pack safe to enable.\n\nThis pack registers only endpoints the SuiteTalk REST Web Services documentation on docs.oracle.com documents: collection reads on the vendor, vendorBill, purchaseOrder and customer records (GET /services/rest/record/v1/<recordType>, with filtering via the documented q parameter), and creation of a vendor bill (POST /services/rest/record/v1/vendorBill, which the vendor bill record page documents with a worked sample). All reads are collection reads only: single-record reads (GET /services/rest/record/v1/vendor/{id} and the equivalent for the other record types) exist in the API and are deliberately not registered.\n\nDocumented exclusions, framed as what this pack does not register: record update (PATCH) and record delete (DELETE) on every record type; upsert (PUT); record actions and transforms (POST.../{id}/action/... and transform operations); the vendorPayment and customerPayment records, which record payments against documents (money moves); the customerRefund record, which returns money; and the vendorCredit record, which is a credit memo — an accounting record that reduces the balance owed rather than a record that moves funds, excluded alongside the money records because this pack registers no money-adjacent writes at all; the SuiteQL query service (POST /services/rest/query/v1/suiteql) and every other query subservice; RESTlets; and the metadata-catalog.\n\nThe vendor bill create is registered as create plus approve at the minimum R3 tier: Oracle documents approving a vendor bill by setting its approval status on this same record surface (the Use Case for Approving a Vendor Bill shows PATCH /services/rest/record/v1/vendorbill/{id} setting approvalstatus to 2), and Oracle's record-creation documentation states only that not all record fields can be set with POST, without enumerating which — so no documented provider-side restriction prevents an unrestricted creation POST from carrying an approval status, and this registration does not constrain the request body beyond what the role's own permissions permit.\n\nAn unrestricted creation path that can create an already-approved bill is approve-capable and must sit at the approve floor rather than the create floor. A created bill is otherwise a payables record, not a payment: Oracle documents payment against bills through the separate vendorPayment record, which this pack does not register, so object-created is not payment-scheduled and not money-moved. Authentication: SuiteTalk REST supports two credential schemes.\n\nThis pack registers OAuth 2.0, whose documented header is 'Authorization: Bearer <access token>' — a stored value the connector can inject verbatim.\n\nNetSuite's other scheme, token-based authentication (TBA), is an OAuth 1.0a-style per-request signed Authorization header; this pack format injects a stored header value verbatim and the connector's only signing mode is aws-v4, so TBA is not expressible in this pack today (the same position packs/aws.json was in before SigV4 landed): a deployment that must use TBA cannot wire it through this pack and must not fake it by storing a static TBA header, because a TBA signature is computed per request and a stored one is not a valid credential.",
  "credential": {
    "secret_ref_id": "secret-ref-netsuite-oauth2-access-token",
    "custody": "customer_vault",
    "inject": "header",
    "inject_name": "Authorization",
    "note": "An OAuth 2.0 access token for the customer's own NetSuite account, held in the client's own secret manager. The stored material must be the complete Authorization header value (scheme included): 'Bearer', one separating space, then the access token — 'Bearer <token>'. The executor injects the stored value verbatim and performs no token lifecycle itself: an external deployment process obtains and renews the token.\n\nFor machine-to-machine use NetSuite documents the OAuth 2.0 client credentials flow: an administrator maps an entity, role and application to a certificate on the OAuth 2.0 Client Credentials (M2M) Setup page, and the external process signs a JWT client assertion with the certificate's private key and POSTs it to https://<accountID>.suitetalk.api.netsuite.com/services/rest/auth/oauth2/v1/token; the certificate's private key is itself secret material and must live in the deployment's own custody, outside the executor. customer_vault is the only generally-supported production custody model here — identity_federation and customer_broker are refused at startup and inline is lab-only.\n\nExpiry and revocation: OAuth 2.0 access tokens are short-lived and the external process must re-request them on expiry — Oracle documents the M2M flow as a POST to the token endpoint that returns an access token, with renewal owned by the external process.\n\nAn administrator can revoke the certificate mapping on the M2M setup page at any time (a revoked certificate cannot be reused to obtain new tokens), and the mapped role's permissions can be removed at any time, which changes what subsequently issued tokens can do; disabling issuance and changing role permissions are different events from invalidating an already-issued token, and Oracle's documentation does not describe either step as invalidating a token already issued before its natural expiry.\n\nAn expired value fails closed.\n\nLeast privilege: the integration record should carry only the REST Web Services scope, and the mapped role should hold only the record permissions the registered capabilities need (vendor, customer, purchase order and vendor bill inquiry, plus bill entry for the create) and nothing more — the same identity must not hold permissions for vendor payments or record deletion, which this pack deliberately does not register.\n\nApproval caution: because Oracle documents no field-level restriction preventing a creation POST from carrying an approval status, the bill-entry permission is treated as approve-capable and the create capability is tiered R3 on that basis; a deployment whose role configuration demonstrably prevents setting approval status on creation may record that restriction in its own review, but the tiering here does not rely on it. Token-based authentication (TBA) is a different, per-request-signed scheme that this pack cannot express; see the pack notes.\n\nExecutor hygiene: the value must live only in executor memory for the lifetime of a call, must never be written to logs, traces or diagnostics, and must not appear in crash dumps; a deployment that cannot meet that bar must not enable the pack."
  },
  "capabilities": [
    {
      "capability_id": "netsuite.vendors.read",
      "version": "1.0.0",
      "kind": "tool",
      "risk_tier": "R0",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN",
      "data_class": "pii",
      "egress_allowlist": [
        "netsuite-account.invalid"
      ],
      "endpoint": "https://netsuite-account.invalid/services/rest/record/v1/vendor",
      "method": "GET",
      "connector": "http",
      "custody": "customer_vault",
      "secret_ref_id": "secret-ref-netsuite-oauth2-access-token",
      "inject": "header",
      "inject_name": "Authorization",
      "actions": [
        "read"
      ],
      "resource_id": "netsuite-vendors",
      "description": "Read the vendor record collection. Payload precision: Oracle's collection-paging documentation shows a collection response whose items array carries only each record's id and a self link (with count, hasMore, offset and totalResults paging fields) — the full vendor fields (names, legal names, addresses, emails, phone numbers, tax registration details) come only from the single-record read GET /services/rest/record/v1/vendor/{id}, which this pack deliberately does not register, so this capability returns record references and no unregistered detail read happens automatically.\n\nA vendor can be an individual person, so the read is classified as pii (personal data) on the strength of the records it references (a deployment whose policy classifies vendor master data differently may change it).\n\nThe registered path covers the collection read only — single-vendor reads (GET /services/rest/record/v1/vendor/{id}) and every sublist and subresource are not registered by this pack.\n\nThe host is a reserved placeholder: substitute the customer's account-specific host before enabling.",
      "requires_review": true
    },
    {
      "capability_id": "netsuite.vendorbills.read",
      "version": "1.0.0",
      "kind": "tool",
      "risk_tier": "R0",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN",
      "data_class": "financial",
      "egress_allowlist": [
        "netsuite-account.invalid"
      ],
      "endpoint": "https://netsuite-account.invalid/services/rest/record/v1/vendorBill",
      "method": "GET",
      "connector": "http",
      "custody": "customer_vault",
      "secret_ref_id": "secret-ref-netsuite-oauth2-access-token",
      "inject": "header",
      "inject_name": "Authorization",
      "actions": [
        "read"
      ],
      "resource_id": "netsuite-vendorbills",
      "description": "Read the vendor bill record collection, classified as financial data. Oracle's own use-case documentation shows collection reads on this resource filtered with the q parameter (GET.../record/v1/vendorBill?q=entity EQUAL <id>).\n\nPayload precision: Oracle's collection-paging documentation shows a collection response whose items array carries only each record's id and a self link (with count, hasMore, offset and totalResults paging fields) — the bill header fields (vendor, amounts, currencies, terms, statuses) come only from the single-record read, which this pack deliberately does not register, so this capability returns record references and no unregistered detail read happens automatically.\n\nThe registered path covers the collection read only — single-bill reads, the billingAddress subrecord and the expense and item sublists are not registered by this pack.\n\nThe host is a reserved placeholder: substitute the customer's account-specific host before enabling.",
      "requires_review": true
    },
    {
      "capability_id": "netsuite.vendorbills.create",
      "version": "1.0.0",
      "kind": "tool",
      "risk_tier": "R3",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN",
      "data_class": "financial",
      "egress_allowlist": [
        "netsuite-account.invalid"
      ],
      "endpoint": "https://netsuite-account.invalid/services/rest/record/v1/vendorBill",
      "method": "POST",
      "connector": "http",
      "custody": "customer_vault",
      "secret_ref_id": "secret-ref-netsuite-oauth2-access-token",
      "inject": "header",
      "inject_name": "Authorization",
      "actions": [
        "create",
        "approve"
      ],
      "resource_id": "netsuite-vendorbills",
      "description": "Create one vendor bill record; Oracle documents POST /services/rest/record/v1/vendorBill with a worked creation sample.\n\nRegistered as create plus approve at the minimum R3 tier: Oracle documents approving a vendor bill by setting its approval status on this same record surface (PATCH /services/rest/record/v1/vendorbill/{id} with approvalstatus set to 2), and Oracle's creation documentation states only that not all record fields can be set using POST, without enumerating which — so no documented provider-side restriction prevents an unrestricted creation POST from carrying an approval status, and this registration does not restrict which writable fields a request may carry beyond what the role's own permissions permit.\n\nAn unrestricted creation path that can create an already-approved bill is approve-capable, so it sits at the approve floor rather than the create floor.\n\nResult: the request is accepted and a payables document is created; the call itself schedules no payment and moves no money — Oracle documents payment against bills through the separate vendorPayment record, which this pack does not register.\n\nThe host is a reserved placeholder: substitute the customer's account-specific host before enabling.",
      "requires_review": true
    },
    {
      "capability_id": "netsuite.purchaseorders.read",
      "version": "1.0.0",
      "kind": "tool",
      "risk_tier": "R0",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN",
      "data_class": "financial",
      "egress_allowlist": [
        "netsuite-account.invalid"
      ],
      "endpoint": "https://netsuite-account.invalid/services/rest/record/v1/purchaseOrder",
      "method": "GET",
      "connector": "http",
      "custody": "customer_vault",
      "secret_ref_id": "secret-ref-netsuite-oauth2-access-token",
      "inject": "header",
      "inject_name": "Authorization",
      "actions": [
        "read"
      ],
      "resource_id": "netsuite-purchaseorders",
      "description": "Read the purchase order record collection, classified as financial data. The Purchase Orders feature must be enabled for this record to be accessible, per Oracle's record documentation.\n\nPayload precision: Oracle's collection-paging documentation shows a collection response whose items array carries only each record's id and a self link (with count, hasMore, offset and totalResults paging fields) — the order header fields (vendors, buyers, amounts, currencies, statuses) come only from the single-record read, which this pack deliberately does not register, so this capability returns record references and no unregistered detail read happens automatically.\n\nThe registered path covers the collection read only — single-order reads, the billingAddress and shippingAddress subrecords and the item and expense sublists are not registered by this pack.\n\nThe host is a reserved placeholder: substitute the customer's account-specific host before enabling.",
      "requires_review": true
    },
    {
      "capability_id": "netsuite.customers.read",
      "version": "1.0.0",
      "kind": "tool",
      "risk_tier": "R0",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN",
      "data_class": "pii",
      "egress_allowlist": [
        "netsuite-account.invalid"
      ],
      "endpoint": "https://netsuite-account.invalid/services/rest/record/v1/customer",
      "method": "GET",
      "connector": "http",
      "custody": "customer_vault",
      "secret_ref_id": "secret-ref-netsuite-oauth2-access-token",
      "inject": "header",
      "inject_name": "Authorization",
      "actions": [
        "read"
      ],
      "resource_id": "netsuite-customers",
      "description": "Read the customer record collection.\n\nPayload precision: Oracle's collection-paging documentation shows a collection response whose items array carries only each record's id and a self link (with count, hasMore, offset and totalResults paging fields) — the customer fields (names, company names, emails, addresses, phone numbers) are personal data held on the single record, read via GET /services/rest/record/v1/customer/{id}, which this pack deliberately does not register, so this capability returns record references and no unregistered detail read happens automatically; the read is still classified as pii (personal data) on the strength of the records it references.\n\nThe registered path covers the collection read only — single-customer reads (GET /services/rest/record/v1/customer/{id}) and every sublist (addressbook, currencylist, partners, salesteam and the rest) are not registered by this pack.\n\nThe host is a reserved placeholder: substitute the customer's account-specific host before enabling.",
      "requires_review": true
    }
  ],
  "resources": [
    {
      "resource_id": "netsuite-vendors",
      "kind": "api",
      "locator": "https://netsuite-account.invalid/services/rest/record/v1/vendor",
      "data_class": "pii",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN"
    },
    {
      "resource_id": "netsuite-vendorbills",
      "kind": "api",
      "locator": "https://netsuite-account.invalid/services/rest/record/v1/vendorBill",
      "data_class": "financial",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN"
    },
    {
      "resource_id": "netsuite-purchaseorders",
      "kind": "api",
      "locator": "https://netsuite-account.invalid/services/rest/record/v1/purchaseOrder",
      "data_class": "financial",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN"
    },
    {
      "resource_id": "netsuite-customers",
      "kind": "api",
      "locator": "https://netsuite-account.invalid/services/rest/record/v1/customer",
      "data_class": "pii",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN"
    }
  ],
  "review": {
    "state": "library",
    "date": "2026-09-22",
    "sources": [
      "https://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/article_164337045826.html (retrieved 2026-09-21)",
      "https://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/article_164484956387.html (retrieved 2026-09-21)",
      "https://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/article_161165602348.html (retrieved 2026-09-21)",
      "https://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/article_161581923822.html (retrieved 2026-09-21)",
      "https://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/section_1546938065.html (retrieved 2026-09-21)",
      "https://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/section_0504060740.html (retrieved 2026-09-21)",
      "https://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/section_157780312610.html (retrieved 2026-09-21)",
      "https://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/section_162730264820.html (retrieved 2026-09-21)",
      "https://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/chapter_1540391670.html (retrieved 2026-09-21)",
      "https://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/section_156414087576.html (retrieved 2026-09-21)",
      "https://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/article_0728114850.html (retrieved 2026-09-21)",
      "https://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/section_0504060412.html (retrieved 2026-09-21)",
      "https://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/section_1545141395.html (retrieved 2026-09-21)",
      "https://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/section_162790605110.html (retrieved 2026-09-21)",
      "https://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/section_4267258715.html (retrieved 2026-09-21)"
    ],
    "reviewer_id": "aaes-eng"
  }
}
