Pular para o conteúdo

Início rápido da API

No final desta página, terá trocado uma chave de API por um bearer token, identificado a organização e a Equipa em que a sua credencial pode atuar, criado um Registo e voltado a lê-lo com o respetivo histórico de eventos.

Os dois percursos por linguagem abaixo são completos e independentes: tudo é definido antes de ser utilizado e nenhum depende de um passo do outro. Escolha um separador e mantenha-se nele.

Precisa de:

  • Uma chave de API de uma Conta de Serviço, emitida por um administrador da organização. Não existem chaves de API pessoais — consulte Autenticação e chaves de API caso ainda não tenha uma.
  • A Conta de Serviço tem de ser membro da Equipa na qual pretende escrever. A criação de Registos exige que seja atualmente membro da Equipa selecionada; uma credencial ao nível da organização que não pertença a nenhuma Equipa pode ler /api/v1/me, mas não pode criar registos. Peça ao administrador para a adicionar a uma Equipa se o passo 3 devolver 403 FORBIDDEN.
  • Percurso com curl: curl e jq (os exemplos utilizam-no para analisar JSON; se preferir não instalar o jq, copie manualmente os valores das respostas).
  • Percurso com TypeScript: um ambiente de execução que execute TypeScript diretamente e disponibilize fetch globalmente — Node.js 22.18 ou mais recente, Bun ou Deno. No Node.js 18 ou 20, execute o ficheiro com um carregador como o tsx. Não é necessário instalar pacotes: os exemplos utilizam apenas fetch simples. Está disponível separadamente um cliente tipado; consulte Cliente TypeScript.

Todos os pedidos são enviados para https://apid.dustid.io; consulte Ambientes para conhecer os restantes URLs de serviço.

  1. Terminal window
    export APID_URL="https://apid.dustid.io"
    export DUST_API_KEY="your-service-account-key" # read this from your secrets manager
  2. As chaves de API nunca são enviadas para endpoints /api/v1/*. Troque a chave uma vez em GET /api/auth/token, passando-a no cabeçalho x-api-key, e envie o JWT resultante como Authorization: Bearer <token> em todas as chamadas seguintes.

    Terminal window
    curl -fsS "$APID_URL/api/auth/token" -H "x-api-key: $DUST_API_KEY"
    { "token": "eyJhbGciOi...", "expiresIn": 900, "expiresAt": "2026-09-20T22:40:00.000Z" }
    Terminal window
    export DUST_TOKEN="$(
    curl -fsS "$APID_URL/api/auth/token" -H "x-api-key: $DUST_API_KEY" | jq -r '.token'
    )"

    A resposta contém token e — sempre que o próprio JWT tiver uma declaração de expiração — expiresIn (segundos restantes) e expiresAt (ISO 8601). Leia o tempo de vida a partir da resposta em vez de o codificar diretamente: atualmente, os tokens têm uma duração curta (cerca de 15 minutos) e não existe refresh token, pelo que uma tarefa de longa duração tem de efetuar uma nova troca durante a execução. O contrato completo relativo ao tempo de vida, uma implementação de colocação em cache e o padrão de atualização única após um 401 encontram-se em Autenticação → Expiração e atualização de tokens.

  3. GET /api/v1/me é um dos poucos endpoints que não necessita de cabeçalhos de contexto. Descreve a própria credencial: o principal, as organizações a que pertence e qual delas está ativa.

    Terminal window
    curl -fsS "$APID_URL/api/v1/me" -H "Authorization: Bearer $DUST_TOKEN"
    {
    "userId": "6a1f…",
    "email": "sap-connector@example.com",
    "name": "SAP Connector",
    "activeOrganizationId": "b2c7…",
    "organizations": [
    { "id": "b2c7…", "name": "Anchor Electronics", "slug": "anchor-electronics", "roles": ["member"] }
    ]
    }
    Terminal window
    # Prefer the active organization; fall back to the first membership.
    export DUST_ORG_ID="$(
    curl -fsS "$APID_URL/api/v1/me" -H "Authorization: Bearer $DUST_TOKEN" \
    | jq -er '.activeOrganizationId // .organizations[0].id'
    )"
    echo "Organization: $DUST_ORG_ID"
  4. Os registos pertencem a uma Equipa dentro da organização. Existem duas opções suportadas:

    • Não fazer nada. Omita Dust-Ctx-Team-Id e a API atua na Equipa raiz da organização. Isto constitui a totalidade do passo 4 para uma organização com uma única Equipa, e os exemplos do passo 5 seguem este percurso.
    • Indicar uma Equipa. GET /api/v1/teams apresenta as Equipas das quais a sua credencial é membro, no formato { "teams": [ … ], "total": n }, cada uma com teamId, orgId e name. Envie a Equipa pretendida como Dust-Ctx-Team-Id.
    Terminal window
    curl -fsS "$APID_URL/api/v1/teams?pageSize=50" \
    -H "Authorization: Bearer $DUST_TOKEN" \
    -H "Dust-Ctx-Org-Id: $DUST_ORG_ID" \
    | jq '.teams[] | { teamId, name }'
    { "teamId": "b2c7…", "name": "Anchor Electronics" }
    { "teamId": "4e90…", "name": "Line 3 Receiving" }
    Terminal window
    # Optional. Leave DUST_TEAM_ID unset to use the organization's root Team.
    export DUST_TEAM_ID="4e90…"

    Todos os pedidos abaixo enviam -H "Dust-Ctx-Team-Id: ${DUST_TEAM_ID:-}". Um valor vazio é tratado exatamente como um cabeçalho ausente — é utilizada a Equipa raiz da organização — pelo que o mesmo script é executado quer defina ou não a variável.

  5. Um Registo corresponde ao registo de um único ativo ou item. POST /api/v1/threads com type: "single" cria um; thread.name é o único campo obrigatório e a matriz opcional data contém campos tipados.

    Terminal window
    curl -fsS "$APID_URL/api/v1/threads" \
    -H "Authorization: Bearer $DUST_TOKEN" \
    -H "Dust-Ctx-Org-Id: $DUST_ORG_ID" \
    -H "Dust-Ctx-Team-Id: ${DUST_TEAM_ID:-}" \
    -H "Content-Type: application/json" \
    -d '{
    "type": "single",
    "thread": {
    "name": "Tire SZ3J-11-ZJ17",
    "description": "Production asset"
    },
    "data": [
    { "name": "Serial Number", "type": "text", "value": { "text": "SZ3J-11-ZJ17" } },
    { "name": "Max PSI", "type": "number", "value": { "number": 51 } }
    ]
    }' | tee /tmp/created.json | jq '.created[0] | { threadId, name }'
    { "threadId": "0f13c0de-2f1a-4a2e-9f60-6d2f7b9f0a11", "name": "Tire SZ3J-11-ZJ17" }
    Terminal window
    export THREAD_ID="$(jq -r '.created[0].threadId' /tmp/created.json)"

    O estado é 201 Created e o corpo é { "created": [ … ], "uploadResponses": [] } — um formato de lote, porque o mesmo endpoint cria vários Registos de uma só vez com type: "list" ou type: "raw". Cada entrada em created é um registo completo de Registo, incluindo o respetivo threadId gerado.

    As entradas dos campos necessitam de type e value, e a estrutura de value varia consoante o tipo: { "text": "…" } para text e { "number": 51 } para number. name é a etiqueta do campo. A lista completa de tipos de campo encontra-se no guia de Registos.

  6. GET /api/v1/threads/{thread_id} devolve o Registo juntamente com o respetivo histórico de eventos — todas as escritas são registadas, pelo que o histórico de auditoria começa na criação.

    Terminal window
    curl -fsS "$APID_URL/api/v1/threads/$THREAD_ID" \
    -H "Authorization: Bearer $DUST_TOKEN" \
    -H "Dust-Ctx-Org-Id: $DUST_ORG_ID" \
    -H "Dust-Ctx-Team-Id: ${DUST_TEAM_ID:-}" \
    | jq '{ name: .thread.name, fields: [.thread.data[]?.name], events: (.events | length) }'
    { "name": "Tire SZ3J-11-ZJ17", "fields": ["Serial Number", "Max PSI"], "events": 1 }

    A estrutura da resposta é { "thread": { … }, "events": [ … ] }. A contagem exata de eventos não faz parte do contrato — conte com pelo menos um.

O que observouO que significa
401 UNAUTHORIZED durante a trocaA chave de API está incorreta, foi revogada ou não é uma chave de Conta de Serviço. As chaves pessoais não permitem a autenticação.
401 UNAUTHORIZED numa chamada /api/v1/*O bearer token expirou (os tokens têm uma duração curta). Efetue novamente a troca e repita uma vez.
400 ORG_ID_REQUIREDOmitiu Dust-Ctx-Org-Id num endpoint com âmbito de organização.
400 INVALID_REQUEST que menciona um cabeçalhoUm cabeçalho de contexto não era um UUID. Os cabeçalhos são validados antes de o endpoint ser executado.
403 FORBIDDEN durante a criaçãoA Conta de Serviço não é membro da Equipa selecionada. Peça ao administrador para a adicionar.
404 ao voltar a lerNormalmente significa que o contexto está incorreto, não que o registo está em falta — um Registo apenas é visível na organização e na Equipa que o possuem ou com as quais foi partilhado.

Todos os corpos de erro têm o formato { code, message, status, detail? }, e todas as respostas incluem um cabeçalho x-request-id que deve ser registado. A lista completa de códigos, as tabelas de resultados da digitalização e as orientações sobre novas tentativas encontram-se em Erros e resultados da digitalização.