SEP: 0012
Title: KYC API
Author: Interstellar
Status: Active
Created: 2018-09-11
Updated: 2024-07-23
Version 1.14.0
This SEP defines a standard way for stellar clients to upload KYC (or other) information to anchors and other services. SEP-6 and SEP-31 use this protocol, but it can serve as a stand-alone service as well.
This SEP was made with these goals in mind:
- interoperability
- Allow a customer to enter their KYC information to their wallet once and use it across many services without re-entering information manually
- handle the most common 80% of use cases
- handle image and binary data
- support the set of fields defined in SEP-9
- support authentication via SEP-10
- support the provision of data for SEP-6, SEP-24, SEP-31, and others
- give customers control over their data by supporting complete data erasure
To support this protocol an anchor acts as a server and implements the specified REST API endpoints, while a wallet implements a client that consumes the API. The goal is interoperability, so a wallet implements a single client according to the protocol, and will be able to interact with any compliant anchor. Similarly, an anchor that implements the API endpoints according to the protocol will work with any compliant wallet.
- An anchor must define the location of their
KYC_SERVER
orTRANSFER_SERVER
in theirstellar.toml
. This is how a client app knows where to find the anchor's server. A client app will send KYC requests to theKYC_SERVER
if it is specified, otherwise to theTRANSFER_SERVER
. - Anchors and clients must support SEP-10 web authentication and use it for all SEP-12 endpoints.
GET /customer
: Check the status of a customers infoPUT /customer
: Idempotent upload of customer infoPUT /customer/callback
: Set a callback for a wallet to receive status updates from the anchorPUT /customer/verification
: (Deprecated) Idempotent upload of data for verifying customer infoDELETE /customer/[account]
: Deletion of customer infoPOST /customer/files
GET /customer/files
Clients should submit the JWT previously obtained from the anchor via the SEP-10 authentication flow. The JWT should be included in all requests as request header:
Authorization: Bearer <JWT>
Client applications can use a single Stellar account to hold multiple users' funds. To distinguish users that use the
same Stellar account, the decoded SEP-10 JWT's sub
value may contain a memo value after the Stellar account
(G...:2810101841641761712
) OR the sub
value will be a Muxed Account (M...
). The anchor
should use this sub
attribute in their data model to identify unique users.
This document will refer to these accounts as shared accounts. See the SEP-10 Memos and Muxed Accounts sections for more information.
SEP-12 implementations should expect the memo in the SEP-10 JWT's sub
field to match the memo request parameter and
should return an error response if they do not. If the JWT's sub
field does not contain a muxed account or memo then
the memo request parameters may contain any value. This behavior allows shared account owners, such as
SEP-31 sending anchors, to submit user information about their users using the memos assigned to
their users.
Note that Stellar accounts are either shared or they are not. This means anchors should ensure that a Stellar account previously authenticated with a memo should not be authenticated later without a memo. Conversely, an account that was previously authenticated without a memo should not be later authenticated as a shared account.
All endpoints accept in requests the following Content-Type
s:
multipart/form-data
application/x-www-form-urlencoded
application/json
multipart/form-data
should be used for requests including binary data type values from SEP-9. Any of
the above encoding schemes may be used when requests do not include binary data.
All endpoints respond with content type:
application/json
This endpoint allows clients to:
- Fetch the fields the server requires in order to register a new customer via a
PUT /customer
request
If the server does not have a customer registered for the parameters sent in the request, it should return the fields required in the response. The same response should be returned when no parameters are sent.
- Check the status of a customer that may already be registered
This allows clients to check whether the customers information was accepted, rejected, or still needs more info. If the server still needs more info, or the server needs updated information, it should return the fields required.
GET [KYC_SERVER]/customer?transaction_id=<transaction-id>&type=<customer-type>
GET [KYC_SERVER]/customer?account=<stellar-account>&type=<customer-type>
GET [KYC_SERVER]/customer?account=<stellar-account>&memo=<memo>&type=<customer-type>
GET [KYC_SERVER]/customer?account=<muxed-account>&type=<customer-type>
GET [KYC_SERVER]/customer?id=<customer-id>&type=<customer-type>
Name | Type | Description |
---|---|---|
id |
string |
(optional) The ID of the customer as returned in the response of a previous PUT request. If the customer has not been registered, they do not yet have an id . |
account |
G... or M... string |
(deprecated, optional) The server should infer the account from the sub value in the SEP-10 JWT to identify the customer. The account parameter is only used for backwards compatibility, and if explicitly provided in the request body it should match the sub value of the decoded SEP-10 JWT. |
memo |
string | (optional) the client-generated memo that uniquely identifies the customer. If a memo is present in the decoded SEP-10 JWT's sub value, it must match this parameter value. If a muxed account is used as the JWT's sub value, memos sent in requests must match the 64-bit integer subaccount ID of the muxed account. See the Shared Accounts section for more information. |
memo_type |
string | (deprecated, optional) type of memo . One of text , id or hash . Deprecated because memos should always be of type id , although anchors should continue to support this parameter for outdated clients. If hash , memo should be base64-encoded. If a memo is present in the decoded SEP-10 JWT's sub value, this parameter can be ignored. See the Shared Accounts section for more information. |
type |
string | (optional) the type of action the customer is being KYCd for. See the Type Specification below. |
transaction_id |
string |
(optional) The transaction id with which the customer's info is associated. When information from the customer depends on the transaction (e.g., more information is required for larger amounts) |
lang |
string | (optional) Defaults to en . Language code specified using ISO 639-1. Human readable descriptions, choices, and messages should be in this language. |
The client can always use the account
and optional memo
parameters to uniquely identify a customer, and when not
explicitly passed in the request body the server can still infer this information from the decoded SEP-10 JWT's sub
value. If a PUT /customer
request has already been made for the customer, the client should preferrably use the id
returned in the response instead.
Different types of customers may have different KYC requirements depending on the action a given customer wants to take.
The type
parameter is used to specify the action a customer wants to make so the server can identify what information
must be collected. SEP-12 does not define what type
values are accepted and instead leaves that to the other
protocols, such as SEP-6 and SEP-31, that use SEP-12 for the actions associated with those
protocols.
For example, if a customer is being KYC'd as a SEP-31 sender, they may only require full name and email, but a SEP-31 receiver would require banking information in order to receive a direct deposit.
Note that it is possible for the same customer to have different status
values for different type
parameters. For
example, a customer could have an ACCEPTED
status for the small-transaction-amount
type
parameter but have a
NEEDS_INFO
status for the large-transaction-amount
type. Therefore, it is recommended to always pass the type
parameter when making requests to GET /customer
or PUT /customer
, even though the field is optional to accommodate
for implementations that do not require type
.
If the implementor requires the same set of fields for all customers, there is no need for the type
parameter.
If transaction_id
is in use, type
must be provided and set (e.g. sep6
, sep31-sender
, or sep31-receiver
).
Name | Type | Description |
---|---|---|
id |
string | (optional) ID of the customer, if the customer has already been created via a PUT /customer request. |
status |
string | Status of the customers KYC process. |
fields |
object | (optional) An object containing the fields the anchor has not yet received for the given customer of the type provided in the request. Required for customers in the NEEDS_INFO status. See Fields for more detailed information. |
provided_fields |
object | (optional) An object containing the fields the anchor has received for the given customer. See Provided Fields for more detailed information. Required for customers whose information needs verification. |
message |
string | (optional) Human readable message describing the current state of customer's KYC process. |
// The case when a customer has been successfully KYC'd and approved
{
"id": "d1ce2f48-3ff1-495d-9240-7a50d806cfed",
"status": "ACCEPTED",
"provided_fields": {
"first_name": {
"description": "The customer's first name",
"type": "string",
"status": "ACCEPTED"
},
"last_name": {
"description": "The customer's last name",
"type": "string",
"status": "ACCEPTED"
},
"email_address": {
"description": "The customer's email address",
"type": "string",
"status": "ACCEPTED"
}
}
}
// The case when a customer has provided some but not all required information
{
"id": "d1ce2f48-3ff1-495d-9240-7a50d806cfed",
"status": "NEEDS_INFO",
"fields": {
"mobile_number": {
"description": "phone number of the customer",
"type": "string"
},
"email_address": {
"description": "email address of the customer",
"type": "string",
"optional": true
}
},
"provided_fields": {
"first_name": {
"description": "The customer's first name",
"type": "string",
"status": "ACCEPTED"
},
"last_name": {
"description": "The customer's last name",
"type": "string",
"status": "ACCEPTED"
}
}
}
// The case when an anchor requires info about an unknown customer
{
"status": "NEEDS_INFO",
"fields": {
"email_address": {
"description": "Email address of the customer",
"type": "string",
"optional": true
},
"id_type": {
"description": "Government issued ID",
"type": "string",
"choices": [
"Passport",
"Drivers License",
"State ID"
]
},
"photo_id_front": {
"description": "A clear photo of the front of the government issued ID",
"type": "binary"
}
}
}
// The case when the Anchor is processing KYC information
{
"id": "46116754-695e-43f6-84c4-8c05e50a7b12",
"status": "PROCESSING",
"message": "Photo ID requires manual review. This process typically takes 1-2 business days.",
"provided_fields": {
"photo_id_front": {
"description": "A clear photo of the front of the government issued ID",
"type": "binary",
"status": "PROCESSING"
}
}
}
// The case when a customer has been rejected and cannot be KYC'd
{
"id": "d1ce2f48-3ff1-495d-9240-7a50d806cfed",
"status": "REJECTED",
"message": "This person is on a sanctions list"
}
// the case when the anchor requires a verification code to be sent to the server
{
"id": "d1ce2f48-3ff1-495d-9240-7a50d806cfed",
"status": "NEEDS_INFO",
"provided_fields": {
"mobile_number": {
"description": "phone number of the customer",
"type": "string",
"status": "VERIFICATION_REQUIRED"
}
}
}
Status | Description |
---|---|
ACCEPTED | All required KYC fields have been accepted and the customer has been validated for the type passed. It is possible for an accepted customer to move back to another status if the KYC provider determines it needs more info at a later date, or if the customer shows up on a sanctions list. |
PROCESSING | KYC process is in flight and client can check again in the future to see if any further info is needed. |
NEEDS_INFO | More info needs to be provided to finish KYC for this customer. The fields entry is required in this case. |
REJECTED | This customer's KYC has failed and will never succeed. The message must be supplied in this case. |
The fields object defines the pieces of information the anchor has not yet received for the customer. It is required for
the NEEDS_INFO
status but may be included with any status. Fields should be specified as an object with keys
representing the SEP-9 field names required.
Customers in the ACCEPTED
status should not have any required fields present in the object, since all required fields
should have already been provided.
Property | Type | Description |
---|---|---|
type |
enum | The data type of the field value. Can be string , binary , number , or date |
description |
string | A human-readable description of this field, especially important if this is not a SEP-9 field. |
choices |
array | (optional) An array of valid values for this field. |
optional |
boolean | (optional) A boolean whether this field is required to proceed or not. Defaults to false. |
The provided fields object defines the pieces of information the anchor has received for the customer. It is not required unless one or more of provided fields require verification.
Property | Type | Description |
---|---|---|
type |
enum | The data type of the field value. Can be string , binary , number , or date |
description |
string | A human-readable description of this field, especially important if this is not a SEP-9 field. |
choices |
array | (optional) An array of valid values for this field. |
optional |
boolean | (optional) A boolean whether this field is required to proceed or not. Defaults to false. |
status |
string | (optional) One of the values described in Provided Field Statuses. If the server does not wish to expose which field(s) were accepted or rejected, this property can be omitted. |
error |
string | (optional) The human readable description of why the field is REJECTED . |
Status | Description |
---|---|
ACCEPTED | The field has been validated. When all required fields are accepted, the Customer Status should also be accepted. |
PROCESSING | The field is being validated. The client can make GET /customer requests to check on the result of this validation in the future. |
REJECTED | The field was in the PROCESSING status but did not pass validation. If the client may resubmit this field, the Customer Status should be NEEDS_INFO , otherwise it should be REJECTED . |
VERIFICATION_REQUIRED | The field must be verified using the verification process. For example, the mobile_number field could be placed in this status until a confirmation code is sent to the customer and passed back to the this endpoint. |
For requests containing an id
parameter value that does not exist or exists for a customer created by another anchor,
return a 404
response.
{
"error": "customer not found for id: 7e285e7d-d984-412c-97bc-909d0e399fbf"
}
For invalid requests, return a 400
response describing the issue. For example:
{
"error": "unrecognized 'type' value. see valid values in the /info response"
}
Upload customer information to an anchor in an authenticated and idempotent fashion.
PUT [KYC_SERVER || TRANSFER_SERVER]/customer
Content-Type: multipart/form-data;boundary="boundary"
--boundary
Content-Disposition: form-data; name="account"
GBORFR3GDNVZ5PLUTBDQHKGWVD26CQUHORO2T3SDQ2JPLGLUJCCA5GK6
--boundary
Content-Disposition: form-data; name="memo"
21bf91a4-7db1-401d-8108-fab7660a45d6
--boundary--
Content-Type: application/x-www-form-urlencoded
account=GBORFR3GDNVZ5PLUTBDQHKGWVD26CQUHORO2T3SDQ2JPLGLUJCCA5GK6&memo=1273187815064134326&type=sep31-sender
Content-Type: application/json
{
"account": "GBORFR3GDNVZ5PLUTBDQHKGWVD26CQUHORO2T3SDQ2JPLGLUJCCA5GK6",
"memo": "10638330804770506835",
"type": "counterparty_organization"
}
Name | Type | Description |
---|---|---|
id |
string | (optional) The id value returned from a previous call to this endpoint. If specified, no other parameter is required. |
account |
G... or M... string |
(deprecated, optional) The server should infer the account from the sub value in the SEP-10 JWT to identify the customer. The account parameter is only used for backwards compatibility, and if explicitly provided in the request body it should match the sub value of the decoded SEP-10 JWT. |
memo |
string | (optional) the client-generated memo that uniquely identifies the customer. If a memo is present in the decoded SEP-10 JWT's sub value, it must match this parameter value. If a muxed account is used as the JWT's sub value, memos sent in requests must match the 64-bit integer subaccount ID of the muxed account. See the Shared Accounts section for more information. |
memo_type |
string | (deprecated, optional) type of memo . One of text , id or hash . Deprecated because memos should always be of type id , although anchors should continue to support this parameter for outdated clients. If hash , memo should be base64-encoded. If a memo is present in the decoded SEP-10 JWT's sub value, this parameter can be ignored. See the Shared Accounts section for more information. |
type |
string | (optional) The type of the customer as defined in the Type Specification. |
transaction_id |
string |
(optional) The transaction id with which the customer's info is associated. When information from the customer depends on the transaction (e.g., more information is required for larger amounts) |
The wallet should also transmit one or more of the fields listed in SEP-9, depending on what the anchor has indicated it needs.
When uploading data for fields specificed in SEP-9, binary
type fields (typically files) should be
submitted after all other fields. The reason for this is that some web servers require binary
fields at the end so
that they know when they can begin processing the request as a stream.
For any field that require verification (such as mobile number, or email address), it will first receive status
VERIFICATION_REQUIRED
by the application (see fields statuses for details). Afterward, all
such fields should be passed to the PUT /customer
request and suffixed with _verification
string, with an
appropriate verification as the value of the field.
Example:
{
"id": "391fb415-c223-4608-b2f5-dd1e91e3a986",
"email": "[email protected]",
"mobile_number_verification": "123456"
}
In the example above customer with id 391fb415-c223-4608-b2f5-dd1e91e3a986
will update their email and send their
mobile number confirmation to the application. On success, client application will receive an ACCEPTED
status on
mobile_number
field if the application instantly verified the mobile number, and PROCESSING
if it needs time to
process it.
If the anchor received and stored the data successfully, it should respond with a 202 Accepted
or 200 Success
HTTP
status code in addition to a response body containing the customer ID.
Name | Type | Description |
---|---|---|
id |
string |
An identifier for the updated or created customer |
{
"id": "391fb415-c223-4608-b2f5-dd1e91e3a986"
}
The id
can be used in future requests to retrieve the status of the customer or update the customer's information. It
may also be used in other SEPs to identify the customer.
Anchors should return 404 Not Found
for requests including an id
value that does not exist in the database. Anchors
should also return 404
when the id
specified in the request was initially used to create a customer for a different
stellar account.
{
"error": "customer with `id` not found"
}
All error responses should contain details under the error
key. For example:
{
"error": "'photo_id_front' cannot be decoded. Must be jpg or png."
}
{
"error": "The provided confirmation code was invalid."
}
This endpoint has been deprecated in favor of existing PUT /customer
endpoint.
This endpoint allows servers to accept data values, usually confirmation codes, that verify a previously provided field
via PUT /customer
, such as mobile_number
or email_address
. Note that while fields such as photo_proof_residence
or notary_approval_of_photo_id
are verifications of other fields described in SEP-9, the server does
not require the associated fields before verification can be accomplished, so this endpoint would not be useful for
such fields.
Fields in the VERIFICATION_REQUIRED
status require a request to this endpoint.
PUT [KYC_SERVER || TRANSFER_SERVER]/customer/verification
Name | Type | Description |
---|---|---|
id |
string | The ID of the customer as returned in the response of a previous PUT request. |
*_verification |
string | One or more SEP-9 fields appended with _verification . |
{
"id": "391fb415-c223-4608-b2f5-dd1e91e3a986",
"mobile_number_verification": "2735021"
}
Success responses should return a 200 Success
status as well as a body matching the GET /customer
response schema. The field statuses for which verifications were sent must be updated to either PROCESSING
or
ACCEPTED
.
All error responses should contain details under the error
key. If the id
provide is not known, a 404
status
should be returned. On any other client error, use a 400
status.
{
"id": "d1ce2f48-3ff1-495d-9240-7a50d806cfed",
"status": "ACCEPTED",
"provided_fields": {
"mobile_number": {
"description": "phone number of the customer",
"type": "string",
"status": "ACCEPTED"
}
}
}
{
"error": "The provided confirmation code was invalid."
}
Delete all personal information that the anchor has stored about a given customer. [account]
is the Stellar account ID
(G...
) of the customer to delete. This request must be authenticated (via SEP-10) as coming from the
owner of the account that will be deleted. If account
does not uniquely identify an individual customer (a shared
account), the client should include the memo
and memo_type
fields in the request body.
DELETE [KYC_SERVER || TRANSFER_SERVER]/customer/[account]
Name | Type | Description |
---|---|---|
memo |
string | (optional) the client-generated memo that uniquely identifies the customer. If a memo is present in the decoded SEP-10 JWT's sub value, it must match this parameter value. If a muxed account is used as the JWT's sub value, memos sent in requests must match the 64-bit integer subaccount ID of the muxed account. See the Shared Accounts section for more information. |
memo_type |
string | (deprecated, optional) type of memo . One of text , id or hash . Deprecated because memos should always be of type id , although anchors should continue to support this parameter for outdated clients. If hash , memo should be base64-encoded. If a memo is present in the decoded SEP-10 JWT's sub value, this parameter can be ignored. See the Shared Accounts section for more information. |
Situation | Response |
---|---|
Success | 200 OK |
Client not authenticated properly | 401 Unauthorized |
Anchor has no information on the customer | 404 Not Found |
Allow the wallet to provide a callback URL to the anchor. The provided callback URL will replace (and supercede) any previously-set callback URL for this account.
Whenever the user's status
field changes, the anchor will issue a POST request to the callback URL. The payload of the
POST request will be the same as the response of GET /customer
. Anchors will submit POST requests
until the user's status changes to ACCEPTED
or REJECTED
. If a wallet needs to watch a user's KYC status after that,
it will need to set a callback again.
PUT [KYC_SERVER || TRANSFER_SERVER]/customer/callback
Name | Type | Description |
---|---|---|
id |
string |
(optional) The ID of the customer as returned in the response of a previous PUT request. If the customer has not been registered, they do not yet have an id . |
account |
G... or M... string |
(deprecated, optional) The server should infer the account from the sub value in the SEP-10 JWT to identify the customer. The account parameter is only used for backwards compatibility, and if explicitly provided in the request body it should match the sub value of the decoded SEP-10 JWT. |
memo |
string | (optional) the client-generated memo that uniquely identifies the customer. If a memo is present in the decoded SEP-10 JWT's sub value, it must match this parameter value. If a muxed account is used as the JWT's sub value, memos sent in requests must match the 64-bit integer subaccount ID of the muxed account. See the Shared Accounts section for more information. |
memo_type |
string | (deprecated, optional) type of memo . One of text , id or hash . Deprecated because memos should always be of type id , although anchors should continue to support this parameter for outdated clients. If hash , memo should be base64-encoded. If a memo is present in the decoded SEP-10 JWT's sub value, this parameter can be ignored. See the Shared Accounts section for more information. |
url |
string |
A callback URL that the SEP-12 server will POST to when the state of the account changes. |
Situation | Response |
---|---|
Success | 200 OK |
Client not authenticated properly | 401 Unauthorized |
Anchor has no information on the customer | 404 Not Found |
POST [url from PUT request]
See GET /customer reponse
for the POST request fields.
In order to validate the integrity and provenance of the request, the Anchor MUST include a signature in the HTTP Header
Signature
or X-Stellar-Signature
(deprecated). Wallets should support both headers until the X-Stellar-Signature
header is removed from the specification.
These headers MUST follow the specification: t=<timestamp>, s=<base64 signature>
where:
- timestamp is the current Unix timestamp (number of seconds since epoch) at the time the callback is sent. This is used to assure the freshness of the request and to prevent this request to be replayed in the future.
- base64 signature is the base64 encoding of the request signature. We explain below how to compute and verify this
signature. The signature is computed using the Stellar private key linked to the
SIGNING_KEY
field of the anchor'sstellar.toml
. Note that the timestamp and the Wallet hostname will be part of the signature to prevent replay and relay attacks.
It is the wallet's responsibility to:
- Verify the signature using the corresponding Stellar
SIGNING_KEY
field of the anchor'sstellar.toml
. - Verify the freshness of the request by comparing the
timestamp
in the request with the current timestamp at the time of the reception and discard every request above a threshold of few seconds (1 or 2 minute(s) maximum). - Send a working callback URL to the anchor.
- Check that callback request has
Signature
orX-Stellar-Signature
(deprecated) header - Parse the header and extract:
- Key
t
: timestamp - Key
s
: base64 signature
- Key
- Verify the request freshness: current timestamp - timestamp < few seconds (1-2 minute(s) max)
- Extract the body of the request
- Base64 decode the base64 signature to get the signature
- Prepare the payload to verify the signature:
- The timestamp (as a string)
- The character
.
- The wallet host to send the callback request to
- The character
.
- The body
- Verify the signature using the correct
SIGNING_KEY
- Prepare the callback request body
- Prepare the payload to sign:
- Current timestamp (as a string)
- The character
.
- The wallet host to send the callback request to
- The character
.
- The callback request body
- Sign the payload
<timestamp>.<host>.<body>
using the Anchor private key - Base64 encode the signature
- Build the
Signature
orX-Stellar-Signature
(deprecated) header:Signature: t=<current timestamp>, s=<base64 encoded signature>
X-Stellar-Signature: t=<current timestamp>, s=<base64 encoded signature>
Passing binary fields such as photo_id_front
or organization.photo_proof_address
in PUT /customer
requests must be done using the multipart/form-data
content type. This is acceptable in most cases, but
multipart/form-data
does not support nested data structures such as arrays or sub-objects.
This endpoint is intended to decouple requests containing binary fields from requests containing nested data structures,
supported by content types such as application/json
. This endpoint is optional and only needs to be supported if your
use case requires accepting nested data structures in PUT /customer
requests.
Once a file has been uploaded using this endpoint, it's file_id
can be used in subsequent PUT /customer
requests.
The field name for the file_id
should be the appropriate SEP-9 field followed by _file_id
. For
example, if file_abc
is returned as a file_id
from POST /customer/files, it can be used in a
PUT /customer
request like so:
{
"account": "GBORFR3GDNVZ5PLUTBDQHKGWVD26CQUHORO2T3SDQ2JPLGLUJCCA5GK6",
"memo": "21bf91a4-7db1-401d-8108-fab7660a45d6",
"memo_type": "text",
"photo_id_front_file_id": "file_abc"
}
{
"id": "2f417dab-18d2-4081-8c59-c9d3afb59d3f",
"photo_id_front_file_id": "file_abc"
}
POST [KYC_SERVER || TRANSFER_SERVER]/customer/files
Name | Type | Description |
---|---|---|
file |
binary | A file to upload. The file should follow the specifications of RFC 2388 (which defines file transfers for the multipart/form-data protocol). |
Name | Type | Description |
---|---|---|
file_id |
string | Unique identifier for the object. |
content_type |
string | The Content-Type of the file. |
size |
integer | The size in bytes of the file object. |
expires_at |
UTC ISO 8601 string | (optional) The date and time the file will be discarded by the server if not referenced by the client in a PUT /customer request. |
customer_id |
string | (optional) The id of the customer this file is associated with. If the customer record does not yet exist this will be null . |
{
"file_id": "file_d3d54529-6683-4341-9b66-4ac7d7504238",
"content_type": "image/jpeg",
"size": 4089371,
"customer_id": "2bf95490-db23-442d-a1bd-c6fd5efb584e"
}
A 413 Payload Too Large error should be returned when a file exceeds the server's limit, defined by the implementor. A reasonable size limit is 10MB, as most smartphone photos are around 3MB.
All other error responses should use the 400 Bad Request
status and contain details under the error
key.
{
"error": "'photo_id_front' cannot be decoded. Must be jpg or png."
}
GET [KYC_SERVER || TRANSFER_SERVER]/customer/files
One of the following parameters is required.
Name | Type | Description |
---|---|---|
file_id |
string | (optional) The file_id returned from a previous POST /customer/files request. The response's files list will contain a single object if this parameter is used. |
customer_id |
string | (optional) The id returned from a previous PUT /customer request. The response should include all files uploaded for the specified customer. |
Name | Type | Description |
---|---|---|
files |
array | A list file objects as described in the POST /customer/files response. |
{
"files": [
{
"file_id": "file_d5c67b4c-173c-428c-baab-944f4b89a57f",
"content_type": "image/png",
"size": 6134063,
"customer_id": "2bf95490-db23-442d-a1bd-c6fd5efb584e"
},
{
"file_id": "file_d3d54529-6683-4341-9b66-4ac7d7504238",
"content_type": "image/jpeg",
"size": 4089371,
"customer_id": "2bf95490-db23-442d-a1bd-c6fd5efb584e"
}
]
}
All responses should return 200 OK
. If no files are found for the identifer used, an empty list should be returned.
{
"files": []
}
- Flutter SDK: https://github.com/Soneso/stellar_flutter_sdk/blob/master/documentation/sdk_examples/sep-0012-kyc.md
- PHP SDK: https://github.com/Soneso/stellar-php-sdk/blob/main/examples/sep-0012-kyc.md
v1.14.0
: Update SEP31 with async kyc flow (#1502)v1.13.0
: Addtransaction_id
field to/customer
GET
andPUT
(#1432)v1.12.0
: DeprecatePUT /verifcation
and update verification process (#1431)v1.11.1
: Allow anchors to omit the deprecatedX-Stellar-Signature
header (#1335)v1.11.0
: DeprecateX-Stellar-Signature
in favor ofSignature
(#1333)v1.10.0
: Clarify that theaccount
andmemo
fields should be inferred from the decoded SEP-10 JWT'ssub
value even when not provided in the request body.v1.9.1
: Callback signature: using expected host instead of HTTP Header to validate signaturev1.9.0
: Added signature requirement for thecallback