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

# Integration pattern

> Copy a minimal roll.codes consumer that requests randomness, stores request state, and settles safely in the callback.

Use this pattern as the starting point for most Solidity integrations against the hosted roll.codes coordinator.

## What this example shows

* requesting one random number
* storing request metadata keyed by `requestId`
* authenticating the callback caller
* rejecting unknown or already-settled requests

## Minimal consumer

```solidity theme={null}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import {IVRFSystem} from "@rollcodes/interfaces/IVRFSystem.sol";
import {IVRFSystemCallback} from "@rollcodes/interfaces/IVRFSystemCallback.sol";

contract ExampleConsumer is IVRFSystemCallback {
    error Unauthorized();
    error RequestNotFound(uint256 requestId);
    error AlreadySettled(uint256 requestId);

    IVRFSystem public immutable vrfSystem;

    struct Pending {
        address player;
        bool settled;
        uint256 randomNumber;
    }

    mapping(uint256 => Pending) public pendingByRequestId;

    constructor(address coordinatorAddress) {
        vrfSystem = IVRFSystem(coordinatorAddress);
    }

    function play() external payable returns (uint256 requestId) {
        uint256 fee = vrfSystem.requestFee();
        require(msg.value == fee, "fee mismatch");

        uint256 traceId = 0;
        requestId = vrfSystem.requestRandomNumberWithTraceId{ value: fee }(traceId);

        pendingByRequestId[requestId] = Pending({
            player: msg.sender,
            settled: false,
            randomNumber: 0
        });
    }

    function randomNumberCallback(uint256 requestId, uint256 randomNumber) external override {
        if (msg.sender != address(vrfSystem)) revert Unauthorized();

        Pending storage p = pendingByRequestId[requestId];
        if (p.player == address(0)) revert RequestNotFound(requestId);
        if (p.settled) revert AlreadySettled(requestId);

        p.settled = true;
        p.randomNumber = randomNumber;

        // settle your game or app logic here
    }
}
```

## Required guards

<Steps>
  <Step title="Authorize the callback">
    Reject any callback where `msg.sender` is not the configured coordinator.
  </Step>

  <Step title="Validate the request ID">
    Reject callbacks for request IDs that were never created or already settled.
  </Step>

  <Step title="Keep settlement deterministic">
    Persist state and derive outcomes without unnecessary branches or external calls.
  </Step>
</Steps>

## Why the request is stored after creation

The request and callback happen in separate transactions. As soon as `requestRandomNumberWithTraceId` returns, store the metadata you will need later to settle the request.

Typical fields include:

* player or account
* match or session ID
* user choice or wager
* settled flag

## Implementation notes

<Tip>
  Derive bounded outcomes such as dice rolls inside the callback from the delivered `randomNumber`. Do not try to precompute outcomes before the request exists.
</Tip>

<Tip>
  Same-round deliveries share the same base `randomNumber`. If you need distinct values per request inside that window, derive them locally, for example with `uint256(keccak256(abi.encodePacked(requestId, randomNumber)))`.
</Tip>

<Warning>
  If your callback reverts, delivery fails and the request will not be marked as settled in your consumer. Keep the callback small enough to succeed reliably.
</Warning>

## Next steps

<CardGroup cols={2}>
  <Card title="Consumer patterns" icon="dice-5" href="/contracts/consumer-patterns">
    See common mappings from request IDs to users, rounds, and outcomes.
  </Card>

  <Card title="Coordinator reference" icon="file-text" href="/contracts/coordinator-reference">
    Look up the exact function signatures and config fields used in this example.
  </Card>

  <Card title="Callback security" icon="shield-check" href="/concepts/callback-security">
    Review the callback guardrails before adapting the example to production logic.
  </Card>

  <Card title="Troubleshooting" icon="life-buoy" href="/faq/troubleshooting">
    Diagnose fee mismatches, unauthorized callbacks, and pending requests.
  </Card>
</CardGroup>
