openapi: 3.0.3 info: title: EFXPay Mobile API description: | Contrato HTTP para consumo pelo **app mobile**. Apenas rotas `/api/v1/*` expostas pelo EFXPay Middleware. - Autenticação do app: **JWT** (`Authorization: Bearer`) emitido em `POST /auth/login`. - PIX envio/cobrança exigem header **`Idempotency-Key`** (UUID recomendado). - Status de PIX outbound é atualizado por **webhook** no backend; `GET /pix/{id}` reflete estado **local**. - Não inclui endpoints GlobalSCM (`/internal/api/v1/*`). Documentação humana: [index.html](./index.html) · Alterações: [CHANGELOG-api.md](./CHANGELOG-api.md) version: 1.0.0 contact: name: EFXPay / BaaS Middleware servers: - url: '{baseUrl}/api/v1' description: Ambiente (substituir baseUrl) variables: baseUrl: default: https://api.exemplo.com description: URL raiz sem barra final (ex. APP_URL em produção) tags: - name: Auth description: Login e logout - name: Accounts description: Dados da conta e saldo (requer JWT) - name: PIX description: Envio e cobrança PIX (requer JWT) - name: PIX Keys description: Gestão de chaves PIX (requer JWT) - name: Onboarding description: Fluxo PF multi-etapa (rotas públicas, sem JWT) - name: Registration description: Cadastro simplificado PF/PJ (rotas públicas) paths: /auth/login: post: tags: [Auth] summary: Login description: Valida credenciais no EFXPay e na GlobalSCM; retorna JWT do app. Guardar token para rotas protegidas. operationId: authLogin security: [] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/LoginRequest' responses: '200': description: Login OK content: application/json: schema: $ref: '#/components/schemas/LoginResponse' '422': $ref: '#/components/responses/ValidationError' '502': $ref: '#/components/responses/ProviderError' /auth/logout: post: tags: [Auth] summary: Logout operationId: authLogout responses: '200': description: Sessão encerrada content: application/json: schema: type: object properties: message: type: string example: Sessão encerrada. /accounts/me: get: tags: [Accounts] summary: Perfil e conta operationId: accountsMe responses: '200': description: Dados do utilizador e conta local content: application/json: schema: $ref: '#/components/schemas/AccountsMeResponse' '401': $ref: '#/components/responses/Unauthorized' /accounts/balance: get: tags: [Accounts] summary: Saldo operationId: accountsBalance responses: '200': description: Saldo (provider quando sessão bancária activa) content: application/json: schema: $ref: '#/components/schemas/BalanceResponse' '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' /accounts/statement: get: tags: [Accounts] summary: Extrato operationId: accountsStatement parameters: - name: start_date in: query schema: type: string format: date - name: end_date in: query schema: type: string format: date responses: '200': description: Itens locais e remotos content: application/json: schema: $ref: '#/components/schemas/StatementResponse' '401': $ref: '#/components/responses/Unauthorized' /accounts/pf: post: tags: [Registration] summary: Cadastro PF (legado) description: Inicia onboarding PF num único passo. Preferir fluxo `/onboarding/pf` para apps novos. operationId: registerPf security: [] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/RegisterPfRequest' responses: '201': description: Conta PF criada content: application/json: schema: $ref: '#/components/schemas/RegisterPfResponse' '422': $ref: '#/components/responses/ValidationError' /accounts/pj: post: tags: [Registration] summary: Cadastro PJ operationId: registerPj security: [] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/RegisterPjRequest' responses: '501': description: Não implementado content: application/json: schema: $ref: '#/components/schemas/ErrorBody' /pix/send: post: tags: [PIX] summary: Enviar PIX operationId: pixSend parameters: - $ref: '#/components/parameters/IdempotencyKey' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/PixSendRequest' responses: '200': description: Transação criada ou idempotente (mesma chave) content: application/json: schema: $ref: '#/components/schemas/PixTransactionResponse' '401': $ref: '#/components/responses/Unauthorized' '422': $ref: '#/components/responses/ValidationError' '502': $ref: '#/components/responses/ProviderError' /pix/charge: post: tags: [PIX] summary: Gerar cobrança QR Code operationId: pixCharge parameters: - $ref: '#/components/parameters/IdempotencyKey' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/PixChargeRequest' responses: '200': description: Cobrança criada content: application/json: schema: $ref: '#/components/schemas/PixChargeResponse' '401': $ref: '#/components/responses/Unauthorized' '422': $ref: '#/components/responses/ValidationError' '502': $ref: '#/components/responses/ProviderError' /pix/{transactionId}: get: tags: [PIX] summary: Consultar transação PIX (local) description: Não consulta o provider em tempo real. Status pode mudar via webhook no servidor. operationId: pixShow parameters: - $ref: '#/components/parameters/TransactionId' responses: '200': description: Transação content: application/json: schema: $ref: '#/components/schemas/PixTransactionResponse' '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' /pix/keys: get: tags: [PIX Keys] summary: Listar chaves PIX operationId: pixKeysList responses: '200': description: Lista do DICT (payload do provider em `data`) content: application/json: schema: type: object properties: data: type: object additionalProperties: true '401': $ref: '#/components/responses/Unauthorized' '502': $ref: '#/components/responses/ProviderError' post: tags: [PIX Keys] summary: Criar chave PIX operationId: pixKeysCreate requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/PixKeyCreateRequest' responses: '201': description: Chave criada content: application/json: schema: type: object properties: data: type: object additionalProperties: true '401': $ref: '#/components/responses/Unauthorized' '422': $ref: '#/components/responses/ValidationError' '502': $ref: '#/components/responses/ProviderError' delete: tags: [PIX Keys] summary: Excluir chave PIX operationId: pixKeysDelete requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/PixKeyDeleteRequest' responses: '200': description: Chave excluída content: application/json: schema: type: object properties: data: type: object additionalProperties: true '401': $ref: '#/components/responses/Unauthorized' '422': $ref: '#/components/responses/ValidationError' '502': $ref: '#/components/responses/ProviderError' /onboarding/pf: post: tags: [Onboarding] summary: Iniciar onboarding PF operationId: onboardingStartPf security: [] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/StartOnboardingPfRequest' responses: '201': description: Aplicação criada content: application/json: schema: $ref: '#/components/schemas/OnboardingApplication' '422': $ref: '#/components/responses/ValidationError' /onboarding/cep/{cep}: get: tags: [Onboarding] summary: Consultar CEP operationId: onboardingLookupCep security: [] parameters: - name: cep in: path required: true schema: type: string example: '01310100' responses: '200': content: application/json: schema: type: object properties: cep: type: object additionalProperties: true '502': $ref: '#/components/responses/ProviderError' /onboarding/{applicationId}: get: tags: [Onboarding] summary: Estado do onboarding operationId: onboardingShow security: [] parameters: - $ref: '#/components/parameters/ApplicationId' responses: '200': content: application/json: schema: $ref: '#/components/schemas/OnboardingApplication' '404': $ref: '#/components/responses/NotFound' /onboarding/{applicationId}/address: post: tags: [Onboarding] summary: Adicionar endereço operationId: onboardingStoreAddress security: [] parameters: - $ref: '#/components/parameters/ApplicationId' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/OnboardingAddressRequest' responses: '201': description: Endereço criado '422': $ref: '#/components/responses/ValidationError' /onboarding/{applicationId}/documents: post: tags: [Onboarding] summary: Upload documento operationId: onboardingStoreDocument security: [] parameters: - $ref: '#/components/parameters/ApplicationId' requestBody: required: true content: multipart/form-data: schema: type: object required: [tipo_documento, arquivo] properties: tipo_documento: type: integer minimum: 1 maximum: 21 description: '1=RG, 2=CNH, 5=comprovante, 6=selfie, etc.' arquivo: type: string format: binary responses: '201': description: Documento registado '422': $ref: '#/components/responses/ValidationError' /onboarding/{applicationId}/proposal: post: tags: [Onboarding] summary: Criar proposta operationId: onboardingStoreProposal security: [] parameters: - $ref: '#/components/parameters/ApplicationId' requestBody: content: application/json: schema: type: object properties: tipo: type: string default: CONTA_CORRENTE observacoes: type: string valor_solicitado: type: number responses: '202': description: Proposta enfileirada /onboarding/{applicationId}/electronic-validation: post: tags: [Onboarding] summary: Solicitar validação electrónica operationId: onboardingRequestElectronicValidation security: [] parameters: - $ref: '#/components/parameters/ApplicationId' requestBody: content: application/json: schema: type: object properties: tipo: type: integer default: 1 responses: '202': description: Pedido aceite (homologação código ABC123) /onboarding/{applicationId}/electronic-validation/confirm: post: tags: [Onboarding] summary: Confirmar código validação electrónica operationId: onboardingConfirmElectronicValidation security: [] parameters: - $ref: '#/components/parameters/ApplicationId' requestBody: content: application/json: schema: type: object properties: codigo: type: string default: ABC123 tipo: type: integer default: 1 responses: '202': description: Validação enfileirada /onboarding/{applicationId}/prova-vida: post: tags: [Onboarding] summary: Iniciar prova de vida operationId: onboardingStartProvaVida security: [] parameters: - $ref: '#/components/parameters/ApplicationId' responses: '202': description: URL iframe na resposta content: application/json: schema: type: object properties: application: $ref: '#/components/schemas/OnboardingApplication' url_iframe: type: string format: uri /onboarding/{applicationId}/kyc: get: tags: [Onboarding] summary: Atualizar / consultar KYC operationId: onboardingKyc security: [] parameters: - $ref: '#/components/parameters/ApplicationId' responses: '200': content: application/json: schema: type: object properties: application: $ref: '#/components/schemas/OnboardingApplication' /onboarding/{applicationId}/sync: post: tags: [Onboarding] summary: Sincronizar steps pendentes com provider operationId: onboardingSync security: [] parameters: - $ref: '#/components/parameters/ApplicationId' responses: '202': description: Sync iniciado components: securitySchemes: bearerAuth: type: http scheme: bearer bearerFormat: JWT description: Token obtido em `POST /auth/login` (campo `access_token`) parameters: IdempotencyKey: name: Idempotency-Key in: header required: true description: UUID único por operação; reutilizar em retry para mesma transação schema: type: string minLength: 1 maxLength: 128 example: 550e8400-e29b-41d4-a716-446655440000 TransactionId: name: transactionId in: path required: true schema: type: string format: uuid ApplicationId: name: applicationId in: path required: true schema: type: string format: uuid responses: Unauthorized: description: JWT ausente, inválido ou sessão bancária expirada content: application/json: schema: $ref: '#/components/schemas/MessageError' NotFound: description: Recurso não encontrado content: application/json: schema: $ref: '#/components/schemas/MessageError' ValidationError: description: Erro de validação content: application/json: schema: $ref: '#/components/schemas/ValidationError' ProviderError: description: Erro do provedor bancário content: application/json: schema: $ref: '#/components/schemas/ErrorBody' schemas: LoginRequest: type: object required: [email, password] properties: email: type: string format: email password: type: string format: password LoginResponse: type: object properties: access_token: type: string token_type: type: string example: Bearer MessageError: type: object properties: message: type: string ErrorBody: type: object properties: code: type: string message: type: string ValidationError: type: object properties: message: type: string errors: type: object additionalProperties: type: array items: type: string AccountsMeResponse: type: object properties: user: type: object properties: id: { type: integer } name: { type: string } email: { type: string, format: email } document: { type: string, nullable: true } person_type: { type: string, nullable: true } account: nullable: true type: object properties: id: { type: integer } provider: { type: string } agency: { type: string, nullable: true } account_number: { type: string, nullable: true } status: { type: string } provider_company_id: { type: string, nullable: true } provider_client_token: { type: string, nullable: true } BalanceResponse: type: object properties: balance: type: number format: double source: type: string enum: [provider, local] StatementResponse: type: object properties: items: type: object properties: local: type: array items: $ref: '#/components/schemas/StatementLocalItem' remote: type: array items: type: object additionalProperties: true StatementLocalItem: type: object properties: id: { type: string, format: uuid } type: { type: string } amount: { type: number } status: { type: string } pix_key: { type: string, nullable: true } provider_txid: { type: string, nullable: true } created_at: { type: string, format: date-time } PixSendRequest: type: object required: [pix_key, amount] properties: pix_key: type: string maxLength: 255 amount: type: number format: double minimum: 0.01 description: type: string maxLength: 512 PixChargeRequest: type: object required: [type, amount] properties: type: type: string enum: [dynamic, static] amount: type: number minimum: 0.01 description: type: string maxLength: 140 key: type: string maxLength: 255 receiver_name: type: string maxLength: 25 city: type: string maxLength: 15 zipcode: type: string maxLength: 8 expiration_qr: type: integer minimum: 60 maximum: 86400 payer_name: type: string maxLength: 140 payer_cpf: type: string maxLength: 14 reusable: type: boolean code_category: type: string maxLength: 10 additional_data: type: array items: type: object required: [name, value] properties: name: { type: string } value: { type: string } PixTransactionResponse: type: object properties: transaction_id: type: string format: uuid status: $ref: '#/components/schemas/PixStatus' end_to_end: type: string description: Presente em envios PIX quando disponível PixChargeResponse: allOf: - $ref: '#/components/schemas/PixTransactionResponse' - type: object properties: qr_code: type: string description: Imagem ou payload QR (conforme provider) copy_paste: type: string description: PIX copia e cola PixStatus: type: string enum: [PROCESSING, COMPLETED, FAILED] PixKeyCreateRequest: type: object required: [key_type] properties: key_type: type: string enum: [CPF, CNPJ, CELULAR, E_MAIL, EVP_ENDERECO_VIRTUAL_DE_PAGAMENTO] email: type: string format: email description: Obrigatório se key_type=E_MAIL e diferente do email da conta PixKeyDeleteRequest: type: object required: [key] properties: key: type: string maxLength: 255 StartOnboardingPfRequest: type: object required: [name, email, password, password_confirmation, document, phone] properties: name: { type: string } email: { type: string, format: email } password: { type: string, format: password } password_confirmation: { type: string } document: { type: string } phone: { type: string } RegisterPfRequest: allOf: - $ref: '#/components/schemas/StartOnboardingPfRequest' - type: object properties: address: $ref: '#/components/schemas/OnboardingAddressRequest' RegisterPfResponse: type: object properties: user_id: { type: integer } account_id: { type: integer, nullable: true } onboarding_id: { type: string, format: uuid } pessoa_fisica_id: { type: string, nullable: true } message: { type: string } onboarding: $ref: '#/components/schemas/OnboardingApplication' RegisterPjRequest: type: object required: [name, company_name, email, password, password_confirmation, document, phone] properties: name: { type: string } company_name: { type: string } email: { type: string, format: email } password: { type: string } password_confirmation: { type: string } document: { type: string } phone: { type: string } OnboardingAddressRequest: type: object required: [cep, logradouro, numero, bairro, cidade, estado] properties: cep: { type: string } logradouro: { type: string } numero: { type: string } complemento: { type: string, nullable: true } bairro: { type: string } cidade: { type: string } estado: { type: string, minLength: 2, maxLength: 2 } OnboardingApplication: type: object properties: id: { type: string, format: uuid } user_id: { type: integer } person_type: { type: string } status: { type: string } name: { type: string } email: { type: string } document: { type: string } phone: { type: string } provider: type: object properties: pessoa_fisica_id: { type: string, nullable: true } client_token: { type: string, nullable: true } agency: { type: string, nullable: true } account_number: { type: string, nullable: true } prova_vida: type: object properties: session_id: { type: string, nullable: true } url_iframe: { type: string, nullable: true } kyc_status: { type: string, nullable: true } conta_bancaria_criada: { type: boolean } steps: type: array items: type: object additionalProperties: true security: - bearerAuth: []