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

# Start a hosted checkout

> Creates a checkout and sends the payer to it. Submit it as an HTML form post from the payer's browser, which follows the redirect. Or send it as JSON from your server without following redirects, and send the payer to the `Location` it returns. The answer is always a `303` redirect, never a JSON body: to the checkout page or to a failure address.

Each request creates a new checkout. Its link works until it is paid or `expires_at` passes, whichever comes first.



## OpenAPI

````yaml /openapi.json post /api/v1/payer/intake
openapi: 3.1.0
info:
  title: Partner Payments API
  version: 1.0.0
  description: >
    Use the Partner Payments API to create, refund, void, and retrieve payments
    from your backend.


    ## Payments and portals


    A payment is one charge, identified by `id`. Its line items describe what
    the payer paid for. The payer is the person making the payment, and the
    agency receives the payment.


    A portal is an agency's payment configuration in GroGov. It determines the
    payment gateway and service fee configuration used for a payment. GroGov
    provides the `portalId` values your API account can access. Requests for an
    inaccessible or unknown portal return `403 PORTAL_ACCESS_DENIED`. Contact
    GroGov support to request access.


    ## Environments


    Use the sandbox at `https://apistagepc.grogov.us` to test without moving
    real money. GroGov provides your sandbox API key, portal IDs, and test
    cards. Production processes live payments and requires separate access.


    ## Authentication


    All payment endpoints require one of these credentials:


    - API key: `Authorization: ApiKey pc_<your-key>`. Request your key from
    GroGov support.

    - Access token: exchange your API key at `POST /api/partner/v1/auth/token`,
    then send `Authorization: Bearer <token>`. The access token is a JWT valid
    for one hour. When it expires, exchange your API key again. There is no
    refresh token.


    Rotating an API key invalidates the previous key. Access tokens already
    issued remain valid until they expire. Deactivating your API account blocks
    both credentials on the next request.


    A card token represents card details and is separate from an access token.
    Contact GroGov support for the supported card-token integration for your
    portal. This API does not create card tokens.


    ## Amounts


    All monetary amounts are integer cents in `USD`. Monetary field names end in
    `Cents`, including `amountCents` and `serviceFeeCents`. `100` cents is $1.00
    USD. Sending a field named `amount` returns `400 VALIDATION_ERROR`.


    The principal is the payment amount excluding the service fee. GroGov adds
    the service fee to `amountCents`. Use `GET /api/partner/v1/fees/quote` to
    calculate the fee before charging.


    ## Settlement


    A batch is a group of transactions the payment processor submits for
    settlement. Settlement transfers funds for those transactions. A settled
    payment requires a refund instead of a void.


    ## Idempotency


    For `POST /payments`, `POST /payments/{id}/refund`, and `POST
    /payments/{id}/void`, use an `Idempotency-Key` header. The key can be any
    unique string up to 255 characters. The header is optional but recommended
    to prevent duplicate operations when retrying. Keys are scoped to your API
    account and kept for 24 hours.


    - Same key and body: the original response is returned with
    `Idempotent-Replayed: true`. No additional charge, refund, or void occurs.

    - Same key with a different body: `409 IDEMPOTENCY_MISMATCH`.

    - Same key while the first request is still processing: `409
    IDEMPOTENCY_IN_PROGRESS` with `Retry-After`.

    - After a `5xx` on create, the key stays reserved and a retry returns `409
    IDEMPOTENCY_RECONCILIATION_REQUIRED`. Check the payment list and resolve the
    original outcome before attempting a new charge. After a `5xx` on refund or
    void, the key is released and you can retry with the same key.


    ## Errors


    Payment errors include a machine-readable `details.code`: `{ "success":
    false, "message": "…", "details": { "code": "…" } }`. Authentication
    failures with HTTP status `401` or `403` can omit `details` and include only
    `message`.


    Case-specific restrictions use the payment-level `referenceId`. This is
    separate from each line item's `referenceId`. The applicable restrictions
    depend on the agency's payment configuration.


    | Code | HTTP | Meaning |

    |---|---|---|

    | `VALIDATION_ERROR` | 400 | The request is malformed or a field is invalid.
    See `message` for details |

    | `PAYMENT_DECLINED` | 402 | The card was declined |

    | `PAYMENT_BLOCKED` | 403 | Payments are blocked for the case identified by
    the payment-level `referenceId`. Do not retry |

    | `PAYMENT_HELD` | 409 | The case identified by the payment-level
    `referenceId` has a temporary payment hold. Try again later |

    | `DECLINE_BLOCKED` | 409 | This card was declined recently and is
    temporarily blocked. Use another card or try again later |

    | `VELOCITY_LIMIT` | 429 | Too many recent attempts for this case or card.
    Wait before retrying |

    | `PAYMENT_NOT_ALLOWED` | 422 | The payment does not meet the portal's
    payment rules or applicable case restrictions |

    | `PORTAL_ACCESS_DENIED` | 403 | The portal does not exist or your API
    account may not use it |

    | `PAYMENT_NOT_FOUND` | 404 | The payment does not exist or belongs to
    another API account |

    | `IDEMPOTENCY_MISMATCH` | 409 | The `Idempotency-Key` was already used with
    a different request |

    | `IDEMPOTENCY_IN_PROGRESS` | 409 | A request with this `Idempotency-Key` is
    still being processed. Retry after `Retry-After` |

    | `IDEMPOTENCY_RECONCILIATION_REQUIRED` | 409 | An earlier request with this
    key ended in an unknown state. Contact GroGov before retrying |

    | `INVALID_STATE` | 422 | The payment cannot be refunded or voided in its
    current state, or the refund exceeds the remaining amount |

    | `VOID_FAILED` | 422 | The payment gateway rejected the void. Check
    `details.suggestedAction` for the next operation |

    | `INTERNAL_ERROR` | 500 | An unexpected server error |

    | `CAPTURE_NOT_SUPPORTED` | 501 | Authorize-then-capture is not supported.
    Payments charge immediately |

    | `VAULT_NOT_SUPPORTED` | 501 | Storing cards and charging stored vault
    cards are not supported |

    | `PAYMENT_GATEWAY_ERROR` | 502 | The payment gateway returned an error. The
    payment did not succeed |

    | `PARTIAL_REFUND_PENDING` | 502 | The principal was refunded but the
    service fee refund failed. Retry the refund |

    | `GATEWAY_NOT_CONFIGURED` | 503 | The portal has no payment gateway
    configured |

    | `IDEMPOTENCY_UNAVAILABLE` | 503 | A request with an `Idempotency-Key`
    cannot be processed safely right now. Nothing was charged or refunded.
    Contact GroGov support |

    | `PAYMENT_TIMEOUT` | 504 | The payment gateway response was missing or
    unreadable. The outcome is unknown. Check the payment before retrying |


    ## Unsupported operations


    - Authorizing payments for later capture. `capture: "auth"` and `POST
    /payments/{id}/capture` return `501 CAPTURE_NOT_SUPPORTED`.

    - Storing cards or charging stored cards. `POST /vault` and
    `paymentMethod.type: "vault"` return `501 VAULT_NOT_SUPPORTED`.

    - Individual line-item refunds. Use the payment's `id`. A line-item ID
    returns `404 PAYMENT_NOT_FOUND`.

    - Filtering `GET /payments` by `referenceId`.
  contact:
    name: GroGov Partner Support
    email: support@grogov.us
servers:
  - url: https://apistagepc.grogov.us
    description: Sandbox
  - url: https://apiprodpc.grogov.us
    description: Production. Live payments require production access.
security:
  - ApiKeyAuth: []
  - BearerAuth: []
tags:
  - name: Auth
    description: >-
      Exchange an API key for a one-hour access token to authenticate subsequent
      requests.
  - name: Vault
    description: >-
      Storing cards and charging stored cards are not supported. Requests return
      501 `VAULT_NOT_SUPPORTED`.
  - name: Payments
    description: Create and manage payments containing one or more line items.
  - name: Hosted checkout
    description: >-
      Send the payer's browser to a GroGov-hosted checkout page instead of
      collecting card details yourself. You never handle card data, and these
      endpoints need no API key: the portal's hosted-checkout settings authorize
      the request.


      Start a checkout by posting a form or JSON to `POST /api/v1/payer/intake`,
      or by sending the payer to a launch link, `GET /api/v1/payer/intake/link`.
      Both answer with a `303` redirect. On success the payer lands on the
      checkout page with your line items filled in. On failure they go to your
      `cancel_url` with an error code, or to a GroGov error page.


      The result comes back on the payer's browser: when they press Done on the
      receipt, they go to your `return_url`. When they leave the checkout, they
      go to your `cancel_url`. Both carry a `sig` you can verify with the
      portal's signing secret. See `HostedCheckoutPaidResult`,
      `HostedCheckoutCancelledResult`, and `HostedCheckoutFailedResult`.


      Ask the agency or GroGov support to turn on hosted checkout for the
      portal, to add your return and cancel addresses to its allowlist, and for
      the signing secret. Every address must use `https`.
paths:
  /api/v1/payer/intake:
    post:
      tags:
        - Hosted checkout
      summary: Start a hosted checkout
      description: >-
        Creates a checkout and sends the payer to it. Submit it as an HTML form
        post from the payer's browser, which follows the redirect. Or send it as
        JSON from your server without following redirects, and send the payer to
        the `Location` it returns. The answer is always a `303` redirect, never
        a JSON body: to the checkout page or to a failure address.


        Each request creates a new checkout. Its link works until it is paid or
        `expires_at` passes, whichever comes first.
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/HostedCheckoutRequest'
            example:
              portal_id: 3f6c2a1e-8b4d-4c1a-9e2f-7a5b6c8d9e01
              reference_id: INV-10293
              return_url: https://partner.example.com/checkout/return
              cancel_url: https://partner.example.com/checkout/cancel
              items:
                - id: FINE-2026-0042
                  description: Parking citation 0042
                  amount: 7500
          application/json:
            schema:
              $ref: '#/components/schemas/HostedCheckoutRequest'
            example:
              portal_id: 3f6c2a1e-8b4d-4c1a-9e2f-7a5b6c8d9e01
              reference_id: INV-10293
              payer_email: jane.doe@example.com
              return_url: https://partner.example.com/checkout/return
              cancel_url: https://partner.example.com/checkout/cancel
              items:
                - id: FINE-2026-0042
                  description: Parking citation 0042
                  amount: 7500
                - id: LATE-FEE
                  description: Late fee
                  amount: 2500
      responses:
        '303':
          description: >-
            Always a redirect. On success, to the checkout page. On failure, to
            `cancel_url` with `HostedCheckoutFailedResult` parameters, or to the
            GroGov error page with `?code=<HostedCheckoutErrorCode>` when there
            is no usable `cancel_url`.
          headers:
            Location:
              schema:
                type: string
                format: uri
              description: The checkout page or the failure address
      security: []
components:
  schemas:
    HostedCheckoutRequest:
      type: object
      description: >-
        Starts a hosted checkout. In a form post, nest fields with brackets:
        `items[0][id]`, `items[0][amount]`, `metadata[account]`.
      required:
        - portal_id
        - reference_id
        - items
      properties:
        portal_id:
          type: string
          format: uuid
          description: The portal GroGov gave you for hosted checkout
        reference_id:
          type: string
          minLength: 1
          maxLength: 64
          description: Your reference for this checkout. It comes back on the result.
          example: INV-10293
        label:
          type: string
          minLength: 1
          maxLength: 80
          description: A heading shown to the payer. Must not contain a URL.
          example: Court fees
        payer_name:
          type: string
          maxLength: 200
          description: >-
            Shown on the confirm step and pre-fills the cardholder name, which
            the payer can change. The payment records the name the payer
            submits.
        payer_email:
          type: string
          format: email
          description: >-
            Stored with the payment when the payer does not enter an email of
            their own. Not shown to the payer; the emailed receipt goes to the
            address the payer enters.
        payer_phone:
          type: string
          maxLength: 50
          description: >-
            Stored with the payment when the payer does not enter a phone of
            their own. Not shown to the payer.
        return_url:
          type: string
          format: uri
          description: >-
            Where the payer goes after paying. Must be `https` and on the
            portal's allowlist. Defaults to the portal's configured return
            address.
          example: https://partner.example.com/checkout/return
        cancel_url:
          type: string
          format: uri
          description: >-
            Where the payer goes on cancellation or a failed request. Must be
            `https` and on the portal's allowlist. Defaults to the portal's
            configured cancel address.
          example: https://partner.example.com/checkout/cancel
        expires_at:
          type: string
          format: date-time
          description: >-
            When the checkout link stops working. An ISO 8601 time in the
            future, ending in `Z` or a UTC offset. Defaults to the portal's link
            lifetime, 24 hours unless the agency set another; a later time is
            shortened to that lifetime, not refused.
        metadata:
          type: object
          additionalProperties: true
          description: >-
            Your own data, at most 8 KB as JSON. It is stored with the checkout
            and not shown to the payer.
        items:
          type: array
          minItems: 1
          maxItems: 100
          items:
            $ref: '#/components/schemas/HostedCheckoutItem'
    HostedCheckoutItem:
      type: object
      description: >-
        One line on the checkout. The checkout total is the sum of `amount` ×
        `quantity` over all items, before the service fee.
      required:
        - id
        - description
        - amount
      properties:
        id:
          type: string
          minLength: 1
          maxLength: 64
          description: Your identifier for the line
          example: FINE-2026-0042
        description:
          type: string
          minLength: 1
          maxLength: 200
          description: Shown to the payer. Must not contain a URL.
          example: Parking citation 0042
        amount:
          type: integer
          minimum: 0
          description: Price of one unit, in cents
          example: 7500
        quantity:
          type: integer
          minimum: 1
          default: 1
        required:
          type: boolean
          default: false
          description: >-
            Stored with the line. It does not change the checkout: the payer
            always pays every line. In a form post, send `true` or `false`.
        category:
          type: string
          maxLength: 32
        metadata:
          type: object
          additionalProperties: true
          description: Your own data for this line, at most 8 KB as JSON
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: Authorization
      description: >-
        Send your API key as `Authorization: ApiKey pc_<your-key>`. The API also
        accepts the key without the `ApiKey ` prefix. API keys authenticate
        requests to `/api/partner/v1/*`. Contact GroGov support to rotate your
        key or deactivate your API account. Rotation invalidates the previous
        key. Account deactivation blocks both API keys and access tokens.
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: >-
        Exchange your API key at `POST /api/partner/v1/auth/token` for a
        one-hour access token, then send `Authorization: Bearer <token>`. An
        access token cannot obtain another access token. When a token expires or
        is rejected, exchange your API key for a new one. Tokens authenticate
        requests only to `/api/partner/v1/*`.

````

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