You're viewing **Apigee Edge** documentation.  
[Go to the
**Apigee X** documentation](http://cloud.google.com/apigee/docs/api-platform/publish/portal/publish-apis). info

This section describes how to use the Edge API to create API products for publication in developer portals.

## Create API products using the API


API products enable developers to register
apps that consume APIs using API keys and OAuth access tokens. API products are designed to
enable you to 'bundle' API resources and then publish those bundles to different groups of
developers. For example, you may need to publish one set of API resources to your partner
developers, while you publish another bundle to external developers. API products enable you to
perform this bundling on-the-fly, without requiring any changes to your APIs themselves. An
additional benefit is that developer access can 'upgraded' and 'downgraded' without requiring
developers to obtain new consumer keys for their apps.

To create an API product using the API, issue a POST request to
`/organizations/{org_name}/apiproducts`.
For more information, see [Create API Product](https://apidocs.apigee.com/docs/api-products/1/routes/organizations/%7Borg_name%7D/apiproducts/post) API reference.

The following request creates an API product called `weather_free`. The API product
provides access to all APIs exposed by the API proxy called `weatherapi` that is
deployed in the `test` environment. The approval type is set to `auto` indicating that any
request for access will be approved.

```
curl -X POST https://api.enterprise.apigee.com/v1/organization/myorg/apiproducts \
-H "Content-Type:application/json" \
-d \
'{
  "approvalType": "auto",
  "displayName": "Free API Product",
  "name": "weather_free",
  "proxies": [ "weatherapi" ],
  "environments": [ "test" ]
}' \
-u email:password 
```

Sample response:

```
{
  "apiResources" : [ ],
  "approvalType" : "auto",
  "attributes" : [ ],
  "createdAt" : 1362759663145,
  "createdBy" : "developer@apigee.com",
  "displayName" : "Free API Product",
  "environments" : [ "test" ],
  "lastModifiedAt" : 1362759663145,
  "lastModifiedBy" : "developer@apigee.com",
  "name" : "weather_free",
  "proxies" : [ "weatherapi" ],
  "scopes" : [ ]
}
```

The API product created above implements the most basic scenario, authorizing requests to an
API proxy in an environment. It defines an API product that enables an authorized app to access
any API resources accessed through the API proxy running in the test environment. API products
expose additional configuration settings that enable you to customize access control to your APIs
for different developer groups. For example you can create two API products that provide access
to different API proxies. You can also create two API products that provide access to the same
API proxies, but with different associated Quota settings.

### API product configuration settings

API products expose the following configuration options:

| Name | Description | Default | Required? |
|---|---|---|---|
| `apiResources` | A comma-separated list of URIs, or *resource paths*, 'bundled' into the API product. By default, the resource paths are mapped from the `proxy.pathsuffix` variable. The proxy path suffix is defined as the URI fragment following the ProxyEndpoint base path. For example, in the sample API product below, the `apiResources` element is defined to be `/forecastrss`. Since the Base Path defined for this API proxy is `/weather`, that means that only requests to `/weather/forecastrss` are permitted by this API product. You can select a specific path, or you can select all subpaths with a wildcard. Wildcards (/\*\* and /\*) are supported. The double asterisk wildcard indicates that all sub-URIs are included. A single asterisk indicates that only URIs one level down are included. <br /> By default, **'** /' supports the same resources as '/\*\*' as well as the Base Path defined by the API proxy. For example, if the Base Path of the API proxy is /v1/weatherapikey, then the API product supports requests to /v1/weatherapikey and to any sub-URIs, such as /v1/weatherapikey/forecastrss, /v1/weatherapikey/region/CA, and so on. See [Manage API products](https://docs.apigee.com/api-platform/publish/create-api-products) for information on changing the behavior of this default. | N/A | No |
| `approvalType` | Specifies how API keys are approved to access the APIs defined by the API product. If set to `manual`, the key that is generated for app is in the 'pending' state. Such keys won't work until they have been explicitly approved. If set to `auto`, all keys are generated in the 'approved' and work right away. (`auto` is typically used for providing access to free/trial API products that provide limited Quota or capabilities.) | N/A | Yes |
| `attributes` | Array of attributes that may be used to extend the default API product profile with customer-specific metadata. Use this property to specify the access level of the API product as either public, private, or internal. For example: "attributes": \[ { "name": "access", "value": "public" }, { "name": "foo", "value": "foo" }, { "name": "bar", "value": "bar" } \] | N/A | No |
| `scopes` | A comma-separated list of OAuth scopes that are validated at runtime. (Apigee Edge validates that the scopes in any access token presented match the scope set in the API product.) | N/A | No |
| `proxies` | Named API proxies to which this API product is bound. By specifying proxies, you can associate resources in the API product with specific API proxies, preventing developers from accessing those resources through other API proxies. | N/A | No. If not defined, `apiResources` must be explicitly defined (see the info for `apiResources` above), and `flow.resource.name` variable set in AssignMessage policy. |
| `environments` | Named environments (for example 'test' or 'prod") to which this API product is bound. By specifying one or more environment, you can bind the resources listed in the API product to specific environment, preventing developer from accessing those resources through API proxies in another environment. This setting is used, for example, to prevent resources associated with API proxies in 'prod' from being accessed by API proxies deployed in 'test'. | N/A | No. If not defined, `apiResources` must be explicitly defined, and `flow.resource.name` variable set in AssignMessage policy. |
| `quota` | Number of requests permitted per app over the time interval specified. | N/A | No |
| `quotaInterval` | Number of time units over which quotas are evaluated | N/A | No |
| `quotaTimeUnit` | The time unit (minute, hour, day, or month) over which quotas are counted. | N/A | No |


The following provides a more detailed example for creating an API product.

```
curl -X POST  https://api.enterprise.apigee.com/v1/o/{org_name}/apiproducts \
-H "Content-Type:application/json" -d \
'{
  "apiResources": [ "/forecastrss" ],
  "approvalType": "auto", 
  "attributes":
    [ {"name": "access", "value": "public"} ],
  "description": "Free API Product",
  "displayName": "Free API Product",
  "name": "weather_free",
  "scopes": [],
  "proxies": [ "weatherapi" ],
  "environments": [ "test" ],
  "quota": "10",
  "quotaInterval": "2",
  "quotaTimeUnit": "hour" }' \
-u email:password
```

Sample Response

```
{
  "apiResources" : [ "/forecastrss" ],
  "approvalType" : "auto",
  "attributes" : [ {
    "name" : "access",
    "value" : "public"
  },
  "createdAt" : 1344454200828,
  "createdBy" : "admin@apigee.com",
  "description" : "Free API Product",
  "displayName" : "Free API Product",
  "lastModifiedAt" : 1344454200828,
  "lastModifiedBy" : "admin@apigee.com",
  "name" : "weather_free",
  "scopes" : [ ],
  "proxies": [ {'weatherapi'} ],
  "environments": [ {'test'} ],
  "quota": "10",
  "quotaInterval": "1",
  "quotaTimeUnit": "hour"}'
}
```

### About scopes

A scope is a concept drawn from OAuth and maps roughly to the concept of a 'permission.' On
Apigee Edge, scopes are completely optional. You can use scopes to achieve finer-grained
authorization. Every consumer key issued to an app is associated with a 'master scope'. The
master scope is the set of all scopes in all API products for this the app has been approved. For
apps approved to consume multiple API products, the master scope is the union of all scopes
defined in the API products for which the consumer key has been approved.

## View API products

To view the API products created for an organization using the API, see the following sections:

- [View API products](https://apidocs.apigee.com/docs/monetization/1/routes/mint/organizations/%7Borg_name%7D/products/get)(monetized)

  By default, only monetized API products are displayed (that is, API products with at least one published rate plan).
  To display all API products, set the `monetized` query parameter to `false`. This is equivalent to issuing a GET request to the non-monetized List API products API:
  `https://api.enterprise.apigee.com/v1/organizations/{org_name}/apiproducts?expand=true`
- [View API products](https://docs.apigee.com/management/apis/get/organizations/%7Borg_name%7D/apiproducts-0) (non-monetized)
- [View eligible API products for a developer](https://apidocs.apigee.com/docs/monetization/1/routes/mint/organizations/%7Borg_name%7D/developers/%7Bdeveloper_email%7D/eligible-products/get)
- [View eligible API products for a company](https://apidocs.apigee.com/docs/monetization/1/routes/mint/organizations/%7Borg_name%7D/companies/%7Bcompany_id%7D/eligible-products/get)

The following provides an example of how to view API products using the API:

```
curl -X GET "https://ext.apiexchange.org/v1/mint/organizations/{org_name}/products?monetized=true" \
  -H "Accept:application/json" \
  -u email:password
```

The response should look something like this (only part of the response is shown):

```
{
  "product" : [ {
    "customAtt1Name" : "user",
    "customAtt2Name" : "response size",
    "customAtt3Name" : "content-length",
    "description" : "payment api product",
    "displayName" : "payment",
    "id" : "payment",
    "name" : "payment",
    "organization" : {
      ...
    },
    "pricePoints" : [ ],
    "status" : "CREATED",
    "transactionSuccessCriteria" : "status == 'SUCCESS'"
  }, {
    "customAtt1Name" : "user",
    "customAtt2Name" : "response size",
    "customAtt3Name" : "content-length",
    "description" : "messaging api product",
    "displayName" : "messaging",
    "id" : "messaging",
    "name" : "messaging",
    "organization" : ...
    },
    "pricePoints" : [ ],
    "status" : "CREATED",
    "transactionSuccessCriteria" : "status == 'SUCCESS'"
  } ],
  "totalRecords" : 2
}
```

## Register developers using the API

All apps belong to either developers or companies. Therefore, to create an app, you first need
to register a developer or company.

> [!NOTE]
> **Note:** This section describes how to register apps for developers. You can use the Companies API to set up a company group and the Company Developers API to add developers to the company. See [Companies](https://docs.apigee.com/api/companies-0) and [Company Developers](https://docs.apigee.com/api/company-developers-0) for more.
>
> If you use the Developer Services portal, Apigee recommends that you create, edit, and
> delete developers on the portal itself, not using the Edge management API. For more
> information, see [Add
> and manage user accounts](https://docs.apigee.com/api-platform/publish/drupal/add-and-manage-user-accounts).

Developers are registered in an organization by creating a profile. Note that the developer
email that is included in the profile is used as the unique key for the developer throughout
Apigee Edge.

To support monetization, you must define the [monetization
attributes](https://docs.apigee.com/api-platform/publish/adding-developers-your-api-product#monetization-attributes) when creating or editing developers. You can also define other arbitrary
attributes for use in custom analytics, custom policy enforcement, and so on; these arbitrary
attributes will not be interpreted by Apigee Edge,

For example, the following request registers a profile for a developer whose email address is
`ntesla@theremin.com` and defines a subset of monetization
attributes using the [Create developer](https://apidocs.apigee.com/docs/developers/1/routes/organizations/%7Borg_name%7D/developers/post) API:

```
$ curl -H "Content-type:application/json" -X POST -d \
'{"email" : "ntesla@theremin.com", 
  "firstName" : "Nikola", 
  "lastName" : "Tesla", 
  "userName" : "theremin", 
  "attributes" : [ 
  { 
    "name" : "project_type", 
    "value" : "public"
  },
  {    
   "name": "MINT_BILLING_TYPE",
   "value": "POSTPAID"
  },
  {
   "name": "MINT_DEVELOPER_ADDRESS",
   "value": "{\"address1\":\"Dev One Address\",\"city\":\"Pleasanton\",\"country\":\"US\",\"isPrimary\":true,\"state\":\"CA\",\"zip\":\"94588\"}"
  },
  {
   "name": "MINT_DEVELOPER_TYPE",
   "value": "TRUSTED"
  },
  {    
   "name": "MINT_HAS_SELF_BILLING,
   "value": "FALSE"
  },
  {
   "name" : "MINT_SUPPORTED_CURRENCY",
   "value" : "usd"
  }
 ] 
}' \
https://api.enterprise.apigee.com/v1/o/{org_name}/developers \
-u email:password 
```

Sample Response

```
{
          "email" : "ntesla@theremin.com",
          "firstName" : "Nikola",
          "lastName" : "Tesla",
          "userName" : "theremin",
          "organizationName" : "{org_name}",
          "status" : "active",
          "attributes" : [ 
          {
            "name" : "project_type",
            "value" : "public"
          },
          {    
             "name": "MINT_BILLING_TYPE",
             "value": "POSTPAID"
          },
          {
             "name": "MINT_DEVELOPER_ADDRESS",
             "value": "{\"address1\":\"Dev One Address\",\"city\":\"Pleasanton\",\"country\":\"US\",\"isPrimary\":true,\"state\":\"CA\",\"zip\":\"94588\"}"
          },
          {
             "name": "MINT_DEVELOPER_TYPE",
             "value": "TRUSTED"
          },
          {    
             "name": "MINT_HAS_SELF_BILLING,
             "value": "FALSE"
          },
          {
             "name" : "MINT_SUPPORTED_CURRENCY",
             "value" : "usd"
          } 
          ],
          "createdAt" : 1343189787717,
          "createdBy" : "admin@apigee.com",
          "lastModifiedAt" : 1343189787717,
          "lastModifiedBy" : "admin@apigee.com"
        }
```

## Register developer apps using the API

Every app that is registered on Apigee Edge is associated with a developer and an API product.
When an app is registered on behalf of a developer, Apigee Edge generates a "credential" (a
consumer key and secret pair) that identifies the app. The app then must pass these credentials
as part of every request to an API product associated with the app.
The following request uses the [Create
Developer App](https://docs.apigee.com/management/apis/post/organizations/{org_name}/developers/{developer_email}/apps) API to register an app for the developer you created above: ntesla@theremin.com. When registering an app you define a name for the app, a callbackUrl, and a list of one or more API products:

```
$ curl -H "Content-type:application/json" -X POST -d \
'{
  "apiProducts": [ "weather_free"], 
  "callbackUrl" : "login.weatherapp.com", 
  "keyExpiresIn" : "2630000000",
  "name" : "weatherapp"}' \
https://api.enterprise.apigee.com/v1/o/{org_name}/developers/ntesla@theremin.com/apps \
-u email:password 
```

The callbackUrl is used by
some OAuth grant types (such as authorization code) to validate redirect requests from the app.
If you use OAuth, then this value must be set to the same value as the `redirect_uri`
used to make OAuth requests.

The `keyExpiresIn` attribute specifies, in milliseconds, for the lifetime of the
consumer key that will be generated for the developer app. The default value, -1, indicates an
infinite validity period.

> [!NOTE]
> **Note:** You cannot update the expiration time of any existing consumer keys. You can only generate new keys with certain expiration time.

Sample Response

```
{
  "appId": "5760d130-528f-4388-8c6f-65a6b3042bd1",
  "attributes": [
    {
      "name": "DisplayName",
      "value": "Test Key Expires"
    },
    {
      "name": "Notes",
      "value": "Just testing this attribute"
    }
  ],
  "createdAt": 1421770824390,
  "createdBy": "wwitman@apigee.com",
  "credentials": [
    {
      "apiProducts": [
        {
          "apiproduct": "ProductNoResources",
          "status": "approved"
        }
      ],
      "attributes": [],
      "consumerKey": "jcAFDcfwImkJ19A5gTsZRzfBItlqohBt",
      "consumerSecret": "AX7lGGIRJs6s8J8y",
      "expiresAt": 1424400824401,
      "issuedAt": 1421770824401,
      "scopes": [],
      "status": "approved"
    }
  ],
  "developerId": "e4Oy8ddTo3p1BFhs",
  "lastModifiedAt": 1421770824390,
  "lastModifiedBy": "wwitman@apigee.com",
  "name": "TestKeyExpires",
  "scopes": [],
  "status": "approved"
}
```

> [!NOTE]
> **Note:** If you delete an app, all client keys associated with the apps become invalid. Using an invalid key on a request causes the request to fail. See [Delete
> Developer App](https://docs.apigee.com/management/apis/delete/organizations/{org_name}/developers/{developer_email}/apps/{app_name}) for the API to delete an app.

## Manage consumer keys for apps using the API

### Get the consumer key
(the API Key) for the app

The credentials for an app, (API product, consumer key and secret) are returned as part of the
app profile. An administrator of an organization can retrieve the consumer key at any time.

The app profile displays the value of the consumer key and secret, the status of the consumer
key, as well as any API product associations for the key. As an admin, you can retrieve the
consumer key profile at any time using the **Get Key Details for a Developer App
API**:

```
$ curl -X GET -H "Accept: application/json" \
https://api.enterprise.apigee.com/v1/o/{org_name}/developers/ntesla@theremin.com/apps/weatherapp/keys/HQg0nCZ54adKobpqEJaE8FefGkdKFc2J \
-u email:password
```

Sample Response

```
{
  "apiProducts" : [ {
    "apiproduct" : "weather_free",
    "status" : "approved"
  } ],
  "attributes" : [ ],
  "consumerKey" : "HQg0nCZ54adKobpqEJaE8FefGkdKFc2J",
  "consumerSecret" : "1eluIIdWG3JGDjE0",
  "status" : "approved"
}
```

See [Get Key Details for a Developer App](https://docs.apigee.com/management/apis/get/organizations/{org_name}/developers/{developer_email}/apps/{app_name}/keys/{consumer_key}-0) for more.

### Add an API product to an
app and key

To update an app to add a new API product, you actually add the API product to the app's key
using the **Add API Product to Key API** . See [Add API Product to Key](https://docs.apigee.com/management/apis/post/organizations/{org_name}/developers/{developer_email}/apps/{app_name}/keys/{consumer_key}) for more.

Adding an API product to an app key enables the app that holds the key to access the API
resources bundled in the API product. The following method call adds a new API product to an
app:

```
$ curl -H "Content-type:application/json" -X POST -d \
'{
  "apiProducts": [ "newAPIProduct"]
}' \
https://api.enterprise.apigee.com/v1/o/{org_name}/developers/ntesla@theremin.com/apps/weatherapp/keys/HQg0nCZ54adKobpqEJaE8FefGkdKFc2J \
-u email:password 
```

Sample Response:

```
{
  "apiProducts": [
   {
     "apiproduct": "weather_free",
     "status": "approved"
   },
   {
     "apiproduct": "newAPIProduct",
     "status": "approved"
   }
 ],
 "attributes": [],
 "consumerKey": "HQg0nCZ54adKobpqEJaE8FefGkdKFc2J",
 "consumerSecret": "1eluIIdWG3JGDjE0",
 "expiresAt": -1,
 "issuedAt": 1411491156464,
 "scopes": [],
 "status": "approved"
 }
```

### Approve consumer keys

Setting approval type to manual enables you to control which
developers can access the resources protected by API products. When API products have key
approval set to `manual`, consumer keys must be explicitly approved. Keys can be
explicitly approved using the **Approve or Revoke Specific Key of Developer App**
API:

```
$ curl -X POST -H "Content-type:appilcation/octet-stream" \ 
https://api.enterprise.apigee.com/v1/o/{org_name}/developers/ntesla@theremin.com/apps/weatherapp/keys/HQg0nCZ54adKobpqEJaE8FefGkdKFc2J?"action=approve" \
-u email:password
```

Sample Response

```
{
  "apiProducts" : [ {
  "apiproduct" : "weather_free",
  "status" : "approved"
} ],
  "attributes" : [ ],
  "consumerKey" : "HQg0nCZ54adKobpqEJaE8FefGkdKFc2J",
  "consumerSecret" : "1eluIIdWG3JGDjE0",
  "status" : "approved"
}
```

See [Approve or Revoke Specific Key of Developer App](https://docs.apigee.com/management/apis/post/organizations/{org_name}/developers/{developer_email}/apps/{app_name}/keys/{consumer_key}-0) for more.

### Approve API products
for consumer keys

The association of an API product with a consumer key also has a status. For API access to be
successful, the consumer key must be approved, *and* the consumer key must be approved for
the appropriate API product. The association of a consumer key with an API product can be
approved by using the **Approve or Revoke API Product for a Key for a Developer
App** API:

```
$ curl -X POST -H "Content-type:application/octet-stream" \ 
https://api.enterprise.apigee.com/v1/o/{org_name}/developers/ntesla@theremin.com/apps/weatherapp/keys/HQg0nCZ54adKobpqEJaE8FefGkdKFc2J/apiproducts/weather_free?"action=approve" \
-u email:password
```

This cURL command does not return a response. See [Approve or Revoke API Product for a Key for a Developer App](https://docs.apigee.com/management/apis/post/organizations/{org_name}/developers/{developer_email}/apps/{app_name}/keys/{consumer_key}/apiproducts/{apiproduct_name}) for more.

### Revoke API products for
consumer keys

There are many reasons why you may need to revoke a consumer key's association with an API
product. You may need to remove an API product from a consumer key due to non-payment by the
developer, an expired trial period, or When an app is promoted from one API product to
another.

To revoke the association of a consumer key with an API product, use the **Approve
or Revoke Specific Key of Developer App**API, using the action revoke against the
consumer key of the develop app:

```
$ curl -X POST -H "Content-type:application/octet-stream" \ 
https://api.enterprise.apigee.com/v1/o/{org_name}/developers/ntesla@theremin.com/apps/weatherapp/keys/HQg0nCZ54adKobpqEJaE8FefGkdKFc2J/apiproducts/weather_free?"action=revoke" \
-u email:password
```

This cURL command does not return a response. See [Approve or Revoke Specific Key of Developer App](https://docs.apigee.com/management/apis/post/organizations/{org_name}/developers/{developer_email}/apps/{app_name}/keys/{consumer_key}-0) for more.

## Enforce API product settings

> [!IMPORTANT]
> **Tip:** API product settings are enforced by matching policies, such as VerifyAPIKey, OAuthV2, and Quota. Until those policies are attached to API proxies, API products and quotas will not be enforced by Apigee Edge.

For API products to be enforced, one of the following policy types must be attached to the API
proxy flow:

- VerifyAPIKey: Takes a reference to an API key, verifies that it represents a valid app, and matches the API product. See [Verify API Key policy](https://docs.apigee.com/api-platform/reference/policies/verify-api-key-policy) for more.
- OAuthV1, "VerifyAccessToken" operation: Verifies the signature, validates an OAuth 1.0a access token and "consumer key", and matches the app to the API product. Support for OAuth 1.0a is deprecated; see [Deprecated features](https://docs.apigee.com/release/deprecated-features#deprecations).
- OAuthV2, "VerifyAccessToken" operation: Verifies that the OAuth 2.0 access token is valid, matches the token to the app, verifies that the app is valid, and then matches the app to an API product. See [OAuth
  home](https://docs.apigee.com/api-platform/security/oauth/oauth-home) for more.

Once policies and API products are configured, the following process is executed by Apigee
Edge:

1. A request is received by Apigee Edge and routed to the appropriate API proxy.
2. A policy is executed that verifies the API key or OAuth access token presented by the client.
3. Edge resolves the API Key or access token to an app profile.
4. Edge resolves the list (if any) of API products associated with the app.
5. The first API product that matches is used to populate Quota variables.
6. If no API product matches the API key or access token, then the request is rejected.
7. Edge enforces URI-based access control (environment, API proxy, and URI path) based on the API product settings, along with Quota settings.