Use esta API para consultar tickets, registrar pagamentos já recebidos, consultar saídas e cancelamentos para conciliação e enviar reservas antecipadas. Integre apenas os fluxos combinados com a unidade.
Onde está a API: ela é instalada em cada estacionamento e atende somente aquela unidade. O endereço desta wiki é apenas da documentação; a URL da API será fornecida pela unidade.
POST /api/v1/token e envie Authorization: Bearer {token} nas chamadas seguintes.Se você utiliza um serviço intermediário para atender vários parceiros, informe o código do parceiro de origem em cada lote de reservas.
Seu sistema precisa alcançar o IP ou nome privado e a porta informados pela unidade. Quando o serviço intermediário estiver fora da rede local, combine com a unidade uma conexão privada que dê acesso a esse endereço. A API não deve ser exposta diretamente à internet.
localhost funciona somente quando seu sistema e a API estão no mesmo computador. Para computadores diferentes, use o IP ou nome privado fornecido pela unidade.
| Dado | Para que serve | Exemplo |
|---|---|---|
| URL base da API | Endereço das chamadas HTTP | http://192.168.10.20:5000 |
| Usuário e senha de integração | Solicitar o token JWT | fornecidos por canal seguro |
contractId |
Identificar a origem das reservas | INTEGRADOR_A |
| Fuso horário da unidade | Interpretar horários locais | America/Sao_Paulo |
| Dados de homologação | Testar os fluxos combinados | ticket ou reserva de teste |
Nos exemplos, substitua {baseUrl} pela URL recebida, sem / no final. O endereço acima é ilustrativo.
{baseUrl}/api/v1/parking.Content-Type: application/json.camelCase.O primeiro teste deve ser a solicitação de token:
curl -i -X POST "{baseUrl}/api/v1/token" \
-H "Content-Type: application/json" \
-d '{
"user": "usuario-da-integracao",
"password": "senha-da-integracao"
}'
| Resultado | Significado |
|---|---|
| Não conecta ou expira | IP, porta, firewall ou rede local incorretos |
200 OK |
Conectividade e credenciais válidas |
401 Unauthorized |
Usuário ou senha inválidos |
500 Internal Server Error |
Serviço local indisponível; acione o responsável pela unidade |
A documentação interativa da instalação também fica disponível em {baseUrl}/swagger. No botão Authorize, informe somente o token JWT; o Swagger acrescenta o prefixo Bearer automaticamente.
Solicite um token usando as credenciais de integração configuradas na API local:
POST {baseUrl}/api/v1/token
Content-Type: application/json
{
"user": "usuario-da-integracao",
"password": "senha-da-integracao"
}
Resposta:
{
"status": {
"success": true,
"message": "Authentication successful."
},
"token": "eyJ..."
}
O token dessa rota é válido por duas horas. Envie-o em todas as operações de estacionamento:
Authorization: Bearer eyJ...
Credenciais inválidas retornam 401 Unauthorized:
{
"status": {
"success": false,
"message": "Invalid credentials."
},
"token": null
}
Solicite um novo token quando receber 401 ou antes de completar duas horas. Credenciais e tokens devem permanecer dentro da rede local confiável. Caso a unidade forneça HTTPS, use exatamente o endereço fornecido.
| Método | Rota | Finalidade |
|---|---|---|
GET |
/api/v1/parking/tickets/{identifier} |
Consultar ticket, valor atual e pagamentos registrados |
POST |
/api/v1/parking/tickets/{ticketId}/payments |
Registrar o pagamento do ticket |
GET |
/api/v1/parking/osa-billing-movements?movementDate=YYYY-MM-DD |
Consultar saídas e cancelamentos OSA do dia para conciliação |
POST |
/api/v1/parking/reservations |
Criar ou atualizar reservas antecipadas |
O campo payments exige que a unidade tenha implantado a versão da API com histórico de pagamentos. Confirme a atualização com a unidade antes de depender desse campo para conciliação.
Informe o número do ticket ou a placa cadastrada em {identifier}. Na consulta por placa, use o ticketId retornado para registrar o pagamento.
GET {baseUrl}/api/v1/parking/tickets/000123456
Authorization: Bearer {token}
Exemplo por placa:
GET {baseUrl}/api/v1/parking/tickets/ABC1D23
Authorization: Bearer {token}
Resposta 200 OK:
{
"ticketId": "000123456",
"entryDate": "2026-09-25T08:15:00",
"calculatedAt": "2026-09-25T14:51:01",
"stayDuration": "6:36:01",
"plate": "ABC1D23",
"priceTableName": "ROTATIVO",
"prepaidAmount": 0.00,
"minutesToExit": 0,
"amountDue": 15.35,
"payments": []
}
Quando houver pagamentos registrados, payments contém itens como:
{
"amount": 15.35,
"paymentMethod": "PIX_ATM",
"paidAt": "2026-09-25T14:52:10"
}
| Campo | Descrição |
|---|---|
ticketId |
Número real do ticket localizado, inclusive quando a busca foi por placa |
entryDate |
Data e hora de entrada |
calculatedAt |
Horário local em que a consulta terminou; não é uma saída efetiva |
stayDuration |
Permanência formatada como H:mm:ss (as horas podem exceder 24) |
plate |
Placa vinculada ao ticket |
priceTableName |
Nome da tabela de preço aplicada |
prepaidAmount |
Valor já pago antecipadamente |
minutesToExit |
Minutos restantes para saída após um pagamento; 0 quando não houver prazo ativo |
amountDue |
Valor calculado no momento da consulta; não é uma cotação vinculante |
payments |
Histórico de pagamentos do ticket, em ordem de data; [] quando não houver registros |
payments[].amount |
Valor efetivamente recebido, descontado eventual troco |
payments[].paymentMethod |
Forma de pagamento registrada pelo Softpark; pagamentos pela API recebem o sufixo _ATM |
payments[].paidAt |
Data e hora local do registro; pode ser null em dados antigos |
amountDue é informativo e pode mudar com a permanência ou com alterações de tarifa.Ticket ou placa não localizado no pátio:
HTTP/1.1 404 Not Found
{
"message": "Ticket ou placa nao encontrado",
"errorCode": "ticket_not_found"
}
Esta operação registra no Softpark um pagamento que já foi confirmado pelo meio de pagamento do integrador. A API não realiza a transação financeira, não consulta adquirente e não gera cobrança PIX.
Fluxo recomendado:
ticketId e amountDue, se precisar apresentar o valor calculado pela unidade.amountDue consultado.payments no GET.POST {baseUrl}/api/v1/parking/tickets/000123456/payments
Authorization: Bearer {token}
Content-Type: application/json
{
"amount": 15.35,
"paymentMethod": "PIX",
"taxpayerDocument": "12345678901",
"issueRps": true,
"ccm": null
}
| Campo | Obrigatório | Regra |
|---|---|---|
amount |
sim | Entre 0.01 e 9999999.99; valor recebido e informado pelo integrador |
paymentMethod |
não | Padrão ONLINE; máximo de 20 caracteres |
taxpayerDocument |
condicional | Obrigatório quando issueRps for true; máximo de 20 caracteres |
issueRps |
não | Padrão false |
ccm |
não | Máximo de 15 caracteres |
Resposta 200 OK:
{
"exitAllowedUntil": "2026-09-25T18:30:00",
"message": "Validado com sucesso",
"rpsNumber": "0000123",
"rpsSeries": "A",
"rpsMessage": "Sua NFE estará disponível conforme a configuração do Softpark."
}
Quando issueRps for false, os campos de RPS normalmente serão null.
amount com o valor do último GET nem exige consulta prévia.Ticket ja baixado sem chamar a procedure de pagamento quando o novo cálculo resulta em amountDue <= 0 e já existe algum recebimento positivo em T_CAIXA para o ticket. Essa resposta não confirma que o valor deste POST foi registrado.ticketId identifica o pagamento; não existe transactionId nesse contrato.Validado com sucesso confirma a conclusão da chamada e da transação da API, mas não comprova, por si só, a inserção de um novo item de pagamento.Se a conexão cair depois do POST ou a resposta for desconhecida, não presuma falha e não realize outra cobrança financeira. Faça GET /tickets/{ticketId} e examine payments: procure um registro com o mesmo amount enviado, forma de pagamento e horário compatíveis. Se encontrar uma correspondência inequívoca, considere o pagamento registrado no Softpark e não repita o POST.
Se o GET retornar 404, não mostrar um registro correspondente ou houver mais de um pagamento que possa corresponder, confirme com a unidade antes de reenviar. O histórico pode incluir pagamentos de outras origens e registros antigos consolidados. Valor igual sozinho não identifica de forma única uma transação; este contrato não possui transactionId. Os horários e valores de GET e POST são registrados no log local da API para auxiliar a conciliação.
GET {baseUrl}/api/v1/parking/osa-billing-movements?movementDate=2026-09-25
Authorization: Bearer {token}
curl -i "{baseUrl}/api/v1/parking/osa-billing-movements?movementDate=2026-09-25" \
-H "Authorization: Bearer {token}"
Use movementDate no formato YYYY-MM-DD, considerando a data local do estacionamento.
Resposta 200 OK:
{
"movements": [
{
"ticketId": "000123456",
"plate": "ABC1D23",
"entryOsaName": "OPERADORA",
"exitOsaName": "OPERADORA",
"entryAt": "2026-09-25T08:00:00",
"exitAt": "2026-09-25T10:45:12",
"canceledAt": null,
"entryTerminal": "1",
"exitTerminal": "2",
"enteredAsMonthly": false,
"status": "exited",
"cancellationReason": null,
"chargedAmount": 20.00,
"paidAmount": 18.00,
"paidAt": "2026-09-25T10:45:12",
"discountAmount": 2.00,
"discountCode": 12,
"discountName": "CONVÊNIO"
}
]
}
status será exited ou canceled. Para cancelamento, canceledAt informa o horário do cancelamento ou da baixa técnica e exitAt será nulo.entryTerminal e exitTerminal são os identificadores das vias/terminais registrados pela OSA. exitTerminal pode ser nulo num cancelamento.chargedAmount é o valor informado pela OSA para cobrança. paidAmount é o valor recebido registrado no caixa; zero não deve ser interpretado como ausência de movimento.discountAmount, discountCode e discountName vêm do registro de pagamento quando disponíveis. Quando não há desconto registrado, o valor é zero e código/nome são nulos.{ "movements": [] }.POST {baseUrl}/api/v1/parking/reservations
Authorization: Bearer {token}
Content-Type: application/json
{
"contractId": "INTEGRADOR_A",
"reservations": [
{
"reservationId": "6650199571",
"plate": "ABC1D23",
"validFrom": "2026-09-25T08:00:00-03:00",
"validUntil": "2026-09-25T18:00:00-03:00"
}
]
}
contractId responde “qual parceiro enviou esta reserva?”. Envie um código estável para a origem, por exemplo INTEGRADOR_A. Ele aceita de 1 a 20 caracteres: letras, números, _ e -. A API não mantém uma lista de códigos autorizados por credencial; combine o código com a unidade para manter a mesma identificação em todos os envios. Um serviço intermediário envia um lote por parceiro, com o contractId correspondente.
reservationId responde “qual reserva deste parceiro?”. Envie o identificador usado no seu sistema e mantenha-o igual em todos os reenvios da mesma reserva. Ele deve ser único dentro de cada contractId. A API usa o par INTEGRADOR_A:6650199571 para localizar a reserva; mudar qualquer parte desse par identifica outra reserva.
Envie contractId e reservationId como texto, mesmo quando forem compostos apenas por números. Isso preserva zeros à esquerda e evita perda de precisão em identificadores longos.
| Campo | Obrigatório | Regra |
|---|---|---|
contractId |
sim | Até 20 caracteres; letras, números, _ e - |
reservations |
sim | Entre 1 e 500 itens |
reservationId |
sim | Até 29 caracteres; único dentro do lote |
plate |
sim | Até 10 caracteres; letras, números, espaços e hífen |
validFrom |
sim | Início da janela local de utilização |
validUntil |
sim | Fim da janela local; deve ser posterior a validFrom |
Resposta 200 OK:
{
"message": "Ok",
"created": 1,
"updated": 0,
"unchanged": 0
}
A combinação de contractId e reservationId identifica uma reserva. Enquanto ela estiver confirmada e sem ticket, check-in ou check-out, reenviar a mesma combinação atualiza os dados quando mudarem, sem criar duplicidade. Após vínculo com ticket, check-in, check-out, cancelamento ou expiração, o reenvio com a mesma placa e período é contado como unchanged; alterações de placa ou diferenças de período superiores a um segundo retornam 400.
Os horários são armazenados como horários locais de utilização. O offset do JSON não desloca a hora civil enviada. Por exemplo, 08:00:00-03:00 é gravado como 08:00:00 na unidade.
O envio é um upsert:
created: a reserva ainda não existia;updated: já existia e algum dado relevante mudou;unchanged: já existia com os mesmos dados.O lote é processado sequencialmente. Se ocorrer uma falha durante um item, reservas anteriores do mesmo lote podem já ter sido gravadas. Reenviar mantém a mesma chave e não duplica esses itens, mas pode retornar 400 se o estado da reserva impedir a operação.
| HTTP | Situação | Ação recomendada |
|---|---|---|
200 |
Chamada concluída; o pagamento pode não ter gerado novo lançamento | Ler message e conciliar a transação em payments quando necessário |
400 |
Payload inválido ou reserva rejeitada | Corrigir os dados; não repetir sem alteração |
401 |
Token ausente, inválido ou expirado | Obter novo token e repetir uma vez |
404 |
Ticket não encontrado | Conferir o ticket e o estado do veículo |
500 |
Erro inesperado do serviço local | Não repetir em loop; acionar o responsável pela unidade |
Erros tratados pela integração usam este formato:
{
"message": "Descrição do erro",
"errorCode": "invalid_reservation"
}
Possíveis errorCode:
ticket_not_found;invalid_payment;invalid_reservation.Erros de validação automática do ASP.NET usam o formato ProblemDetails, com um objeto errors contendo os campos inválidos.
Exemplo:
{
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"errors": {
"amount": [
"The field Amount must be between 0.01 and 9999999.99."
]
}
}
Tome decisões pelo código HTTP e por errorCode, quando presente. Não dependa do texto exato de message.
| Operação | Pode repetir? | Orientação |
|---|---|---|
| Solicitar token | sim | Solicite novamente após 401 |
| Consultar ticket ou placa | sim | Uma nova consulta recalcula o valor informativo |
| Consultar movimentos | sim | Consulta sem gravação |
| Registrar pagamento | somente após conciliação | Após timeout, consulte payments no GET; se a correspondência não for clara, confirme com a unidade antes de repetir o POST |
| Enviar reservas | sim, conforme o estado da reserva | O envio preserva a mesma chave; trate 400 sem repetir em loop |
Não faça repetição automática ilimitada. Para falhas transitórias, use poucas tentativas com intervalo crescente. Pagamentos exigem reconciliação antes da repetição.
GET /tickets/{identifier} usando ticket ou placa e guarde o ticketId retornado.amountDue como valor calculado naquele momento, se aplicável.POST /tickets/{ticketId}/payments.amount com o valor do último GET. Se chegar à procedure de pagamento, envia o valor informado no POST para gravação. Uma nova consulta interna com amountDue <= 0 e algum recebimento anterior pode retornar Ticket ja baixado antes dessa gravação.Validado com sucesso indica que a chamada à procedure terminou e a transação da API foi confirmada; não identifica um novo lançamento específico. Ticket ja baixado indica apenas que a API encontrou algum recebimento anterior e saldo calculado não positivo. Para conciliar a cobrança do integrador, consulte payments no GET e compare valor, forma de pagamento e horário; se não houver correspondência inequívoca, confirme com a unidade.curl -X GET "{baseUrl}/api/v1/parking/tickets/000123456" \
-H "Authorization: Bearer {token}"
curl -X POST "{baseUrl}/api/v1/parking/tickets/000123456/payments" \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"amount": 15.35,
"paymentMethod": "PIX",
"issueRps": false
}'
curl -X POST "{baseUrl}/api/v1/parking/reservations" \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"contractId": "INTEGRADOR_A",
"reservations": [{
"reservationId": "6650199571",
"plate": "ABC1D23",
"validFrom": "2026-09-25T08:00:00-03:00",
"validUntil": "2026-09-25T18:00:00-03:00"
}]
}'
Antes de liberar a integração, homologue os fluxos combinados com a unidade:
401.payments no GET antes de considerar um reenvio.Ao solicitar suporte, informe:
errorCode e message, quando existirem;Nunca envie senha, token JWT completo, CPF/CNPJ completo ou outros dados pessoais em chamados e logs.