---
title: "Diagrams"
description: "Every diagram in these docs on one page, in reading order. Who talks to whom, each flow step by step, the iframe states, and where secrets live."
url: https://docs.tryflume.ai/diagrams
updated: 2026-11-12
---

# Diagrams

> Every diagram in these docs on one page, in reading order. Who talks to whom, each flow step by step, the iframe states, and where secrets live.

Every diagram in these docs, in the order to read them. Each one also sits on the page that explains it, linked under its heading. Every diagram has a text version: open "Read this diagram as text".

## How to read them

| Mark | Meaning |
|---|---|
| A box outlined in ink | Yours: your page or your backend |
| A filled box | Flume's: the iframe or Flume's servers |
| A capsule | A person, or a state |
| A thick solid arrow | A server call over HTTPS |
| A dashed arrow | A postMessage between the iframe and your page |
| A thin grey arrow | A call the iframe makes on its own |
| A dotted arrow | Something a person does |

## The two ways to integrate

From the [overview](https://docs.tryflume.ai/index.md#which-one-should-you-use).

**Diagram: Two ways to integrate, side by side.** With the iframe, Flume draws the screens and your backend makes two calls. With the API, you draw them and your backend makes every call.

```mermaid
flowchart LR
  i-screens["Flume iframe / verify, search, quote, save"]
  i-page["Your page / frames it, handles messages"]
  i-backend["Your backend / 2 server calls"]
  a-screens["Your screens / you build each one"]
  a-backend["Your backend / the six API steps"]
  a-flume["Flume servers / Partner API"]
  i-screens -.->|"4 messages"| i-page
  i-page -.->|"2 replies"| i-screens
  i-page -->|"your routes"| i-backend
  a-screens -->|"your routes"| a-backend
  a-backend -->|"every step"| a-flume
```

1. Embed the iframe, recommended: Flume draws the verify, search, quote and save screens inside an iframe.
2. Your page frames the iframe and handles its messages: four from the iframe, two replies from your page.
3. Your backend makes two server calls: start a session, and exchange a connect code.
4. Call the API: you build every screen yourself.
5. Your backend makes every call to the Partner API, in six steps: verify (two calls), search by photo, product detail, instant quote, and a link into Flume.
6. Both use the same partner key, users and save payload, and you can combine them.

## The big picture

From the [overview](https://docs.tryflume.ai/index.md#how-it-fits-together).

**Diagram: Who talks to whom.** Four parts and one person. Your page and the Flume iframe share the browser. Only your backend calls Flume with your key.

```mermaid
flowchart LR
  user["User"]
  page["Your page / frames the iframe"]
  backend["Your backend / holds the partner key"]
  iframe["Flume iframe / draws every screen"]
  flume["Flume servers"]
  user -->|"clicks"| page
  user -->|"searches, prices, saves"| iframe
  page -->|"your routes"| backend
  backend -->|"server calls, partner key"| flume
  page -.-> iframe
  iframe -.->|"postMessage: 4 to you, 2 back"| page
  iframe -->|"its own calls"| flume
```

1. The user clicks a button on your page.
2. Your page calls your own backend. It never calls Flume.
3. Your backend calls Flume over HTTPS, with your partner key. These are the server calls.
4. Your page frames the Flume iframe. The two talk only with postMessage: four message types from the iframe, two from your page.
5. The user searches, prices and saves inside the iframe. The iframe makes its own calls to Flume with its own short-lived credential.
6. Your partner key and user access tokens stay on your backend. They never reach the browser.

## The order to build in

From [Get a sandbox key](https://docs.tryflume.ai/get-a-key.md#what-happens-next).

**Diagram: From a key to live, step by step.** The order to build in. Each step has a page.

```mermaid
flowchart LR
  r1["1. Get a sandbox key / and an allowed origin"]
  r2["2. Start a session / your backend"]
  r3["3. Mount the iframe / tag and host snippet"]
  r4["4. Exchange the code / store the user token"]
  r5["5. Write the saved item / once per save_uuid"]
  r6["6. Close, expiry, errors / every message handled"]
  r7["7. Go-live checklist / in the sandbox"]
  r8["8. Ask for live access / then switch URL and key"]
  r1 --> r2
  r2 --> r3
  r3 --> r4
  r4 --> r5
  r5 --> r6
  r6 --> r7
  r7 --> r8
```

1. Get a sandbox key, and have Flume set your page origin as an allowed origin.
2. Start a session from your backend with POST /start-iframe-session.
3. Mount the iframe on your page: the iframe tag and the host snippet.
4. Exchange the connect code on your backend and store the user access token.
5. Write the saved item, once per save_uuid, and reply to the iframe.
6. Handle close, expiry, the ready timer and errors.
7. Finish the go-live checklist in the sandbox.
8. Ask Flume for live access, then switch the base URL and the key.

## The API path

From the [API quickstart](https://docs.tryflume.ai/quickstart/api.md).

**Diagram: The API path: six steps.** An API integration makes these six calls, in this order. Every call carries the partner key; steps 3 to 6 also carry the user access token.

```mermaid
sequenceDiagram
  participant backend as Your backend
  participant flume as Flume servers
  backend->>flume: POST /users/trigger-verification
  backend->>flume: POST /users/confirm-verification
  backend->>flume: POST /search
  backend->>flume: GET /products/sku_uuid
  backend->>flume: POST /request-instant-quote
  backend->>flume: POST /deep-links
```

1. Verify a user, send the code: POST /users/trigger-verification. Flume emails the user a 6-digit code.
2. Verify a user, confirm the code: POST /users/confirm-verification returns the user access token.
3. Search by photo: POST /search returns two lists and a search_session_uuid. GET /filters lists the filter options.
4. Product detail: GET /products/{sku_uuid} returns photos, price, specification and shipping.
5. Instant quote: POST /request-instant-quote returns the delivered price. A quote that is still pricing is read with GET /quotes/{quote_uuid}.
6. Open Flume, signed in: POST /deep-links returns a one-time link into the user's Flume account.

## The API path, flow by flow

From [Verify a user](https://docs.tryflume.ai/guides/verify-a-user.md) and [Find products by photo](https://docs.tryflume.ai/guides/find-products-by-photo.md).

**Diagram: Steps 1 and 2: verify a user through the API.** You build the code screen. Two calls, with the partner key only. The second returns the user access token.

```mermaid
sequenceDiagram
  participant user as User
  participant page as Your page
  participant backend as Your backend
  participant flume as Flume servers
  page->>backend: email
  backend->>flume: POST /users/trigger-verification
  flume->>user: email, 6 digits
  user->>page: types the code
  page->>backend: code
  backend->>flume: POST /users/confirm-verification
  flume->>backend: access_token
  Note over backend: store the token
```

1. Your screen sends the user's email to your backend.
2. Your backend calls POST /users/trigger-verification with external_ref and email.
3. Flume emails the user a 6-digit code, valid for 10 minutes.
4. The user types the code on your screen.
5. Your screen sends the code to your backend.
6. Your backend calls POST /users/confirm-verification with the email and the code.
7. Flume returns the user access token, once.
8. Your backend stores the token against that user and sends it on every call made for them.

**Diagram: Steps 3 to 5: search, product, quote.** Each call carries both headers. The search returns a search_session_uuid that the later calls carry. A quote that is still pricing is polled.

```mermaid
sequenceDiagram
  participant page as Your page
  participant backend as Your backend
  participant flume as Flume servers
  backend->>flume: GET /filters
  page->>backend: photo, filters
  backend->>flume: POST /search
  flume->>backend: results, search_session_uuid
  backend->>flume: GET /products/sku_uuid
  backend->>flume: POST /request-instant-quote
  flume->>backend: READY, or still pricing
  backend->>flume: GET /quotes/quote_uuid (not every time)
  backend->>page: prices
```

1. Your backend calls GET /filters and builds your filter menus from the answer.
2. Your screen sends the photo and the chosen filters to your backend.
3. Your backend calls POST /search with the photo.
4. Flume returns up to 24 results a page and a search_session_uuid.
5. Your backend calls GET /products/{sku_uuid} for the product the user opens.
6. Your backend calls POST /request-instant-quote with the product, a quantity, a ZIP code and the search_session_uuid. It carries an Idempotency-Key.
7. Flume answers within 60 seconds: READY with prices, or FAILED with a reason.
8. Only when the reason is TEMPORARILY_UNAVAILABLE: your backend polls GET /quotes/{quote_uuid} until the quote is READY.
9. Your backend returns the prices to your screen.

## One open of the iframe, end to end

From [How the iframe works](https://docs.tryflume.ai/embed.md#what-is-the-lifecycle).

**Diagram: The whole flow, from a click to a saved item.** One open of the iframe, end to end. Lighter steps happen only the first time a user opens it.

```mermaid
sequenceDiagram
  participant iframe as Flume iframe
  participant page as Your page
  participant backend as Your backend
  participant flume as Flume servers
  page->>backend: open item
  backend->>flume: POST /start-iframe-session
  flume->>backend: iframe_url, session_uuid
  backend->>page: iframe_url, session_uuid
  page->>iframe: iframe.src = iframe_url
  iframe-->>page: flume:iframe_ready
  iframe-->>page: flume:user_connected (not every time)
  page->>backend: connect_code (not every time)
  backend->>flume: POST /users/exchange-connect-code (not every time)
  iframe-->>page: flume:save_item
  page-->>iframe: flume:item_saved
  iframe-->>page: flume:close_iframe
```

1. The user clicks your button. Your page asks your backend to start a session.
2. Your backend calls POST /start-iframe-session with the user, project and item.
3. Flume returns iframe_url and session_uuid.
4. Your backend passes both to your page.
5. Your page starts the ready timer, adds the message listener, then sets the iframe src.
6. The iframe posts flume:iframe_ready. Your page clears the timer.
7. First time only: the user verifies their email, and the iframe posts flume:user_connected with a connect code.
8. First time only: your page sends the connect code to your backend.
9. First time only: your backend exchanges the code for the user access token and stores it.
10. The user saves a product. The iframe posts flume:save_item with the save payload.
11. Your page writes its record and replies flume:item_saved, or flume:item_save_failed.
12. The iframe posts flume:close_iframe. Your page removes the iframe.

## Every message

From [Messages](https://docs.tryflume.ai/embed/messages.md#all-messages).

**Diagram: Every message, and which way it goes.** All six postMessage types between the iframe and your page, in the order one open usually sends them. Four come to your page, two go back.

```mermaid
sequenceDiagram
  participant iframe as Flume iframe
  participant page as Your page
  iframe-->>page: flume:iframe_ready
  iframe-->>page: flume:user_connected (not every time)
  iframe-->>page: flume:save_item
  page-->>iframe: flume:item_saved
  page-->>iframe: flume:item_save_failed (not every time)
  iframe-->>page: flume:close_iframe
```

1. The iframe posts flume:iframe_ready once it has painted, with an empty payload. Clear the ready timer and show the iframe.
2. First open only: the iframe posts flume:user_connected with a connect_code. Send it to your backend at once. The iframe expects no reply.
3. The iframe posts flume:save_item with the save payload, which carries save_uuid. It waits 60 seconds for your reply.
4. Your page replies flume:item_saved with the same save_uuid, and item_ref and item_label when you have them.
5. Or your page replies flume:item_save_failed with the same save_uuid and a reason: permission, conflict, storage or error.
6. The iframe posts flume:close_iframe with a reason of done, closed or expired. Remove the iframe. On expired, start a new session.

## Starting a session

From [Server calls](https://docs.tryflume.ai/embed/server-calls.md#start-a-session).

**Diagram: Start a session and mount the iframe.** From the click to a loaded iframe. A user access token, when you hold one, skips the email step.

```mermaid
sequenceDiagram
  participant user as User
  participant iframe as Flume iframe
  participant page as Your page
  participant backend as Your backend
  participant flume as Flume servers
  user->>page: clicks your button
  page->>backend: your route
  backend->>flume: POST /start-iframe-session
  flume->>backend: iframe_url, session_uuid
  backend->>page: iframe_url, session_uuid
  Note over page: ready timer, 15 s
  page->>iframe: iframe.src
  iframe->>flume: launch code, once
  iframe-->>page: flume:iframe_ready
```

1. The user clicks your button for one item.
2. Your page asks your backend to start a session.
3. Your backend calls POST /start-iframe-session with the user, project, item and host_origin. It sends the stored user access token when it holds one.
4. Flume returns iframe_url and session_uuid.
5. Your backend returns only those two values to your page.
6. Your page starts a ready timer of 15 seconds and adds the message listener.
7. Your page sets iframe_url as the iframe src, at once.
8. The iframe spends the launch code with Flume. It works once, within 120 seconds.
9. The iframe posts flume:iframe_ready. Your page clears the timer and hides its spinner. The iframe also posts it when it could not start: it then shows its own error, and its Try again posts flume:close_iframe with reason expired.

## The first open

From [Users and verification](https://docs.tryflume.ai/concepts/users.md#how-does-verification-work-in-the-iframe).

**Diagram: The first open: the user verifies, you get a token.** Happens once per user. You build no screen for it: the iframe asks for the code.

```mermaid
sequenceDiagram
  participant user as User
  participant iframe as Flume iframe
  participant page as Your page
  participant backend as Your backend
  participant flume as Flume servers
  user->>iframe: clicks Connect
  iframe->>flume: send a code
  flume->>user: email, 6 digits
  user->>iframe: types the code
  iframe->>flume: check the code
  iframe-->>page: flume:user_connected
  page->>backend: connect_code
  backend->>flume: POST /users/exchange-connect-code
  flume->>backend: access_token
  Note over backend: store the token
```

1. The iframe opened without a user access token, so it shows the user their name and email. The user clicks Connect.
2. The iframe asks Flume to email a code.
3. Flume emails a 6-digit code to the user. It is valid for 10 minutes.
4. The user types the code in the iframe.
5. The iframe checks the code with Flume. Any token you held for this user stops working now.
6. The iframe posts flume:user_connected with a connect code.
7. Your page sends the connect code to your backend, at once.
8. Your backend calls POST /users/exchange-connect-code. The code works once, within 120 seconds.
9. Flume returns the user access token, once.
10. Your backend checks external_ref, then stores the token over any older one. It sends it on the next POST /start-iframe-session.

## A later open

From [Users and verification](https://docs.tryflume.ai/concepts/users.md#how-does-verification-work-in-the-iframe).

**Diagram: A later open, for a user whose token you hold.** No email step and no flume:user_connected. Lighter steps happen only when the stored token has stopped working.

```mermaid
sequenceDiagram
  participant user as User
  participant iframe as Flume iframe
  participant page as Your page
  participant backend as Your backend
  participant flume as Flume servers
  user->>page: clicks your button
  page->>backend: your route
  backend->>flume: POST /start-iframe-session
  flume->>backend: 401 USER_TOKEN_INVALID (not every time)
  Note over backend: delete the token (not every time)
  backend->>flume: POST /start-iframe-session (not every time)
  flume->>backend: iframe_url, session_uuid
  backend->>page: iframe_url, session_uuid
  page->>iframe: iframe.src
  iframe->>flume: launch code, once
  iframe-->>page: flume:iframe_ready
```

1. The user clicks your button for one item.
2. Your page asks your backend to start a session.
3. Your backend calls POST /start-iframe-session and sends the user access token it stored for this user.
4. Only when the token no longer works, because the user verified again or you revoked it: Flume answers 401 USER_TOKEN_INVALID.
5. Then your backend deletes the stored token.
6. Then your backend calls POST /start-iframe-session again without a token. The user verifies in the iframe, as on a first open.
7. Flume returns iframe_url and session_uuid.
8. Your backend returns those two values to your page.
9. Your page starts the ready timer, adds the message listener and sets the iframe src.
10. The iframe spends the launch code with Flume.
11. The iframe posts flume:iframe_ready and opens with the user already verified.

## Saving an item

From [Save payload](https://docs.tryflume.ai/concepts/save-payload.md#what-is-the-flow) and [Messages](https://docs.tryflume.ai/embed/messages.md#what-does-the-user-see-around-a-save).

**Diagram: Save an item.** The user saves in the iframe, your side writes the record, and your page answers. Your backend calls Flume at no point.

```mermaid
sequenceDiagram
  participant user as User
  participant iframe as Flume iframe
  participant page as Your page
  participant backend as Your backend
  participant flume as Flume servers
  user->>iframe: confirms a save
  iframe->>flume: build the save payload
  iframe-->>page: flume:save_item
  page->>backend: save payload
  Note over backend: write once per save_uuid
  backend->>page: your record id
  page-->>iframe: flume:item_saved
  iframe->>flume: record the result
  iframe->>user: saved screen
```

1. The user confirms a save in the iframe.
2. The iframe asks Flume for the save payload. If that fails, the iframe shows its own error and your page hears nothing.
3. The iframe posts flume:save_item with the save payload and its save_uuid.
4. Your page sends the payload to your backend.
5. Your backend writes one record per save_uuid, and copies the photo bytes if you keep a photo.
6. Your backend answers with your record, or with a failure.
7. Your page replies flume:item_saved with the same save_uuid, within 60 seconds. On a failed write it replies flume:item_save_failed instead.
8. The iframe tells Flume how the save ended. You make no call for this.
9. The iframe shows the saved screen.

**Diagram: Every way a save can end.** Three outcomes of one flume:save_item. Two of them show the user the same message, and a retry repeats the same save_uuid.

```mermaid
flowchart LR
  request["flume:save_item / carries save_uuid"]
  ok["flume:item_saved / your write worked"]
  failed["flume:item_save_failed / permission, conflict, / storage or error"]
  silent["No reply / within 60 seconds"]
  saved["Saved screen / shows item_label"]
  retry["Could not save / Close, or Try again"]
  request --> ok
  request --> failed
  request --> silent
  ok --> saved
  failed --> retry
  silent --> retry
```

1. The iframe posts flume:save_item with a save_uuid.
2. Your page replies flume:item_saved: the user sees the saved screen, with your item_label when you send one.
3. Your page replies flume:item_save_failed with a reason of permission, conflict, storage or error: the user sees one message with Close and Try again. The reason is not shown.
4. Your page does not reply within 60 seconds: the user sees the same message.
5. Try again posts flume:save_item again with the same save_uuid. Your write must be safe to repeat.

## Opening a saved item in Flume

From [Server calls](https://docs.tryflume.ai/embed/server-calls.md#create-a-link-that-opens-flume).

**Diagram: Open in Flume, for a saved item.** Optional. A one-time link, created on the click and never stored.

```mermaid
sequenceDiagram
  participant user as User
  participant page as Your page
  participant backend as Your backend
  participant flume as Flume servers
  user->>page: clicks Open in Flume
  Note over page: open a blank tab
  page->>backend: your route
  backend->>flume: POST /deep-links
  flume->>backend: url
  backend->>page: url
  page->>user: tab goes to the url
```

1. The user clicks "Open in Flume" on a saved item.
2. Your page opens a blank tab in the click handler, so the browser does not block it.
3. Your page asks your backend for a link.
4. Your backend calls POST /deep-links with the user access token, and the search_session_uuid and sku_uuid it kept from the save payload.
5. Flume returns a link that works once, within 7 days.
6. Your backend returns the link. It stores it nowhere.
7. Your page points the tab at the link. Flume opens with the user signed in. With no token, link to product_url instead.

## The states of the iframe on your page

From [Set up your page](https://docs.tryflume.ai/embed/host-page.md#the-handlers-you-write).

**Diagram: The iframe on your page, state by state.** What your page is doing at each moment, and the message or timer that moves it on.

```mermaid
flowchart LR
  failed["Failed to load"]
  starting["Starting"]
  expired["Expired"]
  exchanging["Exchanging"]
  ready["Ready"]
  closed["Closed"]
  saving["Saving"]
  starting -->|"ready timer, 15 s"| failed
  failed -->|"user retries"| starting
  starting -.->|"flume:iframe_ready"| ready
  ready -.->|"flume:user_connected"| exchanging
  exchanging -->|"token stored"| ready
  ready -.->|"flume:save_item"| saving
  saving -.->|"reply, or 60 s"| ready
  ready -.->|"flume:close_iframe done or closed"| closed
  ready -.->|"flume:close_iframe expired"| expired
  expired -->|"new session"| starting
```

1. Starting: your page set the iframe src and runs a ready timer of 15 seconds. Before that, nothing is mounted.
2. Starting to Ready: flume:iframe_ready arrives. Clear the timer.
3. Starting to Failed to load: the timer fires first. Remove the iframe and show an error with a retry. A retry starts a new session.
4. Ready to Exchanging and back: flume:user_connected arrives, your backend exchanges the connect code and stores the token. The iframe does not wait for it.
5. Ready to Saving and back: flume:save_item arrives, and your page replies. After 60 seconds without a reply the iframe treats the save as failed.
6. Ready to Closed: flume:close_iframe with reason done or closed. Remove the iframe.
7. Ready to Expired: flume:close_iframe with reason expired. Start a new session and mount again.
8. flume:close_iframe can arrive at any moment after Starting, also while a save or an exchange is running. Remove the iframe all the same.
9. An iframe that could not start still posts flume:iframe_ready, shows its own error, and posts flume:close_iframe with reason expired when the user asks to try again.

## Where secrets live

From [Security and CSP](https://docs.tryflume.ai/embed/security.md#where-do-credentials-live).

**Diagram: Where each secret lives and travels.** Long-lived secrets stay on servers. Only single-use, short-lived codes pass through the browser.

```mermaid
flowchart LR
  page["Your page / checks origin, source, / version, session_uuid"]
  backend["Your backend / partner key / user access tokens"]
  iframe["Flume iframe / posts only to host_origin / its own short credential"]
  flume["Flume servers / allowed origins / per partner"]
  backend -->|"iframe_url (launch code)"| page
  page -->|"connect_code"| backend
  backend -->|"partner key, user access token"| flume
  flume -->|"iframe_url, access_token"| backend
  page -.->|"save replies"| iframe
  iframe -.->|"connect_code, save payload"| page
  iframe -->|"launch code, once"| flume
```

1. Your backend holds the partner key and each user access token. It sends them only to Flume, over HTTPS.
2. Flume returns iframe_url, which carries a launch code. The launch code works once, within 120 seconds.
3. Your backend hands iframe_url to your page. Your page sets it as the iframe src and stores it nowhere.
4. The iframe spends the launch code with Flume and then uses its own short-lived credential.
5. When a user verifies, the iframe posts a connect code to your page. It works once, within 120 seconds.
6. Your page passes the connect code to your backend, which exchanges it for the user access token.
7. Your page accepts a message only when its origin, source, version and session_uuid are right. The iframe posts only to the host_origin you sent.

## What you store

From [How the iframe works](https://docs.tryflume.ai/embed.md#what-must-you-store).

**Diagram: What you store, and what you never store.** Two things are worth keeping. Everything else is used once and dropped.

```mermaid
flowchart LR
  s-exchange["Exchange response / POST /users/exchange-connect-code"]
  s-save["flume:save_item / the save payload"]
  s-start["Session response / POST /start-iframe-session"]
  s-connected["flume:user_connected"]
  k-token["User access token / per external_ref, encrypted"]
  k-item["Your saved item / keyed by save_uuid: your fields, / photo bytes, product_url, two ids"]
  n-url["iframe_url / set as the iframe src at once"]
  n-code["connect_code / exchange at once"]
  s-exchange -->|"access_token"| k-token
  s-save -->|"mapped fields"| k-item
  s-start -->|"use once"| n-url
  s-connected -->|"use once"| n-code
```

1. From the exchange response, store the user access token, per external_ref, encrypted, on your server.
2. From flume:save_item, store your own record keyed by save_uuid: the fields you map, the photo bytes, product_url, and the two ids an Open in Flume link needs (match.search_session_uuid and product.sku_uuid).
3. Never store iframe_url or its launch code. Set it as the iframe src at once.
4. Never store a connect code. Exchange it at once.
5. Also never store image links or an Open in Flume link: both expire. Log session_uuid with your item id and user id.

## How long things last

From [Limits](https://docs.tryflume.ai/concepts/limits.md#how-long-do-things-last).

**Diagram: How long each thing lasts.** Every timer, code and link in the integration, shortest first. The scale is logarithmic.

1. Ready timer: 15 seconds. On your page. When it fires, remove the iframe and offer a retry.
2. Reply to a save: 60 seconds. After that the iframe treats the save as failed.
3. Launch code: 120 seconds, one use. Inside iframe_url. Set the iframe src at once.
4. Connect code: 120 seconds, one use. Exchange it at once.
5. Verification code: 10 minutes. The emailed code the user types in the iframe.
6. Iframe session: 12 hours. From its first open. Then flume:close_iframe with reason expired.
7. Image links: about 24 hours. In the save payload. Copy the bytes when you save.
8. Open in Flume link: 7 days, one use. Create it on the click. Never store it.
9. Instant quote prices: 30 days. Until pricing.valid_until in the save payload.
10. Unused session: 30 days. A session nobody reopens is dropped. The next open starts fresh.
11. User access token: no expiry. Replaced when the user verifies again, or revoked by you.

## When a server call fails

From [Handle errors](https://docs.tryflume.ai/guides/handle-errors.md).

**Diagram: What to do when a server call fails.** Read the status and error.code on the left, then take the one action beside it.

```mermaid
flowchart LR
  c-key["401 PARTNER_KEY_INVALID"]
  a-key["Fix the key or the base URL / do not retry"]
  c-token["401 USER_TOKEN_INVALID"]
  a-token["Delete the stored token / start again without it"]
  c-code["401 CONNECT_CODE_INVALID"]
  a-code["Store nothing / the user verifies on the next open"]
  c-403["403 USER_NOT_CONNECTED"]
  a-403["Verify the user / then send the user access token"]
  c-4xx["400, 404, 413, 422 / and any other 403 or 409"]
  a-4xx["Fix the request / field names what is wrong"]
  c-409["409 IDEMPOTENCY_IN_PROGRESS"]
  a-409["Retry with the same key / after Retry-After"]
  c-429["429"]
  a-429["Wait for Retry-After, then retry / a daily limit resets at 00:00 UTC"]
  c-5xx["500, 502, 503, timeout"]
  a-5xx["Retry with a growing wait / same Idempotency-Key, up to 3 retries"]
  c-key --> a-key
  c-token --> a-token
  c-code --> a-code
  c-403 --> a-403
  c-4xx --> a-4xx
  c-409 --> a-409
  c-429 --> a-429
  c-5xx --> a-5xx
```

1. 401 PARTNER_KEY_INVALID: fix the key, or the base URL it belongs to. Do not retry.
2. 401 USER_TOKEN_INVALID: delete the stored token and start the session again without it. The user verifies again in the iframe.
3. 401 CONNECT_CODE_INVALID: store nothing and do not retry. The user verifies again on the next open.
4. 403 USER_NOT_CONNECTED: the call needs a verified user. Verify the user, then send the user access token.
5. 400, 404, 413, 422, and any other 403 or 409: fix the request. On a 422, field names what is wrong. Do not retry unchanged.
6. 409 IDEMPOTENCY_IN_PROGRESS: the first request with this Idempotency-Key is still running. Retry with the same key after Retry-After.
7. 429: wait for the number of seconds in Retry-After, then retry. For a daily limit that is the time until 00:00 UTC, so stop for the day.
8. 500, 502, 503 or a timeout: retry with a growing wait and the same Idempotency-Key, up to 3 retries.

## What has a table instead

- Every message with its payload fields and what to do: [Messages](https://docs.tryflume.ai/embed/messages.md#all-messages).
- Sandbox and live, side by side: [Environments](https://docs.tryflume.ai/concepts/environments.md).
- Limits: [Limits](https://docs.tryflume.ai/concepts/limits.md).
