From b7efde8d0847e9c1d1bd3f2e71a0dd8ccc9614e8 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 5 Nov 2026 16:16:39 +0000 Subject: [PATCH 1/2] chore(spec): sync API spec 2026-11-05 --- openapi/SOURCE.json | 6 +- openapi/account.json | 126 +++++++++++++++--- src/didit/resources/account/applications.py | 21 ++- src/didit/types/__init__.py | 5 + .../account/applications/create_params.py | 7 +- .../account/applications/update_params.py | 7 +- src/didit/types/components/application.py | 6 +- .../application_credentials_summary.py | 4 + .../components/application_data_location.py | 12 ++ tests/generated/test_account.py | 8 ++ 10 files changed, 175 insertions(+), 27 deletions(-) create mode 100644 src/didit/types/components/application_data_location.py diff --git a/openapi/SOURCE.json b/openapi/SOURCE.json index e64a3e2..88df192 100644 --- a/openapi/SOURCE.json +++ b/openapi/SOURCE.json @@ -2,12 +2,12 @@ "verification.json": { "url": "https://docs.didit.me/openapi-25.json", "sha256": "9f8cdf8be8157588facc8059c9bd306f3f516a3a5b66b78c8e63cf595ddb6627", - "fetched_at": "2026-11-05T12:12:43Z" + "fetched_at": "2026-11-05T16:15:58Z" }, "account.json": { "url": "https://docs.didit.me/openapi-auth.json", - "sha256": "5b45b1896ef3107dd9a601c76d9ba35761bae5f04ac731b6c27876603903bf05", - "fetched_at": "2026-11-05T12:12:43Z" + "sha256": "ef403603543b119fed4300d08e15b8ec0a13de9fabdfdc02866f61f817d2a1f0", + "fetched_at": "2026-11-05T16:15:58Z" }, "webhook-vectors.json": { "generator": "product-automations scripts/server-sdks/make_vectors.py (seeded 2026-10-17)", diff --git a/openapi/account.json b/openapi/account.json index 22b6117..66322c7 100644 --- a/openapi/account.json +++ b/openapi/account.json @@ -300,7 +300,8 @@ "uuid": "b2c3d4e5-6789-01bc-defg-222222222222", "name": "developer", "client_id": "S9LIYGSoWNuGMLHsvEt9dQ", - "api_key": "sk_live_example_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + "api_key": "sk_live_example_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", + "data_location": "eu" } } } @@ -821,7 +822,7 @@ "/organizations/me/{org_id}/applications/": { "post": { "summary": "Create Application", - "description": "Create an application inside an organization. The response includes `api_key`; persist it now (recoverable via GET). Requires owner/admin JWT.", + "description": "Create an application inside an organization, in the data location you choose (`data_location`, the European Union by default; it can't be changed afterwards). The response includes `api_key`; persist it now (recoverable via GET). Requires owner/admin JWT.", "operationId": "create_organization_application", "x-didit-sdk": { "resource": "account.applications", @@ -868,7 +869,8 @@ "https://acme.example/callback" ], "terms_url": "https://acme.example/terms", - "privacy_url": "https://acme.example/privacy" + "privacy_url": "https://acme.example/privacy", + "data_location": "eu" } }, "Minimal": { @@ -908,6 +910,7 @@ "privacy_url": "https://acme.example/privacy", "description": null, "created_at": "2025-06-01T10:00:00Z", + "data_location": "eu", "products": [ { "product": "identity", @@ -939,7 +942,7 @@ } }, "400": { - "description": "Validation error in the request body (for example a malformed redirect URI).", + "description": "Validation error in the request body: for example a malformed redirect URI, a `data_location` that is not available yet (`au`, `mx`) or one that does not exist. Nothing is created.", "content": { "application/json": { "schema": { @@ -952,6 +955,22 @@ "Enter a valid URL." ] } + }, + "DataLocationNotAvailable": { + "summary": "A data location that is coming soon", + "value": { + "data_location": [ + "This data location is not available yet." + ] + } + }, + "UnknownDataLocation": { + "summary": "A data location that does not exist", + "value": { + "data_location": [ + "\"us\" is not a valid choice." + ] + } } } } @@ -1047,42 +1066,42 @@ { "lang": "curl", "label": "cURL", - "source": "curl -X POST \"https://apx.didit.me/auth/v2/organizations/me/$ORG_ID/applications/\" \\\n -H \"Authorization: Bearer $ACCESS_TOKEN\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\n \"name\": \"Acme Customer App\",\n \"website_url\": \"https://acme.example\",\n \"redirect_uris\": [\"https://acme.example/callback\"]\n }'" + "source": "curl -X POST \"https://apx.didit.me/auth/v2/organizations/me/$ORG_ID/applications/\" \\\n -H \"Authorization: Bearer $ACCESS_TOKEN\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\n \"name\": \"Acme Customer App\",\n \"website_url\": \"https://acme.example\",\n \"redirect_uris\": [\"https://acme.example/callback\"],\n \"data_location\": \"eu\"\n }'" }, { "lang": "python", "label": "Python", - "source": "from didit import Didit\n\n# Use the access token that account.login returns.\nclient = Didit(account_token=\"YOUR_ACCESS_TOKEN\")\n\nresult = client.account.applications.create(\n \"a1b2c3d4-5678-90ab-cdef-111111111111\",\n name=\"Acme Customer App\",\n website_url=\"https://acme.example\",\n redirect_uris=[\"https://acme.example/callback\"],\n terms_url=\"https://acme.example/terms\",\n privacy_url=\"https://acme.example/privacy\",\n)\nprint(result)" + "source": "from didit import Didit\n\n# Use the access token that account.login returns.\nclient = Didit(account_token=\"YOUR_ACCESS_TOKEN\")\n\nresult = client.account.applications.create(\n \"a1b2c3d4-5678-90ab-cdef-111111111111\",\n name=\"Acme Customer App\",\n website_url=\"https://acme.example\",\n redirect_uris=[\"https://acme.example/callback\"],\n terms_url=\"https://acme.example/terms\",\n privacy_url=\"https://acme.example/privacy\",\n data_location=\"eu\",\n)\nprint(result)" }, { "lang": "javascript", "label": "Node.js", - "source": "import Didit from \"@didit-protocol/sdk-node\";\n\n// Use the access token that account.login returns.\nconst didit = new Didit({ accountToken: \"YOUR_ACCESS_TOKEN\" });\n\nconst result = await didit.account.applications.create(\"a1b2c3d4-5678-90ab-cdef-111111111111\", {\n name: \"Acme Customer App\",\n website_url: \"https://acme.example\",\n redirect_uris: [\"https://acme.example/callback\"],\n terms_url: \"https://acme.example/terms\",\n privacy_url: \"https://acme.example/privacy\",\n});\nconsole.log(result);" + "source": "import Didit from \"@didit-protocol/sdk-node\";\n\n// Use the access token that account.login returns.\nconst didit = new Didit({ accountToken: \"YOUR_ACCESS_TOKEN\" });\n\nconst result = await didit.account.applications.create(\"a1b2c3d4-5678-90ab-cdef-111111111111\", {\n name: \"Acme Customer App\",\n website_url: \"https://acme.example\",\n redirect_uris: [\"https://acme.example/callback\"],\n terms_url: \"https://acme.example/terms\",\n privacy_url: \"https://acme.example/privacy\",\n data_location: \"eu\",\n});\nconsole.log(result);" }, { "lang": "go", "label": "Go", - "source": "ctx := context.Background()\n// Use the access token that account.login returns.\nclient := didit.NewClient(option.WithAccountToken(\"YOUR_ACCESS_TOKEN\"))\n\nresult, err := client.Account.Applications.Create(ctx, \"a1b2c3d4-5678-90ab-cdef-111111111111\", didit.ApplicationCreateRequest{\n\tName: didit.String(\"Acme Customer App\"),\n\tWebsiteURL: didit.String(\"https://acme.example\"),\n\tRedirectURIs: didit.Some([]string{\"https://acme.example/callback\"}),\n\tTermsURL: didit.String(\"https://acme.example/terms\"),\n\tPrivacyURL: didit.String(\"https://acme.example/privacy\"),\n})\nif err != nil {\n\tlog.Fatal(err)\n}\nfmt.Printf(\"%+v\\n\", result)" + "source": "ctx := context.Background()\n// Use the access token that account.login returns.\nclient := didit.NewClient(option.WithAccountToken(\"YOUR_ACCESS_TOKEN\"))\n\nresult, err := client.Account.Applications.Create(ctx, \"a1b2c3d4-5678-90ab-cdef-111111111111\", didit.ApplicationCreateRequest{\n\tName: didit.String(\"Acme Customer App\"),\n\tWebsiteURL: didit.String(\"https://acme.example\"),\n\tRedirectURIs: didit.Some([]string{\"https://acme.example/callback\"}),\n\tTermsURL: didit.String(\"https://acme.example/terms\"),\n\tPrivacyURL: didit.String(\"https://acme.example/privacy\"),\n\tDataLocation: didit.Some(didit.ApplicationDataLocation(\"eu\")),\n})\nif err != nil {\n\tlog.Fatal(err)\n}\nfmt.Printf(\"%+v\\n\", result)" }, { "lang": "java", "label": "Java", - "source": "import java.util.List;\nimport me.didit.Didit;\nimport me.didit.types.ApplicationCreateRequest;\n\n// Use the access token that account.login returns.\nDidit client = Didit.builder().accountToken(\"YOUR_ACCESS_TOKEN\").build();\n\nvar result = client.account().applications().create(\"a1b2c3d4-5678-90ab-cdef-111111111111\", ApplicationCreateRequest.builder()\n .name(\"Acme Customer App\")\n .websiteUrl(\"https://acme.example\")\n .redirectUris(List.of(\"https://acme.example/callback\"))\n .termsUrl(\"https://acme.example/terms\")\n .privacyUrl(\"https://acme.example/privacy\")\n .build());\nSystem.out.println(result);" + "source": "import java.util.List;\nimport me.didit.Didit;\nimport me.didit.types.ApplicationCreateRequest;\nimport me.didit.types.ApplicationDataLocation;\n\n// Use the access token that account.login returns.\nDidit client = Didit.builder().accountToken(\"YOUR_ACCESS_TOKEN\").build();\n\nvar result = client.account().applications().create(\"a1b2c3d4-5678-90ab-cdef-111111111111\", ApplicationCreateRequest.builder()\n .name(\"Acme Customer App\")\n .websiteUrl(\"https://acme.example\")\n .redirectUris(List.of(\"https://acme.example/callback\"))\n .termsUrl(\"https://acme.example/terms\")\n .privacyUrl(\"https://acme.example/privacy\")\n .dataLocation(ApplicationDataLocation.of(\"eu\"))\n .build());\nSystem.out.println(result);" }, { "lang": "php", "label": "PHP", - "source": "account->applications->create('a1b2c3d4-5678-90ab-cdef-111111111111', [\n 'name' => 'Acme Customer App',\n 'website_url' => 'https://acme.example',\n 'redirect_uris' => ['https://acme.example/callback'],\n 'terms_url' => 'https://acme.example/terms',\n 'privacy_url' => 'https://acme.example/privacy',\n]);\nprint_r($result->toArray());" + "source": "account->applications->create('a1b2c3d4-5678-90ab-cdef-111111111111', [\n 'name' => 'Acme Customer App',\n 'website_url' => 'https://acme.example',\n 'redirect_uris' => ['https://acme.example/callback'],\n 'terms_url' => 'https://acme.example/terms',\n 'privacy_url' => 'https://acme.example/privacy',\n 'data_location' => 'eu',\n]);\nprint_r($result->toArray());" }, { "lang": "ruby", "label": "Ruby", - "source": "require \"didit\"\n\n# Use the access token that account.login returns.\ndidit = Didit::Client.new(account_token: \"YOUR_ACCESS_TOKEN\")\n\nresult = didit.account.applications.create(\n \"a1b2c3d4-5678-90ab-cdef-111111111111\",\n name: \"Acme Customer App\",\n website_url: \"https://acme.example\",\n redirect_uris: [\"https://acme.example/callback\"],\n terms_url: \"https://acme.example/terms\",\n privacy_url: \"https://acme.example/privacy\"\n)\nputs result.to_h" + "source": "require \"didit\"\n\n# Use the access token that account.login returns.\ndidit = Didit::Client.new(account_token: \"YOUR_ACCESS_TOKEN\")\n\nresult = didit.account.applications.create(\n \"a1b2c3d4-5678-90ab-cdef-111111111111\",\n name: \"Acme Customer App\",\n website_url: \"https://acme.example\",\n redirect_uris: [\"https://acme.example/callback\"],\n terms_url: \"https://acme.example/terms\",\n privacy_url: \"https://acme.example/privacy\",\n data_location: \"eu\"\n)\nputs result.to_h" }, { "lang": "csharp", "label": ".NET", - "source": "using System;\nusing System.Text.Json;\nusing Didit;\n\n// Use the access token that account.login returns.\nusing var client = new DiditClient(new DiditClientOptions { AccountToken = \"YOUR_ACCESS_TOKEN\" });\n\nvar result = await client.Account.Applications.CreateAsync(\"a1b2c3d4-5678-90ab-cdef-111111111111\", new ApplicationCreateRequest\n{\n Name = \"Acme Customer App\",\n WebsiteUrl = \"https://acme.example\",\n RedirectUris = new string[] { \"https://acme.example/callback\" },\n TermsUrl = \"https://acme.example/terms\",\n PrivacyUrl = \"https://acme.example/privacy\",\n});\nConsole.WriteLine(JsonSerializer.Serialize(result));" + "source": "using System;\nusing System.Text.Json;\nusing Didit;\n\n// Use the access token that account.login returns.\nusing var client = new DiditClient(new DiditClientOptions { AccountToken = \"YOUR_ACCESS_TOKEN\" });\n\nvar result = await client.Account.Applications.CreateAsync(\"a1b2c3d4-5678-90ab-cdef-111111111111\", new ApplicationCreateRequest\n{\n Name = \"Acme Customer App\",\n WebsiteUrl = \"https://acme.example\",\n RedirectUris = new string[] { \"https://acme.example/callback\" },\n TermsUrl = \"https://acme.example/terms\",\n PrivacyUrl = \"https://acme.example/privacy\",\n DataLocation = new ApplicationDataLocation(\"eu\"),\n});\nConsole.WriteLine(JsonSerializer.Serialize(result));" } ] }, @@ -1221,6 +1240,7 @@ "privacy_url": "https://example.com/privacy", "description": "Production application", "created_at": "2025-06-01T10:00:00Z", + "data_location": "eu", "products": [ { "product": "identity", @@ -1434,6 +1454,7 @@ "privacy_url": "https://example.com/privacy", "description": "Production application", "created_at": "2025-06-01T10:00:00Z", + "data_location": "eu", "products": [ { "product": "identity", @@ -1586,7 +1607,7 @@ }, "patch": { "summary": "Update Application", - "description": "Update application metadata (name, URLs, redirect URIs). `api_key` and `client_id` are never rotated. `products` is read-only: a `products` key in the body is ignored. Requires owner/admin JWT.", + "description": "Update application metadata (name, URLs, redirect URIs). `api_key` and `client_id` are never rotated. `products` is read-only: a `products` key in the body is ignored. `data_location` can't be changed after the application is created, except once on the live application created with your organization, while it is unused (see the request body). Requires owner/admin JWT.", "operationId": "update_organization_application", "x-didit-sdk": { "resource": "account.applications", @@ -1685,6 +1706,7 @@ "privacy_url": "https://acme.example/privacy", "description": null, "created_at": "2025-06-01T10:00:00Z", + "data_location": "eu", "products": [ { "product": "identity", @@ -1716,7 +1738,7 @@ } }, "400": { - "description": "Validation error in the request body.", + "description": "Validation error in the request body: for example a malformed URL, a `data_location` that is not available yet, or a `data_location` other than the application's own. Nothing is changed.", "content": { "application/json": { "schema": { @@ -1729,6 +1751,22 @@ "Enter a valid URL." ] } + }, + "DataLocationFixed": { + "summary": "Another data location than the application's own", + "value": { + "data_location": [ + "An application's data location can't be changed after it is created." + ] + } + }, + "DataLocationNotAvailable": { + "summary": "A data location that is coming soon", + "value": { + "data_location": [ + "This data location is not available yet." + ] + } } } } @@ -1809,6 +1847,24 @@ } } } + }, + "503": { + "description": "Only when the update chooses another data location for the live application created with your organization: Didit could not confirm that the application has no verification session yet, so nothing was changed. Retry the request.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceUnavailableError" + }, + "examples": { + "DataLocationCheckUnavailable": { + "value": { + "detail": "We couldn't confirm that this application is unused. Try again in a moment.", + "code": "data_location_check_unavailable" + } + } + } + } + } } }, "x-codeSamples": [ @@ -2209,12 +2265,15 @@ "type": "string", "description": "Use this as `x-api-key` on every verification API call. New keys start with `sk_live_` (live application) or `sk_test_` (sandbox application), followed by 43 URL-safe characters (letters, digits, `-` and `_`). Keys created before this format have no prefix and keep working unchanged.", "example": "sk_live_example_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + "data_location": { + "$ref": "#/components/schemas/ApplicationDataLocation" } } }, "Application": { "type": "object", - "description": "Full application record. `uuid`, `client_id`, and `api_key` never change after creation.", + "description": "Full application record. `uuid`, `client_id`, and `api_key` never change after creation. `data_location` doesn't either, except once on the live application created with your organization, before it is used (see the update request).", "properties": { "uuid": { "type": "string", @@ -2275,6 +2334,9 @@ "format": "date-time", "example": "2025-06-01T10:00:00Z" }, + "data_location": { + "$ref": "#/components/schemas/ApplicationDataLocation" + }, "products": { "type": "array", "readOnly": true, @@ -2311,7 +2373,7 @@ }, "ApplicationCreateRequest": { "type": "object", - "description": "All fields are optional. Sending an empty body creates an application with a default name.", + "description": "All fields are optional. Sending an empty body creates an application with a default name, in the European Union.", "properties": { "name": { "type": "string", @@ -2346,12 +2408,15 @@ "description": { "type": "string", "description": "Internal description for the application (not shown to end users)." + }, + "data_location": { + "$ref": "#/components/schemas/ApplicationDataLocation" } } }, "ApplicationUpdateRequest": { "type": "object", - "description": "PATCH body for application metadata. Send only the fields you want to change; omitted fields are preserved. `uuid`, `client_id`, and `api_key` cannot be updated. `products` is read-only: a `products` key in the body is ignored.", + "description": "PATCH body for application metadata. Send only the fields you want to change; omitted fields are preserved. `uuid`, `client_id`, and `api_key` cannot be updated. `products` is read-only: a `products` key in the body is ignored. `data_location` can't be changed after the application is created: naming the location it already has is accepted, and any other location answers 400. The one exception is the live application created with your organization: the first update that names a `data_location` chooses it, once, while no API key of the application has been used and it has no verification session.", "properties": { "name": { "type": "string", @@ -2384,9 +2449,22 @@ "description": { "type": "string", "description": "Internal description for the application." + }, + "data_location": { + "$ref": "#/components/schemas/ApplicationDataLocation" } } }, + "ApplicationDataLocation": { + "type": "string", + "enum": [ + "eu", + "au", + "mx" + ], + "description": "Where the application's verification data is stored and processed, chosen when the application is created. `eu` is the European Union (Ireland), the default. `au` (Australia, Sydney) and `mx` (Mexico) are coming soon: a request that names them answers 400 `This data location is not available yet.` An organization's Sandbox application is always in the European Union.", + "example": "eu" + }, "ValidationError": { "description": "Validation error body. The intended envelope is a `{field: [\"message\", ...]}` map for field-level errors or a `{detail: \"...\"}` single-key envelope for business-rule errors. A handful of validators (password strength on register, code validity on verify-email) currently respond with a bare array `[\"message\"]` -- known server-side inconsistency. The schema below keeps that bare-array branch so client code generated from this spec deserializes today's responses, but new client code should treat it as the relevant field-keyed form (`{password: [...]}` or `{code: [...]}`) and the server contract will converge on that shape.", "oneOf": [ @@ -2653,6 +2731,20 @@ "example": "recovery_setup_required" } } + }, + "ServiceUnavailableError": { + "type": "object", + "description": "The request could not be completed right now and nothing was changed. Retry it in a moment.", + "properties": { + "detail": { + "type": "string", + "example": "We couldn't confirm that this application is unused. Try again in a moment." + }, + "code": { + "type": "string", + "example": "data_location_check_unavailable" + } + } } } } diff --git a/src/didit/resources/account/applications.py b/src/didit/resources/account/applications.py index 47f5394..06a5adb 100644 --- a/src/didit/resources/account/applications.py +++ b/src/didit/resources/account/applications.py @@ -18,6 +18,7 @@ ) from didit._types import NOT_GIVEN, Body, Headers, NotGiven, Query from didit.types.components.application import Application +from didit.types.components.application_data_location import ApplicationDataLocation from didit.types.components.paginated_application_list import PaginatedApplicationList __all__ = [ @@ -100,6 +101,7 @@ def create( terms_url: str | NotGiven = NOT_GIVEN, privacy_url: str | NotGiven = NOT_GIVEN, description: str | NotGiven = NOT_GIVEN, + data_location: ApplicationDataLocation | NotGiven = NOT_GIVEN, extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, @@ -107,7 +109,7 @@ def create( ) -> Application: """Create Application. - Create an application inside an organization. The response includes `api_key`; persist it now (recoverable via GET). Requires owner/admin JWT. + Create an application inside an organization, in the data location you choose (`data_location`, the European Union by default; it can't be changed afterwards). The response includes `api_key`; persist it now (recoverable via GET). Requires owner/admin JWT. ``POST /organizations/me/{org_id}/applications/`` @@ -119,6 +121,7 @@ def create( terms_url: Terms of service URL shown in the verification flow. privacy_url: Privacy policy URL shown in the verification flow. description: Internal description for the application (not shown to end users). + data_location: Where the application's verification data is stored and processed, chosen when the application is created. `eu` is the European Union (Ireland), the default. `au` (Australia, Sydney) and `mx` (Mexico) are coming soon: a request that names them answers 400 `This data location is not available yet.` An organization's Sandbox application is always in the European Union. extra_headers: Headers to add to (or, with ``None``, remove from) this request. extra_query: Query parameters to add to this request. extra_body: Top-level JSON fields to add to this request's body. @@ -140,6 +143,7 @@ def create( "terms_url": terms_url, "privacy_url": privacy_url, "description": description, + "data_location": data_location, }, extra_headers=extra_headers, extra_query=extra_query, @@ -199,6 +203,7 @@ def update( terms_url: str | NotGiven = NOT_GIVEN, privacy_url: str | NotGiven = NOT_GIVEN, description: str | NotGiven = NOT_GIVEN, + data_location: ApplicationDataLocation | NotGiven = NOT_GIVEN, extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, @@ -206,7 +211,7 @@ def update( ) -> Application: """Update Application. - Update application metadata (name, URLs, redirect URIs). `api_key` and `client_id` are never rotated. `products` is read-only: a `products` key in the body is ignored. Requires owner/admin JWT. + Update application metadata (name, URLs, redirect URIs). `api_key` and `client_id` are never rotated. `products` is read-only: a `products` key in the body is ignored. `data_location` can't be changed after the application is created, except once on the live application created with your organization, while it is unused (see the request body). Requires owner/admin JWT. ``PATCH /organizations/me/{org_id}/applications/{app_id}/`` @@ -219,6 +224,7 @@ def update( terms_url: Terms of service URL shown in the verification flow. privacy_url: Privacy policy URL shown in the verification flow. description: Internal description for the application. + data_location: Where the application's verification data is stored and processed, chosen when the application is created. `eu` is the European Union (Ireland), the default. `au` (Australia, Sydney) and `mx` (Mexico) are coming soon: a request that names them answers 400 `This data location is not available yet.` An organization's Sandbox application is always in the European Union. extra_headers: Headers to add to (or, with ``None``, remove from) this request. extra_query: Query parameters to add to this request. extra_body: Top-level JSON fields to add to this request's body. @@ -240,6 +246,7 @@ def update( "terms_url": terms_url, "privacy_url": privacy_url, "description": description, + "data_location": data_location, }, extra_headers=extra_headers, extra_query=extra_query, @@ -319,6 +326,7 @@ async def create( terms_url: str | NotGiven = NOT_GIVEN, privacy_url: str | NotGiven = NOT_GIVEN, description: str | NotGiven = NOT_GIVEN, + data_location: ApplicationDataLocation | NotGiven = NOT_GIVEN, extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, @@ -326,7 +334,7 @@ async def create( ) -> Application: """Create Application. - Create an application inside an organization. The response includes `api_key`; persist it now (recoverable via GET). Requires owner/admin JWT. + Create an application inside an organization, in the data location you choose (`data_location`, the European Union by default; it can't be changed afterwards). The response includes `api_key`; persist it now (recoverable via GET). Requires owner/admin JWT. ``POST /organizations/me/{org_id}/applications/`` @@ -338,6 +346,7 @@ async def create( terms_url: Terms of service URL shown in the verification flow. privacy_url: Privacy policy URL shown in the verification flow. description: Internal description for the application (not shown to end users). + data_location: Where the application's verification data is stored and processed, chosen when the application is created. `eu` is the European Union (Ireland), the default. `au` (Australia, Sydney) and `mx` (Mexico) are coming soon: a request that names them answers 400 `This data location is not available yet.` An organization's Sandbox application is always in the European Union. extra_headers: Headers to add to (or, with ``None``, remove from) this request. extra_query: Query parameters to add to this request. extra_body: Top-level JSON fields to add to this request's body. @@ -359,6 +368,7 @@ async def create( "terms_url": terms_url, "privacy_url": privacy_url, "description": description, + "data_location": data_location, }, extra_headers=extra_headers, extra_query=extra_query, @@ -418,6 +428,7 @@ async def update( terms_url: str | NotGiven = NOT_GIVEN, privacy_url: str | NotGiven = NOT_GIVEN, description: str | NotGiven = NOT_GIVEN, + data_location: ApplicationDataLocation | NotGiven = NOT_GIVEN, extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, @@ -425,7 +436,7 @@ async def update( ) -> Application: """Update Application. - Update application metadata (name, URLs, redirect URIs). `api_key` and `client_id` are never rotated. `products` is read-only: a `products` key in the body is ignored. Requires owner/admin JWT. + Update application metadata (name, URLs, redirect URIs). `api_key` and `client_id` are never rotated. `products` is read-only: a `products` key in the body is ignored. `data_location` can't be changed after the application is created, except once on the live application created with your organization, while it is unused (see the request body). Requires owner/admin JWT. ``PATCH /organizations/me/{org_id}/applications/{app_id}/`` @@ -438,6 +449,7 @@ async def update( terms_url: Terms of service URL shown in the verification flow. privacy_url: Privacy policy URL shown in the verification flow. description: Internal description for the application. + data_location: Where the application's verification data is stored and processed, chosen when the application is created. `eu` is the European Union (Ireland), the default. `au` (Australia, Sydney) and `mx` (Mexico) are coming soon: a request that names them answers 400 `This data location is not available yet.` An organization's Sandbox application is always in the European Union. extra_headers: Headers to add to (or, with ``None``, remove from) this request. extra_query: Query parameters to add to this request. extra_body: Top-level JSON fields to add to this request's body. @@ -459,6 +471,7 @@ async def update( "terms_url": terms_url, "privacy_url": privacy_url, "description": description, + "data_location": data_location, }, extra_headers=extra_headers, extra_query=extra_query, diff --git a/src/didit/types/__init__.py b/src/didit/types/__init__.py index fa8a2dc..7f3d730 100644 --- a/src/didit/types/__init__.py +++ b/src/didit/types/__init__.py @@ -509,6 +509,9 @@ from didit.types.components.application_credentials_summary import ( ApplicationCredentialsSummary as ApplicationCredentialsSummary, ) + from didit.types.components.application_data_location import ( + ApplicationDataLocation as ApplicationDataLocation, + ) from didit.types.components.application_product import ApplicationProduct as ApplicationProduct from didit.types.components.bank_account_check_business_holder import ( BankAccountCheckBusinessHolder as BankAccountCheckBusinessHolder, @@ -3484,6 +3487,7 @@ "ApplicationAnalyticsWorkflowFunnelValue": "components.application_analytics_workflow_funnel", "ApplicationAnalyticsWorkflowFunnelValueStepsValue": "components.application_analytics_workflow_funnel", "ApplicationCredentialsSummary": "components.application_credentials_summary", + "ApplicationDataLocation": "components.application_data_location", "ApplicationProduct": "components.application_product", "BankAccountCheckBusinessHolder": "components.bank_account_check_business_holder", "BankAccountCheckHolder": "components.bank_account_check_holder", @@ -4717,6 +4721,7 @@ "ApplicationAnalyticsWorkflowFunnelValue", "ApplicationAnalyticsWorkflowFunnelValueStepsValue", "ApplicationCredentialsSummary", + "ApplicationDataLocation", "ApplicationProduct", "BankAccountCheckBusinessHolder", "BankAccountCheckHolder", diff --git a/src/didit/types/account/applications/create_params.py b/src/didit/types/account/applications/create_params.py index c21f578..82cdfdb 100644 --- a/src/didit/types/account/applications/create_params.py +++ b/src/didit/types/account/applications/create_params.py @@ -5,11 +5,13 @@ from typing_extensions import TypedDict +from didit.types.components.application_data_location import ApplicationDataLocation + __all__ = ["AccountApplicationsCreateParams"] class AccountApplicationsCreateParams(TypedDict, total=False): - """All fields are optional. Sending an empty body creates an application with a default name.""" + """All fields are optional. Sending an empty body creates an application with a default name, in the European Union.""" name: str """Application display name. Defaults to `" App"`.""" @@ -28,3 +30,6 @@ class AccountApplicationsCreateParams(TypedDict, total=False): description: str """Internal description for the application (not shown to end users).""" + + data_location: ApplicationDataLocation + """Where the application's verification data is stored and processed, chosen when the application is created. `eu` is the European Union (Ireland), the default. `au` (Australia, Sydney) and `mx` (Mexico) are coming soon: a request that names them answers 400 `This data location is not available yet.` An organization's Sandbox application is always in the European Union.""" diff --git a/src/didit/types/account/applications/update_params.py b/src/didit/types/account/applications/update_params.py index 5c166a6..d46adb9 100644 --- a/src/didit/types/account/applications/update_params.py +++ b/src/didit/types/account/applications/update_params.py @@ -5,11 +5,13 @@ from typing_extensions import TypedDict +from didit.types.components.application_data_location import ApplicationDataLocation + __all__ = ["AccountApplicationsUpdateParams"] class AccountApplicationsUpdateParams(TypedDict, total=False): - """PATCH body for application metadata. Send only the fields you want to change; omitted fields are preserved. `uuid`, `client_id`, and `api_key` cannot be updated. `products` is read-only: a `products` key in the body is ignored.""" + """PATCH body for application metadata. Send only the fields you want to change; omitted fields are preserved. `uuid`, `client_id`, and `api_key` cannot be updated. `products` is read-only: a `products` key in the body is ignored. `data_location` can't be changed after the application is created: naming the location it already has is accepted, and any other location answers 400. The one exception is the live application created with your organization: the first update that names a `data_location` chooses it, once, while no API key of the application has been used and it has no verification session.""" name: str """Application display name.""" @@ -28,3 +30,6 @@ class AccountApplicationsUpdateParams(TypedDict, total=False): description: str """Internal description for the application.""" + + data_location: ApplicationDataLocation + """Where the application's verification data is stored and processed, chosen when the application is created. `eu` is the European Union (Ireland), the default. `au` (Australia, Sydney) and `mx` (Mexico) are coming soon: a request that names them answers 400 `This data location is not available yet.` An organization's Sandbox application is always in the European Union.""" diff --git a/src/didit/types/components/application.py b/src/didit/types/components/application.py index d4ffb5f..bf79a73 100644 --- a/src/didit/types/components/application.py +++ b/src/didit/types/components/application.py @@ -4,13 +4,14 @@ import datetime as _dt from didit._models import BaseModel +from didit.types.components.application_data_location import ApplicationDataLocation from didit.types.components.application_product import ApplicationProduct __all__ = ["Application"] class Application(BaseModel): - """Full application record. `uuid`, `client_id`, and `api_key` never change after creation.""" + """Full application record. `uuid`, `client_id`, and `api_key` never change after creation. `data_location` doesn't either, except once on the live application created with your organization, before it is used (see the update request).""" uuid: str | None = None """Application UUID. Use as `{app_id}` in subsequent calls.""" @@ -41,5 +42,8 @@ class Application(BaseModel): created_at: _dt.datetime | None = None + data_location: ApplicationDataLocation | None = None + """Where the application's verification data is stored and processed, chosen when the application is created. `eu` is the European Union (Ireland), the default. `au` (Australia, Sydney) and `mx` (Mexico) are coming soon: a request that names them answers 400 `This data location is not available yet.` An organization's Sandbox application is always in the European Union.""" + products: list[ApplicationProduct] | None = None """The application's products. Always all three, in this order: `identity`, `transactions`, `authentication`. A new application has `identity` enabled with every module on, and `transactions` and `authentication` disabled. Read-only: a `products` key in a create or update body is ignored.""" diff --git a/src/didit/types/components/application_credentials_summary.py b/src/didit/types/components/application_credentials_summary.py index 2092267..f49ce83 100644 --- a/src/didit/types/components/application_credentials_summary.py +++ b/src/didit/types/components/application_credentials_summary.py @@ -2,6 +2,7 @@ from __future__ import annotations from didit._models import BaseModel +from didit.types.components.application_data_location import ApplicationDataLocation __all__ = ["ApplicationCredentialsSummary"] @@ -17,3 +18,6 @@ class ApplicationCredentialsSummary(BaseModel): api_key: str | None = None """Use this as `x-api-key` on every verification API call. New keys start with `sk_live_` (live application) or `sk_test_` (sandbox application), followed by 43 URL-safe characters (letters, digits, `-` and `_`). Keys created before this format have no prefix and keep working unchanged.""" + + data_location: ApplicationDataLocation | None = None + """Where the application's verification data is stored and processed, chosen when the application is created. `eu` is the European Union (Ireland), the default. `au` (Australia, Sydney) and `mx` (Mexico) are coming soon: a request that names them answers 400 `This data location is not available yet.` An organization's Sandbox application is always in the European Union.""" diff --git a/src/didit/types/components/application_data_location.py b/src/didit/types/components/application_data_location.py new file mode 100644 index 0000000..604278b --- /dev/null +++ b/src/didit/types/components/application_data_location.py @@ -0,0 +1,12 @@ +# Code generated by codegen from openapi/*.json. DO NOT EDIT. +from __future__ import annotations + +from typing import Literal + +from typing_extensions import TypeAlias + +__all__ = ["ApplicationDataLocation"] + + +ApplicationDataLocation: TypeAlias = Literal["eu", "au", "mx"] | str +"""Where the application's verification data is stored and processed, chosen when the application is created. `eu` is the European Union (Ireland), the default. `au` (Australia, Sydney) and `mx` (Mexico) are coming soon: a request that names them answers 400 `This data location is not available yet.` An organization's Sandbox application is always in the European Union.""" diff --git a/tests/generated/test_account.py b/tests/generated/test_account.py index 98acbcc..a35a62f 100644 --- a/tests/generated/test_account.py +++ b/tests/generated/test_account.py @@ -104,6 +104,7 @@ def test_account_verify_email() -> None: "name": "developer", "client_id": "S9LIYGSoWNuGMLHsvEt9dQ", "api_key": "sample-secret", + "data_location": "eu", }, }, ), @@ -128,6 +129,7 @@ def test_account_applications_create() -> None: "redirect_uris": ["https://acme.example/callback"], "terms_url": "https://acme.example/terms", "privacy_url": "https://acme.example/privacy", + "data_location": "eu", }, status=201, response_json={ @@ -141,6 +143,7 @@ def test_account_applications_create() -> None: "privacy_url": "https://acme.example/privacy", "description": None, "created_at": "2025-06-01T10:00:00Z", + "data_location": "eu", "products": [ { "product": "identity", @@ -167,6 +170,7 @@ def test_account_applications_create() -> None: redirect_uris=["https://acme.example/callback"], terms_url="https://acme.example/terms", privacy_url="https://acme.example/privacy", + data_location="eu", ), lambda c: c.account.applications.create( "a1b2c3d4-5678-90ab-cdef-111111111111", @@ -175,6 +179,7 @@ def test_account_applications_create() -> None: redirect_uris=["https://acme.example/callback"], terms_url="https://acme.example/terms", privacy_url="https://acme.example/privacy", + data_location="eu", ), lambda r: isinstance(r, Application), lambda r: isinstance(r, Application), @@ -207,6 +212,7 @@ def test_account_applications_list() -> None: "privacy_url": "https://example.com/privacy", "description": "Production application", "created_at": "2025-06-01T10:00:00Z", + "data_location": "eu", "products": [ { "product": "identity", @@ -259,6 +265,7 @@ def test_account_applications_retrieve() -> None: "privacy_url": "https://example.com/privacy", "description": "Production application", "created_at": "2025-06-01T10:00:00Z", + "data_location": "eu", "products": [ { "product": "identity", @@ -310,6 +317,7 @@ def test_account_applications_update() -> None: "privacy_url": "https://acme.example/privacy", "description": None, "created_at": "2025-06-01T10:00:00Z", + "data_location": "eu", "products": [ { "product": "identity", From f2d99f2c04aff8258c7ca73a139c64b36e762b55 Mon Sep 17 00:00:00 2001 From: Alejandro Rosas <46827020+arosasg@users.noreply.github.com> Date: Thu, 5 Nov 2026 20:25:27 +0400 Subject: [PATCH 2/2] ci: run checks on the spec sync Co-Authored-By: Claude Opus 5.5