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

# The Giving Block

> Connect to The Giving Block to accept cryptocurrency payments.

export const connector = {
  displayName: "The Giving Block",
  method: "givingblock",
  features: "create_session create_transaction direct_capture redirect_requires_popup requires_webhook_setup transaction_sync verify_credentials",
  supportedCountries: "GB US",
  supportedCurrencies: "GBP USD"
};

export const ConnectorRegions = ({data, kind, name: nameOverride}) => {
  const [query, setQuery] = useState("");
  const [open, setOpen] = useState(false);
  const isCountries = kind === "countries";
  const raw = data && (isCountries ? data.supportedCountries : data.supportedCurrencies);
  const codes = typeof raw === "string" ? raw.split(/\s+/).filter(Boolean) : Array.isArray(raw) ? raw : [];
  const DISPLAY_NAME_OVERRIDES = {
    authorizenet: "Authorize.net",
    cardpointe: "Fiserv CardPointe",
    dlocal: "dLocal",
    shift4i4go: "Shift4 i4go",
    tokenex: "TokenEx"
  };
  const rawName = data && data.displayName || "";
  const name = nameOverride || DISPLAY_NAME_OVERRIDES[rawName.toLowerCase()] || rawName || "This connector";
  const verb = isCountries ? "supports transactions from buyers in" : "supports processing payments in";
  const noun = isCountries ? "countries" : "currencies";
  if (codes.length === 0) return null;
  let displayNames = null;
  try {
    displayNames = new Intl.DisplayNames(["en"], {
      type: isCountries ? "region" : "currency"
    });
  } catch (e) {
    displayNames = null;
  }
  const resolve = code => {
    if (!displayNames) return null;
    try {
      const resolved = displayNames.of(code);
      return resolved && resolved !== code ? resolved : null;
    } catch (e) {
      return null;
    }
  };
  const MAJOR_CURRENCIES = ["USD", "EUR", "GBP", "CAD", "AUD", "JPY", "CHF", "CNY", "SGD", "HKD", "NZD", "SEK", "NOK", "DKK", "MXN", "BRL", "INR"];
  const items = codes.map(code => ({
    code,
    label: resolve(code)
  }));
  if (isCountries) {
    items.sort((a, b) => (a.label || a.code).localeCompare(b.label || b.code));
  } else {
    const rank = code => {
      const i = MAJOR_CURRENCIES.indexOf(code);
      return i === -1 ? MAJOR_CURRENCIES.length : i;
    };
    items.sort((a, b) => rank(a.code) - rank(b.code) || a.code.localeCompare(b.code));
  }
  if (codes.length <= 3) {
    const parts = items.map(it => isCountries || !it.label ? it.label || it.code : `${it.label} (${it.code})`);
    const joined = parts.length === 1 ? parts[0] : parts.length === 2 ? `${parts[0]} and ${parts[1]}` : `${parts.slice(0, -1).join(", ")}, and ${parts[parts.length - 1]}`;
    return <p>
        {name} {verb} {joined}.
      </p>;
  }
  const chipStyle = {
    display: "inline-flex",
    alignItems: "baseline",
    gap: "0.4rem",
    padding: "0.15rem 0.55rem",
    borderRadius: "0.375rem",
    border: "1px solid rgba(128, 128, 128, 0.25)",
    fontSize: "0.875rem",
    lineHeight: 1.5
  };
  const codeStyle = {
    fontFamily: "var(--font-mono, ui-monospace, monospace)",
    fontWeight: 600,
    fontSize: "0.8125rem"
  };
  const controlStyle = {
    color: "inherit",
    background: "transparent",
    border: "1px solid rgba(128, 128, 128, 0.3)",
    borderRadius: "0.5rem",
    fontSize: "0.875rem"
  };
  const renderChip = it => <span key={it.code} style={chipStyle} title={isCountries ? it.code : it.label || it.code}>
      {isCountries ? it.label || it.code : <span style={codeStyle}>{it.code}</span>}
      {!isCountries && it.label ? <span style={{
    opacity: 0.7
  }}>{it.label}</span> : null}
    </span>;
  const PREVIEW = 5;
  const collapsible = items.length > PREVIEW;
  const q = query.trim().toLowerCase();
  const filtered = q ? items.filter(it => it.code.toLowerCase().includes(q) || it.label && it.label.toLowerCase().includes(q)) : items;
  const expanded = open || q !== "";
  const visible = !collapsible ? items : expanded ? filtered : items.slice(0, PREVIEW);
  const toggle = () => {
    const next = !open;
    setOpen(next);
    if (!next) setQuery("");
  };
  return <div>
      <p>
        {name} {verb} the following {codes.length} {noun}:
      </p>

      {collapsible ? <input type="text" value={query} onChange={e => setQuery(e.target.value)} placeholder={`Filter ${noun}…`} aria-label={`Filter ${noun}`} style={{
    ...controlStyle,
    display: "block",
    width: "100%",
    maxWidth: "22rem",
    padding: "0.4rem 0.7rem",
    margin: "0 0 0.75rem"
  }} /> : null}

      <div style={{
    display: "flex",
    flexWrap: "wrap",
    gap: "0.4rem"
  }}>
        {visible.map(renderChip)}
      </div>

      {q && filtered.length === 0 ? <p style={{
    opacity: 0.7,
    marginTop: "0.6rem"
  }}>
          No {noun} match “{query.trim()}”.
        </p> : null}
      {q && filtered.length > 0 ? <p style={{
    opacity: 0.6,
    fontSize: "0.8125rem",
    marginTop: "0.6rem"
  }}>
          Showing {filtered.length} of {items.length}.
        </p> : null}

      {collapsible && !q ? <button type="button" aria-expanded={open} onClick={toggle} style={{
    ...controlStyle,
    display: "inline-flex",
    alignItems: "center",
    gap: "0.4rem",
    padding: "0.35rem 0.75rem",
    marginTop: "0.75rem",
    cursor: "pointer"
  }}>
          <span aria-hidden="true" style={{
    display: "inline-block",
    transform: open ? "rotate(90deg)" : "none",
    transition: "transform 0.15s ease"
  }}>
            ›
          </span>
          {open ? "Show fewer" : `and ${items.length - PREVIEW} more`}
        </button> : null}
    </div>;
};

export const ConnectorCapabilities = ({data}) => {
  const CAPABILITIES = [{
    keys: ["three_d_secure_hosted"],
    label: "3-D Secure (hosted)",
    description: "Gr4vy-hosted 3DS authentication flow.",
    cardOnly: true
  }, {
    keys: ["three_d_secure_pass_through"],
    label: "3-D Secure (pass-through)",
    description: "Pass through 3DS data authenticated by a third party.",
    cardOnly: true
  }, {
    keys: ["partial_authorization"],
    label: "Partial authorization",
    description: "Support partial approval responses."
  }, {
    keys: ["zero_auth"],
    label: "Zero auth",
    description: "Verify a card without charging it."
  }, {
    keys: ["void"],
    label: "Void",
    description: "Cancel an authorized transaction before capture."
  }, {
    keys: ["direct_capture"],
    label: "Direct capture",
    description: "Capture a payment immediately at authorization.",
    hideWhenUnsupported: true
  }, {
    keys: ["delayed_capture"],
    label: "Delayed capture",
    description: "Authorize a payment and capture it at a later time."
  }, {
    keys: ["partial_capture"],
    label: "Partial capture",
    description: "Capture a portion of the authorized amount."
  }, {
    keys: ["over_capture"],
    label: "Over capture",
    description: "Capture more than the originally authorized amount."
  }, {
    keys: ["refunds"],
    label: "Refunds",
    description: "Refund a captured payment."
  }, {
    keys: ["partial_refunds"],
    label: "Partial refunds",
    description: "Refund a portion of the captured amount."
  }, {
    keys: ["settlement_reporting"],
    label: "Settlement reporting",
    description: "Automatic settlement and reconciliation reporting."
  }, {
    keys: ["create_session"],
    label: "Create session",
    description: "Create a connector session for client-side flows."
  }, {
    keys: ["network_tokens_default", "network_tokens_toggle"],
    label: "Network tokens",
    description: "Network-level tokenization for improved approval rates.",
    cardOnly: true
  }, {
    keys: ["digital_wallets"],
    label: "Digital wallets",
    description: "Apple Pay, Google Pay, and other wallet integrations."
  }, {
    keys: ["payment_method_tokenization", "payment_method_tokenization_toggle"],
    label: "Payment method tokenization",
    description: "Store payment methods outside of transactions."
  }, {
    keys: ["transaction_sync"],
    label: "Transaction sync",
    description: "Synchronize transaction state from the connector."
  }, {
    keys: ["create_token"],
    label: "Tokenization",
    description: "Create a token from card details collected via Secure Fields.",
    hideWhenUnsupported: true
  }, {
    keys: ["delete_token"],
    label: "Delete token",
    description: "Delete a stored token.",
    hideWhenUnsupported: true
  }, {
    keys: ["verify_credentials"],
    label: "Verify credentials",
    description: "Validate the configured credentials against the connector.",
    hideWhenUnsupported: true
  }];
  const raw = data && data.features;
  const enabled = typeof raw === "string" ? new Set(raw.split(/\s+/).filter(Boolean)) : Array.isArray(raw) ? new Set(raw) : new Set(Object.keys(raw || ({})).filter(key => raw[key]));
  const isOn = entry => entry.keys.some(key => enabled.has(key));
  const isNonCard = data && data.method && data.method !== "card";
  const renderGroup = (title, entries, supported) => {
    if (entries.length === 0) return null;
    const mark = supported ? "✓" : "✕";
    const markColor = supported ? "#16a34a" : "#9ca3af";
    return <div style={{
      marginTop: "1rem"
    }}>
        <div style={{
      fontSize: "0.75rem",
      fontWeight: 600,
      letterSpacing: "0.05em",
      textTransform: "uppercase",
      opacity: 0.6,
      marginBottom: "0.25rem"
    }}>
          {title}
        </div>
        {}
        <div role="list">
          {entries.map(entry => <div role="listitem" key={entry.label} style={{
      display: "flex",
      gap: "0.5rem",
      alignItems: "baseline",
      padding: "0.3rem 0",
      opacity: supported ? 1 : 0.7
    }}>
              <span aria-hidden="true" style={{
      color: markColor,
      fontWeight: 700,
      flexShrink: 0
    }}>
                {mark}
              </span>
              <span>
                <strong>{entry.label}</strong>
                {entry.description ? <span style={{
      opacity: 0.85
    }}> — {entry.description}</span> : null}
              </span>
            </div>)}
        </div>
      </div>;
  };
  const visible = isNonCard ? CAPABILITIES.filter(entry => !entry.cardOnly) : CAPABILITIES;
  const supported = visible.filter(isOn);
  const unsupported = visible.filter(entry => !isOn(entry) && !entry.hideWhenUnsupported);
  return <div>
      {renderGroup("Supported", supported, true)}
      {renderGroup("Not supported", unsupported, false)}
    </div>;
};

The Giving Block enables cryptocurrency fundraising for nonprofits, charities, universities, and faith-based organizations. It uses a redirect flow where the buyer completes the crypto payment on The Giving Block hosted page.

## Setup

The Giving Block does not provide self-service sign-up. [Contact their sales team](https://thegivingblock.com) to set up an account.

## Credentials

When setting up The Giving Block in the dashboard, configure the following credentials:

* **Login** - The API login username. This is different from the dashboard login.
* **Password** - The API password. This is different from the dashboard password.
* **Encryption key** - Used to decrypt webhooks sent from The Giving Block.
* **Encryption IV** - Used alongside the encryption key to decrypt webhooks.
* **USD Organisation ID** (optional) - The organization ID for processing USD transactions. Found in The Giving Block dashboard under **Organizations**.
* **GBP Organisation ID** (optional) - The organization ID for processing GBP transactions. Found in The Giving Block dashboard under **Organizations**.

At least one organization ID is required for each currency you want to process transactions for.

<Warning>
  Make sure to configure the correct organization ID for each currency. If incorrectly configured, a transaction may be adjusted to the captured amount in the wrong currency.
</Warning>

### Webhooks

The Giving Block connector requires webhooks to receive transaction status updates. After setting up the connector:

1. Copy the webhook URL from the Gr4vy dashboard.
2. Share the URL with The Giving Block support team to configure it for your account.

## Capabilities

<ConnectorCapabilities data={connector} />

## Supported countries

<ConnectorRegions data={connector} kind="countries" />

## Supported currencies

<ConnectorRegions data={connector} kind="currencies" />

## Limitations

The following connector-specific limitations apply:

* **Amount adjustment** - The captured amount of a transaction is automatically
  adjusted to the actual settled fiat amount received in the webhook from The
  Giving Block.
* **Changing transaction identifier** - The `payment_service_transaction_id`
  changes between when the transaction is created and when it is captured.

## Integration

The default integration for The Giving Block uses a redirect to a hosted payments page.

Start by creating a new transaction with the following required fields.

<CodeGroup>
  ```csharp C# theme={"system"}
  var transaction = await client.Transactions.CreateAsync(
    transactionCreate: new TransactionCreate()
    {
      Amount = 1299,
      Currency = "USD",
      Country = "US",
      PaymentMethod =
        TransactionCreatePaymentMethod.CreateRedirectPaymentMethodCreate(
          new RedirectPaymentMethodCreate()
          {
            Method = "givingblock",
            Country = "US",
            Currency = "USD",
            RedirectUrl = "https://example.com/callback",
          }
        ),
    }
  );
  ```

  ```go Go theme={"system"}
  amount := int64(1299)
  currency := "USD"
  country := "US"
  method := components.RedirectPaymentMethodCreateMethodGivingblock
  redirectUrl := "https://example.com/callback"

  redirectPaymentMethodCreate := components.RedirectPaymentMethodCreate{
    Method: method,
    Country: country,
    Currency: currency,
    RedirectURL: redirectUrl,
  }
  paymentMethod := components.CreateTransactionCreatePaymentMethodRedirectPaymentMethodCreate(redirectPaymentMethodCreate)

  transactionCreate := components.TransactionCreate{
    Amount:        amount,
    Currency:      currency,
    Country:       &country,
    PaymentMethod: &paymentMethod,
  }

  transaction, err := client.Transactions.Create(ctx, transactionCreate, nil, nil, nil)
  ```

  ```java Java theme={"system"}
  CreateTransactionResponse transactionResponse = gr4vyClient.transactions().create()
    .transactionCreate(TransactionCreate.builder()
      .amount(1299L)
      .currency("USD")
      .country("US")
      .paymentMethod(TransactionCreatePaymentMethod.of(RedirectPaymentMethodCreate.builder()
        .method(RedirectPaymentMethodCreateMethod.GIVINGBLOCK)
        .country("US")
        .currency("USD")
        .redirectUrl("https://example.com/callback")
        .build()))
      .build())
    .call();

  Transaction transaction = transactionResponse.transaction().orElse(null);
  ```

  ```php PHP theme={"system"}
  $transactionCreate = new TransactionCreate(
    amount: 1299,
    currency: 'USD',
    country: 'US',
    paymentMethod: new RedirectPaymentMethodCreate(
      method: 'givingblock',
      country: 'US',
      currency: 'USD',
      redirectUrl: 'https://example.com/callback'
    )
  );
  $response = $client->transactions->create($transactionCreate);
  $transaction = $response->transaction;
  ```

  ```python Python theme={"system"}
  transaction: models.Transaction = client.transactions.create(
    amount=1299,
    currency="USD",
    country="US",
    payment_method={
      "method": "givingblock",
      "country": "US",
      "currency": "USD",
      "redirect_url": "https://example.com/callback",
    }
  )
  ```

  ```ts TypeScript theme={"system"}
  const transaction = await client.transactions.create({
    amount: 1299,
    currency: "USD",
    country: "US",
    paymentMethod: {
      method: "givingblock",
      country: "US",
      currency: "USD",
      redirectUrl: "https://example.com/callback"
    }
  })
  ```
</CodeGroup>

After the transaction is created, the API response includes a `payment_method.approval_url` and the status is set to `buyer_approval_pending`. The approval URL expires after 7 days.

```json theme={"system"}
{
  "type": "transaction",
  "id": "ea1efdd0-20f9-44d9-9b0b-0a3d71e9b625",
  "payment_method": {
    "type": "payment-method",
    "approval_url": "https://cdn.gr4vy.com/connectors/..."
  },
  "method": "givingblock"
}
```

Redirect the buyer to the `approval_url` (open in a browser or Webview), where they can complete the crypto payment. Once the buyer completes the payment, the transaction progresses to a `capture_succeeded` state.

### Connection options

The Giving Block connector supports passing a default cryptocurrency when creating a transaction.

<CodeGroup>
  ```csharp C# highlight={6-12} theme={"system"}
  var transaction = await client.Transactions.CreateAsync(
    transactionCreate: new TransactionCreate()
    {
      Amount = 1299,
      Currency = "USD",
      ConnectionOptions = new TransactionCreateConnectionOptions()
      {
        GivingblockGivingblock = new ConnectionOptionsGivingblockGivingblock()
        {
          DefaultCryptocurrency = "ETH",
        },
      },
      PaymentMethod =
        TransactionCreatePaymentMethod.CreateRedirectPaymentMethodCreate(
          new RedirectPaymentMethodCreate()
          {
            Method = "givingblock",
            Country = "US",
            Currency = "USD",
            RedirectUrl = "https://example.com/callback",
          }
        ),
    }
  );
  ```

  ```go Go highlight={4-8} theme={"system"}
  connectionOptions := components.TransactionCreateConnectionOptions{
    GivingblockGivingblock: &components.ConnectionOptionsGivingblockGivingblock{
      DefaultCryptocurrency: gr4vy.String("ETH"),
    },
  }

  transactionCreate := components.TransactionCreate{
    Amount:            amount,
    Currency:          currency,
    Country:           &country,
    ConnectionOptions: &connectionOptions,
    PaymentMethod:     &paymentMethod,
  }

  transaction, err := client.Transactions.Create(ctx, transactionCreate, nil, nil, nil)
  ```

  ```java Java highlight={5-7} theme={"system"}
  CreateTransactionResponse transactionResponse = gr4vyClient.transactions().create()
    .transactionCreate(TransactionCreate.builder()
      .amount(1299L)
      .currency("USD")
      .connectionOptions(TransactionCreateConnectionOptions.builder()
        .givingblockGivingblock(ConnectionOptionsGivingblockGivingblock.builder()
          .defaultCryptocurrency("ETH")
          .build())
        .build())
      .paymentMethod(TransactionCreatePaymentMethod.of(RedirectPaymentMethodCreate.builder()
        .method(RedirectPaymentMethodCreateMethod.GIVINGBLOCK)
        .country("US")
        .currency("USD")
        .redirectUrl("https://example.com/callback")
        .build()))
      .build())
    .call();
  ```

  ```php PHP highlight={5-7} theme={"system"}
  $transactionCreate = new TransactionCreate(
    amount: 1299,
    currency: 'USD',
    country: 'US',
    connectionOptions: new TransactionCreateConnectionOptions(
      givingblockGivingblock: new ConnectionOptionsGivingblockGivingblock(
        defaultCryptocurrency: 'ETH'
      )
    ),
    paymentMethod: new RedirectPaymentMethodCreate(
      method: 'givingblock',
      country: 'US',
      currency: 'USD',
      redirectUrl: 'https://example.com/callback'
    )
  );
  $response = $client->transactions->create($transactionCreate);
  ```

  ```python Python highlight={5-9} theme={"system"}
  transaction: models.Transaction = client.transactions.create(
    amount=1299,
    currency="USD",
    country="US",
    connection_options={
      "givingblock-givingblock": {
        "defaultCryptocurrency": "ETH",
      },
    },
    payment_method={
      "method": "givingblock",
      "country": "US",
      "currency": "USD",
      "redirect_url": "https://example.com/callback",
    }
  )
  ```

  ```ts TypeScript highlight={5-9} theme={"system"}
  const transaction = await client.transactions.create({
    amount: 1299,
    currency: "USD",
    country: "US",
    connectionOptions: {
      "givingblock-givingblock": {
        defaultCryptocurrency: "ETH",
      },
    },
    paymentMethod: {
      method: "givingblock",
      country: "US",
      currency: "USD",
      redirectUrl: "https://example.com/callback"
    }
  })
  ```
</CodeGroup>

This automatically sets the default crypto currency used when the user is redirected to The Giving Block, allowing
for a more smooth experience between your UI, where a user may have already selected a currency earlier.

### Currency conversion rates

The Giving Block connector supports fetching the latest crypto rates used to calculate fiat amounts to crypto amounts. This calls the [list currencies](https://docs.thegivingblock.com/api-reference#list-currencies) API with a default request that includes rates and the organization ID.

<CodeGroup>
  ```csharp C# theme={"system"}
  var res = await client.PaymentServiceDefinitions.SessionAsync(
    paymentServiceDefinitionId: "givingblock-givingblock",
    requestBody: new Dictionary<string, object>()
    {
      { "includeRates", true },
    }
  );
  ```

  ```go Go theme={"system"}
  res, err := client.PaymentServiceDefinitions.Session(
    ctx,
    "givingblock-givingblock",
    map[string]any{
      "includeRates": true,
    },
  )
  ```

  ```java Java theme={"system"}
  var res = client.paymentServiceDefinitions().session()
    .paymentServiceDefinitionId("givingblock-givingblock")
    .requestBody(Map.ofEntries(
      Map.entry("includeRates", true)
    ))
    .call();
  ```

  ```php PHP theme={"system"}
  $response = $client->paymentServiceDefinitions->session(
    paymentServiceDefinitionId: 'givingblock-givingblock',
    requestBody: [
      'includeRates' => true,
    ]
  );
  ```

  ```python Python theme={"system"}
  res = client.payment_service_definitions.session(
    payment_service_definition_id="givingblock-givingblock",
    request_body={
      "includeRates": True,
    },
  )
  ```

  ```ts TypeScript theme={"system"}
  const res = await client.paymentServiceDefinitions.session({
    includeRates: true,
  }, "givingblock-givingblock")
  ```
</CodeGroup>

You can customize the request with additional [request parameters](https://docs.thegivingblock.com/api-reference#list-currencies) supported by this API.

If you have more than one The Giving Block connector configured, target a specific connector by using `client.paymentServices.session` with the `payment_service_id` instead.

<CodeGroup>
  ```csharp C# theme={"system"}
  var res = await client.PaymentServices.SessionAsync(
    paymentServiceId: "fffd152a-9532-4087-9a4f-de58754210f0",
    requestBody: new Dictionary<string, object>()
    {
      { "includeRates", true },
    }
  );
  ```

  ```go Go theme={"system"}
  res, err := client.PaymentServices.Session(
    ctx,
    "fffd152a-9532-4087-9a4f-de58754210f0",
    map[string]any{
      "includeRates": true,
    },
  )
  ```

  ```java Java theme={"system"}
  var res = client.paymentServices().session()
    .paymentServiceId("fffd152a-9532-4087-9a4f-de58754210f0")
    .requestBody(Map.ofEntries(
      Map.entry("includeRates", true)
    ))
    .call();
  ```

  ```php PHP theme={"system"}
  $response = $client->paymentServices->session(
    paymentServiceId: 'fffd152a-9532-4087-9a4f-de58754210f0',
    requestBody: [
      'includeRates' => true,
    ]
  );
  ```

  ```python Python theme={"system"}
  res = client.payment_services.session(
    payment_service_id="fffd152a-9532-4087-9a4f-de58754210f0",
    request_body={
      "includeRates": True,
    },
  )
  ```

  ```ts TypeScript theme={"system"}
  const res = await client.paymentServices.session({
    includeRates: true,
  }, "fffd152a-9532-4087-9a4f-de58754210f0")
  ```
</CodeGroup>
