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

# Build your own connector

> Connect a homegrown ERP or storefront to Elastly in any language. Push your data in, pull approved prices out, over plain REST.

If your system of record is homegrown, or one Elastly cannot reach from the outside, you connect it
yourself: your code calls Elastly, not the other way around. It is plain REST, so you build a connector
in **any language** with the [SDK](/docs/sdks) for that language, or with raw HTTP.

A connector does two things. It **feeds Elastly your data** (products, customers, quotes, orders) so it
can price, and it **applies the prices you approve** back into your system.

There are two ways to build one. Start with the **connector framework**: implement a few functions that
read your data, and the SDK runs the whole sync, with paging, checkpoints, retries, and write-back
leases handled for you. It ships in every language. Reach for the **raw loop** when you want to drive
each step yourself.

<Columns cols={2}>
  <Card title="The connector framework" icon="bolt" href="/docs/sdks/build-a-connector/connector-framework">
    Recommended. Implement your readers, the runtime runs the sync. TypeScript, Python, PHP, Java, Go.
  </Card>

  <Card title="Feeding data in" icon="arrow-down-to-line" href="/docs/sdks/build-a-connector/feeding-data">
    The raw loop: open a batch, stage your records, commit, poll until it drains.
  </Card>

  <Card title="Applying prices" icon="arrow-up-from-line" href="/docs/sdks/build-a-connector/applying-prices">
    The raw loop: claim approved prices, write them into your system, acknowledge.
  </Card>

  <Card title="API reference" icon="terminal" href="/docs/api/ingest">
    The Ingest and Write-back endpoints, with a live playground.
  </Card>
</Columns>

## The loop

| Stage     | What moves                                 | Where                                                      |
| --------- | ------------------------------------------ | ---------------------------------------------------------- |
| Catalog   | Products with real costs                   | [Feeding data in](/docs/sdks/build-a-connector/feeding-data)    |
| Customers | Who you sell to                            | [Feeding data in](/docs/sdks/build-a-connector/feeding-data)    |
| Outcomes  | Quotes (won/lost) and orders (sold prices) | [Feeding data in](/docs/sdks/build-a-connector/feeding-data)    |
| Apply     | Approved prices back into your system      | [Applying prices](/docs/sdks/build-a-connector/applying-prices) |

The outcomes stage is the one teams skip, and skipping it is the expensive mistake. Without quotes and
orders flowing back, Elastly serves prices but never learns whether they won, and your margins stay
frozen at day one, silently.

## Before you start

1. Connect **Custom ERP** or **Custom Storefront** under [Integrations](https://app.elastly.io/integrations).
   Custom ERP accepts quotes; Custom Storefront is catalog and orders only.
2. Create a **Connector** API key under [Settings → API keys](https://app.elastly.io/settings). Ingest
   and write-backs need this scope; an ERP key will not work.

## Set up the client

The [connector framework](/docs/sdks/build-a-connector/connector-framework) sets up its own client, so this
is for the raw loop. On TypeScript the whole surface hangs off one `Elastly`; the generated SDKs expose
an `IngestApi` and a `WritebacksApi`.

<CodeGroup>
  ```ts TypeScript theme={null}
  import { Elastly } from "@elastly/sdk"

  const elastly = new Elastly({ apiKey: process.env.ELASTLY_CONNECTOR_KEY })
  ```

  ```python Python theme={null}
  import elastly

  config = elastly.Configuration(access_token="elastly_live_...")
  client = elastly.ApiClient(config)
  ingest = elastly.IngestApi(client)
  writebacks = elastly.WritebacksApi(client)
  ```

  ```php PHP theme={null}
  $config = Elastly\Configuration::getDefaultConfiguration()->setAccessToken('elastly_live_...');
  $ingest = new Elastly\Api\IngestApi(null, $config);
  $writebacks = new Elastly\Api\WritebacksApi(null, $config);
  ```

  ```java Java theme={null}
  ApiClient client = Configuration.getDefaultApiClient();
  client.setBearerToken("elastly_live_...");
  IngestApi ingest = new IngestApi(client);
  WritebacksApi writebacks = new WritebacksApi(client);
  ```

  ```go Go theme={null}
  ctx := context.WithValue(context.Background(), elastly.ContextAccessToken, "elastly_live_...")
  api := elastly.NewAPIClient(elastly.NewConfiguration())
  ```
</CodeGroup>

## Prove the loop is closed

After your first full sync, check three things in the dashboard:

1. [Products](https://app.elastly.io/integrations) shows your catalog with costs.
2. [Integrations](https://app.elastly.io/integrations) shows the sync run with the counts you expect.
3. After a few closed quotes flow in, the pricing dashboards start attributing wins and losses to
   prices. That is the learning loop working.

If prices serve but the dashboards never move, the `pricingDecisionId` round-trip is broken. That is
always the first thing to check.
