Autentique o parceiro #
https://devprescription.amplimed.cloud/identity/v1
/partners/authenticate
Troque clientId e secretKey por um token de curta duração.
A integração começa trocando as credenciais do parceiro por um token de curta duração. A API
confere o clientId e compara a
secretKey com o hash guardado no
cadastro do parceiro. Esse token existe por um único motivo: autorizar a criação da sessão de prescrição na
etapa seguinte. Ele não dá acesso a dado de paciente nem é o token que o front embarcado usa.
Esta chamada é server-to-server
secretKey nunca pode sair do backend
do parceiro. Não a coloque em JavaScript, em aplicativo mobile, em variável exposta ao browser nem em
repositório — quem tem a secretKey consegue abrir sessões em nome do seu serviço.Onde guardar as credenciais
Em variável de ambiente ou em um gerenciador de segredos (AWS Secrets Manager, Vault, o que já existir na
sua stack). Em Laravel, isso significa .env lido por
config() — nunca o valor escrito
direto no código. O .env não vai
para o versionamento.
O que fazer quando vier 401
Um 401 significa que a credencial
não confere — e repetir a chamada não vai mudar isso. Não coloque retry automático em loop aqui. Confira,
nesta ordem: se você está apontando para o ambiente certo, se o
clientId é o do ambiente em
questão, e se a secretKey não foi
rotacionada. Retry com backoff faz sentido para 5xx e timeout, não para 401.
Rotação da secretKey
A secretKey pode ser trocada a
qualquer momento a pedido do parceiro, e deve ser trocada imediatamente se houver suspeita de vazamento.
Como ela é lida do ambiente, a rotação é: gerar a nova credencial com o time da Amplimed, atualizar o
segredo no seu ambiente e reiniciar a aplicação. Tokens já emitidos continuam válidos até expirar, então a
troca não derruba sessões em andamento.
Cache do token
O token é de curta duração. Guardá-lo em memória ou em cache pelo tempo de vida informado em
expiresIn evita uma chamada de
autenticação a cada sessão criada. Sempre respeite o
expiresAt devolvido em vez de
assumir um prazo fixo.
Corpo da requisição
| Campo | Tipo | Detalhes |
|---|---|---|
clientId
|
string |
obrigatório
|
secretKey
|
string |
obrigatório
|
Resposta 200
`PartnerTokenResource`
| Campo | Tipo | Detalhes |
|---|---|---|
token
|
string |
obrigatório
|
tokenType
|
string |
obrigatório
Bearer
|
expiresIn
|
string |
obrigatório
|
expiresAt
|
string |
obrigatório
|
Erros
{
"error_code": "INVALID_PARTNER_CREDENTIALS",
"message": "Invalid partner credentials."
}
{
"message": "<string>",
"errors": []
}
curl -X POST 'https://devprescription.amplimed.cloud/identity/v1/partners/authenticate' \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-d '{"clientId":"SEU_CLIENT_ID","secretKey":"SUA_SECRET_KEY"}'
use Illuminate\Support\Facades\Http;
$response = Http::acceptJson()
->post('https://devprescription.amplimed.cloud/identity/v1/partners/authenticate', [
'clientId' => 'SEU_CLIENT_ID',
'secretKey' => 'SUA_SECRET_KEY',
]);
if ($response->failed()) {
// Trate o erro com $response->status() e $response->json('error_code').
}
$data = $response->json();
$curl = curl_init('https://devprescription.amplimed.cloud/identity/v1/partners/authenticate');
$payload = json_encode([
'clientId' => 'SEU_CLIENT_ID',
'secretKey' => 'SUA_SECRET_KEY',
]);
curl_setopt_array($curl, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_HTTPHEADER => ['Accept: application/json', 'Content-Type: application/json'],
CURLOPT_POSTFIELDS => $payload,
]);
$body = curl_exec($curl);
$status = curl_getinfo($curl, CURLINFO_RESPONSE_CODE);
curl_close($curl);
$data = json_decode($body, true);
const response = await fetch('https://devprescription.amplimed.cloud/identity/v1/partners/authenticate', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
"clientId": "SEU_CLIENT_ID",
"secretKey": "SUA_SECRET_KEY"
}),
});
if (!response.ok) {
// Trate o erro com response.status e o error_code do corpo.
}
const data = await response.json();
import requests
response = requests.post(
'https://devprescription.amplimed.cloud/identity/v1/partners/authenticate',
headers={'Accept': 'application/json'},
json={
'clientId': 'SEU_CLIENT_ID',
'secretKey': 'SUA_SECRET_KEY',
},
)
response.raise_for_status()
data = response.json()
{
"token": "eyJhbGciOiJIUzI1NiJ9.TOKEN_DE_PARCEIRO.ASSINATURA",
"tokenType": "Bearer",
"expiresIn": "300",
"expiresAt": "2026-01-01T00:05:00Z"
}
Testar
Aponta para o ambiente de desenvolvimento. Não use credenciais de produção aqui.
Crie a sessão de prescrição #
https://devprescription.amplimed.cloud/identity/v1
/sessions
Envie profissional e paciente e receba o embeddedToken.
Com o token de parceiro em mãos, você cria a sessão de prescrição. A API resolve o escopo de módulos, valida os
customFields contra o schema acordado
no seu cadastro, grava um snapshot do contexto (parceiro, profissional, paciente) e devolve o
embeddedToken.
Token de parceiro e embeddedToken são coisas diferentes
Esta é de longe a maior fonte de confusão de quem integra pela primeira vez:
- O token de parceiro (etapa 1) identifica a sua empresa. Ele vive no seu backend, autoriza a criação de sessões e não deve chegar ao browser.
- O embeddedToken (esta etapa) identifica uma sessão específica — este profissional, este paciente, estes escopos, este prazo. É ele, e apenas ele, que vai para o bundle embarcado no front.
Mandar o token de parceiro para o front é um erro de segurança; mandar o
embeddedToken para
POST /sessions simplesmente não
funciona.
Como os scopes são resolvidos
Os módulos liberados na sessão são o cruzamento de duas listas: o piso regulatório do conselho do profissional (o que aquele conselho permite prescrever) e o teto comercial do parceiro (o que a sua empresa contratou). A sessão recebe a interseção.
Na prática: se o seu contrato inclui um módulo que o conselho daquele profissional não autoriza, ele não
aparece nos scopes. E se o
profissional poderia prescrever algo que a sua empresa não contratou, também não aparece. Por isso o
register.type é obrigatório —
é ele que determina o piso. Leia sempre os scopes devolvidos em vez de assumir
o que foi contratado.
customFields
Os customFields precisam bater com
o customFieldsSchema definido no
cadastro do seu parceiro. Campo fora do schema combinado faz a chamada voltar
422. Se você precisa de um campo
novo, ele é acordado no cadastro primeiro — não basta começar a enviá-lo.
professionalId e patientId
São identificadores da Amplimed, não do seu sistema. Envie o id quando o profissional
ou o paciente já existir no nosso cadastro. Se ainda não existir, mande
null — o contrato aceita
null nos dois, e nesse caso quem
identifica a pessoa é o resto do payload: nome, documento e, no profissional, o registro do conselho.
Ciclo de vida da sessão
A sessão nasce em createdAt e vale
até expiresAt, conforme o TTL
configurado para o parceiro. Enquanto o profissional estiver trabalhando, a renovação desliza esse prazo e
devolve um embeddedToken novo.
Quando o atendimento termina, encerre a sessão em vez de deixá-la expirar sozinha — assim ela deixa de ser
utilizável imediatamente. Uma sessão por atendimento: não reaproveite a mesma sessão para outro paciente.
LGPD: dado de paciente trafega aqui
sessionId,
patientId) e o status da resposta.Requer o token de parceiro
Authorization: Bearer
<token>.Corpo da requisição
| Campo | Tipo | Detalhes |
|---|---|---|
professional
|
object |
obrigatório
|
professional.professionalId
|
string |
opcional
nullable
|
professional.name
|
string |
obrigatório
|
professional.register
|
object |
obrigatório
|
professional.register.type
|
string |
obrigatório
|
professional.register.value
|
string |
obrigatório
|
professional.register.state
|
string |
obrigatório
|
professional.specialty
|
string |
opcional
nullable
|
professional.document
|
object |
obrigatório
|
professional.document.type
|
string |
obrigatório
|
professional.document.value
|
string |
obrigatório
|
patient
|
object |
obrigatório
|
patient.patientId
|
string |
opcional
nullable
|
patient.name
|
string |
obrigatório
|
patient.document
|
object |
obrigatório
|
patient.document.type
|
string |
obrigatório
cpf
passport
rg
|
patient.document.value
|
string |
obrigatório
|
patient.birthDate
|
string date-time |
opcional
nullable
|
patient.gender
|
string |
opcional
nullable
|
patient.phone
|
string |
opcional
nullable
|
patient.email
|
string email |
opcional
nullable
|
patient.address
|
object |
opcional
nullable
|
patient.address.street
|
string |
opcional
|
patient.address.number
|
string |
opcional
|
patient.address.complement
|
string |
opcional
nullable
|
patient.address.neighborhood
|
string |
opcional
|
patient.address.city
|
string |
opcional
|
patient.address.state
|
string |
opcional
|
patient.address.zipCode
|
string |
opcional
|
patient.address.country
|
string |
opcional
|
customFields
|
string[] |
opcional
nullable
|
embeddedType
|
string |
opcional
nullable
|
Resposta 201
Sessão de prescrição criada.
| Campo | Tipo | Detalhes |
|---|---|---|
sessionId
|
string |
obrigatório
|
embeddedToken
|
string |
obrigatório
nullable
|
embeddedType
|
string |
obrigatório
nullable
|
status
|
string |
obrigatório
nullable
|
apiVersion
|
string |
obrigatório
nullable
|
scopes
|
string |
obrigatório
nullable
|
featureFlags
|
string |
obrigatório
nullable
|
createdAt
|
string |
obrigatório
|
expiresAt
|
string |
obrigatório
|
Erros
{
"message": "<string>",
"errors": []
}
curl -X POST 'https://devprescription.amplimed.cloud/identity/v1/sessions' \
-H 'Accept: application/json' \
-H 'Authorization: Bearer SEU_TOKEN_DE_PARCEIRO' \
-H 'Content-Type: application/json' \
-d '{"professional":{"professionalId":null,"name":"Dra. Ana Souza","register":{"type":"CRM","value":"123456","state":"SC"},"specialty":"Clínica Médica","document":{"type":"cpf","value":"00000000000"}},"patient":{"patientId":null,"name":"João da Silva","document":{"type":"cpf","value":"11111111111"},"birthDate":"1985-04-12T00:00:00Z","gender":"male","phone":"+5548999999999","email":"joao@exemplo.com","address":{"street":"Rua das Flores","number":"100","complement":null,"neighborhood":"Centro","city":"Florianópolis","state":"SC","zipCode":"88010000","country":"BR"}},"customFields":[],"embeddedType":null}'
use Illuminate\Support\Facades\Http;
$response = Http::acceptJson()
->withToken($partnerToken)
->post('https://devprescription.amplimed.cloud/identity/v1/sessions', [
'professional' => [
'professionalId' => null,
'name' => 'Dra. Ana Souza',
'register' => [
'type' => 'CRM',
'value' => '123456',
'state' => 'SC',
],
'specialty' => 'Clínica Médica',
'document' => [
'type' => 'cpf',
'value' => '00000000000',
],
],
'patient' => [
'patientId' => null,
'name' => 'João da Silva',
'document' => [
'type' => 'cpf',
'value' => '11111111111',
],
'birthDate' => '1985-04-12T00:00:00Z',
'gender' => 'male',
'phone' => '+5548999999999',
'email' => 'joao@exemplo.com',
'address' => [
'street' => 'Rua das Flores',
'number' => '100',
'complement' => null,
'neighborhood' => 'Centro',
'city' => 'Florianópolis',
'state' => 'SC',
'zipCode' => '88010000',
'country' => 'BR',
],
],
'customFields' => [],
'embeddedType' => null,
]);
if ($response->failed()) {
// Trate o erro com $response->status() e $response->json('error_code').
}
$data = $response->json();
$curl = curl_init('https://devprescription.amplimed.cloud/identity/v1/sessions');
$payload = json_encode([
'professional' => [
'professionalId' => null,
'name' => 'Dra. Ana Souza',
'register' => [
'type' => 'CRM',
'value' => '123456',
'state' => 'SC',
],
'specialty' => 'Clínica Médica',
'document' => [
'type' => 'cpf',
'value' => '00000000000',
],
],
'patient' => [
'patientId' => null,
'name' => 'João da Silva',
'document' => [
'type' => 'cpf',
'value' => '11111111111',
],
'birthDate' => '1985-04-12T00:00:00Z',
'gender' => 'male',
'phone' => '+5548999999999',
'email' => 'joao@exemplo.com',
'address' => [
'street' => 'Rua das Flores',
'number' => '100',
'complement' => null,
'neighborhood' => 'Centro',
'city' => 'Florianópolis',
'state' => 'SC',
'zipCode' => '88010000',
'country' => 'BR',
],
],
'customFields' => [],
'embeddedType' => null,
]);
curl_setopt_array($curl, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_HTTPHEADER => ['Accept: application/json', 'Content-Type: application/json', 'Authorization: Bearer '.$partnerToken],
CURLOPT_POSTFIELDS => $payload,
]);
$body = curl_exec($curl);
$status = curl_getinfo($curl, CURLINFO_RESPONSE_CODE);
curl_close($curl);
$data = json_decode($body, true);
const response = await fetch('https://devprescription.amplimed.cloud/identity/v1/sessions', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: `Bearer ${partnerToken}`,
},
body: JSON.stringify({
"professional": {
"professionalId": null,
"name": "Dra. Ana Souza",
"register": {
"type": "CRM",
"value": "123456",
"state": "SC"
},
"specialty": "Clínica Médica",
"document": {
"type": "cpf",
"value": "00000000000"
}
},
"patient": {
"patientId": null,
"name": "João da Silva",
"document": {
"type": "cpf",
"value": "11111111111"
},
"birthDate": "1985-04-12T00:00:00Z",
"gender": "male",
"phone": "+5548999999999",
"email": "joao@exemplo.com",
"address": {
"street": "Rua das Flores",
"number": "100",
"complement": null,
"neighborhood": "Centro",
"city": "Florianópolis",
"state": "SC",
"zipCode": "88010000",
"country": "BR"
}
},
"customFields": [],
"embeddedType": null
}),
});
if (!response.ok) {
// Trate o erro com response.status e o error_code do corpo.
}
const data = await response.json();
import requests
response = requests.post(
'https://devprescription.amplimed.cloud/identity/v1/sessions',
headers={'Accept': 'application/json', 'Authorization': f'Bearer {partner_token}'},
json={
'professional': {
'professionalId': None,
'name': 'Dra. Ana Souza',
'register': {
'type': 'CRM',
'value': '123456',
'state': 'SC',
},
'specialty': 'Clínica Médica',
'document': {
'type': 'cpf',
'value': '00000000000',
},
},
'patient': {
'patientId': None,
'name': 'João da Silva',
'document': {
'type': 'cpf',
'value': '11111111111',
},
'birthDate': '1985-04-12T00:00:00Z',
'gender': 'male',
'phone': '+5548999999999',
'email': 'joao@exemplo.com',
'address': {
'street': 'Rua das Flores',
'number': '100',
'complement': None,
'neighborhood': 'Centro',
'city': 'Florianópolis',
'state': 'SC',
'zipCode': '88010000',
'country': 'BR',
},
},
'customFields': [],
'embeddedType': None,
},
)
response.raise_for_status()
data = response.json()
{
"sessionId": "65f0c3a1d4e5b6a7c8d9e0f1",
"embeddedToken": "eyJhbGciOiJIUzI1NiJ9.TOKEN_DA_SESSAO.ASSINATURA",
"embeddedType": null,
"status": "active",
"apiVersion": "v1",
"scopes": "<string>",
"featureFlags": "<string>",
"createdAt": "2026-01-01T00:00:00Z",
"expiresAt": "2026-01-01T00:05:00Z"
}
Testar
Aponta para o ambiente de desenvolvimento. Não use credenciais de produção aqui.
Carregue o bundle e inicialize com o embeddedToken.
A prescrição V2 roda como um bundle JavaScript montado dentro de um elemento da sua
página — não é iframe. Você carrega o script, cria um elemento host e chama
Ampliprescreve.init() passando o
embeddedToken da sessão criada na
etapa anterior.
Só o embeddedToken vai para o front
sessionToken que o bundle recebe
é o embeddedToken devolvido por
POST /sessions — nunca o token de
parceiro da etapa 1. O token de parceiro autoriza criar sessões em nome da sua empresa: se ele chegar ao
browser, qualquer pessoa com acesso à página pode abrir sessões para qualquer paciente.Como importar o bundle
O script é servido pela Amplimed e a URL varia por ambiente — trate-a como configuração, não como
constante no código. Neste ambiente ela é
https://devprescription.amplimed.cloud/bundle/ampliprescreve.umd.js.
Em página tradicional, uma <script> no HTML resolve.
Em SPA, você pode deixá-la no index.html ou carregá-la sob
demanda, só quando a prescrição for aberta — é o que os exemplos de React e Vue fazem, guardando a
promessa do carregamento para o script não entrar na página mais de uma vez.
shadow e tema
Com shadow: true o bundle
monta dentro de um shadow DOM, isolando o CSS da prescrição do CSS da sua aplicação — é o
recomendado, porque evita que o seu reset ou framework de estilo vaze para dentro da prescrição. O
theme aceita
colorPrimary e
radius para a prescrição
acompanhar a identidade visual do parceiro.
Reabrir a prescrição exige um host novo
attachShadow só pode ser chamado
uma vez por elemento. Se você inicializar o bundle no mesmo elemento de novo — ao reabrir a prescrição,
por exemplo — a chamada falha porque já existe um shadow tree ali. Substitua o host por um clone vazio
antes de reinicializar, como no exemplo ao lado.Quando a sessão expira
O embeddedToken vale até o
expiresAt da sessão. Se o
atendimento for longo, renove a sessão pelo seu backend e reinicialize o bundle com o token novo —
veja as operações opcionais.
<!-- Página tradicional: o bundle entra por script tag. -->
<div id="prescription-bundle"></div>
<script src="https://devprescription.amplimed.cloud/bundle/ampliprescreve.umd.js"></script>
<script>
// O embeddedToken vem do seu backend, de POST /sessions.
Ampliprescreve.init(document.getElementById('prescription-bundle'), {
sessionToken: embeddedToken,
shadow: true,
theme: { colorPrimary: '#6366F1', radius: '8px' },
});
</script>
const BUNDLE_URL = 'https://devprescription.amplimed.cloud/bundle/ampliprescreve.umd.js';
// Carrega o bundle uma única vez, venha de onde vier a chamada.
let bundle = null;
function carregarBundle() {
if (window.Ampliprescreve) return Promise.resolve();
bundle ??= new Promise((resolve, reject) => {
const script = document.createElement('script');
script.src = BUNDLE_URL;
script.onload = resolve;
script.onerror = () => reject(new Error('Falha ao carregar o bundle da prescrição.'));
document.head.appendChild(script);
});
return bundle;
}
// O embeddedToken vem do seu backend, de POST /sessions.
const { embeddedToken } = await criarSessaoNoSeuBackend();
await carregarBundle();
let host = document.getElementById('prescription-bundle');
// attachShadow só roda uma vez por elemento: troque o host por um clone
// vazio antes de reinicializar, senão reabrir a prescrição falha.
host.replaceWith(host.cloneNode(false));
host = document.getElementById('prescription-bundle');
Ampliprescreve.init(host, {
sessionToken: embeddedToken,
shadow: true,
theme: { colorPrimary: '#6366F1', radius: '8px' },
});
import { useEffect, useRef } from 'react';
const BUNDLE_URL = 'https://devprescription.amplimed.cloud/bundle/ampliprescreve.umd.js';
// Fora do componente: o bundle é carregado uma vez por página, não por
// montagem. Alternativa: deixar o <script> no index.html da aplicação.
let bundle = null;
function carregarBundle() {
if (window.Ampliprescreve) return Promise.resolve();
bundle ??= new Promise((resolve, reject) => {
const script = document.createElement('script');
script.src = BUNDLE_URL;
script.onload = resolve;
script.onerror = () => reject(new Error('Falha ao carregar o bundle da prescrição.'));
document.head.appendChild(script);
});
return bundle;
}
export function Prescricao({ embeddedToken }) {
const container = useRef(null);
useEffect(() => {
if (!embeddedToken) return;
let cancelado = false;
carregarBundle().then(() => {
if (cancelado || !container.current) return;
// Um host novo a cada init: attachShadow não pode rodar duas vezes no
// mesmo elemento. Isso também cobre o efeito rodar duas vezes no
// StrictMode em desenvolvimento.
const host = document.createElement('div');
container.current.replaceChildren(host);
window.Ampliprescreve.init(host, {
sessionToken: embeddedToken,
shadow: true,
theme: { colorPrimary: '#6366F1', radius: '8px' },
});
});
return () => {
cancelado = true;
container.current?.replaceChildren();
};
}, [embeddedToken]);
return <div ref={container} />;
}
<script setup>
import { onBeforeUnmount, onMounted, ref, watch } from 'vue';
const BUNDLE_URL = 'https://devprescription.amplimed.cloud/bundle/ampliprescreve.umd.js';
// Fora do componente: o bundle é carregado uma vez por página, não por
// montagem. Alternativa: deixar o <script> no index.html da aplicação.
let bundle = null;
function carregarBundle() {
if (window.Ampliprescreve) return Promise.resolve();
bundle ??= new Promise((resolve, reject) => {
const script = document.createElement('script');
script.src = BUNDLE_URL;
script.onload = resolve;
script.onerror = () => reject(new Error('Falha ao carregar o bundle da prescrição.'));
document.head.appendChild(script);
});
return bundle;
}
const props = defineProps({ embeddedToken: String });
const container = ref(null);
async function montar() {
if (!props.embeddedToken) return;
await carregarBundle();
if (!container.value) return;
// Um host novo a cada init: attachShadow não pode rodar duas vezes no
// mesmo elemento.
const host = document.createElement('div');
container.value.replaceChildren(host);
window.Ampliprescreve.init(host, {
sessionToken: props.embeddedToken,
shadow: true,
theme: { colorPrimary: '#6366F1', radius: '8px' },
});
}
onMounted(montar);
watch(() => props.embeddedToken, montar);
onBeforeUnmount(() => container.value?.replaceChildren());
</script>
<template>
<div ref="container"></div>
</template>
Testar no navegador
Abre a prescrição de verdade, no ambiente de desenvolvimento, com o profissional e o paciente que você enviou na etapa 2.
Prescrição embarcada · ambiente de desenvolvimento
Operações opcionais #
Com as etapas acima a integração já funciona de ponta a ponta. As operações abaixo servem para manter a sessão viva além do prazo inicial e para encerrá-la explicitamente — use conforme a necessidade do seu fluxo.
Valide a sessão #
narrativa em revisão
https://devprescription.amplimed.cloud/identity/v1
/sessions/validate
Confirme que o embeddedToken ainda vale e recupere o contexto da sessão.
Corpo da requisição
Esta operação não recebe corpo.
Resposta 200
`SessionContextResource`
| Campo | Tipo | Detalhes |
|---|---|---|
sessionId
|
string |
obrigatório
|
embeddedToken
|
string |
obrigatório
|
partner
|
object |
obrigatório
|
professional
|
object |
obrigatório
|
patient
|
object |
obrigatório
|
scopes
|
any[] |
obrigatório
|
featureFlags
|
any[] |
obrigatório
|
customFields
|
any[] |
obrigatório
|
status
|
string |
obrigatório
|
apiVersion
|
string |
obrigatório
|
expiresAt
|
string |
obrigatório
|
Erros
{
"error_code": "SESSION_NOT_FOUND",
"message": "Prescription session not found."
}
{
"error_code": "SESSION_EXPIRED",
"message": "Prescription session is no longer active."
}
{
"message": "<string>",
"errors": []
}
curl -X GET 'https://devprescription.amplimed.cloud/identity/v1/sessions/validate' \
-H 'Accept: application/json'
use Illuminate\Support\Facades\Http;
$response = Http::acceptJson()
->get('https://devprescription.amplimed.cloud/identity/v1/sessions/validate');
if ($response->failed()) {
// Trate o erro com $response->status() e $response->json('error_code').
}
$data = $response->json();
$curl = curl_init('https://devprescription.amplimed.cloud/identity/v1/sessions/validate');
curl_setopt_array($curl, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_HTTPHEADER => ['Accept: application/json'],
]);
$body = curl_exec($curl);
$status = curl_getinfo($curl, CURLINFO_RESPONSE_CODE);
curl_close($curl);
$data = json_decode($body, true);
const response = await fetch('https://devprescription.amplimed.cloud/identity/v1/sessions/validate', {
method: 'GET',
headers: {
Accept: 'application/json',
},
});
if (!response.ok) {
// Trate o erro com response.status e o error_code do corpo.
}
const data = await response.json();
import requests
response = requests.get(
'https://devprescription.amplimed.cloud/identity/v1/sessions/validate',
headers={'Accept': 'application/json'},
)
response.raise_for_status()
data = response.json()
{
"sessionId": "65f0c3a1d4e5b6a7c8d9e0f1",
"embeddedToken": "eyJhbGciOiJIUzI1NiJ9.TOKEN_DA_SESSAO.ASSINATURA",
"partner": [],
"professional": [],
"patient": [],
"scopes": [],
"featureFlags": [],
"customFields": [],
"status": "active",
"apiVersion": "v1",
"expiresAt": "2026-01-01T00:05:00Z"
}
Renove a sessão #
narrativa em revisão
https://devprescription.amplimed.cloud/identity/v1
/sessions/renew
Renovação deslizante do expiresAt, devolve um embeddedToken novo.
Corpo da requisição
| Campo | Tipo | Detalhes |
|---|---|---|
embeddedToken
|
string |
obrigatório
|
Resposta 200
`SessionContextResource`
| Campo | Tipo | Detalhes |
|---|---|---|
sessionId
|
string |
obrigatório
|
embeddedToken
|
string |
obrigatório
|
partner
|
object |
obrigatório
|
professional
|
object |
obrigatório
|
patient
|
object |
obrigatório
|
scopes
|
any[] |
obrigatório
|
featureFlags
|
any[] |
obrigatório
|
customFields
|
any[] |
obrigatório
|
status
|
string |
obrigatório
|
apiVersion
|
string |
obrigatório
|
expiresAt
|
string |
obrigatório
|
Erros
{
"error_code": "SESSION_NOT_FOUND",
"message": "Prescription session not found."
}
{
"error_code": "SESSION_EXPIRED",
"message": "Prescription session is no longer active."
}
{
"message": "<string>",
"errors": []
}
curl -X POST 'https://devprescription.amplimed.cloud/identity/v1/sessions/renew' \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-d '{"embeddedToken":"eyJhbGciOiJIUzI1NiJ9.TOKEN_DA_SESSAO.ASSINATURA"}'
use Illuminate\Support\Facades\Http;
$response = Http::acceptJson()
->post('https://devprescription.amplimed.cloud/identity/v1/sessions/renew', [
'embeddedToken' => 'eyJhbGciOiJIUzI1NiJ9.TOKEN_DA_SESSAO.ASSINATURA',
]);
if ($response->failed()) {
// Trate o erro com $response->status() e $response->json('error_code').
}
$data = $response->json();
$curl = curl_init('https://devprescription.amplimed.cloud/identity/v1/sessions/renew');
$payload = json_encode([
'embeddedToken' => 'eyJhbGciOiJIUzI1NiJ9.TOKEN_DA_SESSAO.ASSINATURA',
]);
curl_setopt_array($curl, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_HTTPHEADER => ['Accept: application/json', 'Content-Type: application/json'],
CURLOPT_POSTFIELDS => $payload,
]);
$body = curl_exec($curl);
$status = curl_getinfo($curl, CURLINFO_RESPONSE_CODE);
curl_close($curl);
$data = json_decode($body, true);
const response = await fetch('https://devprescription.amplimed.cloud/identity/v1/sessions/renew', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
"embeddedToken": "eyJhbGciOiJIUzI1NiJ9.TOKEN_DA_SESSAO.ASSINATURA"
}),
});
if (!response.ok) {
// Trate o erro com response.status e o error_code do corpo.
}
const data = await response.json();
import requests
response = requests.post(
'https://devprescription.amplimed.cloud/identity/v1/sessions/renew',
headers={'Accept': 'application/json'},
json={
'embeddedToken': 'eyJhbGciOiJIUzI1NiJ9.TOKEN_DA_SESSAO.ASSINATURA',
},
)
response.raise_for_status()
data = response.json()
{
"sessionId": "65f0c3a1d4e5b6a7c8d9e0f1",
"embeddedToken": "eyJhbGciOiJIUzI1NiJ9.TOKEN_DA_SESSAO.ASSINATURA",
"partner": [],
"professional": [],
"patient": [],
"scopes": [],
"featureFlags": [],
"customFields": [],
"status": "active",
"apiVersion": "v1",
"expiresAt": "2026-01-01T00:05:00Z"
}
Encerre a sessão #
narrativa em revisão
https://devprescription.amplimed.cloud/identity/v1
/sessions/end
Finaliza a sessão de prescrição antes do prazo de expiração.
Corpo da requisição
| Campo | Tipo | Detalhes |
|---|---|---|
embeddedToken
|
string |
obrigatório
|
Resposta 200
`SessionContextResource`
| Campo | Tipo | Detalhes |
|---|---|---|
sessionId
|
string |
obrigatório
|
embeddedToken
|
string |
obrigatório
|
partner
|
object |
obrigatório
|
professional
|
object |
obrigatório
|
patient
|
object |
obrigatório
|
scopes
|
any[] |
obrigatório
|
featureFlags
|
any[] |
obrigatório
|
customFields
|
any[] |
obrigatório
|
status
|
string |
obrigatório
|
apiVersion
|
string |
obrigatório
|
expiresAt
|
string |
obrigatório
|
Erros
{
"error_code": "SESSION_NOT_FOUND",
"message": "Prescription session not found."
}
{
"error_code": "SESSION_EXPIRED",
"message": "Prescription session is no longer active."
}
{
"message": "<string>",
"errors": []
}
curl -X POST 'https://devprescription.amplimed.cloud/identity/v1/sessions/end' \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-d '{"embeddedToken":"eyJhbGciOiJIUzI1NiJ9.TOKEN_DA_SESSAO.ASSINATURA"}'
use Illuminate\Support\Facades\Http;
$response = Http::acceptJson()
->post('https://devprescription.amplimed.cloud/identity/v1/sessions/end', [
'embeddedToken' => 'eyJhbGciOiJIUzI1NiJ9.TOKEN_DA_SESSAO.ASSINATURA',
]);
if ($response->failed()) {
// Trate o erro com $response->status() e $response->json('error_code').
}
$data = $response->json();
$curl = curl_init('https://devprescription.amplimed.cloud/identity/v1/sessions/end');
$payload = json_encode([
'embeddedToken' => 'eyJhbGciOiJIUzI1NiJ9.TOKEN_DA_SESSAO.ASSINATURA',
]);
curl_setopt_array($curl, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_HTTPHEADER => ['Accept: application/json', 'Content-Type: application/json'],
CURLOPT_POSTFIELDS => $payload,
]);
$body = curl_exec($curl);
$status = curl_getinfo($curl, CURLINFO_RESPONSE_CODE);
curl_close($curl);
$data = json_decode($body, true);
const response = await fetch('https://devprescription.amplimed.cloud/identity/v1/sessions/end', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
"embeddedToken": "eyJhbGciOiJIUzI1NiJ9.TOKEN_DA_SESSAO.ASSINATURA"
}),
});
if (!response.ok) {
// Trate o erro com response.status e o error_code do corpo.
}
const data = await response.json();
import requests
response = requests.post(
'https://devprescription.amplimed.cloud/identity/v1/sessions/end',
headers={'Accept': 'application/json'},
json={
'embeddedToken': 'eyJhbGciOiJIUzI1NiJ9.TOKEN_DA_SESSAO.ASSINATURA',
},
)
response.raise_for_status()
data = response.json()
{
"sessionId": "65f0c3a1d4e5b6a7c8d9e0f1",
"embeddedToken": "eyJhbGciOiJIUzI1NiJ9.TOKEN_DA_SESSAO.ASSINATURA",
"partner": [],
"professional": [],
"patient": [],
"scopes": [],
"featureFlags": [],
"customFields": [],
"status": "active",
"apiVersion": "v1",
"expiresAt": "2026-01-01T00:05:00Z"
}
Exemplo de ponta a ponta #
As duas etapas juntas: o backend do parceiro autentica, recebe o token de parceiro e o usa imediatamente para criar a sessão. É nesta ligação que a maioria das integrações erra.
# 1. Autentique o parceiro e guarde o token.
# As credenciais vêm do ambiente, nunca do código versionado.
TOKEN=$(curl -s -X POST 'https://devprescription.amplimed.cloud/identity/v1/partners/authenticate' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d "{\"clientId\": \"$PARTNER_CLIENT_ID\", \"secretKey\": \"$PARTNER_SECRET_KEY\"}" \
| jq -r '.token')
# 2. Crie a sessão com esse token.
curl -X POST 'https://devprescription.amplimed.cloud/identity/v1/sessions' \
-H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{"professional":{"professionalId":null,"name":"Dra. Ana Souza","register":{"type":"CRM","value":"123456","state":"SC"},"specialty":"Clínica Médica","document":{"type":"cpf","value":"00000000000"}},"patient":{"patientId":null,"name":"João da Silva","document":{"type":"cpf","value":"11111111111"},"birthDate":"1985-04-12T00:00:00Z","gender":"male","phone":"+5548999999999","email":"joao@exemplo.com","address":{"street":"Rua das Flores","number":"100","complement":null,"neighborhood":"Centro","city":"Florianópolis","state":"SC","zipCode":"88010000","country":"BR"}},"customFields":[],"embeddedType":null}'
use Illuminate\Support\Facades\Http;
// 1. Autentique o parceiro. A secretKey nunca sai do seu backend.
$credentials = Http::acceptJson()
->post('https://devprescription.amplimed.cloud/identity/v1/partners/authenticate', [
'clientId' => config('services.partners.client_id'),
'secretKey' => config('services.partners.secret_key'),
])
->throw()
->json();
// 2. Use o token de parceiro para criar a sessão.
$session = Http::acceptJson()
->withToken($credentials['token'])
->post('https://devprescription.amplimed.cloud/identity/v1/sessions', [
'professional' => [
'professionalId' => null,
'name' => 'Dra. Ana Souza',
'register' => [
'type' => 'CRM',
'value' => '123456',
'state' => 'SC',
],
'specialty' => 'Clínica Médica',
'document' => [
'type' => 'cpf',
'value' => '00000000000',
],
],
'patient' => [
'patientId' => null,
'name' => 'João da Silva',
'document' => [
'type' => 'cpf',
'value' => '11111111111',
],
'birthDate' => '1985-04-12T00:00:00Z',
'gender' => 'male',
'phone' => '+5548999999999',
'email' => 'joao@exemplo.com',
'address' => [
'street' => 'Rua das Flores',
'number' => '100',
'complement' => null,
'neighborhood' => 'Centro',
'city' => 'Florianópolis',
'state' => 'SC',
'zipCode' => '88010000',
'country' => 'BR',
],
],
'customFields' => [],
'embeddedType' => null,
])
->throw()
->json();
// O embeddedToken é o que vai para o bundle embarcado.
return $session['embeddedToken'];
// 1. Autentique o parceiro. As credenciais vêm do ambiente.
$curl = curl_init('https://devprescription.amplimed.cloud/identity/v1/partners/authenticate');
curl_setopt_array($curl, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Accept: application/json'],
CURLOPT_POSTFIELDS => json_encode([
'clientId' => getenv('PARTNER_CLIENT_ID'),
'secretKey' => getenv('PARTNER_SECRET_KEY'),
]),
]);
$credentials = json_decode(curl_exec($curl), true);
curl_close($curl);
// 2. Crie a sessão com o token recebido.
$curl = curl_init('https://devprescription.amplimed.cloud/identity/v1/sessions');
curl_setopt_array($curl, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'Accept: application/json',
'Authorization: Bearer '.$credentials['token'],
],
CURLOPT_POSTFIELDS => json_encode([
'professional' => [
'professionalId' => null,
'name' => 'Dra. Ana Souza',
'register' => [
'type' => 'CRM',
'value' => '123456',
'state' => 'SC',
],
'specialty' => 'Clínica Médica',
'document' => [
'type' => 'cpf',
'value' => '00000000000',
],
],
'patient' => [
'patientId' => null,
'name' => 'João da Silva',
'document' => [
'type' => 'cpf',
'value' => '11111111111',
],
'birthDate' => '1985-04-12T00:00:00Z',
'gender' => 'male',
'phone' => '+5548999999999',
'email' => 'joao@exemplo.com',
'address' => [
'street' => 'Rua das Flores',
'number' => '100',
'complement' => null,
'neighborhood' => 'Centro',
'city' => 'Florianópolis',
'state' => 'SC',
'zipCode' => '88010000',
'country' => 'BR',
],
],
'customFields' => [],
'embeddedType' => null,
]),
]);
$session = json_decode(curl_exec($curl), true);
curl_close($curl);
// 1. Autentique o parceiro. A secretKey nunca sai do seu backend.
const auth = await fetch('https://devprescription.amplimed.cloud/identity/v1/partners/authenticate', {
method: 'POST',
headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
body: JSON.stringify({
clientId: process.env.PARTNER_CLIENT_ID,
secretKey: process.env.PARTNER_SECRET_KEY,
}),
});
const { token } = await auth.json();
// 2. Use o token de parceiro para criar a sessão.
const response = await fetch('https://devprescription.amplimed.cloud/identity/v1/sessions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
Authorization: `Bearer ${token}`,
},
body: JSON.stringify({
"professional": {
"professionalId": null,
"name": "Dra. Ana Souza",
"register": {
"type": "CRM",
"value": "123456",
"state": "SC"
},
"specialty": "Clínica Médica",
"document": {
"type": "cpf",
"value": "00000000000"
}
},
"patient": {
"patientId": null,
"name": "João da Silva",
"document": {
"type": "cpf",
"value": "11111111111"
},
"birthDate": "1985-04-12T00:00:00Z",
"gender": "male",
"phone": "+5548999999999",
"email": "joao@exemplo.com",
"address": {
"street": "Rua das Flores",
"number": "100",
"complement": null,
"neighborhood": "Centro",
"city": "Florianópolis",
"state": "SC",
"zipCode": "88010000",
"country": "BR"
}
},
"customFields": [],
"embeddedType": null
}),
});
const session = await response.json();
// O embeddedToken é o que vai para o bundle embarcado.
import os
import requests
# 1. Autentique o parceiro. A secretKey nunca sai do seu backend.
credentials = requests.post(
'https://devprescription.amplimed.cloud/identity/v1/partners/authenticate',
headers={'Accept': 'application/json'},
json={
'clientId': os.environ['PARTNER_CLIENT_ID'],
'secretKey': os.environ['PARTNER_SECRET_KEY'],
},
)
credentials.raise_for_status()
token = credentials.json()['token']
# 2. Use o token de parceiro para criar a sessão.
response = requests.post(
'https://devprescription.amplimed.cloud/identity/v1/sessions',
headers={'Accept': 'application/json', 'Authorization': f'Bearer {token}'},
json={
'professional': {
'professionalId': None,
'name': 'Dra. Ana Souza',
'register': {
'type': 'CRM',
'value': '123456',
'state': 'SC',
},
'specialty': 'Clínica Médica',
'document': {
'type': 'cpf',
'value': '00000000000',
},
},
'patient': {
'patientId': None,
'name': 'João da Silva',
'document': {
'type': 'cpf',
'value': '11111111111',
},
'birthDate': '1985-04-12T00:00:00Z',
'gender': 'male',
'phone': '+5548999999999',
'email': 'joao@exemplo.com',
'address': {
'street': 'Rua das Flores',
'number': '100',
'complement': None,
'neighborhood': 'Centro',
'city': 'Florianópolis',
'state': 'SC',
'zipCode': '88010000',
'country': 'BR',
},
},
'customFields': [],
'embeddedType': None,
},
)
response.raise_for_status()
session = response.json()
# O embeddedToken é o que vai para o bundle embarcado.