API Pública Sourced v1
A API Sourced permite que sistemas ERP (como Calipso, SAP, JD Edwards) se integrem diretamente com a plataforma de compras da Sourced. Use-a para:
- Enviar requisições de compra do seu ERP para o Sourced
- Obter ordens de compra de volta no seu ERP após adjudicação
- Verificar quais requisições já foram sincronizadas
- Monitorar o status das suas requisições
A API segue as convenções REST, utiliza JSON para os corpos de solicitação e resposta, e se autentica via API keys.
Autenticação
Todos os endpoints (exceto health check) requerem uma API key enviada no header X-API-Key.
As API keys são criadas no painel de administração do Sourced em Configurações → API Keys. Cada key é exibida apenas uma vez ao ser criada. Armazene-a com segurança.
curl -H "X-API-Key: sk_live_abc123..." \
https://api.gosourced.ai/api/v1/requisitionsURL Base
| Ambiente | URL Base |
|---|---|
| Produção | https://api.gosourced.ai |
| Desenvolvimento | https://api-dev.gosourced.ai |
Todos os endpoints são prefixados com /api/v1.
Limites de taxa
Todos os endpoints são limitados a 60 solicitações por minuto por endpoint. Exceder este limite retorna uma resposta 429 Too Many Requests.
Para operações em massa, use o endpoint de importação em lote (POST /requisitions) que aceita até 100 requisições por solicitação.
Erros
A API utiliza códigos de status HTTP padrão. Erros retornam um corpo JSON com um campo detail.
{
"detail": "Invalid or revoked API key."
}| Status | Significado |
|---|---|
| 200 | Sucesso |
| 400 | Solicitação inválida - erro de validação ou corpo malformado |
| 401 | Não autorizado - API key ausente ou inválida |
| 404 | Não encontrado - o recurso não existe ou não é acessível |
| 422 | Entidade não processável - o corpo da solicitação não passou na validação do esquema |
| 429 | Muitas solicitações - limite de taxa excedido |
| 500 | Erro interno do servidor - erro inesperado do nosso lado |
Exemplos de erros
{
"detail": "Invalid or revoked API key."
}{
"detail": [
{
"loc": ["body", "requisitions", 0, "items", 0, "quantity"],
"msg": "Input should be greater than 0",
"type": "greater_than"
}
]
}{
"success": false,
"created_count": 2,
"updated_count": 0,
"skipped_count": 0,
"error_count": 1,
"errors": [
{
"index": 2,
"external_id": "REQ-2026-0099",
"error": "Failed to process requisition: duplicate external_line_id within items"
}
],
"requisition_ids": [1234, 1235]
}Nota: o endpoint POST /requisitions retorna 200 mesmo com falhas parciais. Sempre verifique o campo success e o array errors para detectar problemas por requisição.
Health Check
/api/v1/healthVerificar se a API está acessível. Não requer autenticação.
curl https://api.gosourced.ai/api/v1/health{
"status": "ok",
"api": "v1"
}Enviar um arquivo (Presigned)
/api/v1/files/presignAPI Key obrigatóriaObtenha uma URL pré-assinada para enviar um arquivo (um manifesto de requisição ou um anexo) diretamente ao S3. Os bytes não passam pela API, então especificações técnicas pesadas de licitações são enviadas sem atingir os limites de tamanho.
Fluxo de duas etapas (por arquivo)
- Chame este endpoint com o nome do arquivo para receber um upload_url e os campos do formulário.
- Faça um POST do arquivo como multipart/form-data para upload_url, incluindo primeiro todos os campos de fields e depois um campo file com os bytes.
Corpo da requisição
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| filename | string | obrigatório | Nome original do arquivo (ex. 'SOL_106177_LINE_001_SEQ010_adjunto.docx'). Componentes de caminho são removidos. |
| content_type | string | opcional | Tipo MIME. Se omitido, qualquer tipo é aceito. |
curl -X POST https://api.gosourced.ai/api/v1/files/presign \
-H "X-API-Key: sk_live_abc123..." \
-H "Content-Type: application/json" \
-d '{
"filename": "SOL_106177_LINE_001_SEQ010_adjunto.docx",
"content_type": "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
}'{
"upload_url": "https://s3.amazonaws.com/your-bucket",
"fields": {
"key": "erp-inbound/42/SOL_106177_LINE_001_SEQ010_adjunto.docx",
"Content-Type": "application/vnd.openxmlformats-...",
"policy": "eyJleHBpcmF0aW9uIjoi...",
"x-amz-signature": "a1b2c3..."
},
"key": "erp-inbound/42/SOL_106177_LINE_001_SEQ010_adjunto.docx",
"max_file_size": 524288000,
"expires_in": 600
}Campos da resposta
- upload_url - a URL do S3 para onde o POST do arquivo é feito.
- fields - campos do formulário que devem ser incluídos no POST multipart, antes do campo file.
- key - a chave sob a qual o arquivo será armazenado.
- max_file_size - tamanho máximo permitido em bytes (aplicado pelo S3).
- expires_in - segundos até a URL pré-assinada expirar.
# Use upload_url + every key in "fields", then the file (last).
curl -X POST "$UPLOAD_URL" \
-F "key=erp-inbound/42/SOL_106177_LINE_001_SEQ010_adjunto.docx" \
-F "Content-Type=application/vnd.openxmlformats-..." \
-F "policy=eyJleHBpcmF0aW9uIjoi..." \
-F "x-amz-signature=a1b2c3..." \
-F "file=@SOL_106177_LINE_001_SEQ010_adjunto.docx"
# HTTP 204 No Content on successImportar requisições
/api/v1/requisitionsAPI Key obrigatóriaImportar uma ou mais requisições de compra do seu ERP. Suporta importação em lote de até 100 requisições por solicitação. Usa external_id para deduplicação.
Corpo da solicitação
O corpo deve conter um array requisitions com 1 a 100 objetos de requisição.
Objeto Requisição
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| external_id | string | obrigatório | ID único no seu ERP (chave de deduplicação). Máx 250 caracteres. |
| items | array | obrigatório | Itens de linha (1-200 itens). Veja o esquema de Item abaixo. |
| requester_name | string | opcional | Nome da pessoa solicitante. Máx 200 caracteres. |
| requester_email | string | opcional | Email do solicitante. Máx 200 caracteres. |
| assigned_buyer | string | opcional | Comprador atribuído no ERP de origem (texto livre). Exibido e filtrável no triage. Máx 200 caracteres. |
| description | string | opcional | Título ou resumo da requisição. Máx 500 caracteres. |
| comments | string | opcional | Instruções adicionais para compradores (HTML suportado). Máx 15.000 caracteres. |
| delivery_address | string | opcional | Endereço de entrega em texto livre. Máx 500 caracteres. |
| delivery_address_code | string | opcional | Código correspondente a um endereço configurado no Sourced. Máx 50 caracteres. |
| desired_delivery_lead_time_days | integer | opcional | Prazo de entrega desejado em dias a partir da confirmação da OC. Aplicado como padrão a todos os itens. |
| created_date | datetime | opcional | Data de criação da requisição no seu sistema (ISO 8601). Exibida como "Criação" no triage. Não é data de entrega: a necessidade vai por item em desired_delivery_date. |
| offer_deadline | datetime | opcional | Data limite para cotações de fornecedores (ISO 8601). |
| total_estimated_value | float | opcional | Valor total estimado. Calculado automaticamente a partir dos itens se omitido. |
| currency | string | opcional | Código da moeda (ex: "ARS", "USD"). Padrão "ARS". Máx 10 caracteres. |
| department_code | string | opcional | Código de departamento/centro de custo (comparado com departamentos do Sourced). Máx 50 caracteres. |
| priority_level | string | opcional | Prioridade: "LOW", "MEDIUM", "HIGH" ou "CRITICAL". |
| attachments | array | opcional | Anexos de arquivo (máx 20). Veja o esquema de Anexo abaixo. |
| raw_data | object | opcional | JSON arbitrário do seu ERP, armazenado para rastreabilidade. |
Objeto Item
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| description | string | obrigatório | Visível para o fornecedorNome ou descrição do item. Máx 1.000 caracteres. |
| quantity | float | obrigatório | Visível para o fornecedorQuantidade necessária (deve ser > 0). |
| external_line_id | string | opcional | ID de linha no seu ERP (ex: "REQ-001-L10"). Retornado nas OC para rastreabilidade. Máx 100 caracteres. |
| unit_of_measure | string | opcional | Visível para o fornecedorCódigo de UOM (ex: "KG", "EA", "LT", "M", "UN"). Comparado com o catálogo da sua org. Máx 50 caracteres. |
| target_price | float | opcional | Preço alvo/orçamento por unidade. |
| estimated_price | float | opcional | Preço total estimado para esta linha. |
| currency | string | opcional | Moeda para preços (ex: "ARS", "USD"). Máx 10 caracteres. |
| category | string | opcional | Categoria do seu ERP. Máx 200 caracteres. |
| material_code | string | opcional | Visível para o fornecedorCódigo de material/peça no seu ERP (ex: código de material SAP). Máx 100 caracteres. |
| specifications | object | opcional | Especificações técnicas. Veja o esquema de Especificações abaixo. |
| desired_delivery_date | datetime | opcional | Data de entrega desejada para este item (ISO 8601, ex: "2026-05-15T00:00:00Z"). |
| desired_delivery_lead_time_days | integer | opcional | Prazo de entrega desejado em dias para esta linha. Sobrescreve o valor a nível de cabeçalho. |
| detail | string | opcional | Visível para o fornecedorDado técnico ou nota desta linha. Máx 1.000 caracteres. É compartilhado com o fornecedor: aparece no e-mail de solicitação de cotação em “Especificações”, a menos que você envie specifications.technical_specs, que tem prioridade. Não use para notas internas de compras. |
| raw_data | object | opcional | JSON arbitrário para este item. |
Objeto Especificações
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| manufacturer_code | string | opcional | Visível para o fornecedorNúmero de peça do fabricante (ex: "6ES7214-1AG40-0XB0"). Máx 100 caracteres. |
| manufacturer_name | string | opcional | Visível para o fornecedorNome do fabricante (ex: "Siemens"). Máx 200 caracteres. |
| manufacturer_description | string | opcional | Descrição do fabricante. Máx 500 caracteres. |
| buyer_code | string | opcional | Visível para o fornecedorCódigo interno no seu sistema (ex: "MAT-001234"). Máx 100 caracteres. |
| buyer_code_description | string | opcional | Descrição do código interno. Máx 500 caracteres. |
| buyer_code_system | string | opcional | Nome do sistema de origem (ex: "SAP", "Calipso"). Máx 50 caracteres. |
| technical_specs | string | opcional | Visível para o fornecedorEspecificações técnicas em texto livre (ex: "220V, 50Hz, IP55"). Máx 2.000 caracteres. É compartilhado com o fornecedor no e-mail de solicitação de cotação. Tem prioridade sobre o detail do item. |
| requirements | string | opcional | Requisitos adicionais (ex: "Certificação ISO 9001 obrigatória"). Máx 2.000 caracteres. Uso interno: não é incluído no e-mail ao fornecedor. |
Objeto Anexo
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| url | string | obrigatório | URL publicamente acessível para baixar o arquivo. Máx 2.000 caracteres. |
| filename | string | obrigatório | Nome do arquivo original (ex: "plano_motor.pdf"). Máx 255 caracteres. |
| description | string | opcional | Descrição do anexo. Máx 500 caracteres. |
| file_type | string | opcional | Tipo MIME (detectado automaticamente se não fornecido). Máx 100 caracteres. |
Lógica de deduplicação
Cada requisição é identificada pelo seu external_id (dentro do escopo da sua organização):
- Nova: Se nenhuma requisição existente for encontrada, uma nova é criada com status
PENDING. - Atualizar: Se uma requisição existente com status
PENDINGfor encontrada, ela é atualizada in-place (os itens são totalmente substituídos). - Superseder: Se uma requisição existente com status
SUPERSEDEDfor encontrada, ela é reativada (volta para PENDING) com os novos dados. - Lançada: Se a requisição já foi lançada como Solicitação de Compra (
LAUNCHED), a importação é rejeitada. A PR ativa não pode ser sobrescrita. - Descartada: Se a requisição foi descartada anteriormente (
DISCARDED), ela é reativada (volta para PENDING) com os novos dados. Útil quando o ERP a cancela e depois a reenvia.
curl -X POST https://api.gosourced.ai/api/v1/requisitions \
-H "X-API-Key: sk_live_abc123..." \
-H "Content-Type: application/json" \
-d '{
"requisitions": [
{
"external_id": "REQ-2026-0042",
"items": [
{
"description": "Bearing SKF 6205",
"quantity": 10
}
]
}
]
}'Resposta
ERPImportResult
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| success | boolean | obrigatório | true se error_count for 0. |
| created_count | integer | obrigatório | Número de novas requisições criadas. |
| updated_count | integer | obrigatório | Número de requisições PENDING existentes atualizadas. |
| skipped_count | integer | obrigatório | Número de requisições ignoradas (atualmente sempre 0). |
| error_count | integer | obrigatório | Número de requisições que falharam ao importar. |
| errors | array | obrigatório | Array de {index, external_id, error} para cada requisição que falhou. |
| requisition_ids | array | obrigatório | IDs internos do Sourced das requisições criadas/atualizadas. |
{
"success": true,
"created_count": 1,
"updated_count": 0,
"skipped_count": 0,
"error_count": 0,
"errors": [],
"requisition_ids": [1234]
}Listar requisições
/api/v1/requisitionsAPI Key obrigatóriaObter uma lista paginada das suas requisições importadas. Retorna apenas requisições criadas via API.
Parâmetros de consulta
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| page | integer | opcional | Número da página (padrão: 1). |
| page_size | integer | opcional | Itens por página, 1-100 (padrão: 20). |
| status | string | opcional | Filtrar por status: "PENDING", "LAUNCHED", "DISCARDED", "SUPERSEDED". |
curl -H "X-API-Key: sk_live_abc123..." \
"https://api.gosourced.ai/api/v1/requisitions?page=1&page_size=20&status=PENDING"{
"data": [
{
"id": 1234,
"external_id": "REQ-2026-0042",
"status": "PENDING",
"requester_name": "Juan Pérez",
"description": "Repuestos línea producción",
"items": [...],
"imported_at": "2026-03-07T14:30:00Z"
}
],
"total": 45,
"page": 1,
"page_size": 20,
"has_more": true
}Detalhe da requisição
/api/v1/requisitions/{requisition_id}API Key obrigatóriaObter uma requisição individual pelo seu ID interno do Sourced, incluindo todos os itens.
curl -H "X-API-Key: sk_live_abc123..." \
https://api.gosourced.ai/api/v1/requisitions/1234Retorna o objeto completo da requisição. Retorna 404 se não encontrada ou não pertencente à sua organização.
Verificar requisições existentes
/api/v1/requisitions/check-existingAPI Key obrigatóriaVerificar quais external_ids já existem no Sourced antes de importar. Útil para evitar chamadas desnecessárias à API.
Corpo da solicitação
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| external_ids | array | obrigatório | Lista de strings external_id para verificar (1-100 itens). |
curl -X POST https://api.gosourced.ai/api/v1/requisitions/check-existing \
-H "X-API-Key: sk_live_abc123..." \
-H "Content-Type: application/json" \
-d '{
"external_ids": ["REQ-2026-0042", "REQ-2026-0043", "REQ-2026-0044"]
}'{
"existing": ["REQ-2026-0042"],
"not_found": ["REQ-2026-0043", "REQ-2026-0044"]
}Cancelar requisição
/api/v1/requisitions/cancelAPI Key obrigatóriaCancelar uma requisição PENDING enviando o external_id no corpo da requisição.
Apenas requisições com status PENDING podem ser canceladas. Se a requisição já foi lançada como Solicitação de Compra, deve ser cancelada dentro do Sourced.
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| external_id | string | obrigatório | O ID da requisição no seu sistema externo (o mesmo usado na importação) |
| reason | string | opcional | Motivo do cancelamento (armazenado para auditoria) |
curl -X POST https://api.gosourced.ai/api/v1/requisitions/cancel \
-H "X-API-Key: sk_live_abc123..." \
-H "Content-Type: application/json" \
-d '{
"external_id": "REQ-2026-0042",
"reason": "Cancelado desde ERP"
}'{
"status": "discarded",
"external_id": "REQ-2026-0042"
}Respostas possíveis:
discarded- A requisição foi descartada com sucesso.already_discarded- A requisição já estava descartada (idempotente).already_superseded- A requisição já foi substituída por uma versão mais nova.- A requisição já foi lançada - retorna
409com detalhes. - Requisição não encontrada - retorna
404.
Listar ordens de compra
/api/v1/purchase-ordersAPI Key obrigatóriaObter ordens de compra da sua organização. Suporta sincronização incremental através do parâmetro 'since'.
Parâmetros de consulta
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| page | integer | opcional | Número da página (padrão: 1). |
| page_size | integer | opcional | Itens por página, 1-100 (padrão: 20). |
| status | string | opcional | Filtrar por status: "DRAFT", "CREATED", "SENT", "CONFIRMED", "REJECTED", "CANCELLED". |
| since | datetime | opcional | Timestamp ISO 8601. Retorna apenas OC criadas ou atualizadas após esta data. |
| requisition_external_id | string | opcional | Filtrar pelo external_id da requisição original no seu ERP. Retorna as OC geradas a partir dessa requisição. |
curl -H "X-API-Key: sk_live_abc123..." \
"https://api.gosourced.ai/api/v1/purchase-orders?since=2026-03-01T00:00:00Z&status=CONFIRMED"{
"data": [
{
"id": 567,
"code": "PO-2026-0089",
"status": "CONFIRMED",
"award_type": "FULL",
"supplier_name": "Distribuidora Industrial SA",
"supplier_id": 42,
"supplier_external_id": "PROV-CAL-00123",
"supplier_tax_id": "30712345678",
"supplier_email": "ventas@distribuidora.com",
"total_price": 285000.00,
"currency": "ARS",
"delivery_address": "Av. Corrientes 1234, CABA",
"delivery_address_code": "001",
"observations": "Entregar en horario de mañana. Coordinar con depósito.",
"delivery_lead_time_days": 15,
"expected_delivery_date": "2026-03-20T16:00:00Z",
"payment_terms_code": "NET30",
"awarded_at": "2026-03-05T16:00:00Z",
"awarded_by_name": "Juan Pérez",
"awarded_by_email": "juan.perez@empresa.com",
"created_at": "2026-03-05T16:00:00Z",
"updated_at": "2026-03-06T10:30:00Z",
"purchase_request_id": 1234,
"requisition_external_id": "REQ-2026-00142",
"exchange_rate_data": {
"date": "2026-03-05",
"usdToArs": 1450.0,
"arsToUsd": 0.00069
},
"total_nominal_savings": 15000.00,
"total_real_savings": 8500.00,
"savings_currency": "ARS",
"items": [
{
"description": "Bearing SKF 6205",
"quantity": 10,
"unit_price": 28500.00,
"total_price": 285000.00,
"unit_of_measure": "UN",
"currency": "ARS",
"delivery_lead_time_days": 15,
"expected_delivery_date": "2026-03-20T16:00:00Z",
"external_line_id": "REQ-2026-0042-L10",
"buyer_code": "MAT-001234",
"buyer_code_system": "SAP",
"manufacturer_code": "6205-2RS",
"technical_specs": "220V, 50Hz, IP55"
}
]
}
],
"total": 12,
"page": 1,
"page_size": 20,
"has_more": false
}Detalhe da ordem de compra
/api/v1/purchase-orders/{po_id}API Key obrigatóriaObter uma ordem de compra individual pelo seu ID interno do Sourced, incluindo todos os itens de linha com rastreabilidade de volta ao seu ERP via external_line_id.
curl -H "X-API-Key: sk_live_abc123..." \
https://api.gosourced.ai/api/v1/purchase-orders/567Este endpoint requer o ID interno do Sourced (po_id). Se você precisa buscar ordens de compra usando o ID de requisição do seu ERP, use o endpoint GET /purchase-orders com o query parameter requisition_external_id:
Você também pode combinar com outros filtros: status para filtrar por status da OC, since para sincronização incremental, e page / page_size para paginação.
Objeto Ordem de Compra
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| id | integer | obrigatório | ID interno da OC no Sourced. |
| code | string | obrigatório | Código legível da OC. |
| status | string | obrigatório | Status da OC: "DRAFT", "CREATED", "SENT", "CONFIRMED", "REJECTED", "CANCELLED". |
| award_type | string | opcional | Tipo de adjudicação: FULL (fornecedor único) ou PARTIAL (adjudicação dividida entre múltiplos fornecedores). |
| supplier_name | string | obrigatório | Nome do fornecedor. |
| supplier_id | integer | opcional | ID interno do fornecedor no Sourced. |
| total_price | float | opcional | Valor total da OC. |
| currency | string | opcional | Código da moeda. |
| delivery_address | string | opcional | Endereço de entrega. |
| delivery_address_code | string | opcional | Código do endereço de entrega da organização vinculado (ex. "001"). Use-o para mapear o destino no seu ERP. Null para endereços de texto livre sem registro vinculado. |
| observations | string | opcional | Comentários ou observações em texto livre inseridos pelo comprador na etapa de revisão pré-adjudicação. Usa as condições especiais cotadas pelo fornecedor quando o comprador não deixou nota. Null quando não há nenhuma. |
| delivery_lead_time_days | integer | opcional | Prazo de entrega em dias, conforme cotado pelo fornecedor a nível de cabeçalho. Quando o fornecedor cota prazos diferentes por linha, os itens podem ter valores distintos - use items[].delivery_lead_time_days para o valor por linha. |
| expected_delivery_date | datetime | opcional | Data de entrega calculada (awarded_at + delivery_lead_time_days). Null se faltar qualquer um dos dois. Para datas por linha use items[].expected_delivery_date. |
| payment_terms_code | string | opcional | Código das condições de pagamento. |
| awarded_at | datetime | opcional | Quando a OC foi adjudicada (ISO 8601). |
| awarded_by_name | string | opcional | Nome do usuário que adjudicou a OC. |
| awarded_by_email | string | opcional | Email do usuário que adjudicou a OC. |
| created_at | datetime | opcional | Timestamp de criação (ISO 8601). |
| updated_at | datetime | opcional | Timestamp da última atualização (ISO 8601). |
| purchase_request_id | integer | opcional | ID da solicitação de compra originária. |
| requisition_external_id | string | opcional | ID do documento de origem no seu ERP (ex. número de requisição em Calipso/SAP/JDE). Resolvido a partir da ERPRequisition de origem quando disponível; caso contrário, recorre ao external_id da PR. Pode ser uma lista separada por vírgulas quando uma única PR agrega múltiplas requisições de origem. |
| exchange_rate_data | object | opcional | Taxas de câmbio no momento do award. Formato: {"date": "2026-03-05", "usdToArs": 1450.0, "arsToUsd": 0.00069}. Null se não houver dados disponíveis. |
| total_nominal_savings | float | opcional | Economia nominal total vs preços históricos (sem ajuste por inflação). |
| total_real_savings | float | opcional | Economia real total vs preços históricos (ajustada por inflação). |
| savings_currency | string | opcional | Moeda dos valores de economia. |
| items | array | obrigatório | Itens de linha da OC. Veja o esquema de Item de OC abaixo. |
Objeto Item de OC
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| description | string | obrigatório | Descrição do item. |
| quantity | float | opcional | Quantidade pedida. |
| unit_price | float | opcional | Preço por unidade. |
| total_price | float | opcional | Preço total da linha (quantidade x preço unitário). |
| unit_of_measure | string | opcional | Unidade de medida. |
| currency | string | opcional | Código da moeda. |
| delivery_lead_time_days | integer | opcional | Prazo de entrega em dias para esta linha, conforme cotado pelo fornecedor. Itens diferentes da mesma OC podem ter prazos distintos. |
| expected_delivery_date | datetime | opcional | Data de entrega calculada para esta linha (PO.awarded_at + delivery_lead_time_days do item). Null se faltar qualquer um dos dois. |
| external_line_id | string | opcional | ID de linha original do seu ERP - use para vincular itens da OC às suas linhas de requisição. |
| buyer_code | string | opcional | Código interno no seu sistema, exatamente como enviado ao importar a requisição (ex: "MAT-001234"). |
| buyer_code_system | string | opcional | Sistema de origem do código interno (ex: "SAP", "JDE", "Calipso"). |
| buyer_code_description | string | opcional | Descrição do código interno. |
| manufacturer_code | string | opcional | Número de peça do fabricante. |
| manufacturer_name | string | opcional | Nome do fabricante (ex: "Siemens"). |
| manufacturer_description | string | opcional | Descrição do fabricante para a peça. |
| technical_specs | string | opcional | Especificações técnicas em texto livre (ex: "220V, 50Hz, IP55"). |
| requirements | string | opcional | Requisitos adicionais (ex: "Certificação ISO 9001 exigida"). |
- O prazo de entrega existe em dois níveis:
delivery_lead_time_daysa nível de cabeçalho (reflete o prazo geral cotado pelo fornecedor) eitems[].delivery_lead_time_daysa nível de linha (preciso por item). Quando o fornecedor cota prazos diferentes por linha, prefira o valor por linha. expected_delivery_dateé um campo calculado:awarded_at + delivery_lead_time_days. O Sourced calcula; o fornecedor não envia uma data diretamente.- Se
delivery_lead_time_daysfor null,expected_delivery_datetambém será null. Isso normalmente significa que o fornecedor não incluiu o prazo na cotação.
Baixar o legajo da OC (dossiê)
/api/v1/purchase-orders/{po_id}/legajoAPI Key obrigatóriaObtenha um link temporário para baixar o legajo - um ZIP com a trilha de auditoria completa da adjudicação: PDF/XLSX comparativo, histórico de e-mails e os anexos de todos os fornecedores participantes.
curl -H "X-API-Key: sk_live_abc123..." \
https://api.gosourced.ai/api/v1/purchase-orders/567/legajoObjeto de resposta
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| download_url | string | obrigatório | URL pré-assinada temporária para baixar o ZIP do legajo. |
| filename | string | obrigatório | Nome sugerido para o arquivo ZIP. |
| expires_in | integer | obrigatório | Segundos até a URL de download expirar. |
| size_bytes | integer | obrigatório | Tamanho do ZIP do legajo em bytes. |
- A resposta é uma URL pré-assinada temporária (válida ~10 minutos). Baixe o ZIP diretamente dela - essa URL não requer API key.
- O legajo corresponde à requisição (PR) por trás da OC. Em uma adjudicação dividida (várias OCs de uma mesma requisição), as OCs irmãs retornam o mesmo dossiê.
Comparativo de cotações da OC
/api/v1/purchase-orders/{po_id}/quotationsAPI Key obrigatóriaObtenha o comparativo completo de cotações que originou esta adjudicação: todas as linhas cotadas por cada fornecedor para a solicitação (PR) por trás da OC, adjudicadas e não adjudicadas - não apenas as que terminaram nesta OC.
curl -H "X-API-Key: sk_live_abc123..." \
https://api.gosourced.ai/api/v1/purchase-orders/567/quotations{
"purchase_order_id": 567,
"purchase_order_code": "PO-4F2A91C3",
"requisition_external_id": "REQ-2026-0042",
"exchange_rate": {
"date": "2026-07-12",
"base": "USD",
"rates": { "ARS": 1450.5, "EUR": 0.92 }
},
"currencies": ["ARS", "USD"],
"items": [
{
"material_code": "MAT-000123",
"external_line_id": "10",
"description": "Guantes de nitrilo talle L",
"quantity": 500.0,
"quotes": [
{
"quotation_id": 8123,
"supplier_id": 42,
"supplier_name": "Proveedor A S.A.",
"supplier_tax_id": "30516242775",
"supplier_erp_code": "PROV-001",
"unit_price": 11.25,
"original_price": 12.5,
"discount": { "type": "percentage", "value": 10, "source": "manual" },
"currency": "ARS",
"quantity": 500,
"awarded": true,
"awarded_po_code": "PO-4F2A91C3",
"lead_time_days": 7,
"payment_term_code": "NET30",
"response_status": "PARTIAL",
"received_at": "2026-07-10T14:32:00+00:00"
},
{
"quotation_id": 8124,
"supplier_id": 57,
"supplier_name": "Proveedor B S.R.L.",
"supplier_tax_id": "30709876541",
"supplier_erp_code": null,
"unit_price": 0.0095,
"original_price": 0.0095,
"discount": null,
"currency": "USD",
"quantity": 500,
"awarded": false,
"awarded_po_code": null,
"lead_time_days": 15,
"payment_term_code": null,
"response_status": "INCOMPLETE",
"received_at": "2026-07-11T09:05:00+00:00"
}
]
}
]
}Objeto de resposta
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| purchase_order_id | integer | obrigatório | ID da OC consultada. |
| purchase_order_code | string | obrigatório | Código da OC consultada (ex.: PO-4F2A91C3). |
| requisition_external_id | string | opcional | ID externo da requisição de origem (sistema ERP), se houver. |
| exchange_rate | object | opcional | Taxas de câmbio salvas na OC no momento da adjudicação, para converter as cotações para uma moeda comum: { date, base: "USD", rates: { BRL: 5.4, ARS: 1450.5 } } (unidades de cada moeda por 1 USD). null se a OC não salvou uma foto (licitação, catálogo ou OC anterior a esta função). |
| currencies | array | obrigatório | Moedas distintas que aparecem nas cotações, ordenadas (ex.: ["BRL", "USD"]). |
| items | array | obrigatório | Linhas da solicitação por trás da OC, cada uma com suas cotações. |
Objeto item (items[])
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| material_code | string | opcional | Código de material do comprador, se a linha tiver um. |
| external_line_id | string | opcional | ID da linha no sistema de origem (ERP), se houver. |
| description | string | obrigatório | Descrição do item solicitado. |
| quantity | float | opcional | Quantidade solicitada. |
| quotes | array | obrigatório | Cotações recebidas para esta linha, uma por fornecedor que cotou com preço. |
Objeto cotação (items[].quotes[])
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| quotation_id | integer | obrigatório | ID da cotação. Um fornecedor que cotou mais de uma vez (rodadas) aparece uma vez por cotação. |
| supplier_id | integer | opcional | ID interno do fornecedor no Sourced. Identidade estável entre linhas (o nome pode se repetir). |
| supplier_name | string | opcional | Nome do fornecedor que cotou. |
| supplier_tax_id | string | opcional | Identificador fiscal do fornecedor (CNPJ no Brasil, CUIT na Argentina, RUT no Chile/Uruguai). |
| supplier_erp_code | string | opcional | Código ERP do fornecedor na sua organização, se configurado. |
| unit_price | float | opcional | Preço unitário FINAL, líquido de desconto, na moeda original do fornecedor. É o mesmo número que o comprador vê no comparativo de adjudicação e no Excel do dossiê, e o preço pelo qual a OC foi adjudicada. |
| original_price | float | opcional | Preço unitário antes do desconto. Igual a unit_price se não houve desconto. |
| discount | object | opcional | Desconto aplicado: { type: "percentage" | "fixed", value, source }. source: supplier_quoted (ofertado pelo fornecedor), negotiation, manual (inserido pelo comprador) ou global. null se não houve desconto. |
| currency | string | opcional | Moeda da cotação (código ISO, ex.: BRL, USD). Se o fornecedor não indicou moeda em nenhum lugar, informa-se "USD". |
| quantity | float | opcional | Quantidade cotada pelo fornecedor. |
| awarded | boolean | obrigatório | true se esta linha foi adjudicada a este fornecedor em alguma OC ativa da solicitação. |
| awarded_po_code | string | opcional | Código da OC onde a linha foi adjudicada (pode ser uma OC irmã em adjudicação dividida). null se não foi adjudicada. |
| lead_time_days | integer | opcional | Prazo de entrega ofertado, em dias (inteiro). Um prazo não numérico é informado como null. |
| payment_term_code | string | opcional | Código da condição de pagamento ofertada pelo fornecedor. |
| response_status | string | opcional | Classificação da análise de IA da resposta do fornecedor. Valores como INCOMPLETE, PARTIAL, NEEDS_HUMAN_REVIEW, EXPLICIT_REJECTION. |
| received_at | datetime | opcional | Data e hora de recebimento da cotação (ISO 8601). |
- O comparativo corresponde à solicitação (PR) por trás da OC: inclui as cotações de todos os fornecedores participantes, mesmo os que não venceram. Uma linha cotada sem preço não gera entrada em quotes; uma OC de catálogo (sem processo de cotação) retorna quotes vazios.
awardedé no nível da solicitação: em uma adjudicação dividida, uma linha pode ter sido adjudicada em uma OC irmã diferente da consultada -awarded_po_codesempre indica o código da OC vencedora daquela linha.- Os preços são os mesmos que o comprador viu no comparativo de adjudicação e os que constam no Excel do dossiê:
unit_pricejá inclui qualquer desconto negociado (original_priceediscountmostram o bruto e o desconto). Uma cotação importada que o usuário ainda não confirmou não aparece. - Os preços são retornados na moeda cotada por cada fornecedor - nenhuma conversão é aplicada.
exchange_ratetraz as taxas salvas na OC ao adjudicar (null se não houver) para que você converta tudo para uma moeda comum. - Todas as chaves estão sempre presentes; se um dado faltar, o valor é null (o formato da resposta nunca muda).
Atualizar status da ordem de compra
/api/v1/purchase-orders/{po_id}/statusAPI Key obrigatóriaAtualizar o status de uma ordem de compra para refletir seu progresso no seu sistema externo (ERP).
Transições de status permitidas:
| De | Para | Significado |
|---|---|---|
| DRAFT | CREATED | A OC foi criada no seu ERP. |
| CREATED | CONFIRMED | A OC foi totalmente aprovada no seu ERP. |
| DRAFT | CONFIRMED | Atalho quando não é necessário o passo intermediário. |
| DRAFT | REJECTED | A OC foi rejeitada no seu ERP. A PR é reaberta no Sourced. |
| CREATED | REJECTED | A OC foi rejeitada no seu ERP após ter sido criada. A PR é reaberta no Sourced. |
| DRAFT / CREATED / SENT / CONFIRMED | CANCELLED | A compra não vai acontecer. A OC é cancelada e a PR também - nada é reaberto. Use REJECTED se a necessidade ainda existir e você quiser readjudicar. |
REJECTED e CANCELLED também funcionam quando a OC foi uma adjudicação parcial, desde que seja a única OC ativa da sua PR. Se a PR tiver várias OCs ativas (split entre fornecedores), o endpoint retorna 409 e a reversão deve ser gerenciada dentro do Sourced.
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| status | string | obrigatório | Status destino: CREATED (OC criada no seu ERP), CONFIRMED (OC aprovada no seu ERP), REJECTED (OC rejeitada, reabre a PR) ou CANCELLED (compra cancelada, cancela a OC e a PR). |
| external_id | string | opcional | Número ou código da OC no seu ERP (ex: OC-CAL-00045678). Armazenado para rastreabilidade. |
| notes | string | opcional | Notas opcionais sobre a mudança de status. |
curl -X POST https://api.gosourced.ai/api/v1/purchase-orders/567/status \
-H "X-API-Key: sk_live_abc123..." \
-H "Content-Type: application/json" \
-d '{
"status": "CREATED",
"external_id": "OC-CAL-00045678",
"notes": "Creada en Calipso"
}'{
"status": "created",
"po_id": 567,
"code": "PO-A1B2C3D4"
}Editar uma OC
/api/v1/purchase-orders/{po_id}API Key obrigatóriaAtualiza os campos editáveis de uma ordem de compra. Apenas os campos presentes no body são alterados: número da OC no seu ERP, condição de pagamento, prazo de entrega, observações e status (mesma máquina de transições do POST /status).
Corpo da solicitação
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| external_id | string | opcional | Número ou código da OC no seu ERP. Sobrescreve o valor armazenado. |
| payment_terms_code | string | opcional | Código da condição de pagamento do catálogo (ex.: NET30). Não diferencia maiúsculas; validado contra os códigos ativos - um código desconhecido retorna 400 com a lista permitida. |
| delivery_lead_time_days | integer | opcional | Prazo de entrega em dias a partir da confirmação da OC. expected_delivery_date deriva deste valor. |
| observations | string | opcional | Texto livre exibido na OC. Uma string vazia o limpa. |
| status | string | opcional | Status de destino: CREATED, CONFIRMED, REJECTED ou CANCELLED - mesmas transições do POST /status. Enviar o status atual é um no-op. REJECTED/CANCELLED retornam o contrato desses fluxos (pr_reopened / pr_code) mais updated_fields. |
| notes | string | opcional | Notas sobre a mudança de status. Válido apenas junto com status. |
curl -X PATCH https://api.gosourced.ai/api/v1/purchase-orders/567 \
-H "X-API-Key: sk_live_abc123..." \
-H "Content-Type: application/json" \
-d '{
"external_id": "OC-CAL-00045678",
"payment_terms_code": "NET30",
"status": "CONFIRMED"
}'{
"status": "updated",
"po_id": 567,
"code": "PO-A1B2C3D4",
"updated_fields": ["external_id", "payment_terms_code", "status"]
}- Partial update real: apenas os campos presentes no body são aplicados. null explícito é um erro (400) - para deixar um campo como está, omita-o.
- Toda a validação roda antes de aplicar qualquer coisa: em uma resposta 400 ou 409, nenhum campo do body foi modificado.
- A mudança de status usa a mesma máquina de transições do
POST /purchase-orders/{po_id}/status(que continua disponível). Uma transição inválida retorna 409. Editar uma OC CANCELLED ou REJECTED retorna 409. - Alterar a condição de pagamento ou o prazo de entrega não regenera o PDF que o fornecedor já recebeu: o dado é atualizado no Sourced, mas o documento enviado não muda.
- O conteúdo da adjudicação (preços, itens, moeda, fornecedor) não é editável: para corrigi-lo, rejeite a OC (status REJECTED) e adjudique novamente.
Listar fornecedores
/api/v1/suppliersAPI Key obrigatóriaListar os fornecedores da sua organização. Use ?has_erp_code=false para encontrar fornecedores sem mapear. Use ?detail=full para contatos, categorias e cobertura.
Parâmetros de consulta
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| page | integer | opcional | Número da página (padrão: 1). |
| page_size | integer | opcional | Resultados por página (1-200, padrão: 50). |
| search | string | opcional | Buscar por nome, nome personalizado, email, CNPJ/CPF ou código ERP. |
| erp_code | string | opcional | Filtrar por código ERP exato. |
| has_erp_code | boolean | opcional | true = apenas mapeados ao ERP, false = apenas sem mapear. |
| detail | string | opcional | Use 'full' para incluir contatos, categorias e cobertura. |
# Light (default)
curl -H "X-API-Key: sk_live_abc123..." \
"https://api.gosourced.ai/api/v1/suppliers?has_erp_code=false"
# Full detail
curl -H "X-API-Key: sk_live_abc123..." \
"https://api.gosourced.ai/api/v1/suppliers?search=30712345678&detail=full"// Light response
{
"data": [
{
"id": 42,
"name": "Distribuidora Industrial SA",
"email": "ventas@distribuidora.com",
"tax_id": "30712345678",
"country_code": "AR",
"city": "Buenos Aires",
"is_active": true,
"is_preferred": true,
"erp_code": "PROV-CAL-00123",
"erp_type": "SAP_B1"
}
],
"total": 85,
"page": 1,
"page_size": 50,
"has_more": true
}
// Full response (?detail=full)
{
"data": [
{
"id": 42,
"name": "Distribuidora Industrial SA",
"email": "ventas@distribuidora.com",
"tax_id": "30712345678",
"country_code": "AR",
"city": "Buenos Aires",
"is_active": true,
"is_preferred": true,
"erp_code": "PROV-CAL-00123",
"erp_type": "SAP_B1",
"address": "Av. Corrientes 1234",
"state_code": "CABA",
"website": "https://distribuidora.com",
"description": "Distribuidor de insumos industriales",
"tax_regime": null,
"employee_count": "50+",
"years_in_business": "5+",
"performance_score": 4.2,
"reliability_score": 4.5,
"quality_score": 4.0,
"contacts": [
{
"name": "Juan Pérez",
"email": "juan@distribuidora.com",
"phone": "+54 11 5555-1234",
"role": "SALES",
"is_primary": true
}
],
"categories": [
{ "id": 15, "code": "IND-001", "name": "Insumos Industriales", "level": "LEVEL_1" }
],
"coverage": [
{ "country": "Argentina", "province": null, "is_nationwide": true }
]
}
],
"total": 1,
"page": 1,
"page_size": 50,
"has_more": false
}Criar fornecedor
/api/v1/suppliersAPI Key obrigatóriaCriar um fornecedor para sua organização. Pelo menos um de tax_id ou erp_code é obrigatório. Pelo menos um contato com papel 'sales' é obrigatório. Se já existir um fornecedor global com o mesmo CNPJ/CPF, ele é reutilizado e vinculado à sua organização.
Corpo da solicitação
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| name | string | obrigatório | Nome do fornecedor para sua organização. |
| tax_id | string | opcional | CNPJ, CUIT, RUT, etc. Pelo menos um de tax_id ou erp_code é obrigatório. |
| erp_code | string | opcional | Código do fornecedor no seu ERP. Pelo menos um de tax_id ou erp_code é obrigatório. |
| erp_type | string | opcional | Tipo de ERP (SAP_B1, JDE, ORACLE_CLOUD, etc.). |
| country_code | string | opcional | Código de país ISO 3166-1 (ex: AR, BR, US). |
| city | string | opcional | Cidade do fornecedor. |
| address | string | opcional | Endereço completo. |
| state_code | string | opcional | Estado/província (ex: SP, RJ). |
| website | string | opcional | Site do fornecedor. |
| contacts | array | obrigatório | Lista de contatos. Pelo menos um com papel 'sales' é obrigatório. |
| contacts[].name | string | obrigatório | Nome do contato. |
| contacts[].email | string | obrigatório | Email do contato. |
| contacts[].phone | string | opcional | Telefone (opcional). |
| contacts[].role | string | obrigatório | Papel: SALES ou LOGISTICS. |
| contacts[].is_primary | boolean | opcional | true se for o contato principal (padrão: false). |
curl -X POST https://api.gosourced.ai/api/v1/suppliers \
-H "X-API-Key: sk_live_abc123..." \
-H "Content-Type: application/json" \
-d '{
"name": "Distribuidora Industrial SA",
"tax_id": "30712345678",
"erp_code": "PROV-CAL-00123",
"erp_type": "SAP_B1",
"country_code": "AR",
"city": "Buenos Aires",
"address": "Av. Corrientes 1234",
"contacts": [
{
"name": "Juan Pérez",
"email": "juan@distribuidora.com",
"phone": "+54 11 5555-1234",
"role": "SALES",
"is_primary": true
},
{
"name": "María García",
"email": "maria@distribuidora.com",
"role": "LOGISTICS"
}
]
}'// 201 Created
{
"id": 42,
"name": "Distribuidora Industrial SA",
"email": null,
"tax_id": "30712345678",
"country_code": "AR",
"city": "Buenos Aires",
"is_active": true,
"is_preferred": false,
"erp_code": "PROV-CAL-00123",
"erp_type": "SAP_B1",
"address": "Av. Corrientes 1234",
"state_code": null,
"website": null,
"description": null,
"tax_regime": null,
"employee_count": null,
"years_in_business": null,
"performance_score": null,
"reliability_score": null,
"quality_score": null,
"contacts": [
{
"name": "Juan Pérez",
"email": "juan@distribuidora.com",
"phone": "+54 11 5555-1234",
"role": "SALES",
"is_primary": true
},
{
"name": "María García",
"email": "maria@distribuidora.com",
"phone": null,
"role": "LOGISTICS",
"is_primary": false
}
],
"categories": [],
"coverage": []
}Criar ou atualizar acompanhamentos de entrega
/api/v1/delivery-trackingsAPI Key obrigatóriaUpsert em lote de 1 a 200 linhas de pedido de compra para acompanhar a entrega. A chave natural é (po_code, line_position): reenviar a mesma linha atualiza o acompanhamento existente em vez de duplicá-lo.
Limite de taxa: 30 solicitações por minuto (os demais endpoints deste grupo usam o limite geral de 60 por minuto).
Corpo da solicitação
O corpo deve conter um array lines com 1 a 200 linhas. Cada linha leva a OC, a posição, a data prometida, o fornecedor (código ERP ou CNPJ/CPF) e o detalhe do item (descrição, quantidade pedida e quantidade pendente): sem isso não há o que acompanhar nem o que mostrar ao fornecedor. Um campo obrigatório ausente rejeita o lote inteiro com 422.
Objeto de linha (lines[])
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| po_code | string | obrigatório | Número do pedido de compra no sistema do cliente. Máximo de 100 caracteres. |
| line_position | integer | obrigatório | Posição da linha dentro do pedido de compra (10, 20, 30…). Inteiro ≥ 0. |
| original_delivery_date | date | obrigatório | Data de entrega combinada (AAAA-MM-DD) |
| supplier_erp_code | string | Um dos dois | Código do fornecedor no ERP do cliente. Identificador recomendado. Obrigatório se supplier_tax_id não for enviado. Máximo 100 caracteres. |
| supplier_tax_id | string | Um dos dois | CNPJ/CPF do fornecedor. Obrigatório se supplier_erp_code não for enviado. Máximo 50 caracteres. |
| supplier_name | string | opcional | Apenas texto de exibição; nunca usado para associar o fornecedor. Máximo de 255 caracteres. |
| material_code | string | opcional | Código do material ou item no sistema do cliente. Máximo de 100 caracteres. |
| description | string | obrigatório | Descrição do item. É o que o fornecedor vê no e-mail de acompanhamento. Máximo 500 caracteres. |
| quantity_ordered | float | obrigatório | Quantidade pedida. ≥ 0. É o que o fornecedor vê no e-mail de acompanhamento. |
| quantity_pending | float | obrigatório | Quantidade pendente de entrega. ≥ 0. É o que o e-mail cobra do fornecedor: com entregas parciais, envie o que falta, não o pedido. |
| unit_of_measure | string | opcional | Unidade de medida. Máximo de 20 caracteres. |
| po_date | date | opcional | Data do pedido de compra (AAAA-MM-DD). |
| buyer_email | string | opcional | CC de escalonamento e destinatário dos avisos de atraso. Se não for enviado, a notificação in-app de atraso vai para o primeiro usuário com papel logistics da organização (só um, não todos). |
| is_urgent | boolean | opcional | Marca a linha como urgente. |
É preciso enviar pelo menos supplier_erp_code ou supplier_tax_id. Para supplier_tax_id, um valor vazio, ou composto só por separadores (por exemplo "-" ou " - "), conta como não enviado, e a correspondência ignora hífens e espaços dos dois lados (30-71234567-8 corresponde a 30712345678). supplier_erp_code só é aparado (trim): um "-" literal CONTA como enviado e é usado tal como está na busca — se não corresponder a nenhum fornecedor, a linha fica em SUPPLIER_NOT_FOUND (não é um erro).
Regras do upsert
- Linha nova: é criada como PENDING_SCHEDULE se o fornecedor foi resolvido, ou SUPPLIER_NOT_FOUND caso contrário. Nasce ativa (sem pausa).
- Linha existente, aberta, criada por esta mesma API: seus dados e quantidades são atualizados. Uma mudança em original_delivery_date ou nas quantidades não reinicia o ciclo de acompanhamento.
- Linha existente já encerrada (DELIVERED ou CANCELLED): é reativada com um novo ciclo de acompanhamento (volta a enviar e-mails de confirmação); o resultado é reactivated e conta dentro de updated_count.
- Corrigir o fornecedor de uma linha existente: se chegar com um supplier_erp_code ou supplier_tax_id que resolve para OUTRO fornecedor, o acompanhamento é revinculado a essa empresa e o ciclo recomeça (os e-mails anteriores foram para a empresa errada). Uma linha que não resolve nenhum fornecedor nunca desvincula o fornecedor já atribuído.
- Sem mudanças: o resultado é unchanged; nenhum evento é registrado e updated_at não é alterado.
- Linha administrada por outra fonte (CSV ou sincronização ERP): é rejeitada com o erro dlvTrackingManagedByOtherSource. Acompanhamentos carregados por CSV ou pela sincronização ERP não podem ser modificados por esta API.
- Quantidade pendente 0: a linha já foi recebida por completo. Em um acompanhamento aberto ela é encerrada como DELIVERED (evento delivered com reason quantity_pending_zero; a data real fica como o dia do envio — se você a conhece, use mark_delivered com actual_delivery_date). Em um já encerrado é unchanged, nunca uma reativação. Uma linha NOVA com pendente 0 retorna o erro dlvNothingPending.
curl -X POST https://api.gosourced.ai/api/v1/delivery-trackings \
-H "X-API-Key: sk_live_abc123..." \
-H "Content-Type: application/json" \
-d '{
"lines": [
{
"po_code": "OC-2026-0455",
"line_position": 10,
"original_delivery_date": "2026-10-15",
"supplier_erp_code": "PROV-CAL-00123",
"material_code": "MAT-001234",
"description": "Rodamiento SKF 6205",
"quantity_ordered": 50,
"quantity_pending": 50,
"unit_of_measure": "UN",
"buyer_email": "compras@empresa.com"
},
{
"po_code": "OC-2026-0455",
"line_position": 20,
"original_delivery_date": "2026-10-15",
"supplier_tax_id": "30-71234567-8",
"description": "Filtro de aceite",
"quantity_ordered": 12,
"quantity_pending": 12,
"unit_of_measure": "UN"
}
]
}'Resposta
Resposta do upsert
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| created_count | integer | obrigatório | Quantidade de linhas criadas. |
| updated_count | integer | obrigatório | Quantidade de linhas atualizadas (inclui as reativadas). |
| unchanged_count | integer | obrigatório | Quantidade de linhas sem mudanças. |
| error_count | integer | obrigatório | Quantidade de linhas com erro. |
| results | array | obrigatório | Resultado de cada linha do lote, na mesma ordem em que foram enviadas. |
Objeto de resultado por linha (results[])
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| po_code | string | obrigatório | Número do pedido de compra, como enviado. |
| line_position | integer | obrigatório | Posição da linha, como enviada. |
| id | integer | opcional | Id interno do acompanhamento. Ausente quando a linha terminou em erro. |
| result | string | obrigatório | created | updated | unchanged | reactivated | error. |
| status | string | opcional | Status do acompanhamento após o upsert. Ausente nas linhas com erro. |
| code | string | opcional | Código do erro (dlv*). Presente apenas quando result é error. |
| message | string | opcional | Detalhe do erro em inglês, pensado para logs. Não traduzir nem exibir ao usuário final: code é a chave i18n. |
// 200 OK
{
"created_count": 1,
"updated_count": 0,
"unchanged_count": 0,
"error_count": 1,
"results": [
{
"po_code": "OC-2026-0455",
"line_position": 10,
"id": 8821,
"result": "created",
"status": "PENDING_SCHEDULE"
},
{
"po_code": "OC-2026-0455",
"line_position": 20,
"result": "error",
"code": "dlvSupplierReferenceAmbiguous",
"message": "supplier_tax_id '30-71234567-8' matches more than one supplier"
}
]
}O HTTP é sempre 200, mesmo quando há linhas com erro: verifique error_count e o code de cada linha em results para saber o que falhou.
Listar acompanhamentos de entrega
/api/v1/delivery-trackingsAPI Key obrigatóriaObter os acompanhamentos de entrega da sua organização, de todas as fontes (API, CSV e sincronização ERP). Suporta sincronização incremental com since.
Parâmetros de consulta
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| page | integer | opcional | Número da página (padrão: 1). |
| page_size | integer | opcional | Itens por página, 1-200 (padrão: 50). |
| status | string | opcional | Filtrar por status (ver a tabela de status abaixo). Inclui STAND_BY. |
| po_code | string | opcional | Filtrar pelo po_code exato. |
| supplier_erp_code | string | opcional | Filtrar pelo código ERP do fornecedor. |
| since | datetime | opcional | Timestamp ISO 8601. Retorna apenas acompanhamentos criados ou modificados a partir dessa data, em ordem crescente por data de modificação. Sem fuso horário é interpretado como UTC: envie sempre um offset explícito (ou "Z") para evitar ambiguidade. |
| open_only | boolean | opcional | Exclui os acompanhamentos DELIVERED e CANCELLED. |
since, a ordem é por data de modificação crescente (não por data de criação decrescente, que é a ordem padrão): guarde o updated_at do último registro recebido e use-o como o próximo since. Para não perder linhas gravadas por uma transação longa (um CSV grande, um sync do ERP), o servidor recua o since 10 minutos: você vai receber de novo registros desses minutos, então deduplique por id (o upsert é idempotente do seu lado). Para um acompanhamento que nunca foi modificado, updated_at é igual a created_at (nunca null): o cursor sempre tem um valor utilizável, sem que você precise resolver esse fallback.Status
| Status | Descrição |
|---|---|
| PENDING_SCHEDULE | Pendente de agendamento. Carregada; ainda não foi pedida confirmação ao fornecedor. |
| READY_TO_SEND | Pronta para enviar. Pronta para enviar o pedido de confirmação de entrega. |
| SENT_PENDING_RESPONSE | Enviada, aguardando resposta. Confirmação solicitada; o fornecedor ainda não respondeu. |
| NO_RESPONSE | Sem resposta. Não respondeu após os lembretes. |
| CONFIRMED_ON_TIME | Confirmada no prazo. O fornecedor confirmou a data original. |
| CONFIRMED_DELAYED | Confirmada com atraso. Confirmou, mas com data posterior à original. |
| CONFIRMED_EARLY | Confirmada antecipada. Confirmou uma data anterior à original. |
| REQUIRES_REVIEW | Requer revisão. Respondeu algo ambíguo ou mudou condições; precisa ser revisado. |
| DELIVERED | Entregue. Já entregue. |
| CANCELLED | Cancelada. O pedido de compra foi cancelado. |
| SUPPLIER_NOT_FOUND | Fornecedor não identificado. Não foi possível associar o fornecedor (por código ERP ou CNPJ). |
| STAND_BY | Pausada manualmente e ainda aberta: nenhum e-mail é enviado para ela. É um status virtual — um status terminal (DELIVERED/CANCELLED) sempre prevalece sobre STAND_BY, então uma linha pausada que é entregue ou cancelada é informada pelo seu status real. |
curl -H "X-API-Key: sk_live_abc123..." \
"https://api.gosourced.ai/api/v1/delivery-trackings?since=2026-09-01T00:00:00Z&open_only=true"Objeto de acompanhamento (delivery tracking)
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| id | integer | obrigatório | Id interno do acompanhamento. |
| po_code | string | obrigatório | Número do pedido de compra no sistema do cliente. |
| line_position | integer | obrigatório | Posição da linha dentro do pedido de compra. |
| source | string | obrigatório | Origem do acompanhamento: api, csv ou erp_sync. A API lê acompanhamentos das três fontes. |
| supplier | object | opcional | Fornecedor vinculado, ou null se ainda não pôde ser resolvido (SUPPLIER_NOT_FOUND). |
| supplier.id | integer | opcional | Id interno do fornecedor. |
| supplier.name | string | opcional | Razão social do fornecedor. |
| supplier.tax_id | string | opcional | CNPJ/CPF do fornecedor. |
| supplier.erp_code | string | opcional | Código ERP do fornecedor para a sua organização. |
| supplier_name | string | opcional | Nome do fornecedor como foi carregado (pode diferir de supplier.name se veio apenas como texto livre). |
| material_code | string | opcional | Código do material ou item. |
| description | string | opcional | Descrição do item. |
| quantity_ordered | float | opcional | Quantidade pedida. |
| quantity_pending | float | opcional | Quantidade pendente de entrega. |
| unit_of_measure | string | opcional | Unidade de medida. |
| po_date | date | opcional | Data do pedido de compra. |
| original_delivery_date | date | opcional | Data de entrega combinada originalmente. |
| eta | date | opcional | Data estimada de entrega. Um comprador a preenche manualmente pelo app (o modal de detalhe); nenhum processo automático a calcula. Em uma linha criada pela API, fica null até alguém preenchê-la. |
| actual_delivery_date | date | opcional | Data real de entrega, quando o status é DELIVERED. |
| received_quantity | float | opcional | Quantidade recebida, quando o status é DELIVERED. |
| status | string | opcional | Status público (ver a tabela de status). |
| is_urgent | boolean | obrigatório | Se a linha está marcada como urgente. |
| paused | boolean | obrigatório | Se o envio de acompanhamento está pausado (sending_paused). |
| pause_reason | string | opcional | Motivo da pausa. null se não estiver pausada. |
| followup_count | integer | obrigatório | Quantidade de lembretes enviados no ciclo atual. |
| last_followup_sent_at | datetime | opcional | Data e hora do último lembrete enviado. |
| next_followup_date | datetime | opcional | Data planejada para o próximo lembrete. |
| supplier_response | object | obrigatório | Última resposta do fornecedor. |
| supplier_response.responded_at | datetime | opcional | Data e hora em que o fornecedor respondeu. |
| supplier_response.confirmed_delivery_date | date | opcional | Data de entrega que o fornecedor confirmou. |
| supplier_response.delay_reason | string | opcional | Motivo do atraso, se o fornecedor indicou. |
| supplier_response.notes | string | opcional | Notas da última resposta do fornecedor. null se ainda não respondeu. |
| supplier_response.quality | string | opcional | Qualidade da resposta interpretada pela IA (por exemplo, concrete). |
| created_at | datetime | opcional | Data de criação do acompanhamento. |
| updated_at | datetime | opcional | Data da última modificação. |
{
"data": [
{
"id": 8821,
"po_code": "OC-2026-0455",
"line_position": 10,
"source": "api",
"supplier": {
"id": 42,
"name": "Distribuidora Industrial SA",
"tax_id": "30712345678",
"erp_code": "PROV-CAL-00123"
},
"supplier_name": "Distribuidora Industrial SA",
"material_code": "MAT-001234",
"description": "Rodamiento SKF 6205",
"quantity_ordered": 50,
"quantity_pending": 20,
"unit_of_measure": "UN",
"po_date": null,
"original_delivery_date": "2026-10-15",
"eta": "2026-10-18",
"actual_delivery_date": null,
"received_quantity": null,
"status": "CONFIRMED_DELAYED",
"is_urgent": false,
"paused": false,
"pause_reason": null,
"followup_count": 2,
"last_followup_sent_at": "2026-09-10T13:05:00+00:00",
"next_followup_date": "2026-09-17T00:00:00+00:00",
"supplier_response": {
"responded_at": "2026-09-12T09:40:00+00:00",
"confirmed_delivery_date": "2026-10-18",
"delay_reason": "Demora del fabricante",
"notes": "Se despachó el lote parcial, el resto llega la semana próxima.",
"quality": "concrete"
},
"created_at": "2026-09-01T12:00:00+00:00",
"updated_at": "2026-09-12T09:40:00+00:00"
}
],
"total": 1,
"page": 1,
"page_size": 50,
"has_more": false
}Obter um acompanhamento de entrega
/api/v1/delivery-trackings/{id}API Key obrigatóriaObter o detalhe de um acompanhamento pelo seu id interno.
Mesmo formato de cada elemento de GET /delivery-trackings.
curl -H "X-API-Key: sk_live_abc123..." \
https://api.gosourced.ai/api/v1/delivery-trackings/8821{
"id": 8821,
"po_code": "OC-2026-0455",
"line_position": 10,
"source": "api",
"supplier": {
"id": 42,
"name": "Distribuidora Industrial SA",
"tax_id": "30712345678",
"erp_code": "PROV-CAL-00123"
},
"supplier_name": "Distribuidora Industrial SA",
"material_code": "MAT-001234",
"description": "Rodamiento SKF 6205",
"quantity_ordered": 50,
"quantity_pending": 20,
"unit_of_measure": "UN",
"po_date": null,
"original_delivery_date": "2026-10-15",
"eta": "2026-10-18",
"actual_delivery_date": null,
"received_quantity": null,
"status": "CONFIRMED_DELAYED",
"is_urgent": false,
"paused": false,
"pause_reason": null,
"followup_count": 2,
"last_followup_sent_at": "2026-09-10T13:05:00+00:00",
"next_followup_date": "2026-09-17T00:00:00+00:00",
"supplier_response": {
"responded_at": "2026-09-12T09:40:00+00:00",
"confirmed_delivery_date": "2026-10-18",
"delay_reason": "Demora del fabricante",
"notes": "Se despachó el lote parcial, el resto llega la semana próxima.",
"quality": "concrete"
},
"created_at": "2026-09-01T12:00:00+00:00",
"updated_at": "2026-09-12T09:40:00+00:00"
}Um id que não existe, ou que pertence a outra organização, retorna 404 dlvTrackingNotFound: a existência de um acompanhamento de outra organização nunca é confirmada.
Histórico de eventos de um acompanhamento
/api/v1/delivery-trackings/{id}/eventsAPI Key obrigatóriaLinha do tempo paginada dos eventos de um acompanhamento, do mais antigo ao mais recente.
Parâmetros de consulta
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| page | integer | opcional | Número da página (padrão: 1). |
| page_size | integer | opcional | Itens por página, 1-200 (padrão: 50). |
Objeto de evento
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| id | integer | obrigatório | Id interno do evento. |
| type | string | obrigatório | Tipo de evento (ver a tabela de tipos). |
| occurred_at | datetime | opcional | Data e hora em que ocorreu. |
| actor_type | string | obrigatório | Quem gerou: system, supplier, user ou api. |
| data | object | obrigatório | Detalhe do evento; o formato depende de type (ver a tabela de tipos). |
Tipos de evento
| Tipo | data |
|---|---|
| created | { source } |
| reactivated | { source } (o caminho da API também adiciona from com o status anterior) |
| cycle_reset | { reason? } — reinício do ciclo de acompanhamento sem reativação (troca de fornecedor pela API, reinício manual pelo app): a resposta do fornecedor anterior a este evento deixa de ser a vigente |
| line_updated | { <campo>: { from, to } } — uma chave para cada campo alterado (exceção: buyer_email leva só to, sem from) |
| followup_sent | { followup_number, escalated } |
| response_received | { confirmed_delivery_date, delay_reason, notes, quality, summary, outcome } |
| status_changed | { from, to, reason? } |
| paused | { reason } |
| resumed | { reason? } |
| urgency_changed | { is_urgent } |
| delivered | { from, to, reason?, actual_delivery_date, received_quantity } |
| cancelled | { from, to, reason? } |
{
"data": [
{
"id": 55009,
"type": "created",
"occurred_at": "2026-09-01T12:00:00+00:00",
"actor_type": "api",
"data": { "source": "api" }
},
{
"id": 55012,
"type": "status_changed",
"occurred_at": "2026-09-12T09:40:00+00:00",
"actor_type": "supplier",
"data": {
"from": "SENT_PENDING_RESPONSE",
"to": "CONFIRMED_DELAYED",
"reason": "supplier_response"
}
}
],
"total": 2,
"page": 1,
"page_size": 50,
"has_more": false
}Ações em lote
/api/v1/delivery-trackings/actionsAPI Key obrigatóriaAplicar uma ação a até 200 linhas de uma vez. Se targets omitir line_position, a ação se aplica a todas as linhas abertas daquele pedido de compra.
Corpo da solicitação
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| action | string | obrigatório | mark_delivered, cancel, pause, resume, set_urgent ou unset_urgent. |
| targets | array | obrigatório | Linhas às quais aplicar a ação. Entre 1 e 200. |
| targets[].po_code | string | obrigatório | Número do pedido de compra. Máximo de 100 caracteres. |
| targets[].line_position | integer | opcional | Posição da linha. Se omitida, aplica-se a todas as linhas abertas do pedido de compra. |
| reason | string | opcional | Motivo. Obrigatório para pause; opcional para as demais. Máximo de 500 caracteres. |
| actual_delivery_date | date | opcional | Data real de entrega. Usada apenas com mark_delivered; padrão: hoje. |
| received_quantity | float | opcional | Quantidade recebida. Usada apenas com mark_delivered. ≥ 0. |
Ações disponíveis
| action | Efeito | Requer |
|---|---|---|
| mark_delivered | Passa para DELIVERED. actual_delivery_date usa a data enviada ou, se não enviada, a data de hoje da organização. received_quantity é registrada se enviada. | — |
| cancel | Passa para CANCELLED. | — |
| pause | Pausa o envio de lembretes (sending_paused = true). | reason |
| resume | Retoma o envio de lembretes (sending_paused = false). | — |
| set_urgent | Marca a linha como urgente. | — |
| unset_urgent | Desmarca a linha como urgente. | — |
- As ações são idempotentes: repetir uma ação já aplicada não registra um evento novo e retorna um destes seis resultados: already_delivered, already_cancelled, already_paused, already_active (para resume), already_urgent ou already_not_urgent.
- Não é possível cruzar entre status terminais: mark_delivered em uma linha CANCELLED, ou cancel em uma linha DELIVERED, retorna o erro dlvActionNotAllowedInStatus. Para reabrir uma linha encerrada é preciso reenviá-la pelo POST /delivery-trackings (o upsert reativa).
- mark_delivered e cancel só se aplicam a linhas criadas por esta API (source = "api"); em linhas de CSV ou da sincronização ERP retornam dlvTrackingManagedByOtherSource. pause, resume, set_urgent e unset_urgent se aplicam a linhas de qualquer fonte, desde que não estejam em um status terminal.
curl -X POST https://api.gosourced.ai/api/v1/delivery-trackings/actions \
-H "X-API-Key: sk_live_abc123..." \
-H "Content-Type: application/json" \
-d '{
"action": "mark_delivered",
"targets": [
{ "po_code": "OC-2026-0455", "line_position": 10 }
],
"received_quantity": 50
}'Resposta das ações
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| applied_count | integer | obrigatório | Quantidade de acompanhamentos (não de targets da requisição) em que a ação foi aplicada. Os resultados already_* não entram nessa conta. |
| error_count | integer | obrigatório | Quantidade de acompanhamentos (não de targets da requisição) com erro. Os resultados already_* não entram nessa conta. |
| results | array | obrigatório | Resultado de cada target. |
Objeto de resultado por target (results[])
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| po_code | string | obrigatório | Número do pedido de compra. |
| line_position | integer | opcional | Posição da linha afetada. Pode diferir do target se foi omitida (um pedido de compra inteiro pode gerar vários resultados). |
| id | integer | opcional | Id interno do acompanhamento. Ausente quando o target não corresponde a nenhum acompanhamento. |
| result | string | obrigatório | applied, error, ou um dos seis resultados idempotentes: already_delivered, already_cancelled, already_paused, already_active, already_urgent, already_not_urgent. |
| status | string | opcional | Status do acompanhamento após a ação. |
| code | string | opcional | Código do erro (dlv*). Presente apenas quando result é error. |
| message | string | opcional | Detalhe do erro em inglês, pensado para logs. |
// 200 OK
{
"applied_count": 1,
"error_count": 0,
"results": [
{
"po_code": "OC-2026-0455",
"line_position": 10,
"id": 8821,
"status": "DELIVERED",
"result": "applied"
}
]
}Códigos de erro — acompanhamento de entregas
Códigos próprios dos endpoints de acompanhamento de entregas. Cinco são erros da solicitação inteira (coluna HTTP 400/403/404); o resto viaja no campo code de cada linha ou target com erro, dentro de uma resposta 200. Um campo obrigatório ausente ou inválido (descrição, quantidades, fornecedor sem código ERP nem CNPJ/CPF, pendente maior que o pedido) não tem código próprio: rejeita o lote inteiro com 422 e o detalhe padrão de validação.
| Código | HTTP | Significado |
|---|---|---|
| dlvFeatureDisabled | 403 | O acompanhamento de entregas não está habilitado para esta organização. |
| dlvTrackingNotFound | 404 | Acompanhamento não encontrado (id inexistente, ou de outra organização). |
| dlvTrackingManagedByOtherSource | 200 | Esta linha é gerenciada por outra fonte (CSV ou sincronização ERP). |
| dlvSupplierReferenceConflict | 200 | O código ERP e o CNPJ/CPF correspondem a fornecedores diferentes. |
| dlvSupplierReferenceAmbiguous | 200 | O código ERP ou o CNPJ/CPF corresponde a mais de um fornecedor. |
| dlvDuplicateLineInBatch | 200 | A linha (mesmo po_code e line_position) aparece mais de uma vez no envio. |
| dlvNothingPending | 200 | A linha não tem nada pendente (quantity_pending = 0): não se cria um acompanhamento para cobrar 0 unidades. |
| dlvConcurrentUpsert | 200 | A linha foi modificada ao mesmo tempo por outro envio. Tente novamente. |
| dlvLineWriteFailed | 200 | Não foi possível salvar a linha. Verifique os dados e tente novamente (não é um problema de concorrência). |
| dlvInvalidStatusFilter | 400 | O valor de status não é um status válido. |
| dlvInvalidSince | 400 | Data inválida em since. Use o formato ISO 8601. |
| dlvPauseReasonRequired | 400 | pause exige que um reason seja informado. |
| dlvActionNotAllowedInStatus | 200 | A ação não se aplica ao status atual do acompanhamento. |
dlvTrackingNotFound é as duas coisas: 404 nos GET por id, e por target dentro de /actions.Webhooks
Receba eventos em tempo real quando um pedido de compra, uma requisição ou um acompanhamento de entrega muda, em vez de precisar consultá-los por polling.
Configuração
Os webhooks são configurados a partir do aplicativo (não por API key), por um usuário organization_admin, em Minha Organização → Desenvolvedores → Webhooks.
Envelope
Todo evento chega com este formato:
{
"id": "evt_5f2a1c9b8e7d4a3f1b2c",
"type": "delivery_tracking.status_changed",
"created_at": "2026-09-17T14:05:00+00:00",
"data": {
"tracking": "... mismo objeto que devuelve GET /delivery-trackings/{id} ...",
"event": "... mismo objeto que devuelve GET /delivery-trackings/{id}/events ..."
}
}Headers
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| X-Webhook-Signature | string | obrigatório | Assinatura HMAC-SHA256 do corpo bruto da solicitação, com o prefixo sha256=. |
| X-Webhook-Event | string | obrigatório | O type do evento — o mesmo valor do campo type de nível superior do envelope. Não existe data.type: data é diretamente o recurso (ou o par tracking / event nos eventos de acompanhamento). |
| X-Webhook-Delivery-Id | string | obrigatório | Id do evento, não deste intento de entrega específico: é o mesmo valor em cada nova tentativa e em cada webhook inscrito que o recebe (igual a id no corpo) — por isso serve para deduplicar. |
Verificar a assinatura
Calcule o HMAC-SHA256 sobre os bytes brutos do corpo da solicitação (antes de fazer o parse do JSON) usando o secret do webhook, e compare com X-Webhook-Signature usando uma comparação de tempo constante.
import hashlib
import hmac
def verify_webhook(secret: str, raw_body: bytes, signature_header: str | None) -> bool:
if not signature_header or not signature_header.startswith("sha256="):
return False
expected = "sha256=" + hmac.new(
secret.encode(), raw_body, hashlib.sha256
).hexdigest()
# compare_digest on two strings of different length returns False,
# it never raises — safe even with a malformed header.
return hmac.compare_digest(expected, signature_header)
const crypto = require("crypto");
function verifyWebhook(secret, rawBody, signatureHeader) {
if (!signatureHeader || !signatureHeader.startsWith("sha256=")) {
return false;
}
const expected =
"sha256=" +
crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
const expectedBuf = Buffer.from(expected);
const receivedBuf = Buffer.from(signatureHeader);
// timingSafeEqual throws on a length mismatch — check first, it never
// needs to be constant-time (the lengths themselves aren't a secret).
if (expectedBuf.length !== receivedBuf.length) {
return false;
}
return crypto.timingSafeEqual(expectedBuf, receivedBuf);
}
Novas tentativas
Se a entrega falhar (timeout, erro de rede, ou uma resposta que não seja 2xx), ela é tentada novamente até 3 vezes (4 tentativas no total: o envio inicial mais 3 novas tentativas). Cada tentativa que falha agenda a próxima com um backoff mínimo de 1, 5 e 15 minutos; essa nova tentativa só é disparada na próxima vez que a varredura de novas tentativas (reminder-checker) roda, o que acontece a cada hora em horário comercial argentino — o tempo real até a próxima tentativa pode ser maior que esses minutos.
- Tentativa 1: imediata, no momento do evento.
- Tentativa 2: não antes de 1 minuto depois.
- Tentativa 3: não antes de 5 minutos depois.
- Tentativa 4: não antes de 15 minutos depois. Se também falhar, a entrega fica FAILED.
Eventos disponíveis
| type | data | Quando dispara |
|---|---|---|
| purchase_order.created | objeto do pedido de compra | Um novo pedido de compra foi criado. |
| purchase_order.updated | id, code, status, reason | O status ou outro dado de um pedido de compra mudou (por exemplo, uma rejeição). |
| requisition.discarded | external_id, requisition_id, discarded_by, discarded_at | Uma requisição foi descartada (por exemplo, cancelada a partir do ERP com POST /requisitions/cancel). |
| delivery_tracking.response_received | tracking, event | O fornecedor respondeu ao pedido de confirmação de entrega. |
| delivery_tracking.status_changed | tracking, event | O status do acompanhamento mudou (inclui a reativação de uma linha previamente encerrada, que volta a PENDING_SCHEDULE). |
| delivery_tracking.delivered | tracking, event | O acompanhamento passou para DELIVERED. |
| delivery_tracking.cancelled | tracking, event | O acompanhamento passou para CANCELLED. |
Referência de esquemas
Referência rápida de todos os esquemas de solicitação/resposta usados nos endpoints.
Status de requisição
| Status | Descrição |
|---|---|
| PENDING | Importada, aguardando revisão de um comprador no Sourced. |
| LAUNCHED | O comprador lançou a requisição como Solicitação de Compra. |
| DISCARDED | A requisição foi descartada manualmente. |
| SUPERSEDED | Uma versão mais nova foi importada com o mesmo external_id. |
Status de ordem de compra
| Status | Descrição |
|---|---|
| DRAFT | OC criada no Sourced, pendente de sincronização com o ERP externo. |
| CREATED | OC criada no ERP externo, pendente de aprovação. |
| CONFIRMED | OC totalmente aprovada no ERP externo. |
| REJECTED | OC rejeitada no ERP externo. A PR associada é reaberta automaticamente. |
| CANCELLED | Compra cancelada. A OC é cancelada e a PR associada também - nada é reaberto. |
Códigos de referência
Catálogos de moedas e tipos de pagamento aceitos pela API. Use-os para mapear esses valores com os códigos equivalentes no seu ERP.
Moedas
O Sourced não usa um enum fechado de moedas: qualquer código ISO 4217 válido de 3 letras é aceito. As moedas mais utilizadas pelos nossos clientes são:
| Código | Moeda |
|---|---|
| ARS | Peso argentino |
| USD | Dólar americano |
| EUR | Euro |
| BRL | Real brasileiro |
Tipos de pagamento (payment_terms_code)
Catálogo global de condições de pagamento disponíveis no Sourced. Use o código (coluna Code) no campo payment_terms_code da PO. O campo type indica a natureza do pagamento: IMMEDIATE (no recebimento), ADVANCE (antecipado), NET_DAYS (a X dias da fatura).
| Código | Nome | Tipo | Dias | Descrição |
|---|---|---|---|---|
| COD | Cash On Delivery | IMMEDIATE | 0 | Pagamento contra entrega |
| IMM | Immediate Payment | IMMEDIATE | 0 | Pagamento imediato / À vista |
| ADV100 | Advance Payment | ADVANCE | 0 | Pagamento antecipado 100% |
| ADV50 | Advance 50% | ADVANCE | 0 | Pagamento antecipado de 50% |
| NET7 | Net 7 Days | NET_DAYS | 7 | Pagamento em 7 dias da data da fatura |
| NET10 | Net 10 Days | NET_DAYS | 10 | Pagamento em 10 dias da data da fatura |
| NET15 | Net 15 Days | NET_DAYS | 15 | Pagamento em 15 dias da data da fatura |
| NET20 | Net 20 Days | NET_DAYS | 20 | Pagamento em 20 dias da data da fatura |
| NET21 | Net 21 Days | NET_DAYS | 21 | Pagamento em 21 dias da data da fatura |
| NET30 | Net 30 Days | NET_DAYS | 30 | Pagamento em 30 dias da data da fatura |
| EOM30 | End of Month + 30 | NET_DAYS | 30 | Pagamento no fim do mês mais 30 dias |
| NET35 | Net 35 Days | NET_DAYS | 35 | Pagamento em 35 dias da data da fatura |
| NET40 | Net 40 Days | NET_DAYS | 40 | Pagamento em 40 dias da data da fatura |
| NET45 | Net 45 Days | NET_DAYS | 45 | Pagamento em 45 dias da data da fatura |
| NET60 | Net 60 Days | NET_DAYS | 60 | Pagamento em 60 dias da data da fatura |
| NET75 | Net 75 Days | NET_DAYS | 75 | Pagamento em 75 dias da data da fatura |
| NET90 | Net 90 Days | NET_DAYS | 90 | Pagamento em 90 dias da data da fatura |
Unidades de medida
Códigos de unidade de medida aceitos em itens de requisições. Enviados no campo unit_of_measure.
| Código | Unidade |
|---|---|
| EA | Unidade |
| PCS | Peças |
| KG | Quilograma |
| G | Grama |
| LB | Libra |
| OZ | Onça |
| M | Metro |
| CM | Centímetro |
| MM | Milímetro |
| IN | Polegada |
| FT | Pé |
| YD | Jarda |
| L | Litro |
| ML | Mililitro |
| GAL | Galão |
| QT | Quarto de galão |
| PT | Pinta |
| FL_OZ | Onça líquida |
| M2 | Metro quadrado |
| CM2 | Centímetro quadrado |
| FT2 | Pé quadrado |
| IN2 | Polegada quadrada |
| YD2 | Jarda quadrada |
| M3 | Metro cúbico |
| CM3 | Centímetro cúbico |
| FT3 | Pé cúbico |
| IN3 | Polegada cúbica |
| YD3 | Jarda cúbica |
| BOX | Caixa |
| CASE | Caixa/Estojo |
| PACK | Pacote |
| SET | Jogo |
| KIT | Kit |
| BUNDLE | Fardo |
| ROLL | Rolo |
| SHEET | Folha/Lâmina |
| PALLET | Palete |
| DRUM | Tambor/Barril |
| BAG | Saco |
| BOTTLE | Garrafa |
| CEN | Centena |
Fluxo de integração
Padrão de integração típico para uma sincronização ERP agendada (ex: cron job a cada 15 minutos):
Coletar novas requisições do ERP
Consultar seu ERP por requisições aprovadas que ainda não foram sincronizadas com o Sourced.
Verificar existentes (opcional)
Chamar POST /requisitions/check-existing com external_ids para filtrar requisições já sincronizadas.
Importar requisições
Chamar POST /requisitions com o lote de requisições novas/atualizadas. Armazenar os requisition_ids retornados.
Consultar novas ordens de compra
Chamar GET /purchase-orders?since={last_sync_timestamp}&status=DRAFT para obter OC novas. Criar a OC no seu ERP e chamar POST /purchase-orders/{id}/status com {"status": "CREATED"}.
Confirmar OCs aprovadas
Quando a OC for aprovada no seu ERP, chamar POST /purchase-orders/{id}/status com {"status": "CONFIRMED"} para fechar o ciclo.
# Step 1: Get pending requisitions from ERP
ERP_REQS=$(query_erp_pending_requisitions)
# Step 2: Check which ones already exist in Sourced
EXISTING=$(curl -s -X POST \
-H "X-API-Key: $API_KEY" \
-H "Content-Type: application/json" \
-d "{"external_ids": $ERP_REQ_IDS}" \
https://api.gosourced.ai/api/v1/requisitions/check-existing)
# Step 3: Import only new requisitions
NEW_REQS=$(filter_not_found $ERP_REQS $EXISTING)
curl -s -X POST \
-H "X-API-Key: $API_KEY" \
-H "Content-Type: application/json" \
-d "{"requisitions": $NEW_REQS}" \
https://api.gosourced.ai/api/v1/requisitions
# Step 4: Pull new POs since last sync
POS=$(curl -s \
-H "X-API-Key: $API_KEY" \
"https://api.gosourced.ai/api/v1/purchase-orders?since=$LAST_SYNC&status=DRAFT")
# Step 5: Create POs in ERP and update status
for PO in $POS; do
create_po_in_erp $PO
curl -s -X POST \
-H "X-API-Key: $API_KEY" \
-H "Content-Type: application/json" \
-d "{"status": "CREATED", "external_id": "$ERP_PO_NUMBER"}" \
"https://api.gosourced.ai/api/v1/purchase-orders/$PO_ID/status"
done
# Step 6: When PO is approved in ERP, confirm it
curl -s -X POST \
-H "X-API-Key: $API_KEY" \
-H "Content-Type: application/json" \
-d '{"status": "CONFIRMED"}' \
"https://api.gosourced.ai/api/v1/purchase-orders/$PO_ID/status"Exemplo completo
Uma solicitação de importação realista com todos os campos disponíveis preenchidos:
curl -X POST https://api.gosourced.ai/api/v1/requisitions \
-H "X-API-Key: sk_live_abc123..." \
-H "Content-Type: application/json" \
-d '{
"requisitions": [
{
"external_id": "CAL-REQ-2026-0042",
"description": "Repuestos bomba centrífuga Planta Norte",
"requester_name": "Carlos Rodríguez",
"requester_email": "carlos.rodriguez@empresa.com",
"comments": "Urgente: bomba fuera de servicio desde 03/03. <b>Necesitamos entrega express.</b>",
"delivery_address": "Av. Industrial 4500, Parque Industrial Pilar, Buenos Aires",
"delivery_address_code": "PLANTA-NORTE",
"desired_delivery_lead_time_days": 7,
"created_date": "2026-03-04T09:15:00Z",
"offer_deadline": "2026-03-10T18:00:00Z",
"total_estimated_value": 1250000.00,
"currency": "ARS",
"department_code": "MANT-001",
"priority_level": "HIGH",
"items": [
{
"external_line_id": "CAL-REQ-2026-0042-L10",
"description": "Sello mecánico para bomba centrífuga KSB ETA 50-200",
"quantity": 2,
"unit_of_measure": "UN",
"target_price": 185000.00,
"estimated_price": 370000.00,
"currency": "ARS",
"category": "Repuestos Bombas",
"material_code": "MAT-BOM-0234",
"desired_delivery_lead_time_days": 10,
"detail": "Sello tipo cartucho, material: carburo de silicio / carburo de silicio",
"specifications": {
"manufacturer_code": "KSB-SEAL-50200",
"manufacturer_name": "KSB",
"manufacturer_description": "Mechanical seal for ETA 50-200 centrifugal pump",
"buyer_code": "MAT-BOM-0234",
"buyer_code_description": "Sello mecánico bomba KSB ETA 50-200",
"buyer_code_system": "Calipso",
"technical_specs": "Diámetro eje: 35mm, Material caras: SiC/SiC, Elastómeros: Viton",
"requirements": "Debe incluir certificado de calidad. Preferencia por repuesto original KSB."
}
},
{
"external_line_id": "CAL-REQ-2026-0042-L20",
"description": "Rodamiento SKF 6310-2RS",
"quantity": 4,
"unit_of_measure": "UN",
"target_price": 45000.00,
"currency": "ARS",
"category": "Rodamientos",
"material_code": "MAT-ROD-0089",
"specifications": {
"manufacturer_code": "6310-2RS1",
"manufacturer_name": "SKF",
"technical_specs": "50x110x27mm, sellado ambos lados, grasa estándar"
}
},
{
"external_line_id": "CAL-REQ-2026-0042-L30",
"description": "Aceite lubricante ISO VG 68",
"quantity": 20,
"unit_of_measure": "LT",
"target_price": 5500.00,
"currency": "ARS",
"category": "Lubricantes",
"specifications": {
"technical_specs": "Aceite mineral ISO VG 68, índice de viscosidad > 95"
}
}
],
"attachments": [
{
"url": "https://erp.empresa.com/files/plano-bomba-eta-50-200.pdf",
"filename": "plano_bomba_KSB_ETA_50-200.pdf",
"description": "Plano de despiece bomba KSB ETA 50-200",
"file_type": "application/pdf"
}
],
"raw_data": {
"calipso_doc_type": "SOL",
"calipso_doc_number": "0042",
"calipso_branch": "001",
"approved_by": "María González",
"cost_center": "CC-MANT-NORTE"
}
}
]
}'{
"success": true,
"created_count": 1,
"updated_count": 0,
"skipped_count": 0,
"error_count": 0,
"errors": [],
"requisition_ids": [1234]
}