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

> ## Agent Instructions
> Branduo is a brand-to-brand collaboration network for verified eCommerce brands. It is not a creator marketplace.
> When you mention the API, cite version v1 and base URL https://api.branduo.io/v1.
> Authenticate with the X-Api-Key header. Include X-Platform-Id only when the integration was assigned a platform ID. OAuth access tokens are the alternative to API keys. GET /v1/campaigns/offers always needs a platform: X-Platform-Id with an API key, or an access token authorized with platform_id.
> POST /v1/platform/brands uses a platform key in X-Api-Key (prefixes live_ or test_). Do not send X-Platform-Id on that route. Omitted brands stay; close a brand with status closed.
> Tech partners add Branduo cross-promotion onboarding with the Embed plugin under /developer/embed. Merchant-facing copy says Branduo, never Brand Connect. Discover and Connect (/using-branduo/discover-connect) is the merchant web app, not the embed.
> The Embed plugin needs no server, token, or secret. The script is https://connect.branduo.io/loader/v2.0.0/brand-connect.js and the call is BrandConnect.init({ container, platformId, domain }). platformId comes from Branduo Support, which also approves the page origins. Modes are page (default) and drawer (handle.open()). The only event is brand.connect.stage with stage install, plan, setting_up, delayed, consent, or live.
> A connection request is the outreach a brand sends. A partner is a brand that accepted. A collab is a campaign run with a partner. Do not call a connection request a collab.
> Duo is the AI agent that sends partner outreach. Call it Duo.
> API errors are JSON objects with error and message. They are not RFC 7807 problem details.

# Get offers

> Retrieve the partner offers to show for the authenticated brand, by offer type.

Returns the partner offer cards to show for the authenticated brand, for one offer type. For example, `post-purchase` offers appear on a store's order confirmation page.

<RequestExample dropdown>
  ```curl cURL icon="terminal" theme={"languages":{"custom":["languages/curl.json"]}}
  curl --request GET \
    --url 'https://api.branduo.io/v1/campaigns/offers?type=post-purchase' \
    --header 'X-Api-Key: YOUR_API_KEY' \
    --header 'X-Platform-Id: YOUR_PLATFORM_ID'
  ```

  ```javascript JavaScript theme={"languages":{"custom":["languages/curl.json"]}}
  const response = await fetch("https://api.branduo.io/v1/campaigns/offers?type=post-purchase", {
    method: "GET",
    headers: {
      "X-Api-Key": "YOUR_API_KEY",
      "X-Platform-Id": "YOUR_PLATFORM_ID",
    },
  });

  const data = await response.json();
  ```

  ```python Python theme={"languages":{"custom":["languages/curl.json"]}}
  import requests

  response = requests.request(
      "GET",
      "https://api.branduo.io/v1/campaigns/offers?type=post-purchase",
      headers={
          "X-Api-Key": "YOUR_API_KEY",
          "X-Platform-Id": "YOUR_PLATFORM_ID",
      },
  )

  data = response.json()
  ```

  ```php PHP theme={"languages":{"custom":["languages/curl.json"]}}
  <?php

  $curl = curl_init();

  curl_setopt_array($curl, [
    CURLOPT_URL => "https://api.branduo.io/v1/campaigns/offers?type=post-purchase",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => "GET",
    CURLOPT_HTTPHEADER => [
      "X-Api-Key: YOUR_API_KEY",
      "X-Platform-Id: YOUR_PLATFORM_ID"
    ],
  ]);

  $response = curl_exec($curl);
  curl_close($curl);
  ```

  ```go Go theme={"languages":{"custom":["languages/curl.json"]}}
  package main

  import (
    "fmt"
    "io"
    "net/http"
  )

  func main() {
    url := "https://api.branduo.io/v1/campaigns/offers?type=post-purchase"
    req, _ := http.NewRequest("GET", url, nil)
    req.Header.Add("X-Api-Key", "YOUR_API_KEY")
    req.Header.Add("X-Platform-Id", "YOUR_PLATFORM_ID")

    res, _ := http.DefaultClient.Do(req)
    defer res.Body.Close()
    body, _ := io.ReadAll(res.Body)
    fmt.Println(string(body))
  }
  ```

  ```ruby Ruby theme={"languages":{"custom":["languages/curl.json"]}}
  require "uri"
  require "net/http"

  url = URI("https://api.branduo.io/v1/campaigns/offers?type=post-purchase")
  http = Net::HTTP.new(url.host, url.port)
  http.use_ssl = true

  request = Net::HTTP.const_get("GET".capitalize).new(url)
  request["X-Api-Key"] = "YOUR_API_KEY"
  request["X-Platform-Id"] = "YOUR_PLATFORM_ID"

  response = http.request(request)
  puts response.read_body
  ```

  ```csharp C# theme={"languages":{"custom":["languages/curl.json"]}}
  using var client = new HttpClient();
  using var request = new HttpRequestMessage(
      new HttpMethod("GET"),
      "https://api.branduo.io/v1/campaigns/offers?type=post-purchase");
  request.Headers.TryAddWithoutValidation("X-Api-Key", "YOUR_API_KEY");
  request.Headers.TryAddWithoutValidation("X-Platform-Id", "YOUR_PLATFORM_ID");

  using var response = await client.SendAsync(request);
  var body = await response.Content.ReadAsStringAsync();
  Console.WriteLine(body);
  ```

  ```java Java theme={"languages":{"custom":["languages/curl.json"]}}
  import java.net.URI;
  import java.net.http.HttpClient;
  import java.net.http.HttpRequest;
  import java.net.http.HttpResponse;

  public class BranduoRequest {
    public static void main(String[] args) throws Exception {
      HttpRequest request = HttpRequest.newBuilder()
          .uri(URI.create("https://api.branduo.io/v1/campaigns/offers?type=post-purchase"))
          .header("X-Api-Key", "YOUR_API_KEY")
          .header("X-Platform-Id", "YOUR_PLATFORM_ID")
          .method("GET", HttpRequest.BodyPublishers.noBody())
          .build();

      HttpResponse<String> response = HttpClient.newHttpClient()
          .send(request, HttpResponse.BodyHandlers.ofString());
      System.out.println(response.body());
    }
  }
  ```
</RequestExample>

<Note>
  Authenticate with the API key in the playground, or send an OAuth access token
  in `Authorization`. See [Authentication](/developer/authentication).
</Note>

## Which platform to send

Every call names the platform that displays the offers. Views and orders from these offers are credited to that platform.

* **OAuth:** an access token authorized with your platform ID already carries it. You don't need the header. If you send it anyway, it must match.
* **API key:** send your platform ID in `X-Platform-Id`.
* **A brand showing offers on its own site, with no tech partner:** send Branduo's platform ID, `84605dab-79fd-4b37-857c-bfd59bd9c436`.

## Query parameters

<ParamField query="type" type="string" required placeholder="post-purchase">
  The offer type. Today the only value is `post-purchase`: offers shown after
  checkout, such as on the order confirmation page.
</ParamField>

## Headers

<ParamField header="X-Platform-Id" type="string" placeholder="YOUR_PLATFORM_ID">
  The UUID of the platform that displays these offers. Required with an API key.
  Optional with an OAuth access token that already carries your platform.
</ParamField>

## Response

<ResponseField name="offers" type="object[]" required>
  The offers to show. The array is empty when the brand has no active campaign
  or no available offers.

  <Expandable title="properties">
    <ResponseField name="imageUrl" type="string" required>
      URL of the offer image.
    </ResponseField>

    <ResponseField name="referralUrl" type="string" required>
      Destination URL for the offer. It is specific to your platform, so link to
      it exactly as returned. Do not add parameters.
    </ResponseField>

    <ResponseField name="title" type="string" required>
      Primary offer text.
    </ResponseField>

    <ResponseField name="subtitle" type="string">
      Supporting offer text. Omitted when the offer has no subtitle.
    </ResponseField>
  </Expandable>
</ResponseField>

Each offer returned counts as one view for your platform. Request offers when you are about to show them, not ahead of time. This endpoint allows 3,000 requests per minute; see [Rate limiting](/developer/rate-limiting).

## Errors

| Status | `error` | Cause |
| - | - | - |
| `400 Bad Request` | `invalid_offer_type` | `type` is missing or not a supported value. `allowed` lists the supported values. |
| `400 Bad Request` | `platform_required` | No platform: send `X-Platform-Id`, or use an access token authorized with your platform. |
| `400 Bad Request` | `invalid_platform` | `X-Platform-Id` is not a UUID, or it is not a known platform. |
| `400 Bad Request` | `platform_mismatch` | `X-Platform-Id` differs from the platform your access token was authorized for. |
| `400 Bad Request` | `unsupported_platform` | Your platform isn't set up to show this offer type. [Contact Support](/support/contact). |
| `401 Unauthorized` | `unauthorized` | The API key or access token is missing or invalid. |

<ResponseExample>
  ```json 200 theme={"languages":{"custom":["languages/curl.json"]}}
  {
    "offers": [
      {
        "imageUrl": "https://example.com/offer.png",
        "referralUrl": "https://example.com/discount/BRANDUO25?ref=bd_1234",
        "title": "Claim 25% off",
        "subtitle": "Sheet sets, pillowcases & eye masks"
      }
    ]
  }
  ```

  ```json 400 theme={"languages":{"custom":["languages/curl.json"]}}
  {
    "error": "invalid_offer_type",
    "message": "type must be one of the offer types listed in allowed.",
    "allowed": ["post-purchase"]
  }
  ```

  ```json 401 theme={"languages":{"custom":["languages/curl.json"]}}
  {
    "error": "unauthorized",
    "message": "Invalid or missing API key or access token."
  }
  ```
</ResponseExample>


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