---
id: onboard-send-magic-link
title: "Send magic link to data verifier user"
description: "Sends a magic link to a data verifier user: by e-mail to the `email` of the user, and by SMS when the user has a `phone`. The user opens the link on the phone, and the Data Verifier app logs in with it."
sidebar_label: "Send magic link to data verifier user"
hide_title: true
hide_table_of_contents: true
api: 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
sidebar_class_name: "post api-method"
info_path: docs/openid4vc-api/igrant-io-api-documentation
custom_edit_url: null
---

> **Build this with an AI coding agent.** Install the iGrant.io Agent Skills, then ask your agent to build the integration:
>
> ```bash
> npx skills add L3-iGrant/skills
> ```


import ApiTabs from "@theme/ApiTabs";
import DiscriminatorTabs from "@theme/DiscriminatorTabs";
import MethodEndpoint from "@theme/ApiExplorer/MethodEndpoint";
import SecuritySchemes from "@theme/ApiExplorer/SecuritySchemes";
import MimeTabs from "@theme/MimeTabs";
import ParamsItem from "@theme/ParamsItem";
import ResponseSamples from "@theme/ResponseSamples";
import SchemaItem from "@theme/SchemaItem";
import SchemaTabs from "@theme/SchemaTabs";
import Markdown from "@theme/Markdown";
import OperationTabs from "@theme/OperationTabs";
import TabItem from "@theme/TabItem";

<h1 className={"openapi__heading"}>Send magic link to data verifier user</h1>

<MethodEndpoint method={"post"} path={"/v4/onboard/platform/organisation/data-verifier-user/{dataVerifierUserId}/send-magic-link"}></MethodEndpoint>



Sends a magic link to a data verifier user: by e-mail to the `email` of the user, and by SMS when the user has a `phone`. The user opens the link on the phone, and the Data Verifier app logs in with it.

The link has the form `<API base URL>/v4/onboard/platform/verifier-app/login/owsm_...`. It is valid for 24 hours and works once. When the user opens it, the app gets a new API key of the user that is valid for 90 days. When the app is not installed, the link opens a web page about the Data Verifier app.

The call revokes the current API key of the user immediately: the app stops working until the user opens the new link. A new link does not revoke an earlier link that the user did not open. The service sends the e-mail and the SMS after the response, so a failed delivery does not change the response.

## Request

<details style={{"marginBottom":"1rem"}} className={"openapi-markdown__details"} data-collapsed={false} open={true}><summary style={{}}><h3 className={"openapi-markdown__details-summary-header-params"}>Path Parameters</h3></summary><div><ul><ParamsItem className={"paramsItem"} param={{"description":"The ID of the data verifier user.","in":"path","name":"dataVerifierUserId","required":true,"schema":{"type":"string","example":"6af1c3d2e4b5a69788990a1b"}}}></ParamsItem></ul></div></details><div><div><ApiTabs label={undefined} id={undefined}><TabItem label={"204"} value={"204"}><div>

The magic link is created and is being sent.

</div><details style={{"textAlign":"left","marginBottom":"1rem"}} className={"openapi-markdown__details"} data-collaposed={true} open={false}><summary style={{}}><strong>Response Headers</strong></summary><ul style={{"marginLeft":"1rem"}}></ul></details><div></div></TabItem><TabItem label={"400"} value={"400"}><div>

No data verifier user of the organisation has the ID, or the user is deleted: `Failed to get data verifier user: <dataVerifierUserId> for org: <organisationId>`.

</div><details style={{"textAlign":"left","marginBottom":"1rem"}} className={"openapi-markdown__details"} data-collaposed={true} open={false}><summary style={{}}><strong>Response Headers</strong></summary><ul style={{"marginLeft":"1rem"}}></ul></details><div><MimeTabs className={"openapi-tabs__mime"} schemaType={"response"}><TabItem label={"application/json"} value={"application/json"}><SchemaTabs className={"openapi-tabs__schema"}><TabItem label={"Schema"} value={"Schema"}><details style={{}} className={"openapi-markdown__details response"} data-collapsed={false} open={true}><summary style={{}} className={"openapi-markdown__details-summary-response"}><strong>Schema</strong></summary><div style={{"textAlign":"left","marginLeft":"1rem"}}></div><ul style={{"marginLeft":"1rem"}}><SchemaItem collapsible={false} name={"errorCode"} required={true} schemaName={"integer"} qualifierMessage={undefined} schema={{"type":"integer","example":400}}></SchemaItem><SchemaItem collapsible={false} name={"errorDescription"} required={true} schemaName={"string"} qualifierMessage={undefined} schema={{"type":"string","example":"Bad input parameter"}}></SchemaItem><SchemaItem collapsible={false} name={"errorKey"} required={false} schemaName={"string"} qualifierMessage={undefined} schema={{"type":"string","description":"A text code of the refusal that does not change when the text changes. Only some refusals have it, for example `organisation_suspended`, `feature_disabled` or `purpose_exists`."}}></SchemaItem></ul></details></TabItem><TabItem label={"Example (from schema)"} value={"Example (from schema)"}><ResponseSamples responseExample={"{\n  \"errorCode\": 400,\n  \"errorDescription\": \"Bad input parameter\",\n  \"errorKey\": \"string\"\n}"} language={"json"}></ResponseSamples></TabItem></SchemaTabs></TabItem></MimeTabs></div></TabItem><TabItem label={"401"} value={"401"}><div>

The `Authorization` header is missing, or the API key or token is not valid.

</div><details style={{"textAlign":"left","marginBottom":"1rem"}} className={"openapi-markdown__details"} data-collaposed={true} open={false}><summary style={{}}><strong>Response Headers</strong></summary><ul style={{"marginLeft":"1rem"}}></ul></details><div><MimeTabs className={"openapi-tabs__mime"} schemaType={"response"}><TabItem label={"application/json"} value={"application/json"}><SchemaTabs className={"openapi-tabs__schema"}><TabItem label={"Schema"} value={"Schema"}><details style={{}} className={"openapi-markdown__details response"} data-collapsed={false} open={true}><summary style={{}} className={"openapi-markdown__details-summary-response"}><strong>Schema</strong></summary><div style={{"textAlign":"left","marginLeft":"1rem"}}></div><ul style={{"marginLeft":"1rem"}}><SchemaItem collapsible={false} name={"errorCode"} required={true} schemaName={"integer"} qualifierMessage={undefined} schema={{"type":"integer","example":400}}></SchemaItem><SchemaItem collapsible={false} name={"errorDescription"} required={true} schemaName={"string"} qualifierMessage={undefined} schema={{"type":"string","example":"Bad input parameter"}}></SchemaItem><SchemaItem collapsible={false} name={"errorKey"} required={false} schemaName={"string"} qualifierMessage={undefined} schema={{"type":"string","description":"A text code of the refusal that does not change when the text changes. Only some refusals have it, for example `organisation_suspended`, `feature_disabled` or `purpose_exists`."}}></SchemaItem></ul></details></TabItem><TabItem label={"Example (from schema)"} value={"Example (from schema)"}><ResponseSamples responseExample={"{\n  \"errorCode\": 400,\n  \"errorDescription\": \"Bad input parameter\",\n  \"errorKey\": \"string\"\n}"} language={"json"}></ResponseSamples></TabItem></SchemaTabs></TabItem></MimeTabs></div></TabItem><TabItem label={"403"} value={"403"}><div>

The API key or token does not allow this call. An API key without the scope of the operation gets the older body `{"Code", "Message"}`. An `X-SandboxOrgId` header that names another sandbox organisation than the one of the API key gets `{"errorCode", "errorDescription"}`. When the feature `account` of the organisation is off (see [Read organisation features](/docs/openid4vc-api/onboard-read-organisation-features)), the body has the `errorKey` `feature_disabled` and the member `feature`.

</div><details style={{"textAlign":"left","marginBottom":"1rem"}} className={"openapi-markdown__details"} data-collaposed={true} open={false}><summary style={{}}><strong>Response Headers</strong></summary><ul style={{"marginLeft":"1rem"}}></ul></details><div><MimeTabs className={"openapi-tabs__mime"} schemaType={"response"}><TabItem label={"application/json"} value={"application/json"}><SchemaTabs className={"openapi-tabs__schema"}><TabItem label={"Schema"} value={"Schema"}><details style={{}} className={"openapi-markdown__details response"} data-collapsed={false} open={true}><summary style={{}} className={"openapi-markdown__details-summary-response"}><strong>Schema</strong></summary><div style={{"textAlign":"left","marginLeft":"1rem"}}></div><ul style={{"marginLeft":"1rem"}}><div><span className={"badge badge--info"}>anyOf</span><SchemaTabs><TabItem label={"MOD1"} value={"0-item-properties"}><SchemaItem collapsible={false} name={"errorCode"} required={true} schemaName={"integer"} qualifierMessage={undefined} schema={{"type":"integer","example":400}}></SchemaItem><SchemaItem collapsible={false} name={"errorDescription"} required={true} schemaName={"string"} qualifierMessage={undefined} schema={{"type":"string","example":"Bad input parameter"}}></SchemaItem><SchemaItem collapsible={false} name={"errorKey"} required={false} schemaName={"string"} qualifierMessage={undefined} schema={{"type":"string","description":"A text code of the refusal that does not change when the text changes. Only some refusals have it, for example `organisation_suspended`, `feature_disabled` or `purpose_exists`."}}></SchemaItem></TabItem><TabItem label={"Older error body"} value={"1-item-properties"}><SchemaItem collapsible={false} name={"Code"} required={true} schemaName={"integer"} qualifierMessage={undefined} schema={{"type":"integer","description":"The HTTP status.","example":403}}></SchemaItem><SchemaItem collapsible={false} name={"Message"} required={true} schemaName={"string"} qualifierMessage={undefined} schema={{"type":"string","description":"What went wrong.","example":"Unauthorized access;User doesn't have enough permissions;"}}></SchemaItem></TabItem></SchemaTabs></div></ul></details></TabItem><TabItem label={"Example (from schema)"} value={"Example (from schema)"}><ResponseSamples responseExample={"{}"} language={"json"}></ResponseSamples></TabItem><TabItem label={"missingScope"} value={"missingScope"}><Markdown> The API key does not have the scope</Markdown><ResponseSamples responseExample={"{\n  \"Code\": 403,\n  \"Message\": \"Unauthorized access;User doesn't have enough permissions;\"\n}"} language={"json"}></ResponseSamples></TabItem><TabItem label={"featureDisabled"} value={"featureDisabled"}><Markdown> The feature account is off</Markdown><ResponseSamples responseExample={"{\n  \"errorCode\": 403,\n  \"errorDescription\": \"The feature account is not enabled for this organisation\",\n  \"errorKey\": \"feature_disabled\",\n  \"feature\": \"account\"\n}"} language={"json"}></ResponseSamples></TabItem></SchemaTabs></TabItem></MimeTabs></div></TabItem><TabItem label={"500"} value={"500"}><div>

Unexpected server error, for example the installation has no base URL for the link (`Failed to create magic link`).

</div><details style={{"textAlign":"left","marginBottom":"1rem"}} className={"openapi-markdown__details"} data-collaposed={true} open={false}><summary style={{}}><strong>Response Headers</strong></summary><ul style={{"marginLeft":"1rem"}}></ul></details><div><MimeTabs className={"openapi-tabs__mime"} schemaType={"response"}><TabItem label={"application/json"} value={"application/json"}><SchemaTabs className={"openapi-tabs__schema"}><TabItem label={"Schema"} value={"Schema"}><details style={{}} className={"openapi-markdown__details response"} data-collapsed={false} open={true}><summary style={{}} className={"openapi-markdown__details-summary-response"}><strong>Schema</strong></summary><div style={{"textAlign":"left","marginLeft":"1rem"}}></div><ul style={{"marginLeft":"1rem"}}><SchemaItem collapsible={false} name={"errorCode"} required={true} schemaName={"integer"} qualifierMessage={undefined} schema={{"type":"integer","example":400}}></SchemaItem><SchemaItem collapsible={false} name={"errorDescription"} required={true} schemaName={"string"} qualifierMessage={undefined} schema={{"type":"string","example":"Bad input parameter"}}></SchemaItem><SchemaItem collapsible={false} name={"errorKey"} required={false} schemaName={"string"} qualifierMessage={undefined} schema={{"type":"string","description":"A text code of the refusal that does not change when the text changes. Only some refusals have it, for example `organisation_suspended`, `feature_disabled` or `purpose_exists`."}}></SchemaItem></ul></details></TabItem><TabItem label={"Example (from schema)"} value={"Example (from schema)"}><ResponseSamples responseExample={"{\n  \"errorCode\": 400,\n  \"errorDescription\": \"Bad input parameter\",\n  \"errorKey\": \"string\"\n}"} language={"json"}></ResponseSamples></TabItem></SchemaTabs></TabItem></MimeTabs></div></TabItem></ApiTabs></div></div>
      