---
id: config-create-digital-wallet-open-id-image
title: "Upload image"
description: "Uploads an image and returns its public URL (`imageUrl`). Put the URL in a display image of a credential definition (`display.logo.uri` or `display.backgroundImage.uri`) when you create or update the definition. Anybody can read the image at the URL with [Read image](/docs/openid4vc-api/config-read-digital-wallet-open-id-image), and the image stays: there is no delete. The image must be PNG, JPEG, GIF or WebP, at most 5 MiB and 4096 x 4096 pixels (the default limits). To set the logo or cover image of a stored credential definition in one call, use [Update credential definition logo image](/docs/openid4vc-api/config-update-digital-wallet-open-id-credential-logo-image)."
sidebar_label: "Upload image"
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"}>Upload image</h1>

<MethodEndpoint method={"post"} path={"/v4/config/ows/wallet/images"}></MethodEndpoint>



Uploads an image and returns its public URL (`imageUrl`). Put the URL in a display image of a credential definition (`display.logo.uri` or `display.backgroundImage.uri`) when you create or update the definition. Anybody can read the image at the URL with [Read image](/docs/openid4vc-api/config-read-digital-wallet-open-id-image), and the image stays: there is no delete. The image must be PNG, JPEG, GIF or WebP, at most 5 MiB and 4096 x 4096 pixels (the default limits). To set the logo or cover image of a stored credential definition in one call, use [Update credential definition logo image](/docs/openid4vc-api/config-update-digital-wallet-open-id-credential-logo-image).

## Request

<MimeTabs className={"openapi-tabs__mime"}><TabItem label={"multipart/form-data"} value={"multipart/form-data-schema"}><details style={{}} className={"openapi-markdown__details mime"} data-collapsed={false} open={true}><summary style={{}} className={"openapi-markdown__details-summary-mime"}><h3 className={"openapi-markdown__details-summary-header-body"}>Body</h3><strong className={"openapi-schema__required"}>required</strong></summary><div style={{"textAlign":"left","marginLeft":"1rem"}}><div style={{"marginTop":"1rem","marginBottom":"1rem"}}>

A multipart form with the image file in the field `image`.

</div></div><ul style={{"marginLeft":"1rem"}}><SchemaItem collapsible={false} name={"image"} required={true} schemaName={"binary"} qualifierMessage={undefined} schema={{"format":"binary","type":"string","description":"The image file: PNG, JPEG, GIF or WebP."}}></SchemaItem></ul></details></TabItem></MimeTabs><div><div><ApiTabs label={undefined} id={undefined}><TabItem label={"200"} value={"200"}><div>

The image is stored.

</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={"imageUrl"} required={true} schemaName={"uri"} qualifierMessage={undefined} schema={{"type":"string","format":"uri","description":"The public URL of the image: `<API host>/v4/config/ows/wallet/images/<imageId>`."}}></SchemaItem></ul></details></TabItem><TabItem label={"Example (from schema)"} value={"Example (from schema)"}><ResponseSamples responseExample={"{\n  \"imageUrl\": \"string\"\n}"} language={"json"}></ResponseSamples></TabItem><TabItem label={"Example"} value={"Example"}><ResponseSamples responseExample={"{\n  \"imageUrl\": \"https://demo-api.igrant.io/v4/config/ows/wallet/images/6af0c4254a55cecc6011ecd8\"\n}"} language={"json"}></ResponseSamples></TabItem></SchemaTabs></TabItem></MimeTabs></div></TabItem><TabItem label={"400"} value={"400"}><div>

The file is not a PNG, JPEG, GIF or WebP image (`Image type is not supported: use PNG, JPEG, GIF or WebP`), the image cannot be read (`Image is not readable`), or it is larger than 4096 x 4096 pixels (`Image is too large: the limit is 4096 x 4096 pixels`). Also when the organisation is unknown (`Failed to get organization: <organisationId>`) or has no deployed wallet (`Open id digital wallet is not deployed 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 a platform admin has turned off the feature of the operation for the organisation, the answer has `errorKey` `feature_disabled` and the member `feature` (the name of the 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={"Example"} value={"Example"}><ResponseSamples responseExample={"{\n  \"Code\": 403,\n  \"Message\": \"Unauthorized access;User doesn't have enough permissions;\"\n}"} language={"json"}></ResponseSamples></TabItem></SchemaTabs></TabItem></MimeTabs></div></TabItem><TabItem label={"413"} value={"413"}><div>

The file is larger than the size limit (5 MiB by default): `Image is too large: the limit is 5 MiB`.

</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={"500"} value={"500"}><div>

The body is not a multipart form or has no file in the field `image` (`Failed to extract image for organization: <organisationId>`), the platform cannot read the file, or the image store cannot store it.

</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>
      