Zero Hash Payins API

Power your checkout with crypto and stablecoins

Documentation

Specifications

Other Resources

OpenAPI Specification

zero-hash-payins-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: zerohash Payins API
  description: '

    ### Authentication


    zerohash Uses HMAC SHA-256 verification to ensure the authenticity of API requests, follow instructions by link [https://docs.zerohash.com/reference/api-authentication](https://docs.zerohash.com/reference/api-authentication)


    <a href="/zh-swagger.json">Download zerohash OpenAPI Schema as JSON</a>

    '
  version: 1.7.0
servers:
- url: https://api.cert.zerohash.com
  description: Certification API server
security:
- apiKey: []
  apiPassphrase: []
tags:
- name: Payins
  description: Power your checkout with crypto and stablecoins
paths:
  /pay/rfq:
    post:
      tags:
      - Payins
      summary: Request a payin quote
      description: "\nRetrieves a quote for a pay event for a given participant code and asset.\nThe response includes a deposit address and rate at which a subsequent on-chain deposit will be honored.\n\nThe quote has an expiry timestamp (`price_expire_ts`) — for volatile assets, the platform must execute the deposit before this time,\nor a new quote can be requested for the same payment to refresh the price.\nFor stablecoins, `price_expire_ts` will be `null`.\n\nThe `request_id` you send (via the `X-Request-Id` header) is the idempotency key for this endpoint: re-submitting the same `request_id` returns the existing active quote — same `transaction_id`, deposit address, and rate — instead of creating a new one.\n\nUse the returned `transaction_id` as the path parameter when calling `POST /pay/{id}/rfq` to refresh a quote.\n\nAfter the on-chain deposit settles or fails, a `crypto_pay_status_changed` webhook reports the outcome (`success` + `status_reason_code`).\n  "
      parameters:
      - $ref: '#/components/parameters/Signature'
      - $ref: '#/components/parameters/Timestamp'
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PostPayRfqBody'
      responses:
        '200':
          description: Pay quote created successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PostPayRfqResponse'
        '400':
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Code400'
        '401':
          description: 'The platform, jurisdiction, or asset is not enabled for the Pay product. The `{"error": ...}` body is one of "Your Platform is not configured to use the Pay product", "The State you live in is not authorized to use this product", or "Asset not enabled for pay".'
          content:
            application/json:
              schema:
                type: object
                required:
                - error
                properties:
                  error:
                    type: string
        '403':
          description: 'The transaction is not authorized. Possible causes: manual approval is required before this transaction can proceed (Level 4 shoppers — the body contains a transaction_id identifying the approval review), or the shopper has exceeded their daily spend limit at the current authorization level. A generic `{"error":"Transaction not authorized"}` body is returned when the transaction is hard-denied (no remediation).'
          content:
            application/json:
              schema:
                oneOf:
                - $ref: '#/components/schemas/PayinsAuthorizationManualApprovalError'
                - $ref: '#/components/schemas/PayinsAuthorizationLimitError'
                - $ref: '#/components/schemas/PayinsTransactionNotAuthorizedError'
        '404':
          description: Not Found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Code404'
        '409':
          description: Shopper KYC requirements are not met for this transaction.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PayinsAuthorizationKycError'
        '422':
          description: 'The transaction could not be authorized. The `{"error": ...}` body is either "Participant is not authorized to transact" (the participant/merchant relationship or state precludes authorization) or "Transaction not authorized" (the authorizer returned an unrecognized status).'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PayinsTransactionNotAuthorizedError'
        '500':
          description: Internal Server Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Code500'
        '503':
          description: Service Unavailable
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Code503'
  /pay/{id}/rfq:
    post:
      tags:
      - Payins
      summary: Refresh a payin quote
      description: "\nRefreshes an existing pay quote identified by its transaction ID.\nThis is used when a previously issued quote is near to expire and the platform wants a new rate for the same deposit address.\nAlready expired quotes can't be refreshed.\n\nThe response format is identical to `POST /pay/rfq` — it returns an updated rate, expiry timestamp, and the same deposit address.\n  "
      parameters:
      - $ref: '#/components/parameters/Signature'
      - $ref: '#/components/parameters/Timestamp'
      - name: id
        in: path
        description: The transaction ID (UUID) returned from the original POST /pay/rfq call
        required: true
        schema:
          type: string
          format: uuid
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PostPayRfqByIdBody'
      responses:
        '200':
          description: Pay quote refreshed successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PostPayRfqResponse'
        '400':
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Code400'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Code403'
        '404':
          description: Transaction not found
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: Transaction not found
        '500':
          description: Internal Server Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Code500'
        '503':
          description: Service Unavailable
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Code503'
  /pay/transactions:
    get:
      tags:
      - Payins
      summary: List payin transactions
      description: "\nRetrieves a paginated list of pay transactions for the authenticated platform.\nResults can be filtered by participant, asset, deposit status, and timestamps.\nEach deposit also emits a `crypto_pay_status_changed` webhook when it settles or fails.\n\n**Note:** Some filtering capabilities may not be available for all platforms. Contact support if you need access to additional filters.\n  "
      parameters:
      - $ref: '#/components/parameters/Signature'
      - $ref: '#/components/parameters/Timestamp'
      - name: participant_code
        in: query
        description: Filter by participant code (6-character alphanumeric)
        required: false
        schema:
          type: string
      - name: transaction_id
        in: query
        description: Filter by specific transaction ID (UUID format)
        required: false
        schema:
          type: string
      - name: client_reference_id
        in: query
        description: Filter by client-provided reference ID. This filter may not be available for all platforms. Contact support if you need access.
        required: false
        schema:
          type: string
      - name: pay_asset
        in: query
        description: Filter by the underlying crypto asset (e.g., BTC, ETH, USDC)
        required: false
        schema:
          type: string
      - name: deposit_address
        in: query
        description: Filter by the deposit address provided by zerohash for this payment.
        required: false
        schema:
          type: string
      - name: success
        in: query
        description: Filters transactions by successful status. This is a boolean field, please specify either `true` or `false`
        required: false
        schema:
          type: string
          enum:
          - 'true'
          - 'false'
      - name: page
        in: query
        description: Page number (1-indexed, max 5 digits)
        required: false
        schema:
          type: string
          pattern: ^[1-9][0-9]*$
      - name: page_size
        in: query
        description: The number of results returned per page, with a maximum of 50 transactions per page
        required: false
        schema:
          type: string
          pattern: ^[1-9][0-9]*$
      - name: deposit_timestamp_gte
        in: query
        description: Deposit timestamp greater than or equal to this value (inclusive). Unix milliseconds (13-19 digits). This filter may not be available for all platforms. Contact support if you need access.
        required: false
        schema:
          type: string
      - name: deposit_timestamp_gt
        in: query
        description: Deposit timestamp strictly greater than this value (exclusive). Unix milliseconds (13-19 digits). This filter may not be available for all platforms. Contact support if you need access.
        required: false
        schema:
          type: string
      - name: deposit_timestamp_lt
        in: query
        description: Deposit timestamp strictly less than this value (exclusive). Unix milliseconds (13-19 digits). This filter may not be available for all platforms. Contact support if you need access.
        required: false
        schema:
          type: string
      - name: deposit_timestamp_lte
        in: query
        description: Deposit timestamp less than or equal to this value (inclusive). Unix milliseconds (13-19 digits). This filter may not be available for all platforms. Contact support if you need access.
        required: false
        schema:
          type: string
      - name: merchant_participant_code
        in: query
        description: Filter by merchant participant code.
        required: false
        schema:
          type: string
      responses:
        '200':
          description: List of pay transactions with pagination metadata
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/GetPayTransactionsResponse'
        '400':
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Code400'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Code403'
        '404':
          description: Not Found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Code404'
        '500':
          description: Internal Server Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Code500'
        '503':
          description: Service Unavailable
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Code503'
  /pay/limits:
    get:
      tags:
      - Payins
      summary: Get payin authorization limits
      description: "\nRetrieves the current authorization level, per-window limits, and volume totals for an\nend-user participant on the authenticated platform. Optionally scoped to a specific\nmerchant when `merchant_participant_code` is supplied (the authenticated platform must\noperate for that merchant).\n  "
      parameters:
      - $ref: '#/components/parameters/Signature'
      - $ref: '#/components/parameters/Timestamp'
      - name: participant_code
        in: query
        description: End-user participant code (6-character alphanumeric).
        required: true
        schema:
          type: string
      - name: merchant_participant_code
        in: query
        description: Optional merchant participant code. When supplied, the response also includes `merchant_totals` (volume totals aggregated against that merchant). The authenticated platform must operate for the merchant or the request is rejected.
        required: false
        schema:
          type: string
      responses:
        '200':
          description: Platform and (optionally) merchant payin limits.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/GetPayLimitsResponse'
        '400':
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Code400'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Code403'
        '404':
          description: Not Found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Code404'
        '500':
          description: Internal Server Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Code500'
        '503':
          description: Service Unavailable
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Code503'
  /pay/{id}/approval:
    delete:
      tags:
      - Payins
      summary: Cancel a pending manual approval
      description: "\nCancels a pending or approved manual approval for a Tier 4 payin transaction,\nsetting it to REJECTED state.\n\nUse this endpoint when a platform or shopper wants to withdraw a transaction\nthat is awaiting compliance review. Once cancelled, the transaction cannot\nbe reinstated — a new `POST /pay/rfq` must be issued.\n\nThe `merchant_code` query parameter is optional. When omitted, the\nauthenticated platform code is used as the merchant identifier.\n  "
      parameters:
      - $ref: '#/components/parameters/Signature'
      - $ref: '#/components/parameters/Timestamp'
      - name: id
        in: path
        description: Transaction id of the manual approval to cancel.
        required: true
        schema:
          type: string
      - name: participant_code
        in: query
        description: End-user participant (shopper) code whose approval to cancel.
        required: true
        schema:
          type: string
      - name: merchant_code
        in: query
        description: Merchant participant code associated with the approval. Defaults to the authenticated platform code when omitted.
        required: false
        schema:
          type: string
      responses:
        '204':
          description: Approval successfully cancelled.
        '400':
          description: Approval is already in a terminal state (FINALIZED or REJECTED) and cannot be cancelled (authorizer FAILED_PRECONDITION). The body carries the error message.
          content:
            application/json:
              schema:
                type: object
                required:
                - error
                properties:
                  error:
                    type: string
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Code403'
        '404':
          description: No cancellable approval found for the given transaction ID and participant.
          content:
            application/json:
              schema:
                type: object
                required:
                - error
                properties:
                  error:
                    type: string
        '500':
          description: Internal Server Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Code500'
        '503':
          description: Service Unavailable
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Code503'
components:
  schemas:
    PayinsTransactionNotAuthorizedError:
      type: object
      required:
      - error
      properties:
        error:
          type: string
          example: Transaction not authorized
          description: Generic authorization denial with no remediation. Returned with HTTP 403 — `{"error":"Transaction not authorized"}` when the authorizer rejection has no specific mapping or reports no missing fields, or `{"error":"Transaction not permitted"}` when the participant is not permitted to transact (e.g. geographic restriction) — and with HTTP 422 (`{"error":"Participant is not authorized to transact"}`) when the participant/merchant context precludes authorization.
    PostPayRfqByIdBody:
      type: object
      required:
      - participant_code
      properties:
        participant_code:
          type: string
          description: The participant code for the shopper whose quote is being refreshed
          example: ABCDEF
    GetPayLimitsResponse:
      type: object
      properties:
        message:
          type: object
          properties:
            request_id:
              type: string
              description: The unique identifier echoed from the request.
              example: test-request-id
            participant_code:
              type: string
              description: The shopper participant code.
              example: SHOPP1
            merchant_participant_code:
              type: string
              description: The merchant participant code.
              example: MERCH1
            merchant_classification:
              type: string
              description: Classification of the merchant (e.g. NON-TRANSFERABLE-3).
              example: NON-TRANSFERABLE-3
            current_level:
              type: integer
              description: Current authorization level for this participant (1–4).
              example: 2
            current_limits:
              type: array
              description: Authorization limits for each time window at the current level.
              items:
                $ref: '#/components/schemas/PayCurrentLimit'
            platform_totals:
              type: array
              description: Aggregated transaction volume totals across the platform.
              items:
                $ref: '#/components/schemas/PayVolumeTotal'
            merchant_totals:
              type: array
              description: Aggregated transaction volume totals for the merchant.
              items:
                $ref: '#/components/schemas/PayVolumeTotal'
    PayFeeTierBreakdown:
      type: object
      description: Breakdown of how the fee was calculated across tiers.
      properties:
        tier:
          type: number
          description: The tier number (1-based).
          example: 1
        amount_in_tier:
          type: string
          description: The deposit amount that fell into this tier.
          example: '100.00'
        fee_bps:
          type: string
          description: The fee rate in basis points applied for this tier.
          example: '40'
        fee_amount:
          type: string
          description: The fee amount calculated for this tier.
          example: '0.40'
    Code503:
      type: object
      description: 'A downstream dependency was unavailable, timed out, or returned a retryable error. Safe to retry; the response carries a `zh-allow-retry: true` header.'
      required:
      - error
      properties:
        error:
          type: string
          example: Service Unavailable
    Code404:
      type: object
      description: The requested resource does not exist or is not visible to the caller.
      required:
      - error
      properties:
        error:
          type: string
          example: Not Found
    PayinsAuthorizationManualApprovalError:
      type: object
      required:
      - error
      - transaction_id
      properties:
        error:
          type: string
          example: Manual approval required for this transaction
          description: 'Human-readable error message. Possible values: "Manual approval required for this transaction" (no approval on file yet), "Approval pending, shopper must wait" (an approval request is already in review), "Manual approval for this transaction was rejected" (the approval was rejected by compliance or the platform), or "Manual approval for this transaction has already been finalized" (the approval was already consumed).'
        transaction_id:
          type: string
          example: txn_01HZF7QWXJ8XK3VYNS6TKDM4G2
          description: Identifier of the manual approval review. Persist this and re-use it when checking approval status or cancelling the request.
    PayVolumeTotal:
      type: object
      properties:
        window:
          type: string
          description: The time window for this total.
          enum:
          - daily
          - annual
          - lifetime
          example: daily
        currency:
          type: string
          description: Currency of the total amount.
          example: USD
        total_amount:
          type: string
          description: Total transacted amount in this window, expressed as a decimal string.
          example: '5000.00'
        transaction_count:
          type: integer
          description: Number of transactions in this window.
          example: 12
    PostPayRfqBody:
      type: object
      required:
      - participant_code
      - pay_asset
      - quoted_total
      - quoted_currency
      properties:
        participant_code:
          type: string
          description: The participant code for the shopper making the payment
          example: ABCDEF
        pay_asset:
          type: string
          description: The cryptocurrency asset to be deposited (e.g., BTC, ETH, USDC)
          example: BTC
        quoted_total:
          type: string
          description: The total fiat amount the shopper is paying
          example: '100.00'
        quoted_currency:
          type: string
          description: The fiat currency for the payment. Currently only USD is supported
          enum:
          - USD
          example: USD
        account_label:
          type: string
          maxLength: 20
          description: Optional account label for the transaction. Defaults to "pay"
          example: pay
        client_reference_id:
          type: string
          maxLength: 50
          description: An optional client-provided reference ID for tracking purposes
          example: order-12345
        merchant_participant_code:
          type: string
          minLength: 1
          maxLength: 50
          description: Optional participant code of the merchant tied to this transaction. When omitted, the platform itself is treated as the merchant.
          example: MERCH01
    PayinsAuthorizationKycError:
      type: object
      required:
      - error
      - missing_requirements
      properties:
        error:
          type: string
          example: Shopper KYC requirements for this transaction are not met
          description: Human-readable error message indicating the shopper is missing required KYC data for the requested transaction.
        missing_requirements:
          type: array
          items:
            type: string
          example:
          - first_name
          - last_name
          - date_of_birth
          description: List of participant fields that must be collected or updated for the shopper to pass authorization at the requested amount and merchant MCC tier.
    Code403:
      type: object
      description: Authentication or authorization failed. `error` is always `true`; `message` explains which check failed (missing API key, bad signature, insufficient permission, etc.).
      required:
      - error
      - message
      properties:
        error:
          type: boolean
          example: true
        message:
          type: string
          example: This api key does not have write permission to this endpoint
    GetPayTransactionsResponse:
      type: object
      properties:
        message:
          type: array
          description: Array of pay transactions
          items:
            $ref: '#/components/schemas/PayTransaction'
        page:
          type: integer
          format: int32
          description: Current page number (1-indexed)
          example: 1
        page_size:
          type: integer
          format: int32
          description: Number of items per page (capped at 50)
          example: 50
        total_pages:
          type: integer
          format: int32
          description: Total number of pages available
          example: 1
    Code500:
      type: object
      description: An unexpected error occurred on the server. The request can be retried after a short delay, but the same inputs may reproduce the error.
      required:
      - error
      properties:
        error:
          type: string
          example: Internal Server Error
    PayinsAuthorizationLimitError:
      type: object
      required:
      - error
      properties:
        error:
          type: string
          example: Shopper's Daily Spend Limit for this type of transaction have been hit.
          description: Returned with a 403 status when the shopper has exceeded their daily or lifetime spend aggregate at the current authorization level. Lifting the limit requires manual review.
    PayCurrentLimit:
      type: object
      properties:
        limit:
          type: string
          description: The authorized limit for this window, expressed as a decimal string.
          example: '1000.00'
        spent:
          type: string
          description: Amount spent within this window, expressed as a decimal string.
          example: '250.00'
        remaining:
          type: string
          description: Remaining capacity within this window, expressed as a decimal string.
          example: '750.00'
        window:
          type: string
          description: The time window this limit applies to.
          enum:
          - daily
          - annual
          - lifetime
          example: daily
    PayTransaction:
      type: object
      properties:
        participant_code:
          type: string
          description: The shopper participant code.
          example: ABCDEF
        pay_asset:
          type: string
          description: Cryptocurrency asset being paid with (e.g., BTC, ETH, USDC).
          example: BTC
        rate:
          type: string
          description: Conversion rate applied at execution time.
          example: '65658.42'
        quoted_currency:
          type: string
          description: Fiat currency for the payment.
          example: USD
        source_address:
          type: string
          description: Sender's wallet address that originated the deposit.
          example: '0xA32A6aA6a3B87b49BeaB01393e2020C3C191CD61'
        deposit_address:
          type: string
          description: Wallet address where the crypto was sent.
          example: bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh
        quantity:
          type: string
          description: Crypto quantity deposited.
          example: '0.00152307'
        notional:
          type: string
          description: Fiat value of the deposit in `quoted_currency`.
          example: '100.00'
        success:
          type: boolean
          description: Whether the payment completed successfully.
          example: true
        status_reason:
          type: string
          description: Human-readable failure reason. Empty string if successful.
          example: ''
        status_reason_code:
          type: string
          description: 'Machine-readable code describing the outcome of the payment. Examples: `DEPOSIT_PROCESSED`, `AMOUNT_ABOVE_MAXIMUM`, `AMOUNT_BELOW_MINIMUM`.'
          example: AMOUNT_ABOVE_MAXIMUM
        fund_timestamp:
          type: number
          description: Unix timestamp in milliseconds indicating when the payment quote was created.
          example: 1712756400000
        deposit_timestamp:
          type: number
          description: Unix timestamp in milliseconds indicating when the blockchain deposit was detected.
          example: 1712756700000
        transaction_id:
          type: string
          description: On-chain transaction identifier associated with the deposit.
          example: '0x408482348dcb0e0331a9148d50f8c76db08138f63fb1586fcfc45200a91ccc5f'
        account_label:
          type: string
          description: The account label that received the payment. Defaults to `pay` for pay transactions.
          example: pay
        fund_id:
          type: string
          format: uuid
          description: zerohash-generated unique identifier for this payment event.
          example: 29e6d7b8-d604-4212-86ee-998fef35505e
        is_first_deposit:
          type: boolean
          description: Indicates whether this was the participant's first deposit (used for first-deposit fee treatment).
          example: false
        raw_fee_bps:
          type: string
          description: Initial fee rate expressed in basis points.
          example: '50'
        deposit_fee_bps:
          type: string
          description: Effective fee rate in basis points that was actually applied after any minimum floors were considered.
          example: '50'
        raw_fee_notional:
          type: string
          description: Initial fee amount calculated directly from `raw_fee_bps`, in `quoted_currency`.
          example: '0.50'
        deposit_fee_notional:
          type: string
          description: Final fee amount actually charged to the participant, in `quoted_currency`.
          example: '0.50'
        deposited_asset:
          type: string
          description: Actual asset deposited on-chain. May differ from `pay_asset` when cross-chain fallback occurred.
          example: BTC
        reference_id:
          type: string
          description: The client-provided reference identifier for this payment, or empty string if none was supplied.
          example: order-12345
        source:
          $ref: '#/components/schemas/PayTransactionSource'
        deposit_fee_type:
          type: string
          description: The fee model applied to this transaction.
          enum:
          - flat
          - tiered
          example: flat
        fee_tier_breakdown:
          type: array
          description: Breakdown of how the fee was calculated across tiers. Only present when `deposit_fee_type` is `tiered`.
          items:
            $ref: '#/components/schemas/PayFeeTierBreakdown'
        merchant_participant_code:
          type: string
          description: The merchant participant code associated with this payment. Only present when a merchant is linked to the transaction.
          example: MERCH01
    Code400:
      type: object
      description: Request was rejected by validation or a downstream service. `errors` is an array of human-readable messages; each entry describes a single validation failure or business-rule violation.
      required:
      - errors
      properties:
        errors:
          type: array
          items:
            type: string
          example:
          - body/amount must be >= 0
          - body/asset is required
    PayTransactionSource:
      type: object
      description: Source of the auth transaction. Only present if Auth Embedded is enabled for the platform.
      properties:
        type:
          type: string
          description: Type of transaction source.
          enum:
          - CUSTO

# --- truncated at 32 KB (35 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/zero-hash/refs/heads/main/openapi/zero-hash-payins-api-openapi.yml