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

# Test the provisioning endpoint

> Dry-runs the external provisioning call against a reward whose
`digital_asset_source` is `external`. It creates no redemption, moves no
points and charges no fee — but it is a **real signed request** to your
endpoint, sent with `test: true` in the body, so return a throwaway
value rather than burning stock.

**The response is HTTP 200 even when the test failed** — `ok` is the real
result, with `error_code` / `error` explaining a failure and
`request_preview` showing the exact body that was signed. Pass a `url` to
try an endpoint you have not saved yet.




## OpenAPI

````yaml /openapi/v1.yaml post /api/v1/rewards/{id}/webhook/test
openapi: 3.1.0
info:
  title: Rigaly Business API
  version: '1.0'
  description: |
    Public API for businesses to manage their Rigaly loyalty programs: issue
    and redeem points, manage rewards, validate redemptions, and generate mass
    codes for physical products.

    All endpoints require an API key created in the Rigaly business dashboard
    (Tools → API Management), passed as `Authorization: Bearer rgly_sk_...`.
  contact:
    email: support@rigaly.com
servers:
  - url: https://api.rigaly.com
    description: Production
security:
  - apiKey: []
paths:
  /api/v1/rewards/{id}/webhook/test:
    post:
      tags:
        - Rewards
      summary: Test the provisioning endpoint
      description: >
        Dry-runs the external provisioning call against a reward whose

        `digital_asset_source` is `external`. It creates no redemption, moves no

        points and charges no fee — but it is a **real signed request** to your

        endpoint, sent with `test: true` in the body, so return a throwaway

        value rather than burning stock.


        **The response is HTTP 200 even when the test failed** — `ok` is the
        real

        result, with `error_code` / `error` explaining a failure and

        `request_preview` showing the exact body that was signed. Pass a `url`
        to

        try an endpoint you have not saved yet.
      operationId: testRewardWebhook
      parameters:
        - $ref: '#/components/parameters/ResourceId'
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WebhookTestSubject'
      responses:
        '200':
          description: Test completed — check `ok`, not the status code
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessEnvelope'
                  - type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/WebhookTestResult'
              example:
                success: true
                message: Endpoint responded correctly
                data:
                  ok: true
                  http_status: 200
                  latency_ms: 148
                  asset:
                    type: code
                    value: TEST-XYZ123
                    expires_at: null
                  error_code: null
                  error: null
                  request_preview:
                    event: reward.provision
                    test: true
                    idempotency_key: test_9f1c3a2e-5b7d-4e21-9a0c-1f2d3e4b5a67
                    redemption_id: null
                    reward_id: 3f2b1c9e-7d4a-4f1b-8c2e-9a0d1e2f3b4c
                    business_id: 7a8b9c0d-1e2f-3a4b-5c6d-7e8f9a0b1c2d
                    user_id: null
                    asset_type: code
                    requested_at: '2026-08-05T12:00:00.000Z'
        '400':
          description: >-
            The reward is not externally sourced
            (`REWARD_NOT_EXTERNALLY_SOURCED`)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
              example:
                success: false
                error:
                  message: REWARD_NOT_EXTERNALLY_SOURCED
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          description: >-
            No endpoint or no signing secret is configured
            (`DIGITAL_WEBHOOK_NOT_CONFIGURED`)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
              example:
                success: false
                error:
                  message: DIGITAL_WEBHOOK_NOT_CONFIGURED
components:
  parameters:
    ResourceId:
      name: id
      in: path
      required: true
      schema:
        type: string
        format: uuid
  schemas:
    WebhookTestSubject:
      type: object
      description: Optional override for the endpoint to test.
      properties:
        url:
          type: string
          format: uri
          maxLength: 500
          example: https://staging.example.com/rigaly/provision
          description: >-
            HTTPS URL to call instead of the reward's saved
            `digital_webhook_url`. Handy for testing a new endpoint before
            saving it. The reward's existing signing secret is used either way.
    SuccessEnvelope:
      type: object
      properties:
        success:
          type: boolean
          example: true
        message:
          type: string
        data:
          type: object
    WebhookTestResult:
      type: object
      description: |
        Outcome of one dry-run call. The endpoint responds **HTTP 200 even when
        the test failed** — read `ok`, not the status code. A failing test never
        creates a redemption, never moves points, and never trips the reward's
        circuit breaker.
      properties:
        ok:
          type: boolean
          example: true
          description: >-
            The real result: true only when the endpoint returned 2xx **and** a
            valid asset.
        http_status:
          type: integer
          nullable: true
          example: 200
          description: >-
            Status your endpoint returned. `null` when nothing was reached (DNS
            failure, timeout, blocked address).
        latency_ms:
          type: integer
          example: 148
          description: Round-trip time. The production timeout is 5000 ms.
        asset:
          type: object
          allOf:
            - $ref: '#/components/schemas/DigitalAsset'
          nullable: true
          description: >-
            The value your endpoint minted, once validated. `null` when the test
            failed. Test calls send `test: true` — do not burn a real code on
            them.
        error_code:
          type: string
          nullable: true
          example: type_mismatch
          description: >
            Machine-readable failure reason: `timeout`, `network`,
            `http_status`,

            `malformed_response`, `type_mismatch`, `expired_asset`,

            `circuit_open`, `ssrf_scheme`, `ssrf_private_host`,

            `ssrf_private_address`, `ssrf_credentials`, `ssrf_dns`,

            `ssrf_invalid_url`, `unknown`. `null` when `ok` is true.
        error:
          type: string
          nullable: true
          example: Endpoint returned type 'link' but the reward delivers 'code'
          description: >-
            Human-readable explanation. Your endpoint's own response body is
            never echoed back.
        request_preview:
          type: object
          description: >-
            The exact payload that was signed and sent, field for field — check
            it against what your handler received when a signature won't verify.
    ErrorEnvelope:
      type: object
      properties:
        success:
          type: boolean
          example: false
        error:
          type: object
          properties:
            message:
              type: string
    DigitalAsset:
      type: object
      description: |
        The code or link a customer receives for a digital reward. Snapshotted
        onto the redemption the moment it is secured, so editing the reward
        afterwards never rewrites what someone already got.
      properties:
        type:
          type: string
          enum:
            - code
            - link
          example: code
        value:
          type: string
          maxLength: 500
          example: NETFLIX-XYZ123
        expires_at:
          type: string
          format: date-time
          nullable: true
          example: '2026-12-31T23:59:59Z'
          description: >
            When the delivered value itself stops working — distinct from the

            redemption code's own expiry. `null` for `static` and `pool`
            sources;

            set only when an `external` endpoint returned one, and it must be in

            the future. Persisted on the redemption as

            `delivered_asset_expires_at` and shown to the customer in the app.
  responses:
    NotFound:
      description: Resource not found (or belongs to another business)
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
          example:
            success: false
            error:
              message: Reward not found
  securitySchemes:
    apiKey:
      type: http
      scheme: bearer
      description: 'API key from the Rigaly dashboard: `Authorization: Bearer rgly_sk_...`'

````