> ## Documentation Index
> Fetch the complete documentation index at: https://docs.pazy.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Procure-to-pay workflow

> Create a vendor and purchase order, upload an invoice, and record its payment

This guide walks through the most common integration: take a vendor from creation to a paid invoice. Each step links to the endpoint page with the full parameter list.

<Info>
  All examples use `YOUR_API_KEY` as a placeholder. See the [overview](/#quickstart) for how to create a key. Your key needs permission for each resource you call, for example **Payment** with **Create** for marking invoices as paid.
</Info>

## The flow

<Steps>
  <Step title="Create the vendor">
    [Create a vendor](/apis/vendor-creation). Only `name` is required, but add `gstNumber`, `panNumber` and `address` if you have them.

    ```bash theme={null}
    curl -X POST https://api.pazy.io/v1.0/vendor \
      -H "Authorization: Api-Key YOUR_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "name": "ABC Suppliers",
        "email": "contact@abcsuppliers.com",
        "paymentTerms": "net_30",
        "gstNumber": "29ABCDE1234F1Z5"
      }'
    ```

    Save `data.vendorId` from the response. Check `data.vendorState` too: `ACTIVE` means the vendor is ready, and `APPROVAL_PENDING` means your vendor admins still need to approve it.

    <Tip>
      If the vendor may already exist, use [Vendor Search](/apis/vendor-search) or [Vendor List](/apis/vendor-list) first. Creation can fail with `DUPLICATE_VENDOR_NAME` or `DUPLICATE_GSTIN`.
    </Tip>
  </Step>

  <Step title="Create the purchase order">
    [Create a purchase order](/apis/po-creation) linked to the vendor.

    ```bash theme={null}
    curl -X POST https://api.pazy.io/v1.0/procurement/purchase-order \
      -H "Authorization: Api-Key YOUR_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "poNumber": "PO-2024-001",
        "poDate": "2024-01-15",
        "poType": "GOODS",
        "matchingType": "TWO_WAY",
        "vendorId": "VENDOR_ID_FROM_STEP_1",
        "gstin": "29ABCDE1234F1Z5",
        "description": "Office supplies",
        "paymentTerms": "Net 30 days",
        "state": "ACTIVE",
        "lineItems": [
          { "identifier": "Printer paper", "quantity": 100, "rate": 50 }
        ]
      }'
    ```

    Save `data.poId`. Three things to know:

    * `gstin` is your own entity's GSTIN. [Company Entities](/apis/company-entities) lists the ones available to you.
    * With `state: "ACTIVE"`, the PO needs a vendor, description, payment terms, and a quantity and rate greater than 0 on every line. If anything is missing, the PO is created as a draft and the response lists what was missing in `submitWarnings`.
    * `THREE_WAY` matching needs every line item to match an existing SKU. See [Bulk SKU Creation](/apis/sku-bulk-creation).
  </Step>

  <Step title="Upload the invoice">
    [Create an invoice](/apis/invoice-creation) by uploading the file (PDF, JPEG, JPG or PNG, up to 50 MB). This request is `multipart/form-data`, not JSON.

    ```bash theme={null}
    curl -X POST https://api.pazy.io/v1.0/invoice \
      -H "Authorization: Api-Key YOUR_API_KEY" \
      -F "file=@/path/to/invoice.pdf" \
      -F "remarks=Against PO-2024-001"
    ```

    Save `data.id`. This is the invoice identifier used everywhere else, including as `slug` when marking it paid.
  </Step>

  <Step title="Wait for processing to finish">
    The invoice is processed asynchronously, so the upload response returns `isReady: false`. Poll [Invoice Details](/apis/invoice-details) until `data.processingStatus.isReady` is `true`.

    ```bash theme={null}
    curl https://api.pazy.io/v1.0/invoice/INVOICE_ID \
      -H "Authorization: Api-Key YOUR_API_KEY"
    ```

    Poll every few seconds, not continuously. Stop and investigate if `processingStatus.status` becomes `FAILED`, `USER_CANCELLED` or `DISCARDED`.
  </Step>

  <Step title="Approve the invoice">
    Only invoices in the `APPROVED` state can be marked as paid. Approval happens through your approval workflow in the [Pazy app](https://app.pazy.io). Check the invoice's state with Invoice Details before the next step.
  </Step>

  <Step title="Record the payment">
    [Mark the invoice as paid](/apis/mark-as-paid). The `x-idempotency-key` header is required on this endpoint.

    ```bash theme={null}
    curl -X POST https://api.pazy.io/v1.0/payment/mark-as-paid \
      -H "Authorization: Api-Key YOUR_API_KEY" \
      -H "Content-Type: application/json" \
      -H "x-idempotency-key: $(uuidgen)" \
      -d '{
        "resourceType": "INVOICE",
        "resources": [
          { "slug": "INVOICE_ID", "amount": 15000, "utr": "UTR123456789" }
        ]
      }'
    ```

    See [Recording payments](/guides/recording-payments) for partial payments, batches, and how to read per-invoice results.
  </Step>
</Steps>

## Related

<CardGroup cols={2}>
  <Card title="Recording payments" icon="credit-card" href="/guides/recording-payments">
    Partial payments, batches over 100 invoices, and result statuses.
  </Card>

  <Card title="Errors and retries" icon="triangle-exclamation" href="/guides/errors-and-retries">
    What each error means and which ones are safe to retry.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.