Guia de integração para ATSs v1.0

Publique as vagas dos seus clientes na Remotar

A integração é um feed XML: você publica um arquivo numa URL e a Remotar lê essa URL periodicamente. Não há API para chamar nem autenticação para implementar.

Baixar o XSD Baixar o exemplo

Endereço permanente do esquema: https://docs.remotar.com.br/feed/v1/remotar-feed-v1.xsd

Como funciona

  1. 1 · vocêPublica o feedUma URL HTTPS com todas as vagas abertas dos clientes que divulgam na Remotar.
  2. 2 · RemotarLê a URLA cada poucas horas, sem nenhuma ação sua.
  3. 3 · RemotarCura e publicaVaga nova entra na curadoria. Vaga que sumiu do feed é encerrada.
  4. 4 · candidatoCandidata-se no seu ATSO botão leva ao applyUrl da vaga. A candidatura acontece no seu sistema.

O feed é sempre uma fotografia completa, não uma lista de alterações. Não é preciso marcar vaga como nova, alterada ou removida: basta o feed refletir o estado atual.

Requisitos da URL

  • HTTPS, respondendo GET com status 200 e Content-Type: application/xml.
  • Codificação UTF-8.
  • URL estável. Se precisar de chave de acesso, coloque-a na própria URL (?token=…). Não suportamos cabeçalhos de autenticação.
  • Resposta completa em menos de 60 segundos. Recomendamos manter o arquivo abaixo de 20 MB.

Estrutura

feed mínimo
<?xml version="1.0" encoding="UTF-8"?>
<remotarFeed version="1.0">
  <generatedAt>2026-09-21T09:00:00-03:00</generatedAt>
  <jobs>
    <job>
      <id>vaga-10482</id>
      <title>Pessoa Desenvolvedora Back-end Python Sênior</title>
      <description><![CDATA[<p>Descrição em HTML…</p>]]></description>
      <applyUrl>https://vagas.seu-ats.com.br/acme/vaga-10482</applyUrl>
      <workplace>remote</workplace>
      <company>
        <id>acme</id>
        <name>Acme Pagamentos</name>
      </company>
    </job>
  </jobs>
</remotarFeed>
  • version é obrigatório e deve ser 1.0 nesta versão do formato.
  • generatedAt é o momento em que o arquivo foi gerado (ISO 8601 com fuso).
  • Dentro de <job> e de <company>, os elementos podem vir em qualquer ordem.
  • Use <![CDATA[ … ]]> em textos com HTML ou com os caracteres < e &.

Campos da vaga

Obrigatórios

CampoFormatoRegra
idLetras, números e . _ : -, até 100 caracteresIdentificador estável e único da vaga no seu ATS. Veja Identificadores.
titleTexto, até 255 caracteresTítulo da vaga, sem código interno nem nome da empresa.
descriptionHTML, até 50.000 caracteresDescrição completa: responsabilidades, requisitos e o que mais houver.
applyUrlURL https://Página de candidatura desta vaga no seu ATS.
workplaceremote · hybrid · onsiteModelo de trabalho. Veja Quais vagas entram.
companyBlocoEmpresa que contrata. Veja Campos da empresa.
location<city> e <state>Obrigatório em vaga híbrida. Cidade e UF de 2 letras (ex.: SP) do escritório.

Opcionais

Os opcionais melhoram a vaga na Remotar: aparecem como filtro, selo ou informação destacada. Mande sempre que tiver o dado.

CampoFormatoUso
publishedAtData e hora ISO 8601Data em que a vaga foi aberta.
contractTypeclt · pj · internship · temporary · freelancer · otherTipo de contratação.
seniorityinternship · junior · mid · senior · specialist · leadNível da vaga.
salarymin · max · currency · periodFaixa salarial. Veja Salário.
categoryTexto, até 255 caracteresÁrea da vaga no seu ATS (ex.: "Tecnologia").
pcdtrue · falsetrue quando a vaga é exclusiva ou afirmativa para pessoas com deficiência.
benefitsLista de <benefit>, até 50Benefícios oferecidos, um por item.

Campos da empresa

CampoObrigatórioRegra
idsimIdentificador estável do seu cliente. Todas as vagas da mesma empresa trazem o mesmo id.
namesimNome público da empresa, até 255 caracteres. Não use "Confidencial": vaga sem empresa identificada não é publicada.
websitenãoSite institucional. Ajuda a identificar a empresa na Remotar.
logoUrlnãoLogo em PNG, JPG ou SVG.
descriptionnãoApresentação curta da empresa, em texto ou HTML.

Quais vagas entram

A Remotar publica apenas vagas remotas e híbridas.

workplaceResultadoObservação
remoteentraSegue para a curadoria.
hybrid com locationentraSegue para a curadoria.
hybrid sem locationdescartadaSem cidade e UF, a pessoa não sabe onde fica o escritório.
onsiteignoradaPode vir no feed. Assim você não precisa filtrar.

Toda vaga passa pela curadoria da Remotar antes de aparecer no site. Na primeira vaga de uma empresa nova, também confirmamos a empresa. Por isso, a publicação não é imediata, e uma vaga pode não ser publicada se não seguir as políticas da Remotar.

Identificadores

O id da vaga e o id da empresa são o que liga o seu feed ao que está publicado na Remotar.

  • Nunca mude o id de uma vaga existente. Para nós, um id novo é uma vaga nova, e o antigo é uma vaga encerrada.
  • Nunca reaproveite um id para outra vaga, mesmo depois de a primeira ser encerrada.
  • Use o identificador interno do seu banco, não o título nem a URL.
  • O id da empresa é o mesmo em todas as vagas dela e em todas as leituras. Se o cliente mudar de nome, o id continua o mesmo.

Ciclo de vida da vaga

SituaçãoNo feedNa Remotar
Vaga abertaPresentePublica, depois da curadoria.
Vaga alteradaPresente, com os dados novosAtualiza.
Vaga fechada ou pausadaAusenteEncerra a vaga.
Vaga reabertaVolta, com o mesmo idReativa a vaga.
Nenhuma vaga aberta<jobs/> vazio, num feed válidoEncerra todas as vagas do feed.
Feed fora do ar ou inválidoErro HTTP, timeout ou XML inválidoNada muda. Mantém o último estado e tenta de novo na próxima leitura.

Um feed com erro nunca derruba as vagas publicadas. Só um feed válido e sem aquela vaga a encerra.

Descrição e salário

Descrição

  • Envie HTML simples: p, br, ul, ol, li, strong, em, h2h4 e a. Scripts, estilos, iframes, imagens e atributos de formatação são removidos.
  • Não inclua o link de candidatura na descrição: ele vem em applyUrl.
  • Descrições muito curtas prejudicam a curadoria e podem impedir a publicação.

Salário

bloco salary
<salary>
  <min>12000</min>
  <max>16000</max>
  <currency>BRL</currency>
  <period>month</period>
</salary>
  • Valores inteiros, sem separador de milhar nem centavos.
  • max é obrigatório dentro de salary. Para salário fixo, mande só max.
  • currency: BRL, USD ou EUR. period: hour, month ou year.
  • Se a vaga não divulga salário, omita o bloco inteiro. Não mande 0.

Link de candidatura e rastreamento

Ao enviar a pessoa para o applyUrl, a Remotar acrescenta utm_source=remotar à URL, a menos que ela já traga um utm_source. Assim você mede as candidaturas vindas da Remotar. Garanta que o seu ATS aceite parâmetros extras na URL de candidatura.

Validando o feed

O XSD confere estrutura e formatos. Com xmllint:

shell
xmllint --noout --schema remotar-feed-v1.xsd seu-feed.xml

Ou em Python, com lxml:

python
from lxml import etree

schema = etree.XMLSchema(etree.parse("remotar-feed-v1.xsd"))
feed = etree.parse("seu-feed.xml")
schema.assertValid(feed)

O XSD não expressa duas regras, que conferimos na leitura: vaga hybrid precisa de location, e o id de cada empresa precisa ser estável entre leituras.

Elementos fora do esquema tornam o feed inválido. Se você precisa mandar um dado que o formato não prevê, fale com a gente: o formato cresce por versão.

Checklist antes de enviar a URL

  • O feed valida contra remotar-feed-v1.xsd.
  • A URL responde por HTTPS em menos de 60 segundos.
  • O feed contém todas as vagas abertas, não só as recentes.
  • Os ids de vaga e de empresa vêm do seu banco e não mudam.
  • Toda vaga híbrida tem cidade e UF.
  • O applyUrl abre a candidatura da vaga certa, sem exigir login prévio.
  • O applyUrl continua funcionando com ?utm_source=remotar no final.

Próximo passo

Com o feed validado, envie à Remotar a URL do feed, o nome do seu ATS com um contato técnico e, se houver, a lista dos clientes que já têm vagas no feed. Fazemos uma leitura de teste, mostramos o resultado (vagas aceitas, descartadas e o motivo de cada descarte) e só então ativamos a integração.

Versionamento

  • Mudanças compatíveis, como um campo opcional novo, sobem a versão menor: 1.1, 1.2. Um feed 1.0 continua válido.
  • Mudanças incompatíveis geram uma versão 2.0, com novo XSD e prazo de transição combinado com cada parceiro.

XSD e exemplo

Os dois arquivos oficiais da versão 1.0: remotar-feed-v1.xsd e exemplo-v1.xml. O exemplo traz uma vaga remota completa, uma híbrida e uma só com os campos obrigatórios, e valida contra o XSD.

Exemplo de feed exemplo-v1.xml
xml
<?xml version="1.0" encoding="UTF-8"?>
<remotarFeed version="1.0">
  <generatedAt>2026-09-21T09:00:00-03:00</generatedAt>
  <jobs>

    <!-- Vaga remota, com todos os campos opcionais preenchidos -->
    <job>
      <id>vaga-10482</id>
      <title>Pessoa Desenvolvedora Back-end Python Sênior</title>
      <description><![CDATA[
        <p>Buscamos uma pessoa desenvolvedora para evoluir nossa plataforma de pagamentos.</p>
        <h3>Responsabilidades</h3>
        <ul>
          <li>Projetar e manter APIs em Python (FastAPI)</li>
          <li>Participar das decisões de arquitetura</li>
        </ul>
        <h3>Requisitos</h3>
        <ul>
          <li>Experiência sólida com Python e PostgreSQL</li>
          <li>Vivência com filas e mensageria</li>
        </ul>
      ]]></description>
      <applyUrl>https://vagas.exemplo-ats.com.br/acme/vaga-10482</applyUrl>
      <workplace>remote</workplace>
      <publishedAt>2026-09-18T14:30:00-03:00</publishedAt>
      <contractType>pj</contractType>
      <seniority>senior</seniority>
      <salary>
        <min>12000</min>
        <max>16000</max>
        <currency>BRL</currency>
        <period>month</period>
      </salary>
      <category>Tecnologia</category>
      <pcd>false</pcd>
      <benefits>
        <benefit>Auxílio home office</benefit>
        <benefit>Plano de saúde</benefit>
      </benefits>
      <company>
        <id>acme</id>
        <name>Acme Pagamentos</name>
        <website>https://acme.com.br</website>
        <logoUrl>https://acme.com.br/logo.png</logoUrl>
        <description>Fintech que simplifica pagamentos para pequenos negócios.</description>
      </company>
    </job>

    <!-- Vaga híbrida: location é obrigatório -->
    <job>
      <id>vaga-10517</id>
      <title>Analista de Dados Pleno</title>
      <description><![CDATA[<p>Apoie o time comercial com análises e dashboards.</p>]]></description>
      <applyUrl>https://vagas.exemplo-ats.com.br/beta/vaga-10517</applyUrl>
      <workplace>hybrid</workplace>
      <location>
        <city>Belo Horizonte</city>
        <state>MG</state>
      </location>
      <contractType>clt</contractType>
      <company>
        <id>beta-logistica</id>
        <name>Beta Logística</name>
      </company>
    </job>

    <!-- Vaga só com os campos obrigatórios -->
    <job>
      <id>vaga-10533</id>
      <title>Designer de Produto</title>
      <description><![CDATA[<p>Desenhe a experiência do nosso app.</p>]]></description>
      <applyUrl>https://vagas.exemplo-ats.com.br/acme/vaga-10533</applyUrl>
      <workplace>remote</workplace>
      <company>
        <id>acme</id>
        <name>Acme Pagamentos</name>
      </company>
    </job>

  </jobs>
</remotarFeed>
Esquema remotar-feed-v1.xsd
xsd
<?xml version="1.0" encoding="UTF-8"?>
<!--
  Feed de vagas Remotar — versão 1.0

  Esquema do XML que um ATS publica para enviar vagas à Remotar.
  Guia completo: README.md, na mesma pasta.

  Os filhos de <job> e de <company> podem vir em qualquer ordem.
  Elementos fora deste esquema tornam o feed inválido: se precisar de um
  campo novo, fale com a Remotar.
-->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">

  <xs:element name="remotarFeed">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="generatedAt" type="xs:dateTime"/>
        <xs:element name="jobs">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="job" type="Job" minOccurs="0" maxOccurs="unbounded"/>
            </xs:sequence>
          </xs:complexType>
          <xs:unique name="jobIdUnico">
            <xs:selector xpath="job"/>
            <xs:field xpath="id"/>
          </xs:unique>
        </xs:element>
      </xs:sequence>
      <xs:attribute name="version" use="required">
        <xs:simpleType>
          <xs:restriction base="xs:string">
            <xs:pattern value="1\.[0-9]+"/>
          </xs:restriction>
        </xs:simpleType>
      </xs:attribute>
    </xs:complexType>
  </xs:element>

  <xs:complexType name="Job">
    <xs:all>
      <!-- Obrigatórios -->
      <xs:element name="id" type="Identificador"/>
      <xs:element name="title" type="TextoCurto"/>
      <xs:element name="description" type="TextoLongo"/>
      <xs:element name="applyUrl" type="UrlHttps"/>
      <xs:element name="workplace" type="Workplace"/>
      <xs:element name="company" type="Company"/>

      <!-- Obrigatório quando workplace = hybrid ou onsite -->
      <xs:element name="location" type="Location" minOccurs="0"/>

      <!-- Opcionais -->
      <xs:element name="publishedAt" type="xs:dateTime" minOccurs="0"/>
      <xs:element name="contractType" type="ContractType" minOccurs="0"/>
      <xs:element name="seniority" type="Seniority" minOccurs="0"/>
      <xs:element name="salary" type="Salary" minOccurs="0"/>
      <xs:element name="category" type="TextoCurto" minOccurs="0"/>
      <xs:element name="pcd" type="xs:boolean" minOccurs="0"/>
      <xs:element name="benefits" type="Benefits" minOccurs="0"/>
    </xs:all>
  </xs:complexType>

  <xs:complexType name="Company">
    <xs:all>
      <xs:element name="id" type="Identificador"/>
      <xs:element name="name" type="TextoCurto"/>
      <xs:element name="website" type="UrlHttp" minOccurs="0"/>
      <xs:element name="logoUrl" type="UrlHttp" minOccurs="0"/>
      <xs:element name="description" type="TextoLongo" minOccurs="0"/>
    </xs:all>
  </xs:complexType>

  <xs:complexType name="Location">
    <xs:all>
      <xs:element name="city" type="TextoCurto"/>
      <xs:element name="state" type="UF"/>
    </xs:all>
  </xs:complexType>

  <xs:complexType name="Salary">
    <xs:all>
      <xs:element name="min" type="xs:nonNegativeInteger" minOccurs="0"/>
      <xs:element name="max" type="xs:positiveInteger"/>
      <xs:element name="currency" type="Currency"/>
      <xs:element name="period" type="SalaryPeriod"/>
    </xs:all>
  </xs:complexType>

  <xs:complexType name="Benefits">
    <xs:sequence>
      <xs:element name="benefit" type="TextoCurto" maxOccurs="50"/>
    </xs:sequence>
  </xs:complexType>

  <!-- Tipos simples -->

  <xs:simpleType name="Identificador">
    <xs:restriction base="xs:string">
      <xs:minLength value="1"/>
      <xs:maxLength value="100"/>
      <xs:pattern value="[A-Za-z0-9._:\-]+"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="TextoCurto">
    <xs:restriction base="xs:string">
      <xs:minLength value="1"/>
      <xs:maxLength value="255"/>
      <xs:pattern value=".*\S.*"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="TextoLongo">
    <xs:restriction base="xs:string">
      <xs:minLength value="1"/>
      <xs:maxLength value="50000"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="UrlHttps">
    <xs:restriction base="xs:anyURI">
      <xs:pattern value="https://.+"/>
      <xs:maxLength value="2000"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="UrlHttp">
    <xs:restriction base="xs:anyURI">
      <xs:pattern value="https?://.+"/>
      <xs:maxLength value="2000"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="Workplace">
    <xs:restriction base="xs:string">
      <xs:enumeration value="remote"/>
      <xs:enumeration value="hybrid"/>
      <xs:enumeration value="onsite"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="UF">
    <xs:restriction base="xs:string">
      <xs:enumeration value="AC"/><xs:enumeration value="AL"/><xs:enumeration value="AP"/>
      <xs:enumeration value="AM"/><xs:enumeration value="BA"/><xs:enumeration value="CE"/>
      <xs:enumeration value="DF"/><xs:enumeration value="ES"/><xs:enumeration value="GO"/>
      <xs:enumeration value="MA"/><xs:enumeration value="MT"/><xs:enumeration value="MS"/>
      <xs:enumeration value="MG"/><xs:enumeration value="PA"/><xs:enumeration value="PB"/>
      <xs:enumeration value="PR"/><xs:enumeration value="PE"/><xs:enumeration value="PI"/>
      <xs:enumeration value="RJ"/><xs:enumeration value="RN"/><xs:enumeration value="RS"/>
      <xs:enumeration value="RO"/><xs:enumeration value="RR"/><xs:enumeration value="SC"/>
      <xs:enumeration value="SP"/><xs:enumeration value="SE"/><xs:enumeration value="TO"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="ContractType">
    <xs:restriction base="xs:string">
      <xs:enumeration value="clt"/>
      <xs:enumeration value="pj"/>
      <xs:enumeration value="internship"/>
      <xs:enumeration value="temporary"/>
      <xs:enumeration value="freelancer"/>
      <xs:enumeration value="other"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="Seniority">
    <xs:restriction base="xs:string">
      <xs:enumeration value="internship"/>
      <xs:enumeration value="junior"/>
      <xs:enumeration value="mid"/>
      <xs:enumeration value="senior"/>
      <xs:enumeration value="specialist"/>
      <xs:enumeration value="lead"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="Currency">
    <xs:restriction base="xs:string">
      <xs:enumeration value="BRL"/>
      <xs:enumeration value="USD"/>
      <xs:enumeration value="EUR"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="SalaryPeriod">
    <xs:restriction base="xs:string">
      <xs:enumeration value="hour"/>
      <xs:enumeration value="month"/>
      <xs:enumeration value="year"/>
    </xs:restriction>
  </xs:simpleType>

</xs:schema>