# Customer portal

Let customers follow, answer and make requests, in your help centre's My requests or inside your own app.


Your Texa Desk help centre has a **My requests** area: customers sign in with a code to their email
or phone and see their tickets, each with every channel's public messages, and can reply or make a
new request. It works on the help centre's pages with no code. This page is about doing the same
**inside your own app**, with the JSON API under:

```text
https://desk.texadesk.com/public/api/v1/portals/{slug}/texa/
```

`{slug}` is your help centre's slug (Settings → Help centre).

## Sign the customer in

**With a code.** The customer gives an email or a phone number; Texa sends a code; you exchange it
for a session.

```bash
curl -X POST https://desk.texadesk.com/public/api/v1/portals/help/texa/code \
  -H "Content-Type: application/json" -d '{"address": "tolu@example.com"}'
# {"sent": true}   (for any address: it never tells who is a customer)

curl -X POST https://desk.texadesk.com/public/api/v1/portals/help/texa/verify \
  -H "Content-Type: application/json" -d '{"address": "tolu@example.com", "code": "482913"}'
```

```json
{"level": "code", "expires_at": 1790003600, "contact": {"id": 345, "name": "Tolu Bello"},
 "token": "..."}
```

**With your own sign-in.** If the customer is already signed in to your app, your **server** proves
who they are: an HMAC-SHA256 of their identifier with the HMAC token of your help centre's live chat
inbox ([identity validation](/desk/live-chat#identity-validation)):

```bash
curl -X POST https://desk.texadesk.com/public/api/v1/portals/help/texa/identity \
  -H "Content-Type: application/json" \
  -d '{"identifier": "user-1842", "identifier_hash": "<hmac>"}'
```

That session is at the `verified` level. Send the `token` as `Authorization: Bearer <token>` on
every call below.

## Their requests

| Call | Does |
|---|---|
| `GET …/requests` | the customer's tickets: reference, title, type, state in the customer's words, dates |
| `GET …/requests/{reference}` | one, with its customer fields and its public `messages` from every channel |
| `POST …/requests/{reference}/messages` | a reply (`content`, up to 5 files in `attachments[]`) |
| `GET …/request_types` | the kinds of request a customer can make, with their fields |
| `POST …/requests` | a new request (`type_id`, `content`, `title`, `fields`, files): made and acknowledged at once |
| `POST …/track` | a code sent to the address on file for a reference, for "track my request" without an account |

- **Only public messages**: never a private note, an activity line or Texa AI's drafts.
- **Sensitive requests** (every complaint) at the `code` level answer `open: false`, with empty
  `messages` and `fields`: show the reference, state and dates, and offer your own sign-in, which
  opens it in full.
- **Limits** per customer: 30 messages an hour; 5 new requests an hour and 20 a day. Over them is `429`.
- **Refusals** are `422 {"error": "..."}` in the help centre's language. `401` means signed out.
- Every sign-in, refused code and view of a sensitive ticket is in your account's **audit log**.

Every route, with its fields: [Customer portal API](/api-reference/portal/signing-in/send-a-sign-in-code).
